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