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