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