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