3 * It has originally been taken from the HelenOS project
4 * (http://www.helenos.eu), and slightly modified for our purposes.
6 * Copyright (C) 2001-2004 Jakub Jermar
7 * Copyright (C) 2006 Josef Cejka
8 * Copyright (C) 2008 Uwe Hermann <uwe@hermann-uwe.de>
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
15 * - Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * - Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * - The name of the author may not be used to endorse or promote products
21 * derived from this software without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 #include <libpayload.h>
39 } _stdout
, _stdin
, _stderr
;
41 FILE *stdout
= &_stdout
;
42 FILE *stdin
= &_stdin
;
43 FILE *stderr
= &_stderr
;
45 /** Structure for specifying output methods for different printf clones. */
47 /* Output function, returns count of printed characters or EOF. */
48 int (*write
) (const char *, size_t, void *);
49 /* Support data - output stream specification, its state, locks, ... */
53 /** Show prefixes 0x or 0. */
54 #define __PRINTF_FLAG_PREFIX 0x00000001
55 /** Signed / unsigned number. */
56 #define __PRINTF_FLAG_SIGNED 0x00000002
57 /** Print leading zeroes. */
58 #define __PRINTF_FLAG_ZEROPADDED 0x00000004
60 #define __PRINTF_FLAG_LEFTALIGNED 0x00000010
61 /** Always show + sign. */
62 #define __PRINTF_FLAG_SHOWPLUS 0x00000020
63 /** Print space instead of plus. */
64 #define __PRINTF_FLAG_SPACESIGN 0x00000040
65 /** Show big characters. */
66 #define __PRINTF_FLAG_BIGCHARS 0x00000080
67 /** Number has - sign. */
68 #define __PRINTF_FLAG_NEGATIVE 0x00000100
71 * Buffer big enough for 64-bit number printed in base 2, sign, and prefix.
72 * Add some more to support sane amounts of zero-padding.
74 #define PRINT_BUFFER_SIZE (64 + 1 + 2 + 13)
76 /** Enumeration of possible arguments types. */
78 PrintfQualifierByte
= 0,
82 PrintfQualifierLongLong
,
83 PrintfQualifierPointer
,
86 static const char digits_small
[] = "0123456789abcdef";
87 static const char digits_big
[] = "0123456789ABCDEF";
90 * Print one or more characters without adding newline.
92 * @param buf Buffer of >= count bytesi size. NULL pointer is not allowed!
93 * @param count Number of characters to print.
94 * @param ps Output method and its data.
95 * @return Number of characters printed.
97 static int printf_putnchars(const char *buf
, size_t count
,
98 struct printf_spec
*ps
)
100 return ps
->write(buf
, count
, ps
->data
);
104 * Print a string without adding a newline.
106 * @param str String to print.
107 * @param ps Write function specification and support data.
108 * @return Number of characters printed.
110 static inline int printf_putstr(const char *str
, struct printf_spec
*ps
)
112 return printf_putnchars(str
, strlen(str
), ps
);
116 * Print one character.
118 * @param c Character to be printed.
119 * @param ps Output method.
120 * @return Number of characters printed.
122 static int printf_putchar(int c
, struct printf_spec
*ps
)
126 return ps
->write(&ch
, 1, ps
->data
);
129 /* Print spaces for padding. Ignores negative counts. */
130 static int print_spaces(int count
, struct printf_spec
*ps
)
133 char buffer
[PRINT_BUFFER_SIZE
];
138 memset(buffer
, ' ', MIN(PRINT_BUFFER_SIZE
, count
));
139 for (tmp
= count
; tmp
> PRINT_BUFFER_SIZE
; tmp
-= PRINT_BUFFER_SIZE
)
140 if ((ret
= printf_putnchars(buffer
, PRINT_BUFFER_SIZE
, ps
)) < 0)
143 if ((ret
= printf_putnchars(buffer
, tmp
, ps
)) < 0)
150 * Print one formatted character.
152 * @param c Character to print.
153 * @param width Width modifier.
154 * @param flags Flags that change the way the character is printed.
155 * @param ps Output methods spec for different printf clones.
156 * @return Number of characters printed, negative value on failure.
158 static int print_char(char c
, int width
, uint64_t flags
, struct printf_spec
*ps
)
163 if (!(flags
& __PRINTF_FLAG_LEFTALIGNED
)) {
164 if ((retval
= print_spaces(width
- 1, ps
)) < 0)
170 if ((retval
= printf_putchar(c
, ps
)) < 0)
173 if (flags
& __PRINTF_FLAG_LEFTALIGNED
) {
174 if ((retval
= print_spaces(width
- 1, ps
)) < 0)
186 * @param s String to be printed.
187 * @param width Width modifier.
188 * @param precision Precision modifier.
189 * @param flags Flags that modify the way the string is printed.
190 * @param ps Output methods spec for different printf clones.
191 * @return Number of characters printed, negative value on failure.
193 /** Structure for specifying output methods for different printf clones. */
194 static int print_string(char *s
, int width
, unsigned int precision
,
195 uint64_t flags
, struct printf_spec
*ps
)
197 int counter
= 0, retval
;
201 return printf_putstr("(NULL)", ps
);
203 /* Print leading spaces. */
208 if (!(flags
& __PRINTF_FLAG_LEFTALIGNED
)) {
209 if ((retval
= print_spaces(width
, ps
)) < 0)
215 if ((retval
= printf_putnchars(s
, MIN(size
, precision
), ps
)) < 0)
219 if (flags
& __PRINTF_FLAG_LEFTALIGNED
) {
220 if ((retval
= print_spaces(width
, ps
)) < 0)
230 * Print a number in a given base.
232 * Print significant digits of a number in given base.
234 * @param num Number to print.
235 * @param width Width modifier.
236 * @param precision Precision modifier.
237 * @param base Base to print the number in (must be between 2 and 16).
238 * @param flags Flags that modify the way the number is printed.
239 * @param ps Output methods spec for different printf clones.
240 * @return Number of characters printed.
242 static int print_number(uint64_t num
, int width
, int precision
, int base
,
243 uint64_t flags
, struct printf_spec
*ps
)
245 const char *digits
= digits_small
;
246 char d
[PRINT_BUFFER_SIZE
];
247 char *ptr
= &d
[PRINT_BUFFER_SIZE
];
248 int size
= 0; /* Size of the string in ptr */
249 int counter
= 0; /* Amount of actually printed bytes. */
253 if (flags
& __PRINTF_FLAG_BIGCHARS
)
261 *--ptr
= digits
[num
% base
];
263 } while (num
/= base
);
266 /* Both precision and LEFTALIGNED overrule ZEROPADDED. */
267 if ((flags
& __PRINTF_FLAG_LEFTALIGNED
) || precision
)
268 flags
&= ~__PRINTF_FLAG_ZEROPADDED
;
270 /* Fix precision now since it doesn't count prefixes/signs. */
273 /* Reserve size for prefixes/signs before filling up padding. */
275 if (flags
& __PRINTF_FLAG_SIGNED
) {
276 if (flags
& __PRINTF_FLAG_NEGATIVE
) {
279 } else if (flags
& __PRINTF_FLAG_SHOWPLUS
) {
282 } else if (flags
& __PRINTF_FLAG_SPACESIGN
) {
287 if (flags
& __PRINTF_FLAG_PREFIX
) {
289 case 2: /* Binary formating is not standard, but useful. */
301 /* If this is still set we didn't have a precision, so repurpose it */
302 if (flags
& __PRINTF_FLAG_ZEROPADDED
)
303 precision
= width
- size
;
305 /* Pad smaller numbers with 0 (larger numbers lead to precision < 0). */
307 precision
= MIN(precision
, PRINT_BUFFER_SIZE
- size
);
310 memset(ptr
, '0', precision
);
313 /* Add sign and prefix (we adjusted size for this beforehand). */
314 if (flags
& __PRINTF_FLAG_PREFIX
) {
316 case 2: /* Binary formating is not standard, but useful. */
317 *--ptr
= (flags
& __PRINTF_FLAG_BIGCHARS
) ? 'B' : 'b';
324 *--ptr
= (flags
& __PRINTF_FLAG_BIGCHARS
) ? 'X' : 'x';
332 /* Pad with spaces up to width, try to avoid extra putnchar if we can */
334 if (width
> 0 && !(flags
& __PRINTF_FLAG_LEFTALIGNED
)) {
335 int tmp
= MIN(width
, PRINT_BUFFER_SIZE
- size
);
338 memset(ptr
, ' ', tmp
);
339 if ((retval
= print_spaces(width
- tmp
, ps
)) < 0)
345 /* Now print the whole thing at once. */
346 if ((retval
= printf_putnchars(ptr
, size
, ps
)) < 0)
350 /* Edge case: left-aligned with width (should be rare). */
351 if (flags
& __PRINTF_FLAG_LEFTALIGNED
) {
352 if ((retval
= print_spaces(width
, ps
)) < 0)
362 * Print formatted string.
364 * Print string formatted according to the fmt parameter and variadic arguments.
365 * Each formatting directive must have the following form:
367 * \% [ FLAGS ] [ WIDTH ] [ .PRECISION ] [ TYPE ] CONVERSION
370 * - "#" Force to print prefix.For \%o conversion, the prefix is 0, for
371 * \%x and \%X prefixes are 0x and 0X and for conversion \%b the
374 * - "-" Align to left.
376 * - "+" Print positive sign just as negative.
378 * - " " If the printed number is positive and "+" flag is not set,
379 * print space in place of sign.
381 * - "0" Print 0 as padding instead of spaces. Zeroes are placed between
382 * sign and the rest of the number. This flag is ignored if "-"
386 * - Specify the minimal width of a printed argument. If it is bigger,
387 * width is ignored. If width is specified with a "*" character instead of
388 * number, width is taken from parameter list. And integer parameter is
389 * expected before parameter for processed conversion specification. If
390 * this value is negative its absolute value is taken and the "-" flag is
394 * - Value precision. For numbers it specifies minimum valid numbers.
395 * Smaller numbers are printed with leading zeroes. Bigger numbers are not
396 * affected. Strings with more than precision characters are cut off. Just
397 * as with width, an "*" can be used used instead of a number. An integer
398 * value is then expected in parameters. When both width and precision are
399 * specified using "*", the first parameter is used for width and the
400 * second one for precision.
403 * - "hh" Signed or unsigned char.@n
404 * - "h" Signed or unsigned short.@n
405 * - "" Signed or unsigned int (default value).@n
406 * - "l" Signed or unsigned long int.@n
407 * - "ll" Signed or unsigned long long int.@n
411 * - % Print percentile character itself.
413 * - c Print single character.
415 * - s Print zero terminated string. If a NULL value is passed as
416 * value, "(NULL)" is printed instead.
418 * - P, p Print value of a pointer. Void * value is expected and it is
419 * printed in hexadecimal notation with prefix (as with \%#X / \%#x
420 * for 32-bit or \%#X / \%#x for 64-bit long pointers).
422 * - b Print value as unsigned binary number. Prefix is not printed by
423 * default. (Nonstandard extension.)
425 * - o Print value as unsigned octal number. Prefix is not printed by
428 * - d, i Print signed decimal number. There is no difference between d
431 * - u Print unsigned decimal number.
433 * - X, x Print hexadecimal number with upper- or lower-case. Prefix is
434 * not printed by default.
436 * All other characters from fmt except the formatting directives are printed in
439 * @param fmt Formatting NULL terminated string.
442 * @return Number of characters printed, negative value on failure.
444 static int printf_core(const char *fmt
, struct printf_spec
*ps
, va_list ap
)
446 int i
= 0; /* Index of the currently processed char from fmt */
447 int j
= 0; /* Index to the first not printed nonformating character */
449 int counter
; /* Counter of printed characters */
450 int retval
; /* Used to store return values from called functions */
452 qualifier_t qualifier
; /* Type of argument */
453 int base
; /* Base in which a numeric parameter will be printed */
454 uint64_t number
; /* Argument value */
455 size_t size
; /* Byte size of integer parameter */
456 int width
, precision
;
461 while ((c
= fmt
[i
])) {
462 /* Control character. */
464 /* Print common characters if any processed. */
466 if ((retval
= printf_putnchars(&fmt
[j
],
467 (size_t) (i
- j
), ps
)) < 0)
473 /* Parse modifiers. */
479 switch (c
= fmt
[i
]) {
481 flags
|= __PRINTF_FLAG_PREFIX
;
484 flags
|= __PRINTF_FLAG_LEFTALIGNED
;
487 flags
|= __PRINTF_FLAG_SHOWPLUS
;
490 flags
|= __PRINTF_FLAG_SPACESIGN
;
493 flags
|= __PRINTF_FLAG_ZEROPADDED
;
501 /* Width & '*' operator. */
503 if (isdigit(fmt
[i
])) {
504 while (isdigit(fmt
[i
])) {
506 width
+= fmt
[i
++] - '0';
508 } else if (fmt
[i
] == '*') {
509 /* Get width value from argument list. */
511 width
= (int)va_arg(ap
, int);
513 /* Negative width sets '-' flag. */
515 flags
|= __PRINTF_FLAG_LEFTALIGNED
;
519 /* Precision and '*' operator. */
523 if (isdigit(fmt
[i
])) {
524 while (isdigit(fmt
[i
])) {
526 precision
+= fmt
[i
++] - '0';
528 } else if (fmt
[i
] == '*') {
529 /* Get precision from argument list. */
531 precision
= (int)va_arg(ap
, int);
532 /* Ignore negative precision. */
539 /** @todo unimplemented qualifiers:
540 * t ptrdiff_t - ISO C 99
542 case 'h': /* char or short */
543 qualifier
= PrintfQualifierShort
;
546 qualifier
= PrintfQualifierByte
;
549 case 'z': /* size_t or ssize_t */
550 qualifier
= PrintfQualifierLong
;
552 case 'l': /* long or long long */
553 qualifier
= PrintfQualifierLong
;
556 qualifier
= PrintfQualifierLongLong
;
561 qualifier
= PrintfQualifierInt
;
567 switch (c
= fmt
[i
]) {
568 /* String and character conversions */
570 if ((retval
= print_string(va_arg(ap
, char *),
571 width
, precision
, flags
, ps
)) < 0)
577 c
= va_arg(ap
, unsigned int);
578 if ((retval
= print_char(c
, width
, flags
, ps
)) < 0)
585 case 'P': /* pointer */
586 flags
|= __PRINTF_FLAG_BIGCHARS
;
589 flags
|= __PRINTF_FLAG_PREFIX
;
591 qualifier
= PrintfQualifierPointer
;
601 flags
|= __PRINTF_FLAG_SIGNED
;
606 flags
|= __PRINTF_FLAG_BIGCHARS
;
611 case '%': /* percentile itself */
614 default: /* Bad formatting */
616 * Unknown format. Now, j is the index of '%'
617 * so we will print whole bad format sequence.
622 /* Print integers. */
625 case PrintfQualifierByte
:
626 size
= sizeof(unsigned char);
627 number
= (uint64_t) va_arg(ap
, unsigned int);
629 case PrintfQualifierShort
:
630 size
= sizeof(unsigned short);
631 number
= (uint64_t) va_arg(ap
, unsigned int);
633 case PrintfQualifierInt
:
634 size
= sizeof(unsigned int);
635 number
= (uint64_t) va_arg(ap
, unsigned int);
637 case PrintfQualifierLong
:
638 size
= sizeof(unsigned long);
639 number
= (uint64_t) va_arg(ap
, unsigned long);
641 case PrintfQualifierLongLong
:
642 size
= sizeof(unsigned long long);
643 number
= (uint64_t) va_arg(ap
, unsigned long long);
645 case PrintfQualifierPointer
:
646 size
= sizeof(void *);
647 number
= (uint64_t) (unsigned long)va_arg(ap
, void *);
651 if (flags
& __PRINTF_FLAG_SIGNED
) {
652 if (number
& (0x1ULL
<< (size
* 8 - 1))) {
653 flags
|= __PRINTF_FLAG_NEGATIVE
;
655 if (size
== sizeof(uint64_t)) {
656 number
= -((int64_t) number
);
659 number
&= ~(0xFFFFFFFFFFFFFFFFll
<< (size
* 8));
665 if ((retval
= print_number(number
, width
, precision
,
666 base
, flags
, ps
)) < 0)
677 if ((retval
= printf_putnchars(&fmt
[j
],
678 (u64
) (i
- j
), ps
)) < 0)
686 int snprintf(char *str
, size_t size
, const char *fmt
, ...)
692 ret
= vsnprintf(str
, size
, fmt
, args
);
698 int sprintf(char *str
, const char *fmt
, ...)
704 ret
= vsprintf(str
, fmt
, args
);
710 int fprintf(FILE *file
, const char *fmt
, ...)
713 if ((file
== stdout
) || (file
== stderr
)) {
716 ret
= vprintf(fmt
, args
);
724 struct vsnprintf_data
{
725 size_t size
; /* Total space for string */
726 size_t len
; /* Count of currently used characters */
727 char *string
; /* Destination string */
731 * Write string to given buffer.
733 * Write at most data->size characters including trailing zero. According to
734 * C99, snprintf() has to return number of characters that would have been
735 * written if enough space had been available. Hence the return value is not
736 * number of really printed characters but size of the input string.
737 * Number of really used characters is stored in data->len.
739 * @param str Source string to print.
740 * @param count Size of source string.
741 * @param _data Structure with destination string, counter of used space
742 * and total string size.
743 * @return Number of characters to print (not characters really printed!).
745 static int vsnprintf_write(const char *str
, size_t count
, void *_data
)
747 struct vsnprintf_data
*data
= _data
;
750 i
= data
->size
- data
->len
;
754 /* We have only one free byte left in buffer => write trailing zero. */
756 data
->string
[data
->size
- 1] = 0;
757 data
->len
= data
->size
;
762 * We have not enough space for whole string with the trailing
763 * zero => print only a part of string.
766 memcpy((void *)(data
->string
+ data
->len
), (void *)str
, i
- 1);
767 data
->string
[data
->size
- 1] = 0;
768 data
->len
= data
->size
;
772 /* Buffer is big enough to print whole string. */
773 memcpy((void *)(data
->string
+ data
->len
), (void *)str
, count
);
776 * Put trailing zero at end, but not count it into data->len so
777 * it could be rewritten next time.
779 data
->string
[data
->len
] = 0;
784 int vsnprintf(char *str
, size_t size
, const char *fmt
, va_list ap
)
786 struct vsnprintf_data data
= { size
, 0, str
};
787 struct printf_spec ps
= { vsnprintf_write
, &data
};
789 /* Print 0 at end of string - fix case that nothing will be printed. */
793 /* vsnprintf_write() ensures that str will be terminated by zero. */
794 return printf_core(fmt
, &ps
, ap
);
797 int vsprintf(char *str
, const char *fmt
, va_list ap
)
799 return vsnprintf(str
, (size_t) - 1, fmt
, ap
);
802 int printf(const char *fmt
, ...)
808 ret
= vprintf(fmt
, args
);
814 static int vprintf_write(const char *str
, size_t count
, void *unused
)
816 console_write(str
, count
);
820 int vprintf(const char *fmt
, va_list ap
)
822 struct printf_spec ps
= { vprintf_write
, NULL
};
824 return printf_core(fmt
, &ps
, ap
);