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