2 * This file is part of the libpayload project.
4 * It has originally been taken from the HelenOS project
5 * (http://www.helenos.eu), and slightly modified for our purposes.
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.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
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.
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.
43 } _stdout, _stdin, _stderr;
45 FILE *stdout = &_stdout;
46 FILE *stdin = &_stdin;
47 FILE *stderr = &_stderr;
49 /** Structure for specifying output methods for different printf clones. */
51 /* Output function, returns count of printed characters or EOF. */
52 int (*write) (const char *, size_t, void *);
53 /* Support data - output stream specification, its state, locks, ... */
57 /** Show prefixes 0x or 0. */
58 #define __PRINTF_FLAG_PREFIX 0x00000001
59 /** Signed / unsigned number. */
60 #define __PRINTF_FLAG_SIGNED 0x00000002
61 /** Print leading zeroes. */
62 #define __PRINTF_FLAG_ZEROPADDED 0x00000004
64 #define __PRINTF_FLAG_LEFTALIGNED 0x00000010
65 /** Always show + sign. */
66 #define __PRINTF_FLAG_SHOWPLUS 0x00000020
67 /** Print space instead of plus. */
68 #define __PRINTF_FLAG_SPACESIGN 0x00000040
69 /** Show big characters. */
70 #define __PRINTF_FLAG_BIGCHARS 0x00000080
71 /** Number has - sign. */
72 #define __PRINTF_FLAG_NEGATIVE 0x00000100
75 * Buffer big enough for 64-bit number printed in base 2, sign, prefix and 0
76 * to terminate string (last one is only for better testing end of buffer by
77 * zero-filling subroutine).
79 #define PRINT_NUMBER_BUFFER_SIZE (64 + 5)
81 /** Enumeration of possible arguments types. */
83 PrintfQualifierByte = 0,
87 PrintfQualifierLongLong,
88 PrintfQualifierPointer,
92 * Print one or more characters without adding newline.
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.
99 static int printf_putnchars(const char *buf, size_t count,
100 struct printf_spec *ps)
102 return ps->write(buf, count, ps->data);
106 * Print a string without adding a newline.
108 * @param str String to print.
109 * @param ps Write function specification and support data.
110 * @return Number of characters printed.
112 static inline int printf_putstr(const char *str, struct printf_spec *ps)
114 return printf_putnchars(str, strlen(str), ps);
118 * Print one character.
120 * @param c Character to be printed.
121 * @param ps Output method.
122 * @return Number of characters printed.
124 static int printf_putchar(int c, struct printf_spec *ps)
128 return ps->write(&ch, 1, ps->data);
132 * Print one formatted character.
134 * @param c Character to print.
135 * @param width Width modifier.
136 * @param flags Flags that change the way the character is printed.
137 * @param ps Output methods spec for different printf clones.
138 * @return Number of characters printed, negative value on failure.
140 static int print_char(char c, int width, uint64_t flags, struct printf_spec *ps)
144 if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
145 while (--width > 0) {
146 if (printf_putchar(' ', ps) > 0)
151 if (printf_putchar(c, ps) > 0)
154 while (--width > 0) {
155 if (printf_putchar(' ', ps) > 0)
165 * @param s String to be printed.
166 * @param width Width modifier.
167 * @param precision Precision modifier.
168 * @param flags Flags that modify the way the string is printed.
169 * @param ps Output methods spec for different printf clones.
170 * @return Number of characters printed, negative value on failure.
172 /** Structure for specifying output methods for different printf clones. */
173 static int print_string(char *s, int width, unsigned int precision,
174 uint64_t flags, struct printf_spec *ps)
176 int counter = 0, retval;
180 return printf_putstr("(NULL)", ps);
182 /* Print leading spaces. */
187 if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
188 while (width-- > 0) {
189 if (printf_putchar(' ', ps) == 1)
194 if ((retval = printf_putnchars(s, (size < precision ? size : precision), ps)) < 0)
198 while (width-- > 0) {
199 if (printf_putchar(' ', ps) == 1)
206 static inline char get_digit(uint64_t num, int base, int upcase)
208 int digit = num % base;
212 return (upcase ? 'A' : 'a') - 10 + digit;
216 * Print a number in a given base.
218 * Print significant digits of a number in given base.
220 * @param num Number to print.
221 * @param width Width modifier.h
222 * @param precision Precision modifier.
223 * @param base Base to print the number in (must be between 2 and 16).
224 * @param flags Flags that modify the way the number is printed.
225 * @param ps Output methods spec for different printf clones.
226 * @return Number of characters printed.
228 static int print_number(uint64_t num, int width, int precision, int base,
229 uint64_t flags, struct printf_spec *ps)
231 char d[PRINT_NUMBER_BUFFER_SIZE];
232 char *ptr = &d[PRINT_NUMBER_BUFFER_SIZE - 1];
233 int size = 0; /* Size of number with all prefixes and signs. */
234 int number_size; /* Size of plain number. */
239 *ptr-- = 0; /* Put zero at end of string. */
246 *ptr-- = get_digit(num, base, flags & __PRINTF_FLAG_BIGCHARS);
248 } while (num /= base);
254 * Collect the sum of all prefixes/signs/... to calculate padding and
257 if (flags & __PRINTF_FLAG_PREFIX) {
259 case 2: /* Binary formating is not standard, but useful. */
272 if (flags & __PRINTF_FLAG_SIGNED) {
273 if (flags & __PRINTF_FLAG_NEGATIVE) {
276 } else if (flags & __PRINTF_FLAG_SHOWPLUS) {
279 } else if (flags & __PRINTF_FLAG_SPACESIGN) {
285 if (flags & __PRINTF_FLAG_LEFTALIGNED)
286 flags &= ~__PRINTF_FLAG_ZEROPADDED;
289 * If the number is left-aligned or precision is specified then
290 * zero-padding is ignored.
292 if (flags & __PRINTF_FLAG_ZEROPADDED) {
293 if ((precision == 0) && (width > size))
294 precision = width - size + number_size;
297 /* Print leading spaces. */
298 if (number_size > precision) {
299 /* Print the whole number not only a part. */
300 precision = number_size;
303 width -= precision + size - number_size;
305 if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
306 while (width-- > 0) {
307 if (printf_putchar(' ', ps) == 1)
314 if (printf_putchar(sgn, ps) == 1)
319 if (flags & __PRINTF_FLAG_PREFIX) {
321 case 2: /* Binary formating is not standard, but useful. */
322 if (printf_putchar('0', ps) == 1)
324 if (flags & __PRINTF_FLAG_BIGCHARS) {
325 if (printf_putchar('B', ps) == 1)
328 if (printf_putchar('b', ps) == 1)
333 if (printf_putchar('o', ps) == 1)
337 if (printf_putchar('0', ps) == 1)
339 if (flags & __PRINTF_FLAG_BIGCHARS) {
340 if (printf_putchar('X', ps) == 1)
343 if (printf_putchar('x', ps) == 1)
350 /* Print leading zeroes. */
351 precision -= number_size;
352 while (precision-- > 0) {
353 if (printf_putchar('0', ps) == 1)
357 /* Print number itself. */
358 if ((retval = printf_putstr(++ptr, ps)) > 0)
361 /* Print ending spaces. */
362 while (width-- > 0) {
363 if (printf_putchar(' ', ps) == 1)
371 * Print formatted string.
373 * Print string formatted according to the fmt parameter and variadic arguments.
374 * Each formatting directive must have the following form:
376 * \% [ FLAGS ] [ WIDTH ] [ .PRECISION ] [ TYPE ] CONVERSION
379 * - "#" Force to print prefix.For \%o conversion, the prefix is 0, for
380 * \%x and \%X prefixes are 0x and 0X and for conversion \%b the
383 * - "-" Align to left.
385 * - "+" Print positive sign just as negative.
387 * - " " If the printed number is positive and "+" flag is not set,
388 * print space in place of sign.
390 * - "0" Print 0 as padding instead of spaces. Zeroes are placed between
391 * sign and the rest of the number. This flag is ignored if "-"
395 * - Specify the minimal width of a printed argument. If it is bigger,
396 * width is ignored. If width is specified with a "*" character instead of
397 * number, width is taken from parameter list. And integer parameter is
398 * expected before parameter for processed conversion specification. If
399 * this value is negative its absolute value is taken and the "-" flag is
403 * - Value precision. For numbers it specifies minimum valid numbers.
404 * Smaller numbers are printed with leading zeroes. Bigger numbers are not
405 * affected. Strings with more than precision characters are cut off. Just
406 * as with width, an "*" can be used used instead of a number. An integer
407 * value is then expected in parameters. When both width and precision are
408 * specified using "*", the first parameter is used for width and the
409 * second one for precision.
412 * - "hh" Signed or unsigned char.@n
413 * - "h" Signed or unsigned short.@n
414 * - "" Signed or unsigned int (default value).@n
415 * - "l" Signed or unsigned long int.@n
416 * - "ll" Signed or unsigned long long int.@n
420 * - % Print percentile character itself.
422 * - c Print single character.
424 * - s Print zero terminated string. If a NULL value is passed as
425 * value, "(NULL)" is printed instead.
427 * - P, p Print value of a pointer. Void * value is expected and it is
428 * printed in hexadecimal notation with prefix (as with \%#X / \%#x
429 * for 32-bit or \%#X / \%#x for 64-bit long pointers).
431 * - b Print value as unsigned binary number. Prefix is not printed by
432 * default. (Nonstandard extension.)
434 * - o Print value as unsigned octal number. Prefix is not printed by
437 * - d, i Print signed decimal number. There is no difference between d
440 * - u Print unsigned decimal number.
442 * - X, x Print hexadecimal number with upper- or lower-case. Prefix is
443 * not printed by default.
445 * All other characters from fmt except the formatting directives are printed in
448 * @param fmt Formatting NULL terminated string.
451 * @return Number of characters printed, negative value on failure.
453 static int printf_core(const char *fmt, struct printf_spec *ps, va_list ap)
455 int i = 0; /* Index of the currently processed char from fmt */
456 int j = 0; /* Index to the first not printed nonformating character */
458 int counter; /* Counter of printed characters */
459 int retval; /* Used to store return values from called functions */
461 qualifier_t qualifier; /* Type of argument */
462 int base; /* Base in which a numeric parameter will be printed */
463 uint64_t number; /* Argument value */
464 size_t size; /* Byte size of integer parameter */
465 int width, precision;
470 while ((c = fmt[i])) {
471 /* Control character. */
473 /* Print common characters if any processed. */
475 if ((retval = printf_putnchars(&fmt[j],
476 (size_t) (i - j), ps)) < 0) {
478 goto out; /* Error */
484 /* Parse modifiers. */
490 switch (c = fmt[i]) {
492 flags |= __PRINTF_FLAG_PREFIX;
495 flags |= __PRINTF_FLAG_LEFTALIGNED;
498 flags |= __PRINTF_FLAG_SHOWPLUS;
501 flags |= __PRINTF_FLAG_SPACESIGN;
504 flags |= __PRINTF_FLAG_ZEROPADDED;
512 /* Width & '*' operator. */
514 if (isdigit(fmt[i])) {
515 while (isdigit(fmt[i])) {
517 width += fmt[i++] - '0';
519 } else if (fmt[i] == '*') {
520 /* Get width value from argument list. */
522 width = (int)va_arg(ap, int);
524 /* Negative width sets '-' flag. */
526 flags |= __PRINTF_FLAG_LEFTALIGNED;
530 /* Precision and '*' operator. */
534 if (isdigit(fmt[i])) {
535 while (isdigit(fmt[i])) {
537 precision += fmt[i++] - '0';
539 } else if (fmt[i] == '*') {
540 /* Get precision from argument list. */
542 precision = (int)va_arg(ap, int);
543 /* Ignore negative precision. */
550 /** @todo unimplemented qualifiers:
551 * t ptrdiff_t - ISO C 99
553 case 'h': /* char or short */
554 qualifier = PrintfQualifierShort;
557 qualifier = PrintfQualifierByte;
560 case 'z': /* size_t or ssize_t */
561 qualifier = PrintfQualifierLong;
563 case 'l': /* long or long long */
564 qualifier = PrintfQualifierLong;
567 qualifier = PrintfQualifierLongLong;
572 qualifier = PrintfQualifierInt;
578 switch (c = fmt[i]) {
579 /* String and character conversions */
581 if ((retval = print_string(va_arg(ap, char *),
582 width, precision, flags, ps)) < 0) {
590 c = va_arg(ap, unsigned int);
591 retval = print_char(c, width, flags, ps);
601 case 'P': /* pointer */
602 flags |= __PRINTF_FLAG_BIGCHARS;
605 flags |= __PRINTF_FLAG_PREFIX;
607 qualifier = PrintfQualifierPointer;
617 flags |= __PRINTF_FLAG_SIGNED;
621 flags |= __PRINTF_FLAG_BIGCHARS;
626 case '%': /* percentile itself */
629 default: /* Bad formatting */
631 * Unknown format. Now, j is the index of '%'
632 * so we will print whole bad format sequence.
637 /* Print integers. */
640 case PrintfQualifierByte:
641 size = sizeof(unsigned char);
642 number = (uint64_t) va_arg(ap, unsigned int);
644 case PrintfQualifierShort:
645 size = sizeof(unsigned short);
646 number = (uint64_t) va_arg(ap, unsigned int);
648 case PrintfQualifierInt:
649 size = sizeof(unsigned int);
650 number = (uint64_t) va_arg(ap, unsigned int);
652 case PrintfQualifierLong:
653 size = sizeof(unsigned long);
654 number = (uint64_t) va_arg(ap, unsigned long);
656 case PrintfQualifierLongLong:
657 size = sizeof(unsigned long long);
658 number = (uint64_t) va_arg(ap, unsigned long long);
660 case PrintfQualifierPointer:
661 size = sizeof(void *);
662 number = (uint64_t) (unsigned long)va_arg(ap, void *);
664 default: /* Unknown qualifier */
669 if (flags & __PRINTF_FLAG_SIGNED) {
670 if (number & (0x1 << (size * 8 - 1))) {
671 flags |= __PRINTF_FLAG_NEGATIVE;
673 if (size == sizeof(uint64_t)) {
674 number = -((int64_t) number);
677 number &= ~(0xFFFFFFFFFFFFFFFFll << (size * 8));
683 if ((retval = print_number(number, width, precision,
684 base, flags, ps)) < 0) {
697 if ((retval = printf_putnchars(&fmt[j],
698 (u64) (i - j), ps)) < 0) {
700 goto out; /* Error */
710 int snprintf(char *str, size_t size, const char *fmt, ...)
716 ret = vsnprintf(str, size, fmt, args);
722 int sprintf(char *str, const char *fmt, ...)
728 ret = vsprintf(str, fmt, args);
734 int fprintf(FILE *file, const char *fmt, ...)
737 if ((file == stdout) || (file == stderr)) {
740 ret = vprintf(fmt, args);
748 struct vsnprintf_data {
749 size_t size; /* Total space for string */
750 size_t len; /* Count of currently used characters */
751 char *string; /* Destination string */
755 * Write string to given buffer.
757 * Write at most data->size characters including trailing zero. According to
758 * C99, snprintf() has to return number of characters that would have been
759 * written if enough space had been available. Hence the return value is not
760 * number of really printed characters but size of the input string.
761 * Number of really used characters is stored in data->len.
763 * @param str Source string to print.
764 * @param count Size of source string.
765 * @param _data Structure with destination string, counter of used space
766 * and total string size.
767 * @return Number of characters to print (not characters really printed!).
769 static int vsnprintf_write(const char *str, size_t count, void *_data)
771 struct vsnprintf_data *data = _data;
774 i = data->size - data->len;
778 /* We have only one free byte left in buffer => write trailing zero. */
780 data->string[data->size - 1] = 0;
781 data->len = data->size;
786 * We have not enough space for whole string with the trailing
787 * zero => print only a part of string.
790 memcpy((void *)(data->string + data->len), (void *)str, i - 1);
791 data->string[data->size - 1] = 0;
792 data->len = data->size;
796 /* Buffer is big enough to print whole string. */
797 memcpy((void *)(data->string + data->len), (void *)str, count);
800 * Put trailing zero at end, but not count it into data->len so
801 * it could be rewritten next time.
803 data->string[data->len] = 0;
808 int vsnprintf(char *str, size_t size, const char *fmt, va_list ap)
810 struct vsnprintf_data data = { size, 0, str };
811 struct printf_spec ps = { vsnprintf_write, &data };
813 /* Print 0 at end of string - fix case that nothing will be printed. */
817 /* vsnprintf_write() ensures that str will be terminated by zero. */
818 return printf_core(fmt, &ps, ap);
821 int vsprintf(char *str, const char *fmt, va_list ap)
823 return vsnprintf(str, (size_t) - 1, fmt, ap);
826 int printf(const char *fmt, ...)
832 ret = vprintf(fmt, args);
838 static int vprintf_write(const char *str, size_t count, void *unused)
841 putchars(str, count);
845 int vprintf(const char *fmt, va_list ap)
847 struct printf_spec ps = { vprintf_write, NULL };
849 return printf_core(fmt, &ps, ap);