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 <[email protected]>
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 */
printf_putnchars(const char * buf,size_t count,struct printf_spec * ps)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 */
printf_putstr(const char * str,struct printf_spec * ps)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 */
printf_putchar(int c,struct printf_spec * ps)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. */
print_spaces(int count,struct printf_spec * ps)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 */
print_char(char c,int width,uint64_t flags,struct printf_spec * ps)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. */
print_string(char * s,int width,unsigned int precision,uint64_t flags,struct printf_spec * ps)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 */
print_number(uint64_t num,int width,int precision,int base,uint64_t flags,struct printf_spec * ps)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 */
printf_core(const char * fmt,struct printf_spec * ps,va_list ap)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
snprintf(char * str,size_t size,const char * fmt,...)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
sprintf(char * str,const char * fmt,...)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
fprintf(FILE * file,const char * fmt,...)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 */
vsnprintf_write(const char * str,size_t count,void * _data)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
vsnprintf(char * str,size_t size,const char * fmt,va_list ap)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
vsprintf(char * str,const char * fmt,va_list ap)797 int vsprintf(char *str, const char *fmt, va_list ap)
798 {
799 return vsnprintf(str, (size_t) - 1, fmt, ap);
800 }
801
printf(const char * fmt,...)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
vprintf_write(const char * str,size_t count,void * unused)814 static int vprintf_write(const char *str, size_t count, void *unused)
815 {
816 console_write(str, count);
817 return count;
818 }
819
vprintf(const char * fmt,va_list ap)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 }
826