]>
glassweightruler.freedombox.rocks Git - Ventoy.git/blob - wimboot/wimboot-2.7.3/src/ipxe/vsprintf.c
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., 51 Franklin Street, Fifth Floor, Boston, MA
20 FILE_LICENCE ( GPL2_OR_LATER
);
27 #include <ipxe/vsprintf.h>
31 #define CHAR_LEN 0 /**< "hh" length modifier */
32 #define SHORT_LEN 1 /**< "h" length modifier */
33 #define INT_LEN 2 /**< no length modifier */
34 #define LONG_LEN 3 /**< "l" length modifier */
35 #define LONGLONG_LEN 4 /**< "ll" length modifier */
36 #define SIZE_T_LEN 5 /**< "z" length modifier */
38 static uint8_t type_sizes
[] = {
39 [CHAR_LEN
] = sizeof ( char ),
40 [SHORT_LEN
] = sizeof ( short ),
41 [INT_LEN
] = sizeof ( int ),
42 [LONG_LEN
] = sizeof ( long ),
43 [LONGLONG_LEN
] = sizeof ( long long ),
44 [SIZE_T_LEN
] = sizeof ( size_t ),
48 * Use lower-case for hexadecimal digits
50 * Note that this value is set to 0x20 since that makes for very
51 * efficient calculations. (Bitwise-ORing with @c LCASE converts to a
52 * lower-case character, for example.)
57 * Use "alternate form"
59 * For hexadecimal numbers, this means to add a "0x" or "0X" prefix to
67 * Note that this value is set to 0x10 since that allows the pad
68 * character to be calculated as @c 0x20|(flags&ZPAD)
73 * Format a hexadecimal number
75 * @v end End of buffer to contain number
76 * @v num Number to format
77 * @v width Minimum field width
78 * @v flags Format flags
79 * @ret ptr End of buffer
81 * Fills a buffer in reverse order with a formatted hexadecimal
82 * number. The number will be zero-padded to the specified width.
83 * Lower-case and "alternate form" (i.e. "0x" prefix) flags may be
86 * There must be enough space in the buffer to contain the largest
87 * number that this function can format.
89 static char * format_hex ( char *end
, unsigned long long num
, int width
,
92 int case_mod
= ( flags
& LCASE
);
93 int pad
= ( ( flags
& ZPAD
) | ' ' );
95 /* Generate the number */
97 *(--ptr
) = "0123456789ABCDEF"[ num
& 0xf ] | case_mod
;
102 while ( ( end
- ptr
) < width
)
105 /* Add "0x" or "0X" if alternate form specified */
106 if ( flags
& ALT_FORM
) {
107 *(--ptr
) = 'X' | case_mod
;
115 * Format a decimal number
117 * @v end End of buffer to contain number
118 * @v num Number to format
119 * @v width Minimum field width
120 * @v flags Format flags
121 * @ret ptr End of buffer
123 * Fills a buffer in reverse order with a formatted decimal number.
124 * The number will be space-padded to the specified width.
126 * There must be enough space in the buffer to contain the largest
127 * number that this function can format.
129 static char * format_decimal ( char *end
, signed long num
, int width
,
133 int zpad
= ( flags
& ZPAD
);
134 int pad
= ( zpad
| ' ' );
136 /* Generate the number */
142 *(--ptr
) = '0' + ( num
% 10 );
146 /* Add "-" if necessary */
147 if ( negative
&& ( ! zpad
) )
151 while ( ( end
- ptr
) < width
)
154 /* Add "-" if necessary */
155 if ( negative
&& zpad
)
162 * Print character via a printf context
167 * Call's the printf_context::handler() method and increments
168 * printf_context::len.
170 static inline void cputchar ( struct printf_context
*ctx
, unsigned int c
) {
171 ctx
->handler ( ctx
, c
);
176 * Write a formatted string to a printf context
179 * @v fmt Format string
180 * @v args Arguments corresponding to the format string
181 * @ret len Length of formatted string
183 size_t vcprintf ( struct printf_context
*ctx
, const char *fmt
, va_list args
) {
188 char tmp_buf
[32]; /* 32 is enough for all numerical formats.
189 * Insane width fields could overflow this buffer. */
192 /* Initialise context */
195 for ( ; *fmt
; fmt
++ ) {
196 /* Pass through ordinary characters */
198 cputchar ( ctx
, *fmt
);
202 /* Process flag characters */
207 } else if ( *fmt
== '0' ) {
210 /* End of flag characters */
214 /* Process field width */
217 if ( ( ( unsigned ) ( *fmt
- '0' ) ) < 10 ) {
218 width
= ( width
* 10 ) + ( *fmt
- '0' );
223 /* We don't do floating point */
224 /* Process length modifier */
225 length
= &type_sizes
[INT_LEN
];
229 } else if ( *fmt
== 'l' ) {
231 } else if ( *fmt
== 'z' ) {
232 length
= &type_sizes
[SIZE_T_LEN
];
237 /* Process conversion specifier */
238 ptr
= tmp_buf
+ sizeof ( tmp_buf
) - 1;
242 if ( length
< &type_sizes
[LONG_LEN
] ) {
243 cputchar ( ctx
, va_arg ( args
, unsigned int ) );
248 wc
= va_arg ( args
, wint_t );
249 len
= wcrtomb ( tmp_buf
, wc
, NULL
);
253 } else if ( *fmt
== 's' ) {
254 if ( length
< &type_sizes
[LONG_LEN
] ) {
255 ptr
= va_arg ( args
, char * );
257 wptr
= va_arg ( args
, wchar_t * );
259 if ( ( ptr
== NULL
) && ( wptr
== NULL
) )
261 } else if ( *fmt
== 'p' ) {
264 ptrval
= ( intptr_t ) va_arg ( args
, void * );
265 ptr
= format_hex ( ptr
, ptrval
, width
,
266 ( ALT_FORM
| LCASE
) );
267 } else if ( ( *fmt
& ~0x20 ) == 'X' ) {
268 unsigned long long hex
;
270 flags
|= ( *fmt
& 0x20 ); /* LCASE */
271 if ( *length
>= sizeof ( unsigned long long ) ) {
272 hex
= va_arg ( args
, unsigned long long );
273 } else if ( *length
>= sizeof ( unsigned long ) ) {
274 hex
= va_arg ( args
, unsigned long );
276 hex
= va_arg ( args
, unsigned int );
278 ptr
= format_hex ( ptr
, hex
, width
, flags
);
279 } else if ( ( *fmt
== 'd' ) || ( *fmt
== 'i' ) ){
282 if ( *length
>= sizeof ( signed long ) ) {
283 decimal
= va_arg ( args
, signed long );
285 decimal
= va_arg ( args
, signed int );
287 ptr
= format_decimal ( ptr
, decimal
, width
, flags
);
291 /* Write out conversion result */
292 if ( wptr
== NULL
) {
293 for ( ; *ptr
; ptr
++ ) {
294 cputchar ( ctx
, *ptr
);
297 for ( ; *wptr
; wptr
++ ) {
298 size_t len
= wcrtomb ( tmp_buf
, *wptr
, NULL
);
299 for ( ptr
= tmp_buf
; len
-- ; ptr
++ ) {
300 cputchar ( ctx
, *ptr
);
309 /** Context used by vsnprintf() and friends */
310 struct sputc_context
{
311 struct printf_context ctx
;
312 /** Buffer for formatted string (used by printf_sputc()) */
314 /** Buffer length (used by printf_sputc()) */
319 * Write character to buffer
324 static void printf_sputc ( struct printf_context
*ctx
, unsigned int c
) {
325 struct sputc_context
* sctx
=
326 container_of ( ctx
, struct sputc_context
, ctx
);
328 if ( ctx
->len
< sctx
->max_len
)
329 sctx
->buf
[ctx
->len
] = c
;
333 * Write a formatted string to a buffer
335 * @v buf Buffer into which to write the string
336 * @v size Size of buffer
337 * @v fmt Format string
338 * @v args Arguments corresponding to the format string
339 * @ret len Length of formatted string
341 * If the buffer is too small to contain the string, the returned
342 * length is the length that would have been written had enough space
345 int vsnprintf ( char *buf
, size_t size
, const char *fmt
, va_list args
) {
346 struct sputc_context sctx
;
350 /* Hand off to vcprintf */
351 sctx
.ctx
.handler
= printf_sputc
;
354 len
= vcprintf ( &sctx
.ctx
, fmt
, args
);
356 /* Add trailing NUL */
368 * Write a formatted string to a buffer
370 * @v buf Buffer into which to write the string
371 * @v size Size of buffer
372 * @v fmt Format string
373 * @v ... Arguments corresponding to the format string
374 * @ret len Length of formatted string
376 int snprintf ( char *buf
, size_t size
, const char *fmt
, ... ) {
380 va_start ( args
, fmt
);
381 i
= vsnprintf ( buf
, size
, fmt
, args
);
387 * Version of vsnprintf() that accepts a signed buffer size
389 * @v buf Buffer into which to write the string
390 * @v size Size of buffer
391 * @v fmt Format string
392 * @v args Arguments corresponding to the format string
393 * @ret len Length of formatted string
395 int vssnprintf ( char *buf
, ssize_t ssize
, const char *fmt
, va_list args
) {
397 /* Treat negative buffer size as zero buffer size */
401 /* Hand off to vsnprintf */
402 return vsnprintf ( buf
, ssize
, fmt
, args
);
406 * Version of vsnprintf() that accepts a signed buffer size
408 * @v buf Buffer into which to write the string
409 * @v size Size of buffer
410 * @v fmt Format string
411 * @v ... Arguments corresponding to the format string
412 * @ret len Length of formatted string
414 int ssnprintf ( char *buf
, ssize_t ssize
, const char *fmt
, ... ) {
418 /* Hand off to vssnprintf */
419 va_start ( args
, fmt
);
420 len
= vssnprintf ( buf
, ssize
, fmt
, args
);
426 * Write character to console
431 static void printf_putchar ( struct printf_context
*ctx __unused
,
437 * Write a formatted string to the console
439 * @v fmt Format string
440 * @v args Arguments corresponding to the format string
441 * @ret len Length of formatted string
443 int vprintf ( const char *fmt
, va_list args
) {
444 struct printf_context ctx
;
446 /* Hand off to vcprintf */
447 ctx
.handler
= printf_putchar
;
448 return vcprintf ( &ctx
, fmt
, args
);
452 * Write a formatted string to the console.
454 * @v fmt Format string
455 * @v ... Arguments corresponding to the format string
456 * @ret len Length of formatted string
458 int printf ( const char *fmt
, ... ) {
462 va_start ( args
, fmt
);
463 i
= vprintf ( fmt
, args
);