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