blob: e3cf8bbb24ca2224879ac96ff3da8add9f0a0548 [file] [log] [blame]
Uwe Hermannc52761b2008-03-20 00:02:07 +00001/*
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>
Patrick Georgi980a69b2010-06-24 11:16:10 +000037#include <ctype.h>
Uwe Hermannc52761b2008-03-20 00:02:07 +000038
Patrick Georgic977c7d2011-02-24 07:18:11 +000039static struct _FILE {
40} _stdout, _stdin, _stderr;
41
42FILE *stdout = &_stdout;
43FILE *stdin = &_stdin;
44FILE *stderr = &_stderr;
45
Uwe Hermannc52761b2008-03-20 00:02:07 +000046/** Structure for specifying output methods for different printf clones. */
47struct 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. */
79typedef enum {
80 PrintfQualifierByte = 0,
81 PrintfQualifierShort,
82 PrintfQualifierInt,
83 PrintfQualifierLong,
84 PrintfQualifierLongLong,
85 PrintfQualifierPointer,
86} qualifier_t;
87
88static char digits_small[] = "0123456789abcdef";
89static 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 */
99static 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 */
112static int printf_putstr(const char *str, struct printf_spec *ps)
113{
114 size_t count;
115
116 if (str == NULL) {
Patrick Georgi7f965832011-04-21 18:57:16 +0200117 const char *nullstr = "(NULL)";
Uwe Hermannc52761b2008-03-20 00:02:07 +0000118 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 */
133static 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.
Uwe Hermann54ec0af2008-08-26 19:37:37 +0000146 * @param ps Output methods spec for different printf clones.
Uwe Hermannc52761b2008-03-20 00:02:07 +0000147 * @return Number of characters printed, negative value on failure.
148 */
149static 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
Jordan Croused772e1e2008-04-25 23:10:23 +0000168 return counter;
Uwe Hermannc52761b2008-03-20 00:02:07 +0000169}
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.
Uwe Hermann54ec0af2008-08-26 19:37:37 +0000178 * @param ps Output methods spec for different printf clones.
Uwe Hermannc52761b2008-03-20 00:02:07 +0000179 * @return Number of characters printed, negative value on failure.
180 */
Uwe Hermann54ec0af2008-08-26 19:37:37 +0000181/** Structure for specifying output methods for different printf clones. */
Uwe Hermannc52761b2008-03-20 00:02:07 +0000182static 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.
Uwe Hermann54ec0af2008-08-26 19:37:37 +0000221 * @param width Width modifier.h
Uwe Hermannc52761b2008-03-20 00:02:07 +0000222 * @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.
Uwe Hermann54ec0af2008-08-26 19:37:37 +0000225 * @param ps Output methods spec for different printf clones.
Uwe Hermannc52761b2008-03-20 00:02:07 +0000226 * @return Number of characters printed.
227 */
228static 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 /*
Uwe Hermann661e3802008-03-21 18:37:23 +0000293 * If the number is left-aligned or precision is specified then
294 * zero-padding is ignored.
Uwe Hermannc52761b2008-03-20 00:02:07 +0000295 */
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
Uwe Hermann54ec0af2008-08-26 19:37:37 +0000374/**
375 * Print formatted string.
Uwe Hermannc52761b2008-03-20 00:02:07 +0000376 *
377 * Print string formatted according to the fmt parameter and variadic arguments.
378 * Each formatting directive must have the following form:
Stefan Reinauer14e22772010-04-27 06:56:47 +0000379 *
Uwe Hermannc52761b2008-03-20 00:02:07 +0000380 * \% [ 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.
Stefan Reinauer14e22772010-04-27 06:56:47 +0000397 *
Uwe Hermannc52761b2008-03-20 00:02:07 +0000398 * 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.
Stefan Reinauer14e22772010-04-27 06:56:47 +0000414 *
Uwe Hermannc52761b2008-03-20 00:02:07 +0000415 * 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
Stefan Reinauer14e22772010-04-27 06:56:47 +0000421 *
422 *
Uwe Hermannc52761b2008-03-20 00:02:07 +0000423 * 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.
Stefan Reinauer14e22772010-04-27 06:56:47 +0000430 *
Uwe Hermannc52761b2008-03-20 00:02:07 +0000431 * - 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.)
Stefan Reinauer14e22772010-04-27 06:56:47 +0000437 *
Uwe Hermannc52761b2008-03-20 00:02:07 +0000438 * - o Print value as unsigned octal number. Prefix is not printed by
Stefan Reinauer14e22772010-04-27 06:56:47 +0000439 * default.
Uwe Hermannc52761b2008-03-20 00:02:07 +0000440 *
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.
Stefan Reinauer14e22772010-04-27 06:56:47 +0000448 *
Uwe Hermannc52761b2008-03-20 00:02:07 +0000449 * 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 */
457static 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 }
691next_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
705out:
706 return counter;
707}
708
Uwe Hermann0a896252008-04-02 12:35:45 +0000709int 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
Uwe Hermannc52761b2008-03-20 00:02:07 +0000721int 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
Patrick Georgicd913bd2011-02-14 19:25:27 +0000733int 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
Uwe Hermannc52761b2008-03-20 00:02:07 +0000747struct 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 */
768static 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
807int 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
821int vsprintf(char *str, const char *fmt, va_list ap)
822{
823 return vsnprintf(str, (size_t) - 1, fmt, ap);
824}
825
826int 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
838static 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
848int 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}