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