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