blob: aae40db30d6a58c30e2dd9fe5fd2d792e87eccaf [file] [log] [blame]
Denys Vlasenko6e4f3c12012-04-16 18:22:19 +02001/*
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"
Denys Vlasenko6e4f3c12012-04-16 18:22:19 +020013
Denys Vlasenko76da8312013-07-16 12:18:59 +020014#if USE_CUSTOM_PRINTF
Denys Vlasenko6e4f3c12012-04-16 18:22:19 +020015
Dmitry V. Levina5fd66b2012-05-01 22:49:49 +000016#include <stdarg.h>
17#include <limits.h>
18
Dmitry V. Levind3541302014-02-26 00:01:00 +000019#ifndef HAVE_FPUTS_UNLOCKED
20# define fputs_unlocked fputs
21#endif
22
Denys Vlasenko6e4f3c12012-04-16 18:22:19 +020023#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
32static inline
33int 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] */
54static noinline_for_stack
55char *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 */
103static noinline_for_stack
104char *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
155static
156char *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
171static noinline_for_stack
172char *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 */
190static
191char *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
250enum 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
266struct 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
275static noinline_for_stack
276char *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
402static noinline_for_stack
403char *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
440static noinline_for_stack
441char *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 */
474static noinline_for_stack
475int 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
545precision:
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
561qualifier:
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 */
648static
649int 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
764int strace_vfprintf(FILE *fp, const char *fmt, va_list args)
765{
Denys Vlasenkodafba9b2013-03-05 17:29:18 +0100766 static char *buf = NULL;
767 static unsigned buflen = 0;
Denys Vlasenko6e4f3c12012-04-16 18:22:19 +0200768
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);
Dmitry V. Levin3e9d71f2015-05-25 20:41:02 +0000779 buf = xmalloc(buflen);
Denys Vlasenko6e4f3c12012-04-16 18:22:19 +0200780 /*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 */