vsprintf.c revision 76da831a4159a58cd321328498496e772e3b4afc
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#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
28static inline
29int 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] */
50static noinline_for_stack
51char *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 */
99static noinline_for_stack
100char *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
151static
152char *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
167static noinline_for_stack
168char *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 */
186static
187char *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
246enum 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
262struct 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
271static noinline_for_stack
272char *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
398static noinline_for_stack
399char *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
436static noinline_for_stack
437char *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 */
470static noinline_for_stack
471int 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
541precision:
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
557qualifier:
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 */
644static
645int 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
760int 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 */
787