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