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