libpayload: Fix a small but aggressive bug in printf()
[coreboot.git] / payloads / libpayload / libc / printf.c
1 /*
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>
37
38 /** Structure for specifying output methods for different printf clones. */
39 struct 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. */
71 typedef enum {
72         PrintfQualifierByte = 0,
73         PrintfQualifierShort,
74         PrintfQualifierInt,
75         PrintfQualifierLong,
76         PrintfQualifierLongLong,
77         PrintfQualifierPointer,
78 } qualifier_t;
79
80 static char digits_small[] = "0123456789abcdef";
81 static 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  */
91 static 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  */
104 static 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  */
125 static 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.
138  * @return      Number of characters printed, negative value on failure.
139  */
140 static int print_char(char c, int width, uint64_t flags, struct printf_spec *ps)
141 {
142         int counter = 0;
143
144         if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
145                 while (--width > 0) {
146                         if (printf_putchar(' ', ps) > 0)
147                                 ++counter;
148                 }
149         }
150
151         if (printf_putchar(c, ps) > 0)
152                 counter++;
153
154         while (--width > 0) {
155                 if (printf_putchar(' ', ps) > 0)
156                         ++counter;
157         }
158
159         return counter;
160 }
161
162 /**
163  * Print string.
164  *
165  * @param s             String to be printed.
166  * @param width         Width modifier.
167  * @param precision     Precision modifier.
168  * @param flags         Flags that modify the way the string is printed.
169  * @return              Number of characters printed, negative value on failure.
170  */
171 static int print_string(char *s, int width, unsigned int precision,
172                         uint64_t flags, struct printf_spec *ps)
173 {
174         int counter = 0, retval;
175         size_t size;
176
177         if (s == NULL)
178                 return printf_putstr("(NULL)", ps);
179         size = strlen(s);
180         /* Print leading spaces. */
181         if (precision == 0)
182                 precision = size;
183         width -= precision;
184
185         if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
186                 while (width-- > 0) {
187                         if (printf_putchar(' ', ps) == 1)
188                                 counter++;
189                 }
190         }
191
192         if ((retval = printf_putnchars(s, MIN(size, precision), ps)) < 0)
193                 return -counter;
194         counter += retval;
195
196         while (width-- > 0) {
197                 if (printf_putchar(' ', ps) == 1)
198                         ++counter;
199         }
200
201         return counter;
202 }
203
204 /**
205  * Print a number in a given base.
206  *
207  * Print significant digits of a number in given base.
208  *
209  * @param num           Number to print.
210  * @param widt          Width modifier.h
211  * @param precision     Precision modifier.
212  * @param base          Base to print the number in (must be between 2 and 16).
213  * @param flags         Flags that modify the way the number is printed.
214  * @return              Number of characters printed.
215  */
216 static int print_number(uint64_t num, int width, int precision, int base,
217                         uint64_t flags, struct printf_spec *ps)
218 {
219         char *digits = digits_small;
220         char d[PRINT_NUMBER_BUFFER_SIZE];
221         char *ptr = &d[PRINT_NUMBER_BUFFER_SIZE - 1];
222         int size = 0;           /* Size of number with all prefixes and signs. */
223         int number_size;        /* Size of plain number. */
224         char sgn;
225         int retval;
226         int counter = 0;
227
228         if (flags & __PRINTF_FLAG_BIGCHARS)
229                 digits = digits_big;
230
231         *ptr-- = 0;             /* Put zero at end of string. */
232
233         if (num == 0) {
234                 *ptr-- = '0';
235                 size++;
236         } else {
237                 do {
238                         *ptr-- = digits[num % base];
239                         size++;
240                 } while (num /= base);
241         }
242
243         number_size = size;
244
245         /*
246          * Collect the sum of all prefixes/signs/... to calculate padding and
247          * leading zeroes.
248          */
249         if (flags & __PRINTF_FLAG_PREFIX) {
250                 switch (base) {
251                 case 2: /* Binary formating is not standard, but useful. */
252                         size += 2;
253                         break;
254                 case 8:
255                         size++;
256                         break;
257                 case 16:
258                         size += 2;
259                         break;
260                 }
261         }
262
263         sgn = 0;
264         if (flags & __PRINTF_FLAG_SIGNED) {
265                 if (flags & __PRINTF_FLAG_NEGATIVE) {
266                         sgn = '-';
267                         size++;
268                 } else if (flags & __PRINTF_FLAG_SHOWPLUS) {
269                         sgn = '+';
270                         size++;
271                 } else if (flags & __PRINTF_FLAG_SPACESIGN) {
272                         sgn = ' ';
273                         size++;
274                 }
275         }
276
277         if (flags & __PRINTF_FLAG_LEFTALIGNED)
278                 flags &= ~__PRINTF_FLAG_ZEROPADDED;
279
280         /*
281          * If the number is left-aligned or precision is specified then
282          * zero-padding is ignored.
283          */
284         if (flags & __PRINTF_FLAG_ZEROPADDED) {
285                 if ((precision == 0) && (width > size))
286                         precision = width - size + number_size;
287         }
288
289         /* Print leading spaces. */
290         if (number_size > precision) {
291                 /* Print the whole number not only a part. */
292                 precision = number_size;
293         }
294
295         width -= precision + size - number_size;
296
297         if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
298                 while (width-- > 0) {
299                         if (printf_putchar(' ', ps) == 1)
300                                 counter++;
301                 }
302         }
303
304         /* Print sign. */
305         if (sgn) {
306                 if (printf_putchar(sgn, ps) == 1)
307                         counter++;
308         }
309
310         /* Print prefix. */
311         if (flags & __PRINTF_FLAG_PREFIX) {
312                 switch (base) {
313                 case 2: /* Binary formating is not standard, but useful. */
314                         if (printf_putchar('0', ps) == 1)
315                                 counter++;
316                         if (flags & __PRINTF_FLAG_BIGCHARS) {
317                                 if (printf_putchar('B', ps) == 1)
318                                         counter++;
319                         } else {
320                                 if (printf_putchar('b', ps) == 1)
321                                         counter++;
322                         }
323                         break;
324                 case 8:
325                         if (printf_putchar('o', ps) == 1)
326                                 counter++;
327                         break;
328                 case 16:
329                         if (printf_putchar('0', ps) == 1)
330                                 counter++;
331                         if (flags & __PRINTF_FLAG_BIGCHARS) {
332                                 if (printf_putchar('X', ps) == 1)
333                                         counter++;
334                         } else {
335                                 if (printf_putchar('x', ps) == 1)
336                                         counter++;
337                         }
338                         break;
339                 }
340         }
341
342         /* Print leading zeroes. */
343         precision -= number_size;
344         while (precision-- > 0) {
345                 if (printf_putchar('0', ps) == 1)
346                         counter++;
347         }
348
349         /* Print number itself. */
350         if ((retval = printf_putstr(++ptr, ps)) > 0)
351                 counter += retval;
352
353         /* Print ending spaces. */
354         while (width-- > 0) {
355                 if (printf_putchar(' ', ps) == 1)
356                         counter++;
357         }
358
359         return counter;
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                                         counter = -counter;
469                                         goto out;       /* Error */
470                                 }
471                                 counter += retval;
472                         }
473
474                         j = i;
475                         /* Parse modifiers. */
476                         flags = 0;
477                         end = 0;
478
479                         do {
480                                 ++i;
481                                 switch (c = fmt[i]) {
482                                 case '#':
483                                         flags |= __PRINTF_FLAG_PREFIX;
484                                         break;
485                                 case '-':
486                                         flags |= __PRINTF_FLAG_LEFTALIGNED;
487                                         break;
488                                 case '+':
489                                         flags |= __PRINTF_FLAG_SHOWPLUS;
490                                         break;
491                                 case ' ':
492                                         flags |= __PRINTF_FLAG_SPACESIGN;
493                                         break;
494                                 case '0':
495                                         flags |= __PRINTF_FLAG_ZEROPADDED;
496                                         break;
497                                 default:
498                                         end = 1;
499                                 };
500
501                         } while (end == 0);
502
503                         /* Width & '*' operator. */
504                         width = 0;
505                         if (isdigit(fmt[i])) {
506                                 while (isdigit(fmt[i])) {
507                                         width *= 10;
508                                         width += fmt[i++] - '0';
509                                 }
510                         } else if (fmt[i] == '*') {
511                                 /* Get width value from argument list. */
512                                 i++;
513                                 width = (int)va_arg(ap, int);
514                                 if (width < 0) {
515                                         /* Negative width sets '-' flag. */
516                                         width *= -1;
517                                         flags |= __PRINTF_FLAG_LEFTALIGNED;
518                                 }
519                         }
520
521                         /* Precision and '*' operator. */
522                         precision = 0;
523                         if (fmt[i] == '.') {
524                                 ++i;
525                                 if (isdigit(fmt[i])) {
526                                         while (isdigit(fmt[i])) {
527                                                 precision *= 10;
528                                                 precision += fmt[i++] - '0';
529                                         }
530                                 } else if (fmt[i] == '*') {
531                                         /* Get precision from argument list. */
532                                         i++;
533                                         precision = (int)va_arg(ap, int);
534                                         /* Ignore negative precision. */
535                                         if (precision < 0)
536                                                 precision = 0;
537                                 }
538                         }
539
540                         switch (fmt[i++]) {
541                         /** @todo unimplemented qualifiers:
542                          * t ptrdiff_t - ISO C 99
543                          */
544                         case 'h':       /* char or short */
545                                 qualifier = PrintfQualifierShort;
546                                 if (fmt[i] == 'h') {
547                                         i++;
548                                         qualifier = PrintfQualifierByte;
549                                 }
550                                 break;
551                         case 'l':       /* long or long long */
552                                 qualifier = PrintfQualifierLong;
553                                 if (fmt[i] == 'l') {
554                                         i++;
555                                         qualifier = PrintfQualifierLongLong;
556                                 }
557                                 break;
558                         default:
559                                 /* default type */
560                                 qualifier = PrintfQualifierInt;
561                                 --i;
562                         }
563
564                         base = 10;
565
566                         switch (c = fmt[i]) {
567                         /* String and character conversions */
568                         case 's':
569                                 if ((retval = print_string(va_arg(ap, char *),
570                                     width, precision, flags, ps)) < 0) {
571                                         counter = -counter;
572                                         goto out;
573                                 };
574                                 counter += retval;
575                                 j = i + 1;
576                                 goto next_char;
577                         case 'c':
578                                 c = va_arg(ap, unsigned int);
579                                 retval = print_char(c, width, flags, ps);
580                                 if (retval < 0) {
581                                         counter = -counter;
582                                         goto out;
583                                 };
584                                 counter += retval;
585                                 j = i + 1;
586                                 goto next_char;
587
588                         /* Integer values */
589                         case 'P':       /* pointer */
590                                 flags |= __PRINTF_FLAG_BIGCHARS;
591                         case 'p':
592                                 flags |= __PRINTF_FLAG_PREFIX;
593                                 base = 16;
594                                 qualifier = PrintfQualifierPointer;
595                                 break;
596                         case 'b':
597                                 base = 2;
598                                 break;
599                         case 'o':
600                                 base = 8;
601                                 break;
602                         case 'd':
603                         case 'i':
604                                 flags |= __PRINTF_FLAG_SIGNED;
605                         case 'u':
606                                 break;
607                         case 'X':
608                                 flags |= __PRINTF_FLAG_BIGCHARS;
609                         case 'x':
610                                 base = 16;
611                                 break;
612                         case '%': /* percentile itself */
613                                 j = i;
614                                 goto next_char;
615                         default: /* Bad formatting */
616                                 /*
617                                  * Unknown format. Now, j is the index of '%'
618                                  * so we will print whole bad format sequence.
619                                  */
620                                 goto next_char;
621                         }
622
623                         /* Print integers. */
624                         /* Print number. */
625                         switch (qualifier) {
626                         case PrintfQualifierByte:
627                                 size = sizeof(unsigned char);
628                                 number = (uint64_t) va_arg(ap, unsigned int);
629                                 break;
630                         case PrintfQualifierShort:
631                                 size = sizeof(unsigned short);
632                                 number = (uint64_t) va_arg(ap, unsigned int);
633                                 break;
634                         case PrintfQualifierInt:
635                                 size = sizeof(unsigned int);
636                                 number = (uint64_t) va_arg(ap, unsigned int);
637                                 break;
638                         case PrintfQualifierLong:
639                                 size = sizeof(unsigned long);
640                                 number = (uint64_t) va_arg(ap, unsigned long);
641                                 break;
642                         case PrintfQualifierLongLong:
643                                 size = sizeof(unsigned long long);
644                                 number = (uint64_t) va_arg(ap, unsigned long long);
645                                 break;
646                         case PrintfQualifierPointer:
647                                 size = sizeof(void *);
648                                 number = (uint64_t) (unsigned long)va_arg(ap, void *);
649                                 break;
650                         default:        /* Unknown qualifier */
651                                 counter = -counter;
652                                 goto out;
653                         }
654
655                         if (flags & __PRINTF_FLAG_SIGNED) {
656                                 if (number & (0x1 << (size * 8 - 1))) {
657                                         flags |= __PRINTF_FLAG_NEGATIVE;
658
659                                         if (size == sizeof(uint64_t)) {
660                                                 number = -((int64_t) number);
661                                         } else {
662                                                 number = ~number;
663                                                 number &= ~(0xFFFFFFFFFFFFFFFFll << (size * 8));
664                                                 number++;
665                                         }
666                                 }
667                         }
668
669                         if ((retval = print_number(number, width, precision,
670                                                    base, flags, ps)) < 0) {
671                                 counter = -counter;
672                                 goto out;
673                         }
674
675                         counter += retval;
676                         j = i + 1;
677                 }
678 next_char:
679                 ++i;
680         }
681
682         if (i > j) {
683                 if ((retval = printf_putnchars(&fmt[j],
684                     (u64) (i - j), ps)) < 0) {
685                         counter = -counter;
686                         goto out;       /* Error */
687
688                 }
689                 counter += retval;
690         }
691
692 out:
693         return counter;
694 }
695
696 int snprintf(char *str, size_t size, const char *fmt, ...)
697 {
698         int ret;
699         va_list args;
700
701         va_start(args, fmt);
702         ret = vsnprintf(str, size, fmt, args);
703         va_end(args);
704
705         return ret;
706 }
707
708 int sprintf(char *str, const char *fmt, ...)
709 {
710         int ret;
711         va_list args;
712
713         va_start(args, fmt);
714         ret = vsprintf(str, fmt, args);
715         va_end(args);
716
717         return ret;
718 }
719
720 struct vsnprintf_data {
721         size_t size;            /* Total space for string */
722         size_t len;             /* Count of currently used characters */
723         char *string;           /* Destination string */
724 };
725
726 /**
727  * Write string to given buffer.
728  *
729  * Write at most data->size characters including trailing zero. According to
730  * C99, snprintf() has to return number of characters that would have been
731  * written if enough space had been available. Hence the return value is not
732  * number of really printed characters but size of the input string.
733  * Number of really used characters is stored in data->len.
734  *
735  * @param str   Source string to print.
736  * @param count Size of source string.
737  * @param data  Structure with destination string, counter of used space
738  *              and total string size.
739  * @return Number of characters to print (not characters really printed!).
740  */
741 static int vsnprintf_write(const char *str, size_t count,
742                            struct vsnprintf_data *data)
743 {
744         size_t i;
745
746         i = data->size - data->len;
747         if (i == 0)
748                 return count;
749
750         /* We have only one free byte left in buffer => write trailing zero. */
751         if (i == 1) {
752                 data->string[data->size - 1] = 0;
753                 data->len = data->size;
754                 return count;
755         }
756
757         /*
758          * We have not enough space for whole string with the trailing
759          * zero => print only a part of string.
760          */
761         if (i <= count) {
762                 memcpy((void *)(data->string + data->len), (void *)str, i - 1);
763                 data->string[data->size - 1] = 0;
764                 data->len = data->size;
765                 return count;
766         }
767
768         /* Buffer is big enough to print whole string. */
769         memcpy((void *)(data->string + data->len), (void *)str, count);
770         data->len += count;
771         /*
772          * Put trailing zero at end, but not count it into data->len so
773          * it could be rewritten next time.
774          */
775         data->string[data->len] = 0;
776
777         return count;
778 }
779
780 int vsnprintf(char *str, size_t size, const char *fmt, va_list ap)
781 {
782         struct vsnprintf_data data = { size, 0, str };
783         struct printf_spec ps =
784             { (int (*)(void *, size_t, void *))vsnprintf_write, &data };
785
786         /* Print 0 at end of string - fix case that nothing will be printed. */
787         if (size > 0)
788                 str[0] = 0;
789
790         /* vsnprintf_write() ensures that str will be terminated by zero. */
791         return printf_core(fmt, &ps, ap);
792 }
793
794 int vsprintf(char *str, const char *fmt, va_list ap)
795 {
796         return vsnprintf(str, (size_t) - 1, fmt, ap);
797 }
798
799 int printf(const char *fmt, ...)
800 {
801         int ret;
802         va_list args;
803
804         va_start(args, fmt);
805         ret = vprintf(fmt, args);
806         va_end(args);
807
808         return ret;
809 }
810
811 static int vprintf_write(const char *str, size_t count, void *unused)
812 {
813         size_t i;
814
815         for (i = 0; i < count; i++)
816                 putchar(str[i]);
817
818         return i;
819 }
820
821 int vprintf(const char *fmt, va_list ap)
822 {
823         struct printf_spec ps =
824             { (int (*)(void *, size_t, void *))vprintf_write, NULL };
825
826         return printf_core(fmt, &ps, ap);
827 }