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