| Denys Vlasenko | 6e4f3c1 | 2012-04-16 18:22:19 +0200 | [diff] [blame] | 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" | 
| Denys Vlasenko | 6e4f3c1 | 2012-04-16 18:22:19 +0200 | [diff] [blame] | 13 |  | 
| Denys Vlasenko | 76da831 | 2013-07-16 12:18:59 +0200 | [diff] [blame] | 14 | #if USE_CUSTOM_PRINTF | 
| Denys Vlasenko | 6e4f3c1 | 2012-04-16 18:22:19 +0200 | [diff] [blame] | 15 |  | 
| Dmitry V. Levin | a5fd66b | 2012-05-01 22:49:49 +0000 | [diff] [blame] | 16 | #include <stdarg.h> | 
|  | 17 | #include <limits.h> | 
|  | 18 |  | 
| Dmitry V. Levin | d354130 | 2014-02-26 00:01:00 +0000 | [diff] [blame] | 19 | #ifndef HAVE_FPUTS_UNLOCKED | 
|  | 20 | # define fputs_unlocked fputs | 
|  | 21 | #endif | 
|  | 22 |  | 
| Denys Vlasenko | 6e4f3c1 | 2012-04-16 18:22:19 +0200 | [diff] [blame] | 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 | { | 
| Denys Vlasenko | dafba9b | 2013-03-05 17:29:18 +0100 | [diff] [blame] | 766 | static char *buf = NULL; | 
|  | 767 | static unsigned buflen = 0; | 
| Denys Vlasenko | 6e4f3c1 | 2012-04-16 18:22:19 +0200 | [diff] [blame] | 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); | 
| Dmitry V. Levin | 3e9d71f | 2015-05-25 20:41:02 +0000 | [diff] [blame] | 779 | buf = xmalloc(buflen); | 
| Denys Vlasenko | 6e4f3c1 | 2012-04-16 18:22:19 +0200 | [diff] [blame] | 780 | /*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 */ |