add chdir
[snitchaser:mainline.git] / src / arch / x86 / interp / printf / vsprintf.c
1 /*
2  *  linux/lib/vsprintf.c
3  *
4  *  Copyright (C) 1991, 1992  Linus Torvalds
5  */
6
7 #include <errno.h>
8 #include <stdarg.h>
9 #include <stdint.h>
10 #include <stddef.h>
11 #include <limits.h>
12 #include <xasm/__ctype.h>
13 #include <xasm/vsprintf.h>
14 #define PAGE_SIZE (4096)
15 #define noinline __attribute__((noinline))
16 typedef unsigned int size_t;
17 #define do_div(n,base) ({ \
18         unsigned long __upper, __low, __high, __mod, __base; \
19         __base = (base); \
20         asm("":"=a" (__low), "=d" (__high):"A" (n)); \
21         __upper = __high; \
22         if (__high) { \
23                 __upper = __high % (__base); \
24                 __high = __high / (__base); \
25         } \
26         asm("divl %2":"=a" (__low), "=d" (__mod):"rm" (__base), "0" (__low), "1" (__upper)); \
27         asm("":"=A" (n):"a" (__low),"d" (__high)); \
28         __mod; \
29 })
30 #define unlikely(x)     __builtin_expect(!!(x), 0)
31
32
33 /* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
34 /*
35  * Wirzenius wrote this portably, Torvalds fucked it up :-)
36  */
37
38 /* 
39  * Fri Jul 13 2001 Crutcher Dunnavant <crutcher+kernel@datastacks.com>
40  * - changed to provide snprintf and vsnprintf functions
41  * So Feb  1 16:51:32 CET 2004 Juergen Quade <quade@hsnr.de>
42  * - scnprintf and vscnprintf
43  */
44
45 /* Works only for digits and letters, but small and fast */
46 #define TOLOWER(x) ((x) | 0x20)
47
48 /**
49  * simple_strtoul - convert a string to an unsigned long
50  * @cp: The start of the string
51  * @endp: A pointer to the end of the parsed string will be placed here
52  * @base: The number base to use
53  */
54 unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
55 {
56         unsigned long result = 0,value;
57
58         if (!base) {
59                 base = 10;
60                 if (*cp == '0') {
61                         base = 8;
62                         cp++;
63                         if ((TOLOWER(*cp) == 'x') && isxdigit(cp[1])) {
64                                 cp++;
65                                 base = 16;
66                         }
67                 }
68         } else if (base == 16) {
69                 if (cp[0] == '0' && TOLOWER(cp[1]) == 'x')
70                         cp += 2;
71         }
72         while (isxdigit(*cp) &&
73                (value = isdigit(*cp) ? *cp-'0' : TOLOWER(*cp)-'a'+10) < base) {
74                 result = result*base + value;
75                 cp++;
76         }
77         if (endp)
78                 *endp = (char *)cp;
79         return result;
80 }
81
82
83 /**
84  * simple_strtol - convert a string to a signed long
85  * @cp: The start of the string
86  * @endp: A pointer to the end of the parsed string will be placed here
87  * @base: The number base to use
88  */
89 long simple_strtol(const char *cp,char **endp,unsigned int base)
90 {
91         if(*cp=='-')
92                 return -simple_strtoul(cp+1,endp,base);
93         return simple_strtoul(cp,endp,base);
94 }
95
96
97 /**
98  * simple_strtoull - convert a string to an unsigned long long
99  * @cp: The start of the string
100  * @endp: A pointer to the end of the parsed string will be placed here
101  * @base: The number base to use
102  */
103 unsigned long long simple_strtoull(const char *cp,char **endp,unsigned int base)
104 {
105         unsigned long long result = 0,value;
106
107         if (!base) {
108                 base = 10;
109                 if (*cp == '0') {
110                         base = 8;
111                         cp++;
112                         if ((TOLOWER(*cp) == 'x') && isxdigit(cp[1])) {
113                                 cp++;
114                                 base = 16;
115                         }
116                 }
117         } else if (base == 16) {
118                 if (cp[0] == '0' && TOLOWER(cp[1]) == 'x')
119                         cp += 2;
120         }
121         while (isxdigit(*cp)
122          && (value = isdigit(*cp) ? *cp-'0' : TOLOWER(*cp)-'a'+10) < base) {
123                 result = result*base + value;
124                 cp++;
125         }
126         if (endp)
127                 *endp = (char *)cp;
128         return result;
129 }
130
131
132 /**
133  * simple_strtoll - convert a string to a signed long long
134  * @cp: The start of the string
135  * @endp: A pointer to the end of the parsed string will be placed here
136  * @base: The number base to use
137  */
138 long long simple_strtoll(const char *cp,char **endp,unsigned int base)
139 {
140         if(*cp=='-')
141                 return -simple_strtoull(cp+1,endp,base);
142         return simple_strtoull(cp,endp,base);
143 }
144
145
146 /**
147  * strict_strtoul - convert a string to an unsigned long strictly
148  * @cp: The string to be converted
149  * @base: The number base to use
150  * @res: The converted result value
151  *
152  * strict_strtoul converts a string to an unsigned long only if the
153  * string is really an unsigned long string, any string containing
154  * any invalid char at the tail will be rejected and -EINVAL is returned,
155  * only a newline char at the tail is acceptible because people generally
156  * change a module parameter in the following way:
157  *
158  *      echo 1024 > /sys/module/e1000/parameters/copybreak
159  *
160  * echo will append a newline to the tail.
161  *
162  * It returns 0 if conversion is successful and *res is set to the converted
163  * value, otherwise it returns -EINVAL and *res is set to 0.
164  *
165  * simple_strtoul just ignores the successive invalid characters and
166  * return the converted value of prefix part of the string.
167  */
168 int strict_strtoul(const char *cp, unsigned int base, unsigned long *res);
169
170 /**
171  * strict_strtol - convert a string to a long strictly
172  * @cp: The string to be converted
173  * @base: The number base to use
174  * @res: The converted result value
175  *
176  * strict_strtol is similiar to strict_strtoul, but it allows the first
177  * character of a string is '-'.
178  *
179  * It returns 0 if conversion is successful and *res is set to the converted
180  * value, otherwise it returns -EINVAL and *res is set to 0.
181  */
182 int strict_strtol(const char *cp, unsigned int base, long *res);
183
184 /**
185  * strict_strtoull - convert a string to an unsigned long long strictly
186  * @cp: The string to be converted
187  * @base: The number base to use
188  * @res: The converted result value
189  *
190  * strict_strtoull converts a string to an unsigned long long only if the
191  * string is really an unsigned long long string, any string containing
192  * any invalid char at the tail will be rejected and -EINVAL is returned,
193  * only a newline char at the tail is acceptible because people generally
194  * change a module parameter in the following way:
195  *
196  *      echo 1024 > /sys/module/e1000/parameters/copybreak
197  *
198  * echo will append a newline to the tail of the string.
199  *
200  * It returns 0 if conversion is successful and *res is set to the converted
201  * value, otherwise it returns -EINVAL and *res is set to 0.
202  *
203  * simple_strtoull just ignores the successive invalid characters and
204  * return the converted value of prefix part of the string.
205  */
206 int strict_strtoull(const char *cp, unsigned int base, unsigned long long *res);
207
208 /**
209  * strict_strtoll - convert a string to a long long strictly
210  * @cp: The string to be converted
211  * @base: The number base to use
212  * @res: The converted result value
213  *
214  * strict_strtoll is similiar to strict_strtoull, but it allows the first
215  * character of a string is '-'.
216  *
217  * It returns 0 if conversion is successful and *res is set to the converted
218  * value, otherwise it returns -EINVAL and *res is set to 0.
219  */
220 int strict_strtoll(const char *cp, unsigned int base, long long *res);
221
222 #define define_strict_strtoux(type, valtype)                            \
223 int strict_strtou##type(const char *cp, unsigned int base, valtype *res)\
224 {                                                                       \
225         char *tail;                                                     \
226         valtype val;                                                    \
227         size_t len;                                                     \
228                                                                         \
229         *res = 0;                                                       \
230         len = strlen(cp);                                               \
231         if (len == 0)                                                   \
232                 return -EINVAL;                                         \
233                                                                         \
234         val = simple_strtoul(cp, &tail, base);                          \
235         if ((*tail == '\0') ||                                          \
236                 ((len == (size_t)(tail - cp) + 1) && (*tail == '\n'))) {\
237                 *res = val;                                             \
238                 return 0;                                               \
239         }                                                               \
240                                                                         \
241         return -EINVAL;                                                 \
242 }                                                                       \
243
244 #define define_strict_strtox(type, valtype)                             \
245 int strict_strto##type(const char *cp, unsigned int base, valtype *res) \
246 {                                                                       \
247         int ret;                                                        \
248         if (*cp == '-') {                                               \
249                 ret = strict_strtou##type(cp+1, base, (unsigned valtype *)res);         \
250                 if (!ret)                                               \
251                         *res = -(*res);                                 \
252         } else                                                          \
253                 ret = strict_strtou##type(cp, base, (unsigned valtype *)res);           \
254                                                                         \
255         return ret;                                                     \
256 }                                                                       \
257
258 define_strict_strtoux(l, unsigned long)
259 define_strict_strtox(l, long)
260 define_strict_strtoux(ll, unsigned long long)
261 define_strict_strtox(ll, long long)
262
263 static int skip_atoi(const char **s)
264 {
265         int i=0;
266
267         while (isdigit(**s))
268                 i = i*10 + *((*s)++) - '0';
269         return i;
270 }
271
272 /* Decimal conversion is by far the most typical, and is used
273  * for /proc and /sys data. This directly impacts e.g. top performance
274  * with many processes running. We optimize it for speed
275  * using code from
276  * http://www.cs.uiowa.edu/~jones/bcd/decimal.html
277  * (with permission from the author, Douglas W. Jones). */
278
279 /* Formats correctly any integer in [0,99999].
280  * Outputs from one to five digits depending on input.
281  * On i386 gcc 4.1.2 -O2: ~250 bytes of code. */
282 static char* put_dec_trunc(char *buf, unsigned q)
283 {
284         unsigned d3, d2, d1, d0;
285         d1 = (q>>4) & 0xf;
286         d2 = (q>>8) & 0xf;
287         d3 = (q>>12);
288
289         d0 = 6*(d3 + d2 + d1) + (q & 0xf);
290         q = (d0 * 0xcd) >> 11;
291         d0 = d0 - 10*q;
292         *buf++ = d0 + '0'; /* least significant digit */
293         d1 = q + 9*d3 + 5*d2 + d1;
294         if (d1 != 0) {
295                 q = (d1 * 0xcd) >> 11;
296                 d1 = d1 - 10*q;
297                 *buf++ = d1 + '0'; /* next digit */
298
299                 d2 = q + 2*d2;
300                 if ((d2 != 0) || (d3 != 0)) {
301                         q = (d2 * 0xd) >> 7;
302                         d2 = d2 - 10*q;
303                         *buf++ = d2 + '0'; /* next digit */
304
305                         d3 = q + 4*d3;
306                         if (d3 != 0) {
307                                 q = (d3 * 0xcd) >> 11;
308                                 d3 = d3 - 10*q;
309                                 *buf++ = d3 + '0';  /* next digit */
310                                 if (q != 0)
311                                         *buf++ = q + '0';  /* most sign. digit */
312                         }
313                 }
314         }
315         return buf;
316 }
317 /* Same with if's removed. Always emits five digits */
318 static char* put_dec_full(char *buf, unsigned q)
319 {
320         /* BTW, if q is in [0,9999], 8-bit ints will be enough, */
321         /* but anyway, gcc produces better code with full-sized ints */
322         unsigned d3, d2, d1, d0;
323         d1 = (q>>4) & 0xf;
324         d2 = (q>>8) & 0xf;
325         d3 = (q>>12);
326
327         /* Possible ways to approx. divide by 10 */
328         /* gcc -O2 replaces multiply with shifts and adds */
329         // (x * 0xcd) >> 11: 11001101 - shorter code than * 0x67 (on i386)
330         // (x * 0x67) >> 10:  1100111
331         // (x * 0x34) >> 9:    110100 - same
332         // (x * 0x1a) >> 8:     11010 - same
333         // (x * 0x0d) >> 7:      1101 - same, shortest code (on i386)
334
335         d0 = 6*(d3 + d2 + d1) + (q & 0xf);
336         q = (d0 * 0xcd) >> 11;
337         d0 = d0 - 10*q;
338         *buf++ = d0 + '0';
339         d1 = q + 9*d3 + 5*d2 + d1;
340                 q = (d1 * 0xcd) >> 11;
341                 d1 = d1 - 10*q;
342                 *buf++ = d1 + '0';
343
344                 d2 = q + 2*d2;
345                         q = (d2 * 0xd) >> 7;
346                         d2 = d2 - 10*q;
347                         *buf++ = d2 + '0';
348
349                         d3 = q + 4*d3;
350                                 q = (d3 * 0xcd) >> 11; /* - shorter code */
351                                 /* q = (d3 * 0x67) >> 10; - would also work */
352                                 d3 = d3 - 10*q;
353                                 *buf++ = d3 + '0';
354                                         *buf++ = q + '0';
355         return buf;
356 }
357 /* No inlining helps gcc to use registers better */
358 static noinline char* put_dec(char *buf, unsigned long long num)
359 {
360         while (1) {
361                 unsigned rem;
362                 if (num < 100000)
363                         return put_dec_trunc(buf, num);
364                 rem = do_div(num, 100000);
365                 buf = put_dec_full(buf, rem);
366         }
367 }
368
369 #define ZEROPAD 1               /* pad with zero */
370 #define SIGN    2               /* unsigned/signed long */
371 #define PLUS    4               /* show plus */
372 #define SPACE   8               /* space if plus */
373 #define LEFT    16              /* left justified */
374 #define SMALL   32              /* Must be 32 == 0x20 */
375 #define SPECIAL 64              /* 0x */
376
377 static char *number(char *buf, char *end, unsigned long long num, int base, int size, int precision, int type)
378 {
379         /* we are called with base 8, 10 or 16, only, thus don't need "G..."  */
380         static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */
381
382         char tmp[66];
383         char sign;
384         char locase;
385         int need_pfx = ((type & SPECIAL) && base != 10);
386         int i;
387
388         /* locase = 0 or 0x20. ORing digits or letters with 'locase'
389          * produces same digits or (maybe lowercased) letters */
390         locase = (type & SMALL);
391         if (type & LEFT)
392                 type &= ~ZEROPAD;
393         sign = 0;
394         if (type & SIGN) {
395                 if ((signed long long) num < 0) {
396                         sign = '-';
397                         num = - (signed long long) num;
398                         size--;
399                 } else if (type & PLUS) {
400                         sign = '+';
401                         size--;
402                 } else if (type & SPACE) {
403                         sign = ' ';
404                         size--;
405                 }
406         }
407         if (need_pfx) {
408                 size--;
409                 if (base == 16)
410                         size--;
411         }
412
413         /* generate full string in tmp[], in reverse order */
414         i = 0;
415         if (num == 0)
416                 tmp[i++] = '0';
417         /* Generic code, for any base:
418         else do {
419                 tmp[i++] = (digits[do_div(num,base)] | locase);
420         } while (num != 0);
421         */
422         else if (base != 10) { /* 8 or 16 */
423                 int mask = base - 1;
424                 int shift = 3;
425                 if (base == 16) shift = 4;
426                 do {
427                         tmp[i++] = (digits[((unsigned char)num) & mask] | locase);
428                         num >>= shift;
429                 } while (num);
430         } else { /* base 10 */
431                 i = put_dec(tmp, num) - tmp;
432         }
433
434         /* printing 100 using %2d gives "100", not "00" */
435         if (i > precision)
436                 precision = i;
437         /* leading space padding */
438         size -= precision;
439         if (!(type & (ZEROPAD+LEFT))) {
440                 while(--size >= 0) {
441                         if (buf < end)
442                                 *buf = ' ';
443                         ++buf;
444                 }
445         }
446         /* sign */
447         if (sign) {
448                 if (buf < end)
449                         *buf = sign;
450                 ++buf;
451         }
452         /* "0x" / "0" prefix */
453         if (need_pfx) {
454                 if (buf < end)
455                         *buf = '0';
456                 ++buf;
457                 if (base == 16) {
458                         if (buf < end)
459                                 *buf = ('X' | locase);
460                         ++buf;
461                 }
462         }
463         /* zero or space padding */
464         if (!(type & LEFT)) {
465                 char c = (type & ZEROPAD) ? '0' : ' ';
466                 while (--size >= 0) {
467                         if (buf < end)
468                                 *buf = c;
469                         ++buf;
470                 }
471         }
472         /* hmm even more zero padding? */
473         while (i <= --precision) {
474                 if (buf < end)
475                         *buf = '0';
476                 ++buf;
477         }
478         /* actual digits of result */
479         while (--i >= 0) {
480                 if (buf < end)
481                         *buf = tmp[i];
482                 ++buf;
483         }
484         /* trailing space padding */
485         while (--size >= 0) {
486                 if (buf < end)
487                         *buf = ' ';
488                 ++buf;
489         }
490         return buf;
491 }
492
493 /**
494  * vsnprintf - Format a string and place it in a buffer
495  * @buf: The buffer to place the result into
496  * @size: The size of the buffer, including the trailing null space
497  * @fmt: The format string to use
498  * @args: Arguments for the format string
499  *
500  * The return value is the number of characters which would
501  * be generated for the given input, excluding the trailing
502  * '\0', as per ISO C99. If you want to have the exact
503  * number of characters written into @buf as return value
504  * (not including the trailing '\0'), use vscnprintf(). If the
505  * return is greater than or equal to @size, the resulting
506  * string is truncated.
507  *
508  * Call this function if you are already dealing with a va_list.
509  * You probably want snprintf() instead.
510  */
511 int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
512 {
513         int len;
514         unsigned long long num;
515         int i, base;
516         char *str, *end, c;
517         const char *s;
518
519         int flags;              /* flags to number() */
520
521         int field_width;        /* width of output field */
522         int precision;          /* min. # of digits for integers; max
523                                    number of chars for from string */
524         int qualifier;          /* 'h', 'l', or 'L' for integer fields */
525                                 /* 'z' support added 23/7/1999 S.H.    */
526                                 /* 'z' changed to 'Z' --davidm 1/25/99 */
527                                 /* 't' added for ptrdiff_t */
528
529         /* Reject out-of-range values early.  Large positive sizes are
530            used for unknown buffer sizes. */
531         if (unlikely((int) size < 0)) {
532                 /* There can be only one.. */
533                 static char warn = 1;
534                 /* FIXME */
535                 /* REMOVE WARN_ON(warn); */
536 //              WARN_ON(warn);
537                 warn = 0;
538                 return 0;
539         }
540
541         str = buf;
542         end = buf + size;
543
544         /* Make sure end is always >= buf */
545         if (end < buf) {
546                 end = ((void *)-1);
547                 size = end - buf;
548         }
549
550         for (; *fmt ; ++fmt) {
551                 if (*fmt != '%') {
552                         if (str < end)
553                                 *str = *fmt;
554                         ++str;
555                         continue;
556                 }
557
558                 /* process flags */
559                 flags = 0;
560                 repeat:
561                         ++fmt;          /* this also skips first '%' */
562                         switch (*fmt) {
563                                 case '-': flags |= LEFT; goto repeat;
564                                 case '+': flags |= PLUS; goto repeat;
565                                 case ' ': flags |= SPACE; goto repeat;
566                                 case '#': flags |= SPECIAL; goto repeat;
567                                 case '0': flags |= ZEROPAD; goto repeat;
568                         }
569
570                 /* get field width */
571                 field_width = -1;
572                 if (isdigit(*fmt))
573                         field_width = skip_atoi(&fmt);
574                 else if (*fmt == '*') {
575                         ++fmt;
576                         /* it's the next argument */
577                         field_width = va_arg(args, int);
578                         if (field_width < 0) {
579                                 field_width = -field_width;
580                                 flags |= LEFT;
581                         }
582                 }
583
584                 /* get the precision */
585                 precision = -1;
586                 if (*fmt == '.') {
587                         ++fmt;  
588                         if (isdigit(*fmt))
589                                 precision = skip_atoi(&fmt);
590                         else if (*fmt == '*') {
591                                 ++fmt;
592                                 /* it's the next argument */
593                                 precision = va_arg(args, int);
594                         }
595                         if (precision < 0)
596                                 precision = 0;
597                 }
598
599                 /* get the conversion qualifier */
600                 qualifier = -1;
601                 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
602                     *fmt =='Z' || *fmt == 'z' || *fmt == 't') {
603                         qualifier = *fmt;
604                         ++fmt;
605                         if (qualifier == 'l' && *fmt == 'l') {
606                                 qualifier = 'L';
607                                 ++fmt;
608                         }
609                 }
610
611                 /* default base */
612                 base = 10;
613
614                 switch (*fmt) {
615                         case 'c':
616                                 if (!(flags & LEFT)) {
617                                         while (--field_width > 0) {
618                                                 if (str < end)
619                                                         *str = ' ';
620                                                 ++str;
621                                         }
622                                 }
623                                 c = (unsigned char) va_arg(args, int);
624                                 if (str < end)
625                                         *str = c;
626                                 ++str;
627                                 while (--field_width > 0) {
628                                         if (str < end)
629                                                 *str = ' ';
630                                         ++str;
631                                 }
632                                 continue;
633
634                         case 's':
635                                 s = va_arg(args, char *);
636                                 if ((unsigned long)s < PAGE_SIZE)
637                                         s = "<NULL>";
638
639                                 len = strnlen(s, precision);
640
641                                 if (!(flags & LEFT)) {
642                                         while (len < field_width--) {
643                                                 if (str < end)
644                                                         *str = ' ';
645                                                 ++str;
646                                         }
647                                 }
648                                 for (i = 0; i < len; ++i) {
649                                         if (str < end)
650                                                 *str = *s;
651                                         ++str; ++s;
652                                 }
653                                 while (len < field_width--) {
654                                         if (str < end)
655                                                 *str = ' ';
656                                         ++str;
657                                 }
658                                 continue;
659
660                         case 'p':
661                                 flags |= SMALL;
662                                 if (field_width == -1) {
663                                         field_width = 2*sizeof(void *);
664                                         flags |= ZEROPAD;
665                                 }
666                                 if (str < end)
667                                         *str = '0';
668                                 str ++;
669                                 if (str < end)
670                                         *str = 'x';
671                                 str ++;
672                                 str = number(str, end,
673                                                 (unsigned long) va_arg(args, void *),
674                                                 16, field_width, precision, flags);
675                                 continue;
676
677
678                         case 'n':
679                                 /* FIXME:
680                                 * What does C99 say about the overflow case here? */
681                                 if (qualifier == 'l') {
682                                         long * ip = va_arg(args, long *);
683                                         *ip = (str - buf);
684                                 } else if (qualifier == 'Z' || qualifier == 'z') {
685                                         size_t * ip = va_arg(args, size_t *);
686                                         *ip = (str - buf);
687                                 } else {
688                                         int * ip = va_arg(args, int *);
689                                         *ip = (str - buf);
690                                 }
691                                 continue;
692
693                         case '%':
694                                 if (str < end)
695                                         *str = '%';
696                                 ++str;
697                                 continue;
698
699                                 /* integer number formats - set up the flags and "break" */
700                         case 'o':
701                                 base = 8;
702                                 break;
703
704                         case 'x':
705                                 flags |= SMALL;
706                         case 'X':
707                                 base = 16;
708                                 break;
709
710                         case 'd':
711                         case 'i':
712                                 flags |= SIGN;
713                         case 'u':
714                                 break;
715
716                         default:
717                                 if (str < end)
718                                         *str = '%';
719                                 ++str;
720                                 if (*fmt) {
721                                         if (str < end)
722                                                 *str = *fmt;
723                                         ++str;
724                                 } else {
725                                         --fmt;
726                                 }
727                                 continue;
728                 }
729                 if (qualifier == 'L')
730                         num = va_arg(args, long long);
731                 else if (qualifier == 'l') {
732                         num = va_arg(args, unsigned long);
733                         if (flags & SIGN)
734                                 num = (signed long) num;
735                 } else if (qualifier == 'Z' || qualifier == 'z') {
736                         num = va_arg(args, size_t);
737                 } else if (qualifier == 't') {
738                         num = va_arg(args, ptrdiff_t);
739                 } else if (qualifier == 'h') {
740                         num = (unsigned short) va_arg(args, int);
741                         if (flags & SIGN)
742                                 num = (signed short) num;
743                 } else {
744                         num = va_arg(args, unsigned int);
745                         if (flags & SIGN)
746                                 num = (signed int) num;
747                 }
748                 str = number(str, end, num, base,
749                                 field_width, precision, flags);
750         }
751         if (size > 0) {
752                 if (str < end)
753                         *str = '\0';
754                 else
755                         end[-1] = '\0';
756         }
757         /* the trailing null byte doesn't count towards the total */
758         return str-buf;
759 }
760
761
762 /**
763  * vscnprintf - Format a string and place it in a buffer
764  * @buf: The buffer to place the result into
765  * @size: The size of the buffer, including the trailing null space
766  * @fmt: The format string to use
767  * @args: Arguments for the format string
768  *
769  * The return value is the number of characters which have been written into
770  * the @buf not including the trailing '\0'. If @size is <= 0 the function
771  * returns 0.
772  *
773  * Call this function if you are already dealing with a va_list.
774  * You probably want scnprintf() instead.
775  */
776 int vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
777 {
778         size_t i;
779
780         i=vsnprintf(buf,size,fmt,args);
781         return (i >= size) ? (size - 1) : i;
782 }
783
784
785 /**
786  * snprintf - Format a string and place it in a buffer
787  * @buf: The buffer to place the result into
788  * @size: The size of the buffer, including the trailing null space
789  * @fmt: The format string to use
790  * @...: Arguments for the format string
791  *
792  * The return value is the number of characters which would be
793  * generated for the given input, excluding the trailing null,
794  * as per ISO C99.  If the return is greater than or equal to
795  * @size, the resulting string is truncated.
796  */
797 int snprintf(char * buf, size_t size, const char *fmt, ...)
798 {
799         va_list args;
800         int i;
801
802         va_start(args, fmt);
803         i=vsnprintf(buf,size,fmt,args);
804         va_end(args);
805         return i;
806 }
807
808
809 /**
810  * scnprintf - Format a string and place it in a buffer
811  * @buf: The buffer to place the result into
812  * @size: The size of the buffer, including the trailing null space
813  * @fmt: The format string to use
814  * @...: Arguments for the format string
815  *
816  * The return value is the number of characters written into @buf not including
817  * the trailing '\0'. If @size is <= 0 the function returns 0.
818  */
819
820 int scnprintf(char * buf, size_t size, const char *fmt, ...)
821 {
822         va_list args;
823         size_t i;
824
825         va_start(args, fmt);
826         i = vsnprintf(buf, size, fmt, args);
827         va_end(args);
828         return (i >= size) ? (size - 1) : i;
829 }
830
831 /**
832  * vsprintf - Format a string and place it in a buffer
833  * @buf: The buffer to place the result into
834  * @fmt: The format string to use
835  * @args: Arguments for the format string
836  *
837  * The function returns the number of characters written
838  * into @buf. Use vsnprintf() or vscnprintf() in order to avoid
839  * buffer overflows.
840  *
841  * Call this function if you are already dealing with a va_list.
842  * You probably want sprintf() instead.
843  */
844 int vsprintf(char *buf, const char *fmt, va_list args)
845 {
846         return vsnprintf(buf, INT_MAX, fmt, args);
847 }
848
849
850 /**
851  * sprintf - Format a string and place it in a buffer
852  * @buf: The buffer to place the result into
853  * @fmt: The format string to use
854  * @...: Arguments for the format string
855  *
856  * The function returns the number of characters written
857  * into @buf. Use snprintf() or scnprintf() in order to avoid
858  * buffer overflows.
859  */
860 int sprintf(char * buf, const char *fmt, ...)
861 {
862         va_list args;
863         int i;
864
865         va_start(args, fmt);
866         i=vsnprintf(buf, INT_MAX, fmt, args);
867         va_end(args);
868         return i;
869 }
870
871
872 /**
873  * vsscanf - Unformat a buffer into a list of arguments
874  * @buf:        input buffer
875  * @fmt:        format of buffer
876  * @args:       arguments
877  */
878 int vsscanf(const char * buf, const char * fmt, va_list args)
879 {
880         const char *str = buf;
881         char *next;
882         char digit;
883         int num = 0;
884         int qualifier;
885         int base;
886         int field_width;
887         int is_sign = 0;
888
889         while(*fmt && *str) {
890                 /* skip any white space in format */
891                 /* white space in format matchs any amount of
892                  * white space, including none, in the input.
893                  */
894                 if (isspace(*fmt)) {
895                         while (isspace(*fmt))
896                                 ++fmt;
897                         while (isspace(*str))
898                                 ++str;
899                 }
900
901                 /* anything that is not a conversion must match exactly */
902                 if (*fmt != '%' && *fmt) {
903                         if (*fmt++ != *str++)
904                                 break;
905                         continue;
906                 }
907
908                 if (!*fmt)
909                         break;
910                 ++fmt;
911                 
912                 /* skip this conversion.
913                  * advance both strings to next white space
914                  */
915                 if (*fmt == '*') {
916                         while (!isspace(*fmt) && *fmt)
917                                 fmt++;
918                         while (!isspace(*str) && *str)
919                                 str++;
920                         continue;
921                 }
922
923                 /* get field width */
924                 field_width = -1;
925                 if (isdigit(*fmt))
926                         field_width = skip_atoi(&fmt);
927
928                 /* get conversion qualifier */
929                 qualifier = -1;
930                 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
931                     *fmt == 'Z' || *fmt == 'z') {
932                         qualifier = *fmt++;
933                         if (unlikely(qualifier == *fmt)) {
934                                 if (qualifier == 'h') {
935                                         qualifier = 'H';
936                                         fmt++;
937                                 } else if (qualifier == 'l') {
938                                         qualifier = 'L';
939                                         fmt++;
940                                 }
941                         }
942                 }
943                 base = 10;
944                 is_sign = 0;
945
946                 if (!*fmt || !*str)
947                         break;
948
949                 switch(*fmt++) {
950                 case 'c':
951                 {
952                         char *s = (char *) va_arg(args,char*);
953                         if (field_width == -1)
954                                 field_width = 1;
955                         do {
956                                 *s++ = *str++;
957                         } while (--field_width > 0 && *str);
958                         num++;
959                 }
960                 continue;
961                 case 's':
962                 {
963                         char *s = (char *) va_arg(args, char *);
964                         if(field_width == -1)
965                                 field_width = INT_MAX;
966                         /* first, skip leading white space in buffer */
967                         while (isspace(*str))
968                                 str++;
969
970                         /* now copy until next white space */
971                         while (*str && !isspace(*str) && field_width--) {
972                                 *s++ = *str++;
973                         }
974                         *s = '\0';
975                         num++;
976                 }
977                 continue;
978                 case 'n':
979                         /* return number of characters read so far */
980                 {
981                         int *i = (int *)va_arg(args,int*);
982                         *i = str - buf;
983                 }
984                 continue;
985                 case 'o':
986                         base = 8;
987                         break;
988                 case 'x':
989                 case 'X':
990                         base = 16;
991                         break;
992                 case 'i':
993                         base = 0;
994                 case 'd':
995                         is_sign = 1;
996                 case 'u':
997                         break;
998                 case '%':
999                         /* looking for '%' in str */
1000                         if (*str++ != '%') 
1001                                 return num;
1002                         continue;
1003                 default:
1004                         /* invalid format; stop here */
1005                         return num;
1006                 }
1007
1008                 /* have some sort of integer conversion.
1009                  * first, skip white space in buffer.
1010                  */
1011                 while (isspace(*str))
1012                         str++;
1013
1014                 digit = *str;
1015                 if (is_sign && digit == '-')
1016                         digit = *(str + 1);
1017
1018                 if (!digit
1019                     || (base == 16 && !isxdigit(digit))
1020                     || (base == 10 && !isdigit(digit))
1021                     || (base == 8 && (!isdigit(digit) || digit > '7'))
1022                     || (base == 0 && !isdigit(digit)))
1023                                 break;
1024
1025                 switch(qualifier) {
1026                 case 'H':       /* that's 'hh' in format */
1027                         if (is_sign) {
1028                                 signed char *s = (signed char *) va_arg(args,signed char *);
1029                                 *s = (signed char) simple_strtol(str,&next,base);
1030                         } else {
1031                                 unsigned char *s = (unsigned char *) va_arg(args, unsigned char *);
1032                                 *s = (unsigned char) simple_strtoul(str, &next, base);
1033                         }
1034                         break;
1035                 case 'h':
1036                         if (is_sign) {
1037                                 short *s = (short *) va_arg(args,short *);
1038                                 *s = (short) simple_strtol(str,&next,base);
1039                         } else {
1040                                 unsigned short *s = (unsigned short *) va_arg(args, unsigned short *);
1041                                 *s = (unsigned short) simple_strtoul(str, &next, base);
1042                         }
1043                         break;
1044                 case 'l':
1045                         if (is_sign) {
1046                                 long *l = (long *) va_arg(args,long *);
1047                                 *l = simple_strtol(str,&next,base);
1048                         } else {
1049                                 unsigned long *l = (unsigned long*) va_arg(args,unsigned long*);
1050                                 *l = simple_strtoul(str,&next,base);
1051                         }
1052                         break;
1053                 case 'L':
1054                         if (is_sign) {
1055                                 long long *l = (long long*) va_arg(args,long long *);
1056                                 *l = simple_strtoll(str,&next,base);
1057                         } else {
1058                                 unsigned long long *l = (unsigned long long*) va_arg(args,unsigned long long*);
1059                                 *l = simple_strtoull(str,&next,base);
1060                         }
1061                         break;
1062                 case 'Z':
1063                 case 'z':
1064                 {
1065                         size_t *s = (size_t*) va_arg(args,size_t*);
1066                         *s = (size_t) simple_strtoul(str,&next,base);
1067                 }
1068                 break;
1069                 default:
1070                         if (is_sign) {
1071                                 int *i = (int *) va_arg(args, int*);
1072                                 *i = (int) simple_strtol(str,&next,base);
1073                         } else {
1074                                 unsigned int *i = (unsigned int*) va_arg(args, unsigned int*);
1075                                 *i = (unsigned int) simple_strtoul(str,&next,base);
1076                         }
1077                         break;
1078                 }
1079                 num++;
1080
1081                 if (!next)
1082                         break;
1083                 str = next;
1084         }
1085
1086         /*
1087          * Now we've come all the way through so either the input string or the
1088          * format ended. In the former case, there can be a %n at the current
1089          * position in the format that needs to be filled.
1090          */
1091         if (*fmt == '%' && *(fmt + 1) == 'n') {
1092                 int *p = (int *)va_arg(args, int *);
1093                 *p = str - buf;
1094         }
1095
1096         return num;
1097 }
1098
1099
1100 /**
1101  * sscanf - Unformat a buffer into a list of arguments
1102  * @buf:        input buffer
1103  * @fmt:        formatting of buffer
1104  * @...:        resulting arguments
1105  */
1106 int sscanf(const char * buf, const char * fmt, ...)
1107 {
1108         va_list args;
1109         int i;
1110
1111         va_start(args,fmt);
1112         i = vsscanf(buf,fmt,args);
1113         va_end(args);
1114         return i;
1115 }
1116
1117 // vim:ts=4:sw=4
1118