2 * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include <gpxe/vsprintf.h>
28 #define CHAR_LEN 0 /**< "hh" length modifier */
29 #define SHORT_LEN 1 /**< "h" length modifier */
30 #define INT_LEN 2 /**< no length modifier */
31 #define LONG_LEN 3 /**< "l" length modifier */
32 #define LONGLONG_LEN 4 /**< "ll" length modifier */
33 #define SIZE_T_LEN 5 /**< "z" length modifier */
35 static uint8_t type_sizes
[] = {
36 [CHAR_LEN
] = sizeof ( char ),
37 [SHORT_LEN
] = sizeof ( short ),
38 [INT_LEN
] = sizeof ( int ),
39 [LONG_LEN
] = sizeof ( long ),
40 [LONGLONG_LEN
] = sizeof ( long long ),
41 [SIZE_T_LEN
] = sizeof ( size_t ),
45 * Use lower-case for hexadecimal digits
47 * Note that this value is set to 0x20 since that makes for very
48 * efficient calculations. (Bitwise-ORing with @c LCASE converts to a
49 * lower-case character, for example.)
54 * Use "alternate form"
56 * For hexadecimal numbers, this means to add a "0x" or "0X" prefix to
62 * Format a hexadecimal number
64 * @v end End of buffer to contain number
65 * @v num Number to format
66 * @v width Minimum field width
67 * @ret ptr End of buffer
69 * Fills a buffer in reverse order with a formatted hexadecimal
70 * number. The number will be zero-padded to the specified width.
71 * Lower-case and "alternate form" (i.e. "0x" prefix) flags may be
74 * There must be enough space in the buffer to contain the largest
75 * number that this function can format.
77 static char * format_hex ( char *end
, unsigned long long num
, int width
,
82 /* Generate the number */
83 case_mod
= flags
& LCASE
;
85 *(--ptr
) = "0123456789ABCDEF"[ num
& 0xf ] | case_mod
;
89 /* Zero-pad to width */
90 while ( ( end
- ptr
) < width
)
93 /* Add "0x" or "0X" if alternate form specified */
94 if ( flags
& ALT_FORM
) {
95 *(--ptr
) = 'X' | case_mod
;
103 * Format a decimal number
105 * @v end End of buffer to contain number
106 * @v num Number to format
107 * @v width Minimum field width
108 * @ret ptr End of buffer
110 * Fills a buffer in reverse order with a formatted decimal number.
111 * The number will be space-padded to the specified width.
113 * There must be enough space in the buffer to contain the largest
114 * number that this function can format.
116 static char * format_decimal ( char *end
, signed long num
, int width
) {
120 /* Generate the number */
126 *(--ptr
) = '0' + ( num
% 10 );
130 /* Add "-" if necessary */
134 /* Space-pad to width */
135 while ( ( end
- ptr
) < width
)
142 * Print character via a printf context
147 * Call's the printf_context::handler() method and increments
148 * printf_context::len.
150 static inline void cputchar ( struct printf_context
*ctx
, unsigned int c
) {
151 ctx
->handler ( ctx
, c
);
156 * Write a formatted string to a printf context
159 * @v fmt Format string
160 * @v args Arguments corresponding to the format string
161 * @ret len Length of formatted string
163 size_t vcprintf ( struct printf_context
*ctx
, const char *fmt
, va_list args
) {
168 char tmp_buf
[32]; /* 32 is enough for all numerical formats.
169 * Insane width fields could overflow this buffer. */
171 /* Initialise context */
174 for ( ; *fmt
; fmt
++ ) {
175 /* Pass through ordinary characters */
177 cputchar ( ctx
, *fmt
);
181 /* Process flag characters */
186 } else if ( *fmt
== '0' ) {
187 /* We always 0-pad hex and space-pad decimal */
189 /* End of flag characters */
193 /* Process field width */
196 if ( ( ( unsigned ) ( *fmt
- '0' ) ) < 10 ) {
197 width
= ( width
* 10 ) + ( *fmt
- '0' );
202 /* We don't do floating point */
203 /* Process length modifier */
204 length
= &type_sizes
[INT_LEN
];
208 } else if ( *fmt
== 'l' ) {
210 } else if ( *fmt
== 'z' ) {
211 length
= &type_sizes
[SIZE_T_LEN
];
216 /* Process conversion specifier */
217 ptr
= tmp_buf
+ sizeof ( tmp_buf
) - 1;
220 cputchar ( ctx
, va_arg ( args
, unsigned int ) );
221 } else if ( *fmt
== 's' ) {
222 ptr
= va_arg ( args
, char * );
225 } else if ( *fmt
== 'p' ) {
228 ptrval
= ( intptr_t ) va_arg ( args
, void * );
229 ptr
= format_hex ( ptr
, ptrval
, width
,
230 ( ALT_FORM
| LCASE
) );
231 } else if ( ( *fmt
& ~0x20 ) == 'X' ) {
232 unsigned long long hex
;
234 flags
|= ( *fmt
& 0x20 ); /* LCASE */
235 if ( *length
>= sizeof ( unsigned long long ) ) {
236 hex
= va_arg ( args
, unsigned long long );
237 } else if ( *length
>= sizeof ( unsigned long ) ) {
238 hex
= va_arg ( args
, unsigned long );
240 hex
= va_arg ( args
, unsigned int );
242 ptr
= format_hex ( ptr
, hex
, width
, flags
);
243 } else if ( ( *fmt
== 'd' ) || ( *fmt
== 'i' ) ){
246 if ( *length
>= sizeof ( signed long ) ) {
247 decimal
= va_arg ( args
, signed long );
249 decimal
= va_arg ( args
, signed int );
251 ptr
= format_decimal ( ptr
, decimal
, width
);
255 /* Write out conversion result */
256 for ( ; *ptr
; ptr
++ ) {
257 cputchar ( ctx
, *ptr
);
264 /** Context used by vsnprintf() and friends */
265 struct sputc_context
{
266 struct printf_context ctx
;
267 /** Buffer for formatted string (used by printf_sputc()) */
269 /** Buffer length (used by printf_sputc()) */
274 * Write character to buffer
279 static void printf_sputc ( struct printf_context
*ctx
, unsigned int c
) {
280 struct sputc_context
* sctx
=
281 container_of ( ctx
, struct sputc_context
, ctx
);
283 if ( ctx
->len
< sctx
->max_len
)
284 sctx
->buf
[ctx
->len
] = c
;
288 * Write a formatted string to a buffer
290 * @v buf Buffer into which to write the string
291 * @v size Size of buffer
292 * @v fmt Format string
293 * @v args Arguments corresponding to the format string
294 * @ret len Length of formatted string
296 * If the buffer is too small to contain the string, the returned
297 * length is the length that would have been written had enough space
300 int vsnprintf ( char *buf
, size_t size
, const char *fmt
, va_list args
) {
301 struct sputc_context sctx
;
305 /* Hand off to vcprintf */
306 sctx
.ctx
.handler
= printf_sputc
;
309 len
= vcprintf ( &sctx
.ctx
, fmt
, args
);
311 /* Add trailing NUL */
323 * Write a formatted string to a buffer
325 * @v buf Buffer into which to write the string
326 * @v size Size of buffer
327 * @v fmt Format string
328 * @v ... Arguments corresponding to the format string
329 * @ret len Length of formatted string
331 int snprintf ( char *buf
, size_t size
, const char *fmt
, ... ) {
335 va_start ( args
, fmt
);
336 i
= vsnprintf ( buf
, size
, fmt
, args
);
342 * Version of vsnprintf() that accepts a signed buffer size
344 * @v buf Buffer into which to write the string
345 * @v size Size of buffer
346 * @v fmt Format string
347 * @v args Arguments corresponding to the format string
348 * @ret len Length of formatted string
350 int vssnprintf ( char *buf
, ssize_t ssize
, const char *fmt
, va_list args
) {
352 /* Treat negative buffer size as zero buffer size */
356 /* Hand off to vsnprintf */
357 return vsnprintf ( buf
, ssize
, fmt
, args
);
361 * Version of vsnprintf() that accepts a signed buffer size
363 * @v buf Buffer into which to write the string
364 * @v size Size of buffer
365 * @v fmt Format string
366 * @v ... Arguments corresponding to the format string
367 * @ret len Length of formatted string
369 int ssnprintf ( char *buf
, ssize_t ssize
, const char *fmt
, ... ) {
373 /* Hand off to vssnprintf */
374 va_start ( args
, fmt
);
375 len
= vssnprintf ( buf
, ssize
, fmt
, args
);
381 * Write character to console
386 static void printf_putchar ( struct printf_context
*ctx __unused
,
392 * Write a formatted string to the console
394 * @v fmt Format string
395 * @v args Arguments corresponding to the format string
396 * @ret len Length of formatted string
398 int vprintf ( const char *fmt
, va_list args
) {
399 struct printf_context ctx
;
401 /* Hand off to vcprintf */
402 ctx
.handler
= printf_putchar
;
403 return vcprintf ( &ctx
, fmt
, args
);
407 * Write a formatted string to the console.
409 * @v fmt Format string
410 * @v ... Arguments corresponding to the format string
411 * @ret len Length of formatted string
413 int printf ( const char *fmt
, ... ) {
417 va_start ( args
, fmt
);
418 i
= vprintf ( fmt
, args
);