ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / lib / vsprintf.c
1 /*
2  *  linux/lib/vsprintf.c
3  *
4  *  Copyright (C) 1991, 1992  Linus Torvalds
5  */
6
7 /* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
8 /*
9  * Wirzenius wrote this portably, Torvalds fucked it up :-)
10  */
11
12 /* 
13  * Fri Jul 13 2001 Crutcher Dunnavant <crutcher+kernel@datastacks.com>
14  * - changed to provide snprintf and vsnprintf functions
15  * So Feb  1 16:51:32 CET 2004 Juergen Quade <quade@hsnr.de>
16  * - scnprintf and vscnprintf
17  */
18
19 #include <stdarg.h>
20 #include <linux/module.h>
21 #include <linux/types.h>
22 #include <linux/string.h>
23 #include <linux/ctype.h>
24 #include <linux/kernel.h>
25
26 #include <asm/div64.h>
27
28 /**
29  * simple_strtoul - convert a string to an unsigned long
30  * @cp: The start of the string
31  * @endp: A pointer to the end of the parsed string will be placed here
32  * @base: The number base to use
33  */
34 unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
35 {
36         unsigned long result = 0,value;
37
38         if (!base) {
39                 base = 10;
40                 if (*cp == '0') {
41                         base = 8;
42                         cp++;
43                         if ((*cp == 'x') && isxdigit(cp[1])) {
44                                 cp++;
45                                 base = 16;
46                         }
47                 }
48         }
49         while (isxdigit(*cp) &&
50                (value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) {
51                 result = result*base + value;
52                 cp++;
53         }
54         if (endp)
55                 *endp = (char *)cp;
56         return result;
57 }
58
59 EXPORT_SYMBOL(simple_strtoul);
60
61 /**
62  * simple_strtol - convert a string to a signed long
63  * @cp: The start of the string
64  * @endp: A pointer to the end of the parsed string will be placed here
65  * @base: The number base to use
66  */
67 long simple_strtol(const char *cp,char **endp,unsigned int base)
68 {
69         if(*cp=='-')
70                 return -simple_strtoul(cp+1,endp,base);
71         return simple_strtoul(cp,endp,base);
72 }
73
74 EXPORT_SYMBOL(simple_strtol);
75
76 /**
77  * simple_strtoull - convert a string to an unsigned long long
78  * @cp: The start of the string
79  * @endp: A pointer to the end of the parsed string will be placed here
80  * @base: The number base to use
81  */
82 unsigned long long simple_strtoull(const char *cp,char **endp,unsigned int base)
83 {
84         unsigned long long result = 0,value;
85
86         if (!base) {
87                 base = 10;
88                 if (*cp == '0') {
89                         base = 8;
90                         cp++;
91                         if ((*cp == 'x') && isxdigit(cp[1])) {
92                                 cp++;
93                                 base = 16;
94                         }
95                 }
96         }
97         while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
98             ? toupper(*cp) : *cp)-'A'+10) < base) {
99                 result = result*base + value;
100                 cp++;
101         }
102         if (endp)
103                 *endp = (char *)cp;
104         return result;
105 }
106
107 EXPORT_SYMBOL(simple_strtoull);
108
109 /**
110  * simple_strtoll - convert a string to a signed long long
111  * @cp: The start of the string
112  * @endp: A pointer to the end of the parsed string will be placed here
113  * @base: The number base to use
114  */
115 long long simple_strtoll(const char *cp,char **endp,unsigned int base)
116 {
117         if(*cp=='-')
118                 return -simple_strtoull(cp+1,endp,base);
119         return simple_strtoull(cp,endp,base);
120 }
121
122 static int skip_atoi(const char **s)
123 {
124         int i=0;
125
126         while (isdigit(**s))
127                 i = i*10 + *((*s)++) - '0';
128         return i;
129 }
130
131 #define ZEROPAD 1               /* pad with zero */
132 #define SIGN    2               /* unsigned/signed long */
133 #define PLUS    4               /* show plus */
134 #define SPACE   8               /* space if plus */
135 #define LEFT    16              /* left justified */
136 #define SPECIAL 32              /* 0x */
137 #define LARGE   64              /* use 'ABCDEF' instead of 'abcdef' */
138
139 static char * number(char * buf, char * end, unsigned long long num, int base, int size, int precision, int type)
140 {
141         char c,sign,tmp[66];
142         const char *digits;
143         static const char small_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
144         static const char large_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
145         int i;
146
147         digits = (type & LARGE) ? large_digits : small_digits;
148         if (type & LEFT)
149                 type &= ~ZEROPAD;
150         if (base < 2 || base > 36)
151                 return 0;
152         c = (type & ZEROPAD) ? '0' : ' ';
153         sign = 0;
154         if (type & SIGN) {
155                 if ((signed long long) num < 0) {
156                         sign = '-';
157                         num = - (signed long long) num;
158                         size--;
159                 } else if (type & PLUS) {
160                         sign = '+';
161                         size--;
162                 } else if (type & SPACE) {
163                         sign = ' ';
164                         size--;
165                 }
166         }
167         if (type & SPECIAL) {
168                 if (base == 16)
169                         size -= 2;
170                 else if (base == 8)
171                         size--;
172         }
173         i = 0;
174         if (num == 0)
175                 tmp[i++]='0';
176         else while (num != 0)
177                 tmp[i++] = digits[do_div(num,base)];
178         if (i > precision)
179                 precision = i;
180         size -= precision;
181         if (!(type&(ZEROPAD+LEFT))) {
182                 while(size-->0) {
183                         if (buf <= end)
184                                 *buf = ' ';
185                         ++buf;
186                 }
187         }
188         if (sign) {
189                 if (buf <= end)
190                         *buf = sign;
191                 ++buf;
192         }
193         if (type & SPECIAL) {
194                 if (base==8) {
195                         if (buf <= end)
196                                 *buf = '0';
197                         ++buf;
198                 } else if (base==16) {
199                         if (buf <= end)
200                                 *buf = '0';
201                         ++buf;
202                         if (buf <= end)
203                                 *buf = digits[33];
204                         ++buf;
205                 }
206         }
207         if (!(type & LEFT)) {
208                 while (size-- > 0) {
209                         if (buf <= end)
210                                 *buf = c;
211                         ++buf;
212                 }
213         }
214         while (i < precision--) {
215                 if (buf <= end)
216                         *buf = '0';
217                 ++buf;
218         }
219         while (i-- > 0) {
220                 if (buf <= end)
221                         *buf = tmp[i];
222                 ++buf;
223         }
224         while (size-- > 0) {
225                 if (buf <= end)
226                         *buf = ' ';
227                 ++buf;
228         }
229         return buf;
230 }
231
232 /**
233  * vsnprintf - Format a string and place it in a buffer
234  * @buf: The buffer to place the result into
235  * @size: The size of the buffer, including the trailing null space
236  * @fmt: The format string to use
237  * @args: Arguments for the format string
238  *
239  * The return value is the number of characters which would
240  * be generated for the given input, excluding the trailing
241  * '\0', as per ISO C99. If you want to have the exact
242  * number of characters written into @buf as return value
243  * (not including the trailing '\0'), use vscnprintf. If the
244  * return is greater than or equal to @size, the resulting
245  * string is truncated.
246  *
247  * Call this function if you are already dealing with a va_list.
248  * You probably want snprintf instead.
249  */
250 int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
251 {
252         int len;
253         unsigned long long num;
254         int i, base;
255         char *str, *end, c;
256         const char *s;
257
258         int flags;              /* flags to number() */
259
260         int field_width;        /* width of output field */
261         int precision;          /* min. # of digits for integers; max
262                                    number of chars for from string */
263         int qualifier;          /* 'h', 'l', or 'L' for integer fields */
264                                 /* 'z' support added 23/7/1999 S.H.    */
265                                 /* 'z' changed to 'Z' --davidm 1/25/99 */
266
267         /* Reject out-of-range values early */
268         if (unlikely((int) size < 0)) {
269                 /* There can be only one.. */
270                 static int warn = 1;
271                 WARN_ON(warn);
272                 warn = 0;
273                 return 0;
274         }
275
276         str = buf;
277         end = buf + size - 1;
278
279         if (end < buf - 1) {
280                 end = ((void *) -1);
281                 size = end - buf + 1;
282         }
283
284         for (; *fmt ; ++fmt) {
285                 if (*fmt != '%') {
286                         if (str <= end)
287                                 *str = *fmt;
288                         ++str;
289                         continue;
290                 }
291
292                 /* process flags */
293                 flags = 0;
294                 repeat:
295                         ++fmt;          /* this also skips first '%' */
296                         switch (*fmt) {
297                                 case '-': flags |= LEFT; goto repeat;
298                                 case '+': flags |= PLUS; goto repeat;
299                                 case ' ': flags |= SPACE; goto repeat;
300                                 case '#': flags |= SPECIAL; goto repeat;
301                                 case '0': flags |= ZEROPAD; goto repeat;
302                         }
303
304                 /* get field width */
305                 field_width = -1;
306                 if (isdigit(*fmt))
307                         field_width = skip_atoi(&fmt);
308                 else if (*fmt == '*') {
309                         ++fmt;
310                         /* it's the next argument */
311                         field_width = va_arg(args, int);
312                         if (field_width < 0) {
313                                 field_width = -field_width;
314                                 flags |= LEFT;
315                         }
316                 }
317
318                 /* get the precision */
319                 precision = -1;
320                 if (*fmt == '.') {
321                         ++fmt;  
322                         if (isdigit(*fmt))
323                                 precision = skip_atoi(&fmt);
324                         else if (*fmt == '*') {
325                                 ++fmt;
326                                 /* it's the next argument */
327                                 precision = va_arg(args, int);
328                         }
329                         if (precision < 0)
330                                 precision = 0;
331                 }
332
333                 /* get the conversion qualifier */
334                 qualifier = -1;
335                 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
336                     *fmt =='Z' || *fmt == 'z') {
337                         qualifier = *fmt;
338                         ++fmt;
339                         if (qualifier == 'l' && *fmt == 'l') {
340                                 qualifier = 'L';
341                                 ++fmt;
342                         }
343                 }
344
345                 /* default base */
346                 base = 10;
347
348                 switch (*fmt) {
349                         case 'c':
350                                 if (!(flags & LEFT)) {
351                                         while (--field_width > 0) {
352                                                 if (str <= end)
353                                                         *str = ' ';
354                                                 ++str;
355                                         }
356                                 }
357                                 c = (unsigned char) va_arg(args, int);
358                                 if (str <= end)
359                                         *str = c;
360                                 ++str;
361                                 while (--field_width > 0) {
362                                         if (str <= end)
363                                                 *str = ' ';
364                                         ++str;
365                                 }
366                                 continue;
367
368                         case 's':
369                                 s = va_arg(args, char *);
370                                 if ((unsigned long)s < PAGE_SIZE)
371                                         s = "<NULL>";
372
373                                 len = strnlen(s, precision);
374
375                                 if (!(flags & LEFT)) {
376                                         while (len < field_width--) {
377                                                 if (str <= end)
378                                                         *str = ' ';
379                                                 ++str;
380                                         }
381                                 }
382                                 for (i = 0; i < len; ++i) {
383                                         if (str <= end)
384                                                 *str = *s;
385                                         ++str; ++s;
386                                 }
387                                 while (len < field_width--) {
388                                         if (str <= end)
389                                                 *str = ' ';
390                                         ++str;
391                                 }
392                                 continue;
393
394                         case 'p':
395                                 if (field_width == -1) {
396                                         field_width = 2*sizeof(void *);
397                                         flags |= ZEROPAD;
398                                 }
399                                 str = number(str, end,
400                                                 (unsigned long) va_arg(args, void *),
401                                                 16, field_width, precision, flags);
402                                 continue;
403
404
405                         case 'n':
406                                 /* FIXME:
407                                 * What does C99 say about the overflow case here? */
408                                 if (qualifier == 'l') {
409                                         long * ip = va_arg(args, long *);
410                                         *ip = (str - buf);
411                                 } else if (qualifier == 'Z' || qualifier == 'z') {
412                                         size_t * ip = va_arg(args, size_t *);
413                                         *ip = (str - buf);
414                                 } else {
415                                         int * ip = va_arg(args, int *);
416                                         *ip = (str - buf);
417                                 }
418                                 continue;
419
420                         case '%':
421                                 if (str <= end)
422                                         *str = '%';
423                                 ++str;
424                                 continue;
425
426                                 /* integer number formats - set up the flags and "break" */
427                         case 'o':
428                                 base = 8;
429                                 break;
430
431                         case 'X':
432                                 flags |= LARGE;
433                         case 'x':
434                                 base = 16;
435                                 break;
436
437                         case 'd':
438                         case 'i':
439                                 flags |= SIGN;
440                         case 'u':
441                                 break;
442
443                         default:
444                                 if (str <= end)
445                                         *str = '%';
446                                 ++str;
447                                 if (*fmt) {
448                                         if (str <= end)
449                                                 *str = *fmt;
450                                         ++str;
451                                 } else {
452                                         --fmt;
453                                 }
454                                 continue;
455                 }
456                 if (qualifier == 'L')
457                         num = va_arg(args, long long);
458                 else if (qualifier == 'l') {
459                         num = va_arg(args, unsigned long);
460                         if (flags & SIGN)
461                                 num = (signed long) num;
462                 } else if (qualifier == 'Z' || qualifier == 'z') {
463                         num = va_arg(args, size_t);
464                 } else if (qualifier == 'h') {
465                         num = (unsigned short) va_arg(args, int);
466                         if (flags & SIGN)
467                                 num = (signed short) num;
468                 } else {
469                         num = va_arg(args, unsigned int);
470                         if (flags & SIGN)
471                                 num = (signed int) num;
472                 }
473                 str = number(str, end, num, base,
474                                 field_width, precision, flags);
475         }
476         if (str <= end)
477                 *str = '\0';
478         else if (size > 0)
479                 /* don't write out a null byte if the buf size is zero */
480                 *end = '\0';
481         /* the trailing null byte doesn't count towards the total
482         * ++str;
483         */
484         return str-buf;
485 }
486
487 EXPORT_SYMBOL(vsnprintf);
488
489 /**
490  * vscnprintf - Format a string and place it in a buffer
491  * @buf: The buffer to place the result into
492  * @size: The size of the buffer, including the trailing null space
493  * @fmt: The format string to use
494  * @args: Arguments for the format string
495  *
496  * The return value is the number of characters which have been written into
497  * the @buf not including the trailing '\0'. If @size is <= 0 the function
498  * returns 0.
499  *
500  * Call this function if you are already dealing with a va_list.
501  * You probably want scnprintf instead.
502  */
503 int vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
504 {
505         int i;
506
507         i=vsnprintf(buf,size,fmt,args);
508         return (i >= size) ? (size - 1) : i;
509 }
510
511 EXPORT_SYMBOL(vscnprintf);
512
513 /**
514  * snprintf - Format a string and place it in a buffer
515  * @buf: The buffer to place the result into
516  * @size: The size of the buffer, including the trailing null space
517  * @fmt: The format string to use
518  * @...: Arguments for the format string
519  *
520  * The return value is the number of characters which would be
521  * generated for the given input, excluding the trailing null,
522  * as per ISO C99.  If the return is greater than or equal to
523  * @size, the resulting string is truncated.
524  */
525 int snprintf(char * buf, size_t size, const char *fmt, ...)
526 {
527         va_list args;
528         int i;
529
530         va_start(args, fmt);
531         i=vsnprintf(buf,size,fmt,args);
532         va_end(args);
533         return i;
534 }
535
536 EXPORT_SYMBOL(snprintf);
537
538 /**
539  * scnprintf - Format a string and place it in a buffer
540  * @buf: The buffer to place the result into
541  * @size: The size of the buffer, including the trailing null space
542  * @fmt: The format string to use
543  * @...: Arguments for the format string
544  *
545  * The return value is the number of characters written into @buf not including
546  * the trailing '\0'. If @size is <= 0 the function returns 0. If the return is
547  * greater than or equal to @size, the resulting string is truncated.
548  */
549
550 int scnprintf(char * buf, size_t size, const char *fmt, ...)
551 {
552         va_list args;
553         int i;
554
555         va_start(args, fmt);
556         i = vsnprintf(buf, size, fmt, args);
557         va_end(args);
558         return (i >= size) ? (size - 1) : i;
559 }
560 EXPORT_SYMBOL(scnprintf);
561
562 /**
563  * vsprintf - Format a string and place it in a buffer
564  * @buf: The buffer to place the result into
565  * @fmt: The format string to use
566  * @args: Arguments for the format string
567  *
568  * The function returns the number of characters written
569  * into @buf. Use vsnprintf or vscnprintf in order to avoid
570  * buffer overflows.
571  *
572  * Call this function if you are already dealing with a va_list.
573  * You probably want sprintf instead.
574  */
575 int vsprintf(char *buf, const char *fmt, va_list args)
576 {
577         return vsnprintf(buf, (~0U)>>1, fmt, args);
578 }
579
580 EXPORT_SYMBOL(vsprintf);
581
582 /**
583  * sprintf - Format a string and place it in a buffer
584  * @buf: The buffer to place the result into
585  * @fmt: The format string to use
586  * @...: Arguments for the format string
587  *
588  * The function returns the number of characters written
589  * into @buf. Use snprintf or scnprintf in order to avoid
590  * buffer overflows.
591  */
592 int sprintf(char * buf, const char *fmt, ...)
593 {
594         va_list args;
595         int i;
596
597         va_start(args, fmt);
598         i=vsprintf(buf,fmt,args);
599         va_end(args);
600         return i;
601 }
602
603 EXPORT_SYMBOL(sprintf);
604
605 /**
606  * vsscanf - Unformat a buffer into a list of arguments
607  * @buf:        input buffer
608  * @fmt:        format of buffer
609  * @args:       arguments
610  */
611 int vsscanf(const char * buf, const char * fmt, va_list args)
612 {
613         const char *str = buf;
614         char *next;
615         char digit;
616         int num = 0;
617         int qualifier;
618         int base;
619         int field_width;
620         int is_sign = 0;
621
622         while(*fmt && *str) {
623                 /* skip any white space in format */
624                 /* white space in format matchs any amount of
625                  * white space, including none, in the input.
626                  */
627                 if (isspace(*fmt)) {
628                         while (isspace(*fmt))
629                                 ++fmt;
630                         while (isspace(*str))
631                                 ++str;
632                 }
633
634                 /* anything that is not a conversion must match exactly */
635                 if (*fmt != '%' && *fmt) {
636                         if (*fmt++ != *str++)
637                                 break;
638                         continue;
639                 }
640
641                 if (!*fmt)
642                         break;
643                 ++fmt;
644                 
645                 /* skip this conversion.
646                  * advance both strings to next white space
647                  */
648                 if (*fmt == '*') {
649                         while (!isspace(*fmt) && *fmt)
650                                 fmt++;
651                         while (!isspace(*str) && *str)
652                                 str++;
653                         continue;
654                 }
655
656                 /* get field width */
657                 field_width = -1;
658                 if (isdigit(*fmt))
659                         field_width = skip_atoi(&fmt);
660
661                 /* get conversion qualifier */
662                 qualifier = -1;
663                 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
664                     *fmt == 'Z' || *fmt == 'z') {
665                         qualifier = *fmt;
666                         fmt++;
667                 }
668                 base = 10;
669                 is_sign = 0;
670
671                 if (!*fmt || !*str)
672                         break;
673
674                 switch(*fmt++) {
675                 case 'c':
676                 {
677                         char *s = (char *) va_arg(args,char*);
678                         if (field_width == -1)
679                                 field_width = 1;
680                         do {
681                                 *s++ = *str++;
682                         } while (--field_width > 0 && *str);
683                         num++;
684                 }
685                 continue;
686                 case 's':
687                 {
688                         char *s = (char *) va_arg(args, char *);
689                         if(field_width == -1)
690                                 field_width = INT_MAX;
691                         /* first, skip leading white space in buffer */
692                         while (isspace(*str))
693                                 str++;
694
695                         /* now copy until next white space */
696                         while (*str && !isspace(*str) && field_width--) {
697                                 *s++ = *str++;
698                         }
699                         *s = '\0';
700                         num++;
701                 }
702                 continue;
703                 case 'n':
704                         /* return number of characters read so far */
705                 {
706                         int *i = (int *)va_arg(args,int*);
707                         *i = str - buf;
708                 }
709                 continue;
710                 case 'o':
711                         base = 8;
712                         break;
713                 case 'x':
714                 case 'X':
715                         base = 16;
716                         break;
717                 case 'i':
718                         base = 0;
719                 case 'd':
720                         is_sign = 1;
721                 case 'u':
722                         break;
723                 case '%':
724                         /* looking for '%' in str */
725                         if (*str++ != '%') 
726                                 return num;
727                         continue;
728                 default:
729                         /* invalid format; stop here */
730                         return num;
731                 }
732
733                 /* have some sort of integer conversion.
734                  * first, skip white space in buffer.
735                  */
736                 while (isspace(*str))
737                         str++;
738
739                 digit = *str;
740                 if (is_sign && digit == '-')
741                         digit = *(str + 1);
742
743                 if (!digit
744                     || (base == 16 && !isxdigit(digit))
745                     || (base == 10 && !isdigit(digit))
746                     || (base == 8 && (!isdigit(digit) || digit > '7'))
747                     || (base == 0 && !isdigit(digit)))
748                                 break;
749
750                 switch(qualifier) {
751                 case 'h':
752                         if (is_sign) {
753                                 short *s = (short *) va_arg(args,short *);
754                                 *s = (short) simple_strtol(str,&next,base);
755                         } else {
756                                 unsigned short *s = (unsigned short *) va_arg(args, unsigned short *);
757                                 *s = (unsigned short) simple_strtoul(str, &next, base);
758                         }
759                         break;
760                 case 'l':
761                         if (is_sign) {
762                                 long *l = (long *) va_arg(args,long *);
763                                 *l = simple_strtol(str,&next,base);
764                         } else {
765                                 unsigned long *l = (unsigned long*) va_arg(args,unsigned long*);
766                                 *l = simple_strtoul(str,&next,base);
767                         }
768                         break;
769                 case 'L':
770                         if (is_sign) {
771                                 long long *l = (long long*) va_arg(args,long long *);
772                                 *l = simple_strtoll(str,&next,base);
773                         } else {
774                                 unsigned long long *l = (unsigned long long*) va_arg(args,unsigned long long*);
775                                 *l = simple_strtoull(str,&next,base);
776                         }
777                         break;
778                 case 'Z':
779                 case 'z':
780                 {
781                         size_t *s = (size_t*) va_arg(args,size_t*);
782                         *s = (size_t) simple_strtoul(str,&next,base);
783                 }
784                 break;
785                 default:
786                         if (is_sign) {
787                                 int *i = (int *) va_arg(args, int*);
788                                 *i = (int) simple_strtol(str,&next,base);
789                         } else {
790                                 unsigned int *i = (unsigned int*) va_arg(args, unsigned int*);
791                                 *i = (unsigned int) simple_strtoul(str,&next,base);
792                         }
793                         break;
794                 }
795                 num++;
796
797                 if (!next)
798                         break;
799                 str = next;
800         }
801         return num;
802 }
803
804 EXPORT_SYMBOL(vsscanf);
805
806 /**
807  * sscanf - Unformat a buffer into a list of arguments
808  * @buf:        input buffer
809  * @fmt:        formatting of buffer
810  * @...:        resulting arguments
811  */
812 int sscanf(const char * buf, const char * fmt, ...)
813 {
814         va_list args;
815         int i;
816
817         va_start(args,fmt);
818         i = vsscanf(buf,fmt,args);
819         va_end(args);
820         return i;
821 }
822
823 EXPORT_SYMBOL(sscanf);