]> granicus.if.org Git - strace/blob - vsprintf.c
tests/umount2.c: use libtests
[strace] / vsprintf.c
1 /*
2  * Taken from Linux kernel's linux/lib/vsprintf.c
3  * and somewhat simplified.
4  *
5  * Copyright (C) 1991, 1992  Linus Torvalds
6  */
7 /* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
8 /*
9  * Wirzenius wrote this portably, Torvalds fucked it up :-)
10  */
11
12 #include "defs.h"
13
14 #if USE_CUSTOM_PRINTF
15
16 #include <stdarg.h>
17 #include <limits.h>
18
19 #ifndef HAVE_FPUTS_UNLOCKED
20 # define fputs_unlocked fputs
21 #endif
22
23 #define noinline_for_stack /*nothing*/
24 #define likely(expr)       (expr)
25 #define unlikely(expr)     (expr)
26
27 #define do_div(n, d)       ({ __typeof(num) t = n % d; n /= d; t; })
28
29 #undef isdigit
30 #define isdigit(a) ((unsigned char)((a) - '0') <= 9)
31
32 static inline
33 int skip_atoi(const char **s)
34 {
35         int i = 0;
36         const char *p = *s;
37
38         while (isdigit(*p))
39                 i = i*10 + *p++ - '0';
40
41         *s = p;
42         return i;
43 }
44
45 /* Decimal conversion is by far the most typical, and is used
46  * for /proc and /sys data. This directly impacts e.g. top performance
47  * with many processes running. We optimize it for speed
48  * using ideas described at <http://www.cs.uiowa.edu/~jones/bcd/divide.html>
49  * (with permission from the author, Douglas W. Jones).
50  */
51
52 #if LONG_MAX != 0x7fffffffUL || LLONG_MAX != 0x7fffffffffffffffULL
53 /* Formats correctly any integer in [0, 999999999] */
54 static noinline_for_stack
55 char *put_dec_full9(char *buf, unsigned q)
56 {
57         unsigned r;
58
59         /* Possible ways to approx. divide by 10
60          * (x * 0x1999999a) >> 32 x < 1073741829 (multiply must be 64-bit)
61          * (x * 0xcccd) >> 19     x <      81920 (x < 262149 when 64-bit mul)
62          * (x * 0x6667) >> 18     x <      43699
63          * (x * 0x3334) >> 17     x <      16389
64          * (x * 0x199a) >> 16     x <      16389
65          * (x * 0x0ccd) >> 15     x <      16389
66          * (x * 0x0667) >> 14     x <       2739
67          * (x * 0x0334) >> 13     x <       1029
68          * (x * 0x019a) >> 12     x <       1029
69          * (x * 0x00cd) >> 11     x <       1029 shorter code than * 0x67 (on i386)
70          * (x * 0x0067) >> 10     x <        179
71          * (x * 0x0034) >>  9     x <         69 same
72          * (x * 0x001a) >>  8     x <         69 same
73          * (x * 0x000d) >>  7     x <         69 same, shortest code (on i386)
74          * (x * 0x0007) >>  6     x <         19
75          * See <http://www.cs.uiowa.edu/~jones/bcd/divide.html>
76          */
77         r      = (q * (uint64_t)0x1999999a) >> 32;
78         *buf++ = (q - 10 * r) + '0'; /* 1 */
79         q      = (r * (uint64_t)0x1999999a) >> 32;
80         *buf++ = (r - 10 * q) + '0'; /* 2 */
81         r      = (q * (uint64_t)0x1999999a) >> 32;
82         *buf++ = (q - 10 * r) + '0'; /* 3 */
83         q      = (r * (uint64_t)0x1999999a) >> 32;
84         *buf++ = (r - 10 * q) + '0'; /* 4 */
85         r      = (q * (uint64_t)0x1999999a) >> 32;
86         *buf++ = (q - 10 * r) + '0'; /* 5 */
87         /* Now value is under 10000, can avoid 64-bit multiply */
88         q      = (r * 0x199a) >> 16;
89         *buf++ = (r - 10 * q)  + '0'; /* 6 */
90         r      = (q * 0xcd) >> 11;
91         *buf++ = (q - 10 * r)  + '0'; /* 7 */
92         q      = (r * 0xcd) >> 11;
93         *buf++ = (r - 10 * q) + '0'; /* 8 */
94         *buf++ = q + '0'; /* 9 */
95         return buf;
96 }
97 #endif
98
99 /* Similar to above but do not pad with zeros.
100  * Code can be easily arranged to print 9 digits too, but our callers
101  * always call put_dec_full9() instead when the number has 9 decimal digits.
102  */
103 static noinline_for_stack
104 char *put_dec_trunc8(char *buf, unsigned r)
105 {
106         unsigned q;
107
108         /* Copy of previous function's body with added early returns */
109         q      = (r * (uint64_t)0x1999999a) >> 32;
110         *buf++ = (r - 10 * q) + '0'; /* 2 */
111         if (q == 0) return buf;
112         r      = (q * (uint64_t)0x1999999a) >> 32;
113         *buf++ = (q - 10 * r) + '0'; /* 3 */
114         if (r == 0) return buf;
115         q      = (r * (uint64_t)0x1999999a) >> 32;
116         *buf++ = (r - 10 * q) + '0'; /* 4 */
117         if (q == 0) return buf;
118         r      = (q * (uint64_t)0x1999999a) >> 32;
119         *buf++ = (q - 10 * r) + '0'; /* 5 */
120         if (r == 0) return buf;
121         q      = (r * 0x199a) >> 16;
122         *buf++ = (r - 10 * q)  + '0'; /* 6 */
123         if (q == 0) return buf;
124         r      = (q * 0xcd) >> 11;
125         *buf++ = (q - 10 * r)  + '0'; /* 7 */
126         if (r == 0) return buf;
127         q      = (r * 0xcd) >> 11;
128         *buf++ = (r - 10 * q) + '0'; /* 8 */
129         if (q == 0) return buf;
130         *buf++ = q + '0'; /* 9 */
131         return buf;
132 }
133
134 /* There are two algorithms to print larger numbers.
135  * One is generic: divide by 1000000000 and repeatedly print
136  * groups of (up to) 9 digits. It's conceptually simple,
137  * but requires a (unsigned long long) / 1000000000 division.
138  *
139  * Second algorithm splits 64-bit unsigned long long into 16-bit chunks,
140  * manipulates them cleverly and generates groups of 4 decimal digits.
141  * It so happens that it does NOT require long long division.
142  *
143  * If long is > 32 bits, division of 64-bit values is relatively easy,
144  * and we will use the first algorithm.
145  * If long long is > 64 bits (strange architecture with VERY large long long),
146  * second algorithm can't be used, and we again use the first one.
147  *
148  * Else (if long is 32 bits and long long is 64 bits) we use second one.
149  */
150
151 #if LONG_MAX != 0x7fffffffUL || LLONG_MAX != 0x7fffffffffffffffULL
152
153 /* First algorithm: generic */
154
155 static
156 char *put_dec(char *buf, unsigned long long n)
157 {
158         if (n >= 100*1000*1000) {
159                 while (n >= 1000*1000*1000)
160                         buf = put_dec_full9(buf, do_div(n, 1000*1000*1000));
161                 if (n >= 100*1000*1000)
162                         return put_dec_full9(buf, n);
163         }
164         return put_dec_trunc8(buf, n);
165 }
166
167 #else
168
169 /* Second algorithm: valid only for 64-bit long longs */
170
171 static noinline_for_stack
172 char *put_dec_full4(char *buf, unsigned q)
173 {
174         unsigned r;
175         r      = (q * 0xcccd) >> 19;
176         *buf++ = (q - 10 * r) + '0';
177         q      = (r * 0x199a) >> 16;
178         *buf++ = (r - 10 * q)  + '0';
179         r      = (q * 0xcd) >> 11;
180         *buf++ = (q - 10 * r)  + '0';
181         *buf++ = r + '0';
182         return buf;
183 }
184
185 /* Based on code by Douglas W. Jones found at
186  * <http://www.cs.uiowa.edu/~jones/bcd/decimal.html#sixtyfour>
187  * (with permission from the author).
188  * Performs no 64-bit division and hence should be fast on 32-bit machines.
189  */
190 static
191 char *put_dec(char *buf, unsigned long long n)
192 {
193         uint32_t d3, d2, d1, q, h;
194
195         if (n < 100*1000*1000)
196                 return put_dec_trunc8(buf, n);
197
198         d1  = ((uint32_t)n >> 16); /* implicit "& 0xffff" */
199         h   = (n >> 32);
200         d2  = (h      ) & 0xffff;
201         d3  = (h >> 16); /* implicit "& 0xffff" */
202
203         q   = 656 * d3 + 7296 * d2 + 5536 * d1 + ((uint32_t)n & 0xffff);
204
205         buf = put_dec_full4(buf, q % 10000);
206         q   = q / 10000;
207
208         d1  = q + 7671 * d3 + 9496 * d2 + 6 * d1;
209         buf = put_dec_full4(buf, d1 % 10000);
210         q   = d1 / 10000;
211
212         d2  = q + 4749 * d3 + 42 * d2;
213         buf = put_dec_full4(buf, d2 % 10000);
214         q   = d2 / 10000;
215
216         d3  = q + 281 * d3;
217         if (!d3)
218                 goto done;
219         buf = put_dec_full4(buf, d3 % 10000);
220         q   = d3 / 10000;
221         if (!q)
222                 goto done;
223         buf = put_dec_full4(buf, q);
224  done:
225         while (buf[-1] == '0')
226                 --buf;
227
228         return buf;
229 }
230
231 #endif
232
233 /*
234  * For strace, the following formats are not supported:
235  * %h[h]u, %zu, %tu  - use [unsigned] int/long/long long fmt instead
236  * %8.4u  - no precision field for integers allowed (ok for strings)
237  * %+d, % d  - no forced sign or force "space positive" sign
238  * %-07u  - use %-7u instead
239  * %X  - works as %x
240  */
241
242 #define ZEROPAD 1               /* pad with zero */
243 #define SIGN    2               /* unsigned/signed long */
244 //#define PLUS  4               /* show plus */
245 //#define SPACE 8               /* space if plus */
246 #define LEFT    16              /* left justified */
247 //#deefine SMALL        32              /* use lowercase in hex (must be 32 == 0x20) */
248 #define SPECIAL 64              /* prefix hex with "0x", octal with "0" */
249
250 enum format_type {
251         FORMAT_TYPE_NONE, /* Just a string part */
252         FORMAT_TYPE_WIDTH,
253         FORMAT_TYPE_PRECISION,
254         FORMAT_TYPE_CHAR,
255         FORMAT_TYPE_STR,
256         FORMAT_TYPE_PTR,
257         FORMAT_TYPE_PERCENT_CHAR,
258         FORMAT_TYPE_INVALID,
259         FORMAT_TYPE_LONG_LONG,
260         FORMAT_TYPE_ULONG,
261         FORMAT_TYPE_LONG,
262         FORMAT_TYPE_UINT,
263         FORMAT_TYPE_INT,
264 };
265
266 struct printf_spec {
267         uint8_t type;           /* format_type enum */
268         uint8_t flags;          /* flags to number() */
269         uint8_t base;           /* number base, 8, 10 or 16 only */
270         uint8_t qualifier;      /* number qualifier, one of 'hHlLtzZ' */
271         int     field_width;    /* width of output field */
272         int     precision;      /* # of digits/chars */
273 };
274
275 static noinline_for_stack
276 char *number(char *buf, char *end, unsigned long long num,
277              struct printf_spec spec)
278 {
279         /* we are called with base 8, 10 or 16, only, thus don't need "G..."  */
280         static const char digits[16] = "0123456789abcdef"; /* "GHIJKLMNOPQRSTUVWXYZ"; */
281
282         char tmp[sizeof(long long)*3 + 4];
283         char sign;
284         int need_pfx = ((spec.flags & SPECIAL) && spec.base != 10);
285         int i;
286
287         /* We may overflow the buf. Crudely check for it */
288         i = sizeof(long long)*3 + 4;
289         if (i < spec.field_width)
290                 i = spec.field_width;
291         if ((end - buf) <= i)
292                 return buf + i;
293
294 //we don't use formats like "%-07u"
295 //      if (spec.flags & LEFT)
296 //              spec.flags &= ~ZEROPAD;
297         sign = 0;
298         if (spec.flags & SIGN) {
299                 if ((signed long long)num < 0) {
300                         sign = '-';
301                         num = -(signed long long)num;
302                         spec.field_width--;
303 //              } else if (spec.flags & PLUS) {
304 //                      sign = '+';
305 //                      spec.field_width--;
306 //              } else if (spec.flags & SPACE) {
307 //                      sign = ' ';
308 //                      spec.field_width--;
309                 }
310         }
311         if (need_pfx) {
312                 spec.field_width--;
313                 if (spec.base == 16)
314                         spec.field_width--;
315         }
316
317         /* generate full string in tmp[], in reverse order */
318         i = 0;
319         if (num < spec.base)
320                 tmp[i++] = digits[num];
321         /* Generic code, for any base:
322         else do {
323                 tmp[i++] = (digits[do_div(num,base)]);
324         } while (num != 0);
325         */
326         else if (spec.base != 10) { /* 8 or 16 */
327                 int mask = spec.base - 1;
328                 int shift = 3;
329
330                 if (spec.base == 16)
331                         shift = 4;
332                 do {
333                         tmp[i++] = digits[((unsigned char)num) & mask];
334                         num >>= shift;
335                 } while (num);
336         } else { /* base 10 */
337                 i = put_dec(tmp, num) - tmp;
338         }
339
340 //spec.precision is assumed 0 ("not specified")
341 //      /* printing 100 using %2d gives "100", not "00" */
342 //      if (i > spec.precision)
343 //              spec.precision = i;
344 //      /* leading space padding */
345 //      spec.field_width -= spec.precision;
346         spec.field_width -= i;
347         if (!(spec.flags & (ZEROPAD+LEFT))) {
348                 while (--spec.field_width >= 0) {
349                         ///if (buf < end)
350                                 *buf = ' ';
351                         ++buf;
352                 }
353         }
354         /* sign */
355         if (sign) {
356                 ///if (buf < end)
357                         *buf = sign;
358                 ++buf;
359         }
360         /* "0x" / "0" prefix */
361         if (need_pfx) {
362                 ///if (buf < end)
363                         *buf = '0';
364                 ++buf;
365                 if (spec.base == 16) {
366                         ///if (buf < end)
367                                 *buf = 'x';
368                         ++buf;
369                 }
370         }
371         /* zero or space padding */
372         if (!(spec.flags & LEFT)) {
373                 char c = (spec.flags & ZEROPAD) ? '0' : ' ';
374                 while (--spec.field_width >= 0) {
375                         ///if (buf < end)
376                                 *buf = c;
377                         ++buf;
378                 }
379         }
380 //      /* hmm even more zero padding? */
381 //      while (i <= --spec.precision) {
382 //              ///if (buf < end)
383 //                      *buf = '0';
384 //              ++buf;
385 //      }
386         /* actual digits of result */
387         while (--i >= 0) {
388                 ///if (buf < end)
389                         *buf = tmp[i];
390                 ++buf;
391         }
392         /* trailing space padding */
393         while (--spec.field_width >= 0) {
394                 ///if (buf < end)
395                         *buf = ' ';
396                 ++buf;
397         }
398
399         return buf;
400 }
401
402 static noinline_for_stack
403 char *string(char *buf, char *end, const char *s, struct printf_spec spec)
404 {
405         int len, i;
406
407         if (!s)
408                 s = "(null)";
409
410         len = strnlen(s, spec.precision);
411
412         /* We may overflow the buf. Crudely check for it */
413         i = len;
414         if (i < spec.field_width)
415                 i = spec.field_width;
416         if ((end - buf) <= i)
417                 return buf + i;
418
419         if (!(spec.flags & LEFT)) {
420                 while (len < spec.field_width--) {
421                         ///if (buf < end)
422                                 *buf = ' ';
423                         ++buf;
424                 }
425         }
426         for (i = 0; i < len; ++i) {
427                 ///if (buf < end)
428                         *buf = *s;
429                 ++buf; ++s;
430         }
431         while (len < spec.field_width--) {
432                 ///if (buf < end)
433                         *buf = ' ';
434                 ++buf;
435         }
436
437         return buf;
438 }
439
440 static noinline_for_stack
441 char *pointer(const char *fmt, char *buf, char *end, void *ptr,
442               struct printf_spec spec)
443 {
444 //      spec.flags |= SMALL;
445         if (spec.field_width == -1) {
446                 spec.field_width = 2 * sizeof(void *);
447                 spec.flags |= ZEROPAD;
448         }
449         spec.base = 16;
450
451         return number(buf, end, (unsigned long) ptr, spec);
452 }
453
454 /*
455  * Helper function to decode printf style format.
456  * Each call decode a token from the format and return the
457  * number of characters read (or likely the delta where it wants
458  * to go on the next call).
459  * The decoded token is returned through the parameters
460  *
461  * 'h', 'l', or 'L' for integer fields
462  * 'z' support added 23/7/1999 S.H.
463  * 'z' changed to 'Z' --davidm 1/25/99
464  * 't' added for ptrdiff_t
465  *
466  * @fmt: the format string
467  * @type of the token returned
468  * @flags: various flags such as +, -, # tokens..
469  * @field_width: overwritten width
470  * @base: base of the number (octal, hex, ...)
471  * @precision: precision of a number
472  * @qualifier: qualifier of a number (long, size_t, ...)
473  */
474 static noinline_for_stack
475 int format_decode(const char *fmt, struct printf_spec *spec)
476 {
477         const char *start = fmt;
478
479         /* we finished early by reading the field width */
480         if (spec->type == FORMAT_TYPE_WIDTH) {
481                 if (spec->field_width < 0) {
482                         spec->field_width = -spec->field_width;
483                         spec->flags |= LEFT;
484                 }
485                 spec->type = FORMAT_TYPE_NONE;
486                 goto precision;
487         }
488
489         /* we finished early by reading the precision */
490         if (spec->type == FORMAT_TYPE_PRECISION) {
491                 if (spec->precision < 0)
492                         spec->precision = 0;
493
494                 spec->type = FORMAT_TYPE_NONE;
495                 goto qualifier;
496         }
497
498         /* By default */
499         spec->type = FORMAT_TYPE_NONE;
500
501         for (;;) {
502                 if (*fmt == '\0')
503                         return fmt - start;
504                 if (*fmt == '%')
505                         break;
506                 ++fmt;
507         }
508
509         /* Return the current non-format string */
510         if (fmt != start)
511                 return fmt - start;
512
513         /* Process flags */
514         spec->flags = 0;
515
516         while (1) { /* this also skips first '%' */
517                 bool found = true;
518
519                 ++fmt;
520
521                 switch (*fmt) {
522                 case '-': spec->flags |= LEFT;    break;
523 //              case '+': spec->flags |= PLUS;    break;
524 //              case ' ': spec->flags |= SPACE;   break;
525                 case '#': spec->flags |= SPECIAL; break;
526                 case '0': spec->flags |= ZEROPAD; break;
527                 default:  found = false;
528                 }
529
530                 if (!found)
531                         break;
532         }
533
534         /* get field width */
535         spec->field_width = -1;
536
537         if (isdigit(*fmt))
538                 spec->field_width = skip_atoi(&fmt);
539         else if (*fmt == '*') {
540                 /* it's the next argument */
541                 spec->type = FORMAT_TYPE_WIDTH;
542                 return ++fmt - start;
543         }
544
545 precision:
546         /* get the precision */
547         spec->precision = -1;
548         if (*fmt == '.') {
549                 ++fmt;
550                 if (isdigit(*fmt)) {
551                         spec->precision = skip_atoi(&fmt);
552 //                      if (spec->precision < 0)
553 //                              spec->precision = 0;
554                 } else if (*fmt == '*') {
555                         /* it's the next argument */
556                         spec->type = FORMAT_TYPE_PRECISION;
557                         return ++fmt - start;
558                 }
559         }
560
561 qualifier:
562         /* get the conversion qualifier */
563         spec->qualifier = -1;
564         if (*fmt == 'l') {
565                 spec->qualifier = *fmt++;
566                 if (unlikely(spec->qualifier == *fmt)) {
567                         spec->qualifier = 'L';
568                         ++fmt;
569                 }
570         }
571
572         /* default base */
573         spec->base = 10;
574         switch (*fmt) {
575         case 'c':
576                 spec->type = FORMAT_TYPE_CHAR;
577                 return ++fmt - start;
578
579         case 's':
580                 spec->type = FORMAT_TYPE_STR;
581                 return ++fmt - start;
582
583         case 'p':
584                 spec->type = FORMAT_TYPE_PTR;
585                 return ++fmt - start;
586
587         case '%':
588                 spec->type = FORMAT_TYPE_PERCENT_CHAR;
589                 return ++fmt - start;
590
591         /* integer number formats - set up the flags and "break" */
592         case 'o':
593                 spec->base = 8;
594                 break;
595
596         case 'x':
597 //              spec->flags |= SMALL;
598
599         case 'X':
600                 spec->base = 16;
601                 break;
602
603         case 'd':
604         case 'i':
605                 spec->flags |= SIGN;
606         case 'u':
607                 break;
608
609         default:
610                 spec->type = FORMAT_TYPE_INVALID;
611                 return fmt - start;
612         }
613
614         if (spec->qualifier == 'L')
615                 spec->type = FORMAT_TYPE_LONG_LONG;
616         else if (spec->qualifier == 'l') {
617                 if (spec->flags & SIGN)
618                         spec->type = FORMAT_TYPE_LONG;
619                 else
620                         spec->type = FORMAT_TYPE_ULONG;
621         } else {
622                 if (spec->flags & SIGN)
623                         spec->type = FORMAT_TYPE_INT;
624                 else
625                         spec->type = FORMAT_TYPE_UINT;
626         }
627
628         return ++fmt - start;
629 }
630
631 /**
632  * vsnprintf - Format a string and place it in a buffer
633  * @buf: The buffer to place the result into
634  * @size: The size of the buffer, including the trailing null space
635  * @fmt: The format string to use
636  * @args: Arguments for the format string
637  *
638  * The return value is the number of characters which would
639  * be generated for the given input, excluding the trailing
640  * '\0', as per ISO C99. If you want to have the exact
641  * number of characters written into @buf as return value
642  * (not including the trailing '\0'), use vscnprintf(). If the
643  * return is greater than or equal to @size, the resulting
644  * string is truncated.
645  *
646  * If you're not already dealing with a va_list consider using snprintf().
647  */
648 static
649 int kernel_vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
650 {
651         unsigned long long num;
652         char *str, *end;
653         struct printf_spec spec = {0};
654
655         str = buf;
656         end = buf + size;
657
658         while (*fmt) {
659                 const char *old_fmt = fmt;
660                 int read = format_decode(fmt, &spec);
661
662                 fmt += read;
663
664                 switch (spec.type) {
665                 case FORMAT_TYPE_NONE: {
666                         int copy = read;
667                         if (str < end) {
668                                 if (copy > end - str)
669                                         copy = end - str;
670                                 memcpy(str, old_fmt, copy);
671                         }
672                         str += read;
673                         break;
674                 }
675
676                 case FORMAT_TYPE_WIDTH:
677                         spec.field_width = va_arg(args, int);
678                         break;
679
680                 case FORMAT_TYPE_PRECISION:
681                         spec.precision = va_arg(args, int);
682                         break;
683
684                 case FORMAT_TYPE_CHAR: {
685                         char c;
686
687                         if (!(spec.flags & LEFT)) {
688                                 while (--spec.field_width > 0) {
689                                         if (str < end)
690                                                 *str = ' ';
691                                         ++str;
692
693                                 }
694                         }
695                         c = (unsigned char) va_arg(args, int);
696                         if (str < end)
697                                 *str = c;
698                         ++str;
699                         while (--spec.field_width > 0) {
700                                 if (str < end)
701                                         *str = ' ';
702                                 ++str;
703                         }
704                         break;
705                 }
706
707                 case FORMAT_TYPE_STR:
708                         str = string(str, end, va_arg(args, char *), spec);
709                         break;
710
711                 case FORMAT_TYPE_PTR:
712                         str = pointer(fmt+1, str, end, va_arg(args, void *),
713                                       spec);
714 //                      while (isalnum(*fmt))
715 //                              fmt++;
716                         break;
717
718                 case FORMAT_TYPE_PERCENT_CHAR:
719                         if (str < end)
720                                 *str = '%';
721                         ++str;
722                         break;
723
724                 case FORMAT_TYPE_INVALID:
725                         if (str < end)
726                                 *str = '%';
727                         ++str;
728                         break;
729
730                 default:
731                         switch (spec.type) {
732                         case FORMAT_TYPE_LONG_LONG:
733                                 num = va_arg(args, long long);
734                                 break;
735                         case FORMAT_TYPE_ULONG:
736                                 num = va_arg(args, unsigned long);
737                                 break;
738                         case FORMAT_TYPE_LONG:
739                                 num = va_arg(args, long);
740                                 break;
741                         case FORMAT_TYPE_INT:
742                                 num = (int) va_arg(args, int);
743                                 break;
744                         default:
745                                 num = va_arg(args, unsigned int);
746                         }
747
748                         str = number(str, end, num, spec);
749                 }
750         }
751
752 //      if (size > 0) {
753                 if (str < end)
754                         *str = '\0';
755 //              else
756 //                      end[-1] = '\0';
757 //      }
758
759         /* the trailing null byte doesn't count towards the total */
760         return str-buf;
761
762 }
763
764 int strace_vfprintf(FILE *fp, const char *fmt, va_list args)
765 {
766         static char *buf = NULL;
767         static unsigned buflen = 0;
768
769         int r;
770         va_list a1;
771
772         va_copy(a1, args);
773         unsigned len = kernel_vsnprintf(buf, buflen, fmt, a1);
774         va_end(a1);
775
776         if (len >= buflen) {
777                 buflen = len + 256;
778                 free(buf);
779                 buf = xmalloc(buflen);
780                 /*len =*/ kernel_vsnprintf(buf, buflen, fmt, args);
781         }
782
783         r = fputs_unlocked(buf, fp);
784         if (r < 0) return r;
785         return len;
786 }
787
788 #endif /* USE_CUSTOM_PRINTF */