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.
36 #include <libpayload.h>
40 } _stdout
, _stdin
, _stderr
;
42 FILE *stdout
= &_stdout
;
43 FILE *stdin
= &_stdin
;
44 FILE *stderr
= &_stderr
;
46 /** Structure for specifying output methods for different printf clones. */
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, ... */
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
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
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).
76 #define PRINT_NUMBER_BUFFER_SIZE (64 + 5)
78 /** Enumeration of possible arguments types. */
80 PrintfQualifierByte
= 0,
84 PrintfQualifierLongLong
,
85 PrintfQualifierPointer
,
88 static const char digits_small
[] = "0123456789abcdef";
89 static const char digits_big
[] = "0123456789ABCDEF";
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((void *)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
)
126 unsigned char ch
= c
;
128 return ps
->write((void *)&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
, MIN(size
, precision
), ps
)) < 0)
198 while (width
-- > 0) {
199 if (printf_putchar(' ', ps
) == 1)
207 * Print a number in a given base.
209 * Print significant digits of a number in given base.
211 * @param num Number to print.
212 * @param width Width modifier.h
213 * @param precision Precision modifier.
214 * @param base Base to print the number in (must be between 2 and 16).
215 * @param flags Flags that modify the way the number is printed.
216 * @param ps Output methods spec for different printf clones.
217 * @return Number of characters printed.
219 static int print_number(uint64_t num
, int width
, int precision
, int base
,
220 uint64_t flags
, struct printf_spec
*ps
)
222 const char *digits
= digits_small
;
223 char d
[PRINT_NUMBER_BUFFER_SIZE
];
224 char *ptr
= &d
[PRINT_NUMBER_BUFFER_SIZE
- 1];
225 int size
= 0; /* Size of number with all prefixes and signs. */
226 int number_size
; /* Size of plain number. */
231 if (flags
& __PRINTF_FLAG_BIGCHARS
)
234 *ptr
-- = 0; /* Put zero at end of string. */
241 *ptr
-- = digits
[num
% base
];
243 } while (num
/= base
);
249 * Collect the sum of all prefixes/signs/... to calculate padding and
252 if (flags
& __PRINTF_FLAG_PREFIX
) {
254 case 2: /* Binary formating is not standard, but useful. */
267 if (flags
& __PRINTF_FLAG_SIGNED
) {
268 if (flags
& __PRINTF_FLAG_NEGATIVE
) {
271 } else if (flags
& __PRINTF_FLAG_SHOWPLUS
) {
274 } else if (flags
& __PRINTF_FLAG_SPACESIGN
) {
280 if (flags
& __PRINTF_FLAG_LEFTALIGNED
)
281 flags
&= ~__PRINTF_FLAG_ZEROPADDED
;
284 * If the number is left-aligned or precision is specified then
285 * zero-padding is ignored.
287 if (flags
& __PRINTF_FLAG_ZEROPADDED
) {
288 if ((precision
== 0) && (width
> size
))
289 precision
= width
- size
+ number_size
;
292 /* Print leading spaces. */
293 if (number_size
> precision
) {
294 /* Print the whole number not only a part. */
295 precision
= number_size
;
298 width
-= precision
+ size
- number_size
;
300 if (!(flags
& __PRINTF_FLAG_LEFTALIGNED
)) {
301 while (width
-- > 0) {
302 if (printf_putchar(' ', ps
) == 1)
309 if (printf_putchar(sgn
, ps
) == 1)
314 if (flags
& __PRINTF_FLAG_PREFIX
) {
316 case 2: /* Binary formating is not standard, but useful. */
317 if (printf_putchar('0', ps
) == 1)
319 if (flags
& __PRINTF_FLAG_BIGCHARS
) {
320 if (printf_putchar('B', ps
) == 1)
323 if (printf_putchar('b', ps
) == 1)
328 if (printf_putchar('o', ps
) == 1)
332 if (printf_putchar('0', ps
) == 1)
334 if (flags
& __PRINTF_FLAG_BIGCHARS
) {
335 if (printf_putchar('X', ps
) == 1)
338 if (printf_putchar('x', ps
) == 1)
345 /* Print leading zeroes. */
346 precision
-= number_size
;
347 while (precision
-- > 0) {
348 if (printf_putchar('0', ps
) == 1)
352 /* Print number itself. */
353 if ((retval
= printf_putstr(++ptr
, ps
)) > 0)
356 /* Print ending spaces. */
357 while (width
-- > 0) {
358 if (printf_putchar(' ', ps
) == 1)
366 * Print formatted string.
368 * Print string formatted according to the fmt parameter and variadic arguments.
369 * Each formatting directive must have the following form:
371 * \% [ FLAGS ] [ WIDTH ] [ .PRECISION ] [ TYPE ] CONVERSION
374 * - "#" Force to print prefix.For \%o conversion, the prefix is 0, for
375 * \%x and \%X prefixes are 0x and 0X and for conversion \%b the
378 * - "-" Align to left.
380 * - "+" Print positive sign just as negative.
382 * - " " If the printed number is positive and "+" flag is not set,
383 * print space in place of sign.
385 * - "0" Print 0 as padding instead of spaces. Zeroes are placed between
386 * sign and the rest of the number. This flag is ignored if "-"
390 * - Specify the minimal width of a printed argument. If it is bigger,
391 * width is ignored. If width is specified with a "*" character instead of
392 * number, width is taken from parameter list. And integer parameter is
393 * expected before parameter for processed conversion specification. If
394 * this value is negative its absolute value is taken and the "-" flag is
398 * - Value precision. For numbers it specifies minimum valid numbers.
399 * Smaller numbers are printed with leading zeroes. Bigger numbers are not
400 * affected. Strings with more than precision characters are cut off. Just
401 * as with width, an "*" can be used used instead of a number. An integer
402 * value is then expected in parameters. When both width and precision are
403 * specified using "*", the first parameter is used for width and the
404 * second one for precision.
407 * - "hh" Signed or unsigned char.@n
408 * - "h" Signed or unsigned short.@n
409 * - "" Signed or unsigned int (default value).@n
410 * - "l" Signed or unsigned long int.@n
411 * - "ll" Signed or unsigned long long int.@n
415 * - % Print percentile character itself.
417 * - c Print single character.
419 * - s Print zero terminated string. If a NULL value is passed as
420 * value, "(NULL)" is printed instead.
422 * - P, p Print value of a pointer. Void * value is expected and it is
423 * printed in hexadecimal notation with prefix (as with \%#X / \%#x
424 * for 32-bit or \%#X / \%#x for 64-bit long pointers).
426 * - b Print value as unsigned binary number. Prefix is not printed by
427 * default. (Nonstandard extension.)
429 * - o Print value as unsigned octal number. Prefix is not printed by
432 * - d, i Print signed decimal number. There is no difference between d
435 * - u Print unsigned decimal number.
437 * - X, x Print hexadecimal number with upper- or lower-case. Prefix is
438 * not printed by default.
440 * All other characters from fmt except the formatting directives are printed in
443 * @param fmt Formatting NULL terminated string.
446 * @return Number of characters printed, negative value on failure.
448 static int printf_core(const char *fmt
, struct printf_spec
*ps
, va_list ap
)
450 int i
= 0; /* Index of the currently processed char from fmt */
451 int j
= 0; /* Index to the first not printed nonformating character */
453 int counter
; /* Counter of printed characters */
454 int retval
; /* Used to store return values from called functions */
456 qualifier_t qualifier
; /* Type of argument */
457 int base
; /* Base in which a numeric parameter will be printed */
458 uint64_t number
; /* Argument value */
459 size_t size
; /* Byte size of integer parameter */
460 int width
, precision
;
465 while ((c
= fmt
[i
])) {
466 /* Control character. */
468 /* Print common characters if any processed. */
470 if ((retval
= printf_putnchars(&fmt
[j
],
471 (size_t) (i
- j
), ps
)) < 0) {
473 goto out
; /* Error */
479 /* Parse modifiers. */
485 switch (c
= fmt
[i
]) {
487 flags
|= __PRINTF_FLAG_PREFIX
;
490 flags
|= __PRINTF_FLAG_LEFTALIGNED
;
493 flags
|= __PRINTF_FLAG_SHOWPLUS
;
496 flags
|= __PRINTF_FLAG_SPACESIGN
;
499 flags
|= __PRINTF_FLAG_ZEROPADDED
;
507 /* Width & '*' operator. */
509 if (isdigit(fmt
[i
])) {
510 while (isdigit(fmt
[i
])) {
512 width
+= fmt
[i
++] - '0';
514 } else if (fmt
[i
] == '*') {
515 /* Get width value from argument list. */
517 width
= (int)va_arg(ap
, int);
519 /* Negative width sets '-' flag. */
521 flags
|= __PRINTF_FLAG_LEFTALIGNED
;
525 /* Precision and '*' operator. */
529 if (isdigit(fmt
[i
])) {
530 while (isdigit(fmt
[i
])) {
532 precision
+= fmt
[i
++] - '0';
534 } else if (fmt
[i
] == '*') {
535 /* Get precision from argument list. */
537 precision
= (int)va_arg(ap
, int);
538 /* Ignore negative precision. */
545 /** @todo unimplemented qualifiers:
546 * t ptrdiff_t - ISO C 99
548 case 'h': /* char or short */
549 qualifier
= PrintfQualifierShort
;
552 qualifier
= PrintfQualifierByte
;
555 case 'l': /* long or long long */
556 qualifier
= PrintfQualifierLong
;
559 qualifier
= PrintfQualifierLongLong
;
564 qualifier
= PrintfQualifierInt
;
570 switch (c
= fmt
[i
]) {
571 /* String and character conversions */
573 if ((retval
= print_string(va_arg(ap
, char *),
574 width
, precision
, flags
, ps
)) < 0) {
582 c
= va_arg(ap
, unsigned int);
583 retval
= print_char(c
, width
, flags
, ps
);
593 case 'P': /* pointer */
594 flags
|= __PRINTF_FLAG_BIGCHARS
;
596 flags
|= __PRINTF_FLAG_PREFIX
;
598 qualifier
= PrintfQualifierPointer
;
608 flags
|= __PRINTF_FLAG_SIGNED
;
612 flags
|= __PRINTF_FLAG_BIGCHARS
;
616 case '%': /* percentile itself */
619 default: /* Bad formatting */
621 * Unknown format. Now, j is the index of '%'
622 * so we will print whole bad format sequence.
627 /* Print integers. */
630 case PrintfQualifierByte
:
631 size
= sizeof(unsigned char);
632 number
= (uint64_t) va_arg(ap
, unsigned int);
634 case PrintfQualifierShort
:
635 size
= sizeof(unsigned short);
636 number
= (uint64_t) va_arg(ap
, unsigned int);
638 case PrintfQualifierInt
:
639 size
= sizeof(unsigned int);
640 number
= (uint64_t) va_arg(ap
, unsigned int);
642 case PrintfQualifierLong
:
643 size
= sizeof(unsigned long);
644 number
= (uint64_t) va_arg(ap
, unsigned long);
646 case PrintfQualifierLongLong
:
647 size
= sizeof(unsigned long long);
648 number
= (uint64_t) va_arg(ap
, unsigned long long);
650 case PrintfQualifierPointer
:
651 size
= sizeof(void *);
652 number
= (uint64_t) (unsigned long)va_arg(ap
, void *);
654 default: /* Unknown qualifier */
659 if (flags
& __PRINTF_FLAG_SIGNED
) {
660 if (number
& (0x1 << (size
* 8 - 1))) {
661 flags
|= __PRINTF_FLAG_NEGATIVE
;
663 if (size
== sizeof(uint64_t)) {
664 number
= -((int64_t) number
);
667 number
&= ~(0xFFFFFFFFFFFFFFFFll
<< (size
* 8));
673 if ((retval
= print_number(number
, width
, precision
,
674 base
, flags
, ps
)) < 0) {
687 if ((retval
= printf_putnchars(&fmt
[j
],
688 (u64
) (i
- j
), ps
)) < 0) {
690 goto out
; /* Error */
700 int snprintf(char *str
, size_t size
, const char *fmt
, ...)
706 ret
= vsnprintf(str
, size
, fmt
, args
);
712 int sprintf(char *str
, const char *fmt
, ...)
718 ret
= vsprintf(str
, fmt
, args
);
724 int fprintf(FILE *file
, const char *fmt
, ...)
727 if ((file
== stdout
) || (file
== stderr
)) {
730 ret
= vprintf(fmt
, args
);
738 struct vsnprintf_data
{
739 size_t size
; /* Total space for string */
740 size_t len
; /* Count of currently used characters */
741 char *string
; /* Destination string */
745 * Write string to given buffer.
747 * Write at most data->size characters including trailing zero. According to
748 * C99, snprintf() has to return number of characters that would have been
749 * written if enough space had been available. Hence the return value is not
750 * number of really printed characters but size of the input string.
751 * Number of really used characters is stored in data->len.
753 * @param str Source string to print.
754 * @param count Size of source string.
755 * @param data Structure with destination string, counter of used space
756 * and total string size.
757 * @return Number of characters to print (not characters really printed!).
759 static int vsnprintf_write(const char *str
, size_t count
,
760 struct vsnprintf_data
*data
)
764 i
= data
->size
- data
->len
;
768 /* We have only one free byte left in buffer => write trailing zero. */
770 data
->string
[data
->size
- 1] = 0;
771 data
->len
= data
->size
;
776 * We have not enough space for whole string with the trailing
777 * zero => print only a part of string.
780 memcpy((void *)(data
->string
+ data
->len
), (void *)str
, i
- 1);
781 data
->string
[data
->size
- 1] = 0;
782 data
->len
= data
->size
;
786 /* Buffer is big enough to print whole string. */
787 memcpy((void *)(data
->string
+ data
->len
), (void *)str
, count
);
790 * Put trailing zero at end, but not count it into data->len so
791 * it could be rewritten next time.
793 data
->string
[data
->len
] = 0;
798 int vsnprintf(char *str
, size_t size
, const char *fmt
, va_list ap
)
800 struct vsnprintf_data data
= { size
, 0, str
};
801 struct printf_spec ps
=
802 { (int (*)(void *, size_t, void *))vsnprintf_write
, &data
};
804 /* Print 0 at end of string - fix case that nothing will be printed. */
808 /* vsnprintf_write() ensures that str will be terminated by zero. */
809 return printf_core(fmt
, &ps
, ap
);
812 int vsprintf(char *str
, const char *fmt
, va_list ap
)
814 return vsnprintf(str
, (size_t) - 1, fmt
, ap
);
817 int printf(const char *fmt
, ...)
823 ret
= vprintf(fmt
, args
);
829 static int vprintf_write(const char *str
, size_t count
, void *unused
)
833 for (i
= 0; i
< count
; i
++)
839 int vprintf(const char *fmt
, va_list ap
)
841 struct printf_spec ps
=
842 { (int (*)(void *, size_t, void *))vprintf_write
, NULL
};
844 return printf_core(fmt
, &ps
, ap
);