printf.c
1 /* 2 * 3 * It has originally been taken from the HelenOS project 4 * (http://www.helenos.eu), and slightly modified for our purposes. 5 * 6 * Copyright (C) 2001-2004 Jakub Jermar 7 * Copyright (C) 2006 Josef Cejka 8 * Copyright (C) 2008 Uwe Hermann <uwe@hermann-uwe.de> 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 15 * - Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * - Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * - The name of the author may not be used to endorse or promote products 21 * derived from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 #include <libpayload.h> 36 #include <ctype.h> 37 38 static struct _FILE { 39 } _stdout, _stdin, _stderr; 40 41 FILE *stdout = &_stdout; 42 FILE *stdin = &_stdin; 43 FILE *stderr = &_stderr; 44 45 /** Structure for specifying output methods for different printf clones. */ 46 struct printf_spec { 47 /* Output function, returns count of printed characters or EOF. */ 48 int (*write) (const char *, size_t, void *); 49 /* Support data - output stream specification, its state, locks, ... */ 50 void *data; 51 }; 52 53 /** Show prefixes 0x or 0. */ 54 #define __PRINTF_FLAG_PREFIX 0x00000001 55 /** Signed / unsigned number. */ 56 #define __PRINTF_FLAG_SIGNED 0x00000002 57 /** Print leading zeroes. */ 58 #define __PRINTF_FLAG_ZEROPADDED 0x00000004 59 /** Align to left. */ 60 #define __PRINTF_FLAG_LEFTALIGNED 0x00000010 61 /** Always show + sign. */ 62 #define __PRINTF_FLAG_SHOWPLUS 0x00000020 63 /** Print space instead of plus. */ 64 #define __PRINTF_FLAG_SPACESIGN 0x00000040 65 /** Show big characters. */ 66 #define __PRINTF_FLAG_BIGCHARS 0x00000080 67 /** Number has - sign. */ 68 #define __PRINTF_FLAG_NEGATIVE 0x00000100 69 70 /** 71 * Buffer big enough for 64-bit number printed in base 2, sign, and prefix. 72 * Add some more to support sane amounts of zero-padding. 73 */ 74 #define PRINT_BUFFER_SIZE (64 + 1 + 2 + 13) 75 76 /** Enumeration of possible arguments types. */ 77 typedef enum { 78 PrintfQualifierByte = 0, 79 PrintfQualifierShort, 80 PrintfQualifierInt, 81 PrintfQualifierLong, 82 PrintfQualifierLongLong, 83 PrintfQualifierPointer, 84 } qualifier_t; 85 86 static const char digits_small[] = "0123456789abcdef"; 87 static const char digits_big[] = "0123456789ABCDEF"; 88 89 /** 90 * Print one or more characters without adding newline. 91 * 92 * @param buf Buffer of >= count bytesi size. NULL pointer is not allowed! 93 * @param count Number of characters to print. 94 * @param ps Output method and its data. 95 * @return Number of characters printed. 96 */ 97 static int printf_putnchars(const char *buf, size_t count, 98 struct printf_spec *ps) 99 { 100 return ps->write(buf, count, ps->data); 101 } 102 103 /** 104 * Print a string without adding a newline. 105 * 106 * @param str String to print. 107 * @param ps Write function specification and support data. 108 * @return Number of characters printed. 109 */ 110 static inline int printf_putstr(const char *str, struct printf_spec *ps) 111 { 112 return printf_putnchars(str, strlen(str), ps); 113 } 114 115 /** 116 * Print one character. 117 * 118 * @param c Character to be printed. 119 * @param ps Output method. 120 * @return Number of characters printed. 121 */ 122 static int printf_putchar(int c, struct printf_spec *ps) 123 { 124 char ch = c; 125 126 return ps->write(&ch, 1, ps->data); 127 } 128 129 /* Print spaces for padding. Ignores negative counts. */ 130 static int print_spaces(int count, struct printf_spec *ps) 131 { 132 int tmp, ret; 133 char buffer[PRINT_BUFFER_SIZE]; 134 135 if (count <= 0) 136 return 0; 137 138 memset(buffer, ' ', MIN(PRINT_BUFFER_SIZE, count)); 139 for (tmp = count; tmp > PRINT_BUFFER_SIZE; tmp -= PRINT_BUFFER_SIZE) 140 if ((ret = printf_putnchars(buffer, PRINT_BUFFER_SIZE, ps)) < 0) 141 return ret; 142 143 if ((ret = printf_putnchars(buffer, tmp, ps)) < 0) 144 return ret; 145 146 return count; 147 } 148 149 /** 150 * Print one formatted character. 151 * 152 * @param c Character to print. 153 * @param width Width modifier. 154 * @param flags Flags that change the way the character is printed. 155 * @param ps Output methods spec for different printf clones. 156 * @return Number of characters printed, negative value on failure. 157 */ 158 static int print_char(char c, int width, uint64_t flags, struct printf_spec *ps) 159 { 160 int retval; 161 int counter = 1; 162 163 if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) { 164 if ((retval = print_spaces(width - 1, ps)) < 0) 165 return retval; 166 else 167 counter += retval; 168 } 169 170 if ((retval = printf_putchar(c, ps)) < 0) 171 return retval; 172 173 if (flags & __PRINTF_FLAG_LEFTALIGNED) { 174 if ((retval = print_spaces(width - 1, ps)) < 0) 175 return retval; 176 else 177 counter += retval; 178 } 179 180 return counter; 181 } 182 183 /** 184 * Print string. 185 * 186 * @param s String to be printed. 187 * @param width Width modifier. 188 * @param precision Precision modifier. 189 * @param flags Flags that modify the way the string is printed. 190 * @param ps Output methods spec for different printf clones. 191 * @return Number of characters printed, negative value on failure. 192 */ 193 /** Structure for specifying output methods for different printf clones. */ 194 static int print_string(char *s, int width, unsigned int precision, 195 uint64_t flags, struct printf_spec *ps) 196 { 197 int counter = 0, retval; 198 size_t size; 199 200 if (s == NULL) 201 return printf_putstr("(NULL)", ps); 202 size = strlen(s); 203 /* Print leading spaces. */ 204 if (precision == 0) 205 precision = size; 206 width -= precision; 207 208 if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) { 209 if ((retval = print_spaces(width, ps)) < 0) 210 return retval; 211 else 212 counter += retval; 213 } 214 215 if ((retval = printf_putnchars(s, MIN(size, precision), ps)) < 0) 216 return retval; 217 counter += retval; 218 219 if (flags & __PRINTF_FLAG_LEFTALIGNED) { 220 if ((retval = print_spaces(width, ps)) < 0) 221 return retval; 222 else 223 counter += retval; 224 } 225 226 return counter; 227 } 228 229 /** 230 * Print a number in a given base. 231 * 232 * Print significant digits of a number in given base. 233 * 234 * @param num Number to print. 235 * @param width Width modifier. 236 * @param precision Precision modifier. 237 * @param base Base to print the number in (must be between 2 and 16). 238 * @param flags Flags that modify the way the number is printed. 239 * @param ps Output methods spec for different printf clones. 240 * @return Number of characters printed. 241 */ 242 static int print_number(uint64_t num, int width, int precision, int base, 243 uint64_t flags, struct printf_spec *ps) 244 { 245 const char *digits = digits_small; 246 char d[PRINT_BUFFER_SIZE]; 247 char *ptr = &d[PRINT_BUFFER_SIZE]; 248 int size = 0; /* Size of the string in ptr */ 249 int counter = 0; /* Amount of actually printed bytes. */ 250 char sgn; 251 int retval; 252 253 if (flags & __PRINTF_FLAG_BIGCHARS) 254 digits = digits_big; 255 256 if (num == 0) { 257 *--ptr = '0'; 258 size++; 259 } else { 260 do { 261 *--ptr = digits[num % base]; 262 size++; 263 } while (num /= base); 264 } 265 266 /* Both precision and LEFTALIGNED overrule ZEROPADDED. */ 267 if ((flags & __PRINTF_FLAG_LEFTALIGNED) || precision) 268 flags &= ~__PRINTF_FLAG_ZEROPADDED; 269 270 /* Fix precision now since it doesn't count prefixes/signs. */ 271 precision -= size; 272 273 /* Reserve size for prefixes/signs before filling up padding. */ 274 sgn = 0; 275 if (flags & __PRINTF_FLAG_SIGNED) { 276 if (flags & __PRINTF_FLAG_NEGATIVE) { 277 sgn = '-'; 278 size++; 279 } else if (flags & __PRINTF_FLAG_SHOWPLUS) { 280 sgn = '+'; 281 size++; 282 } else if (flags & __PRINTF_FLAG_SPACESIGN) { 283 sgn = ' '; 284 size++; 285 } 286 } 287 if (flags & __PRINTF_FLAG_PREFIX) { 288 switch (base) { 289 case 2: /* Binary formating is not standard, but useful. */ 290 size += 2; 291 break; 292 case 8: 293 size++; 294 break; 295 case 16: 296 size += 2; 297 break; 298 } 299 } 300 301 /* If this is still set we didn't have a precision, so repurpose it */ 302 if (flags & __PRINTF_FLAG_ZEROPADDED) 303 precision = width - size; 304 305 /* Pad smaller numbers with 0 (larger numbers lead to precision < 0). */ 306 if (precision > 0) { 307 precision = MIN(precision, PRINT_BUFFER_SIZE - size); 308 ptr -= precision; 309 size += precision; 310 memset(ptr, '0', precision); 311 } 312 313 /* Add sign and prefix (we adjusted size for this beforehand). */ 314 if (flags & __PRINTF_FLAG_PREFIX) { 315 switch (base) { 316 case 2: /* Binary formating is not standard, but useful. */ 317 *--ptr = (flags & __PRINTF_FLAG_BIGCHARS) ? 'B' : 'b'; 318 *--ptr = '0'; 319 break; 320 case 8: 321 *--ptr = '0'; 322 break; 323 case 16: 324 *--ptr = (flags & __PRINTF_FLAG_BIGCHARS) ? 'X' : 'x'; 325 *--ptr = '0'; 326 break; 327 } 328 } 329 if (sgn) 330 *--ptr = sgn; 331 332 /* Pad with spaces up to width, try to avoid extra putnchar if we can */ 333 width -= size; 334 if (width > 0 && !(flags & __PRINTF_FLAG_LEFTALIGNED)) { 335 int tmp = MIN(width, PRINT_BUFFER_SIZE - size); 336 ptr -= tmp; 337 size += tmp; 338 memset(ptr, ' ', tmp); 339 if ((retval = print_spaces(width - tmp, ps)) < 0) 340 return retval; 341 else 342 counter += retval; 343 } 344 345 /* Now print the whole thing at once. */ 346 if ((retval = printf_putnchars(ptr, size, ps)) < 0) 347 return retval; 348 counter += retval; 349 350 /* Edge case: left-aligned with width (should be rare). */ 351 if (flags & __PRINTF_FLAG_LEFTALIGNED) { 352 if ((retval = print_spaces(width, ps)) < 0) 353 return retval; 354 else 355 counter += retval; 356 } 357 358 return counter; 359 } 360 361 /** 362 * Print formatted string. 363 * 364 * Print string formatted according to the fmt parameter and variadic arguments. 365 * Each formatting directive must have the following form: 366 * 367 * \% [ FLAGS ] [ WIDTH ] [ .PRECISION ] [ TYPE ] CONVERSION 368 * 369 * FLAGS:@n 370 * - "#" Force to print prefix.For \%o conversion, the prefix is 0, for 371 * \%x and \%X prefixes are 0x and 0X and for conversion \%b the 372 * prefix is 0b. 373 * 374 * - "-" Align to left. 375 * 376 * - "+" Print positive sign just as negative. 377 * 378 * - " " If the printed number is positive and "+" flag is not set, 379 * print space in place of sign. 380 * 381 * - "0" Print 0 as padding instead of spaces. Zeroes are placed between 382 * sign and the rest of the number. This flag is ignored if "-" 383 * flag is specified. 384 * 385 * WIDTH:@n 386 * - Specify the minimal width of a printed argument. If it is bigger, 387 * width is ignored. If width is specified with a "*" character instead of 388 * number, width is taken from parameter list. And integer parameter is 389 * expected before parameter for processed conversion specification. If 390 * this value is negative its absolute value is taken and the "-" flag is 391 * set. 392 * 393 * PRECISION:@n 394 * - Value precision. For numbers it specifies minimum valid numbers. 395 * Smaller numbers are printed with leading zeroes. Bigger numbers are not 396 * affected. Strings with more than precision characters are cut off. Just 397 * as with width, an "*" can be used used instead of a number. An integer 398 * value is then expected in parameters. When both width and precision are 399 * specified using "*", the first parameter is used for width and the 400 * second one for precision. 401 * 402 * TYPE:@n 403 * - "hh" Signed or unsigned char.@n 404 * - "h" Signed or unsigned short.@n 405 * - "" Signed or unsigned int (default value).@n 406 * - "l" Signed or unsigned long int.@n 407 * - "ll" Signed or unsigned long long int.@n 408 * 409 * 410 * CONVERSION:@n 411 * - % Print percentile character itself. 412 * 413 * - c Print single character. 414 * 415 * - s Print zero terminated string. If a NULL value is passed as 416 * value, "(NULL)" is printed instead. 417 * 418 * - P, p Print value of a pointer. Void * value is expected and it is 419 * printed in hexadecimal notation with prefix (as with \%#X / \%#x 420 * for 32-bit or \%#X / \%#x for 64-bit long pointers). 421 * 422 * - b Print value as unsigned binary number. Prefix is not printed by 423 * default. (Nonstandard extension.) 424 * 425 * - o Print value as unsigned octal number. Prefix is not printed by 426 * default. 427 * 428 * - d, i Print signed decimal number. There is no difference between d 429 * and i conversion. 430 * 431 * - u Print unsigned decimal number. 432 * 433 * - X, x Print hexadecimal number with upper- or lower-case. Prefix is 434 * not printed by default. 435 * 436 * All other characters from fmt except the formatting directives are printed in 437 * verbatim. 438 * 439 * @param fmt Formatting NULL terminated string. 440 * @param ps TODO. 441 * @param ap TODO. 442 * @return Number of characters printed, negative value on failure. 443 */ 444 static int printf_core(const char *fmt, struct printf_spec *ps, va_list ap) 445 { 446 int i = 0; /* Index of the currently processed char from fmt */ 447 int j = 0; /* Index to the first not printed nonformating character */ 448 int end; 449 int counter; /* Counter of printed characters */ 450 int retval; /* Used to store return values from called functions */ 451 char c; 452 qualifier_t qualifier; /* Type of argument */ 453 int base; /* Base in which a numeric parameter will be printed */ 454 uint64_t number; /* Argument value */ 455 size_t size; /* Byte size of integer parameter */ 456 int width, precision; 457 uint64_t flags; 458 459 counter = 0; 460 461 while ((c = fmt[i])) { 462 /* Control character. */ 463 if (c == '%') { 464 /* Print common characters if any processed. */ 465 if (i > j) { 466 if ((retval = printf_putnchars(&fmt[j], 467 (size_t) (i - j), ps)) < 0) 468 return retval; 469 counter += retval; 470 } 471 472 j = i; 473 /* Parse modifiers. */ 474 flags = 0; 475 end = 0; 476 477 do { 478 ++i; 479 switch (c = fmt[i]) { 480 case '#': 481 flags |= __PRINTF_FLAG_PREFIX; 482 break; 483 case '-': 484 flags |= __PRINTF_FLAG_LEFTALIGNED; 485 break; 486 case '+': 487 flags |= __PRINTF_FLAG_SHOWPLUS; 488 break; 489 case ' ': 490 flags |= __PRINTF_FLAG_SPACESIGN; 491 break; 492 case '0': 493 flags |= __PRINTF_FLAG_ZEROPADDED; 494 break; 495 default: 496 end = 1; 497 }; 498 499 } while (end == 0); 500 501 /* Width & '*' operator. */ 502 width = 0; 503 if (isdigit(fmt[i])) { 504 while (isdigit(fmt[i])) { 505 width *= 10; 506 width += fmt[i++] - '0'; 507 } 508 } else if (fmt[i] == '*') { 509 /* Get width value from argument list. */ 510 i++; 511 width = (int)va_arg(ap, int); 512 if (width < 0) { 513 /* Negative width sets '-' flag. */ 514 width *= -1; 515 flags |= __PRINTF_FLAG_LEFTALIGNED; 516 } 517 } 518 519 /* Precision and '*' operator. */ 520 precision = 0; 521 if (fmt[i] == '.') { 522 ++i; 523 if (isdigit(fmt[i])) { 524 while (isdigit(fmt[i])) { 525 precision *= 10; 526 precision += fmt[i++] - '0'; 527 } 528 } else if (fmt[i] == '*') { 529 /* Get precision from argument list. */ 530 i++; 531 precision = (int)va_arg(ap, int); 532 /* Ignore negative precision. */ 533 if (precision < 0) 534 precision = 0; 535 } 536 } 537 538 switch (fmt[i++]) { 539 /** @todo unimplemented qualifiers: 540 * t ptrdiff_t - ISO C 99 541 */ 542 case 'h': /* char or short */ 543 qualifier = PrintfQualifierShort; 544 if (fmt[i] == 'h') { 545 i++; 546 qualifier = PrintfQualifierByte; 547 } 548 break; 549 case 'z': /* size_t or ssize_t */ 550 qualifier = PrintfQualifierLong; 551 break; 552 case 'l': /* long or long long */ 553 qualifier = PrintfQualifierLong; 554 if (fmt[i] == 'l') { 555 i++; 556 qualifier = PrintfQualifierLongLong; 557 } 558 break; 559 default: 560 /* default type */ 561 qualifier = PrintfQualifierInt; 562 --i; 563 } 564 565 base = 10; 566 567 switch (c = fmt[i]) { 568 /* String and character conversions */ 569 case 's': 570 if ((retval = print_string(va_arg(ap, char *), 571 width, precision, flags, ps)) < 0) 572 return retval; 573 counter += retval; 574 j = i + 1; 575 goto next_char; 576 case 'c': 577 c = va_arg(ap, unsigned int); 578 if ((retval = print_char(c, width, flags, ps)) < 0) 579 return retval; 580 counter += retval; 581 j = i + 1; 582 goto next_char; 583 584 /* Integer values */ 585 case 'P': /* pointer */ 586 flags |= __PRINTF_FLAG_BIGCHARS; 587 __fallthrough; 588 case 'p': 589 flags |= __PRINTF_FLAG_PREFIX; 590 base = 16; 591 qualifier = PrintfQualifierPointer; 592 break; 593 case 'b': 594 base = 2; 595 break; 596 case 'o': 597 base = 8; 598 break; 599 case 'd': 600 case 'i': 601 flags |= __PRINTF_FLAG_SIGNED; 602 break; 603 case 'u': 604 break; 605 case 'X': 606 flags |= __PRINTF_FLAG_BIGCHARS; 607 __fallthrough; 608 case 'x': 609 base = 16; 610 break; 611 case '%': /* percentile itself */ 612 j = i; 613 goto next_char; 614 default: /* Bad formatting */ 615 /* 616 * Unknown format. Now, j is the index of '%' 617 * so we will print whole bad format sequence. 618 */ 619 goto next_char; 620 } 621 622 /* Print integers. */ 623 /* Print number. */ 624 switch (qualifier) { 625 case PrintfQualifierByte: 626 size = sizeof(unsigned char); 627 number = (uint64_t) va_arg(ap, unsigned int); 628 break; 629 case PrintfQualifierShort: 630 size = sizeof(unsigned short); 631 number = (uint64_t) va_arg(ap, unsigned int); 632 break; 633 case PrintfQualifierInt: 634 size = sizeof(unsigned int); 635 number = (uint64_t) va_arg(ap, unsigned int); 636 break; 637 case PrintfQualifierLong: 638 size = sizeof(unsigned long); 639 number = (uint64_t) va_arg(ap, unsigned long); 640 break; 641 case PrintfQualifierLongLong: 642 size = sizeof(unsigned long long); 643 number = (uint64_t) va_arg(ap, unsigned long long); 644 break; 645 case PrintfQualifierPointer: 646 size = sizeof(void *); 647 number = (uint64_t) (unsigned long)va_arg(ap, void *); 648 break; 649 } 650 651 if (flags & __PRINTF_FLAG_SIGNED) { 652 if (number & (0x1ULL << (size * 8 - 1))) { 653 flags |= __PRINTF_FLAG_NEGATIVE; 654 655 if (size == sizeof(uint64_t)) { 656 number = -((int64_t) number); 657 } else { 658 number = ~number; 659 number &= ~(0xFFFFFFFFFFFFFFFFll << (size * 8)); 660 number++; 661 } 662 } 663 } 664 665 if ((retval = print_number(number, width, precision, 666 base, flags, ps)) < 0) 667 return retval; 668 669 counter += retval; 670 j = i + 1; 671 } 672 next_char: 673 ++i; 674 } 675 676 if (i > j) { 677 if ((retval = printf_putnchars(&fmt[j], 678 (u64) (i - j), ps)) < 0) 679 return retval; 680 counter += retval; 681 } 682 683 return counter; 684 } 685 686 int snprintf(char *str, size_t size, const char *fmt, ...) 687 { 688 int ret; 689 va_list args; 690 691 va_start(args, fmt); 692 ret = vsnprintf(str, size, fmt, args); 693 va_end(args); 694 695 return ret; 696 } 697 698 int sprintf(char *str, const char *fmt, ...) 699 { 700 int ret; 701 va_list args; 702 703 va_start(args, fmt); 704 ret = vsprintf(str, fmt, args); 705 va_end(args); 706 707 return ret; 708 } 709 710 int fprintf(FILE *file, const char *fmt, ...) 711 { 712 int ret; 713 if ((file == stdout) || (file == stderr)) { 714 va_list args; 715 va_start(args, fmt); 716 ret = vprintf(fmt, args); 717 va_end(args); 718 719 return ret; 720 } 721 return -1; 722 } 723 724 struct vsnprintf_data { 725 size_t size; /* Total space for string */ 726 size_t len; /* Count of currently used characters */ 727 char *string; /* Destination string */ 728 }; 729 730 /** 731 * Write string to given buffer. 732 * 733 * Write at most data->size characters including trailing zero. According to 734 * C99, snprintf() has to return number of characters that would have been 735 * written if enough space had been available. Hence the return value is not 736 * number of really printed characters but size of the input string. 737 * Number of really used characters is stored in data->len. 738 * 739 * @param str Source string to print. 740 * @param count Size of source string. 741 * @param _data Structure with destination string, counter of used space 742 * and total string size. 743 * @return Number of characters to print (not characters really printed!). 744 */ 745 static int vsnprintf_write(const char *str, size_t count, void *_data) 746 { 747 struct vsnprintf_data *data = _data; 748 size_t i; 749 750 i = data->size - data->len; 751 if (i == 0) 752 return count; 753 754 /* We have only one free byte left in buffer => write trailing zero. */ 755 if (i == 1) { 756 data->string[data->size - 1] = 0; 757 data->len = data->size; 758 return count; 759 } 760 761 /* 762 * We have not enough space for whole string with the trailing 763 * zero => print only a part of string. 764 */ 765 if (i <= count) { 766 memcpy((void *)(data->string + data->len), (void *)str, i - 1); 767 data->string[data->size - 1] = 0; 768 data->len = data->size; 769 return count; 770 } 771 772 /* Buffer is big enough to print whole string. */ 773 memcpy((void *)(data->string + data->len), (void *)str, count); 774 data->len += count; 775 /* 776 * Put trailing zero at end, but not count it into data->len so 777 * it could be rewritten next time. 778 */ 779 data->string[data->len] = 0; 780 781 return count; 782 } 783 784 int vsnprintf(char *str, size_t size, const char *fmt, va_list ap) 785 { 786 struct vsnprintf_data data = { size, 0, str }; 787 struct printf_spec ps = { vsnprintf_write, &data }; 788 789 /* Print 0 at end of string - fix case that nothing will be printed. */ 790 if (size > 0) 791 str[0] = 0; 792 793 /* vsnprintf_write() ensures that str will be terminated by zero. */ 794 return printf_core(fmt, &ps, ap); 795 } 796 797 int vsprintf(char *str, const char *fmt, va_list ap) 798 { 799 return vsnprintf(str, (size_t) - 1, fmt, ap); 800 } 801 802 int printf(const char *fmt, ...) 803 { 804 int ret; 805 va_list args; 806 807 va_start(args, fmt); 808 ret = vprintf(fmt, args); 809 va_end(args); 810 811 return ret; 812 } 813 814 static int vprintf_write(const char *str, size_t count, void *unused) 815 { 816 console_write(str, count); 817 return count; 818 } 819 820 int vprintf(const char *fmt, va_list ap) 821 { 822 struct printf_spec ps = { vprintf_write, NULL }; 823 824 return printf_core(fmt, &ps, ap); 825 }