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