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