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