]>
glassweightruler.freedombox.rocks Git - Ventoy.git/blob - IPXE/ipxe-3fe683e/src/core/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
19 * You can also choose to distribute this program under the terms of
20 * the Unmodified Binary Distribution Licence (as given in the file
21 * COPYING.UBDL), provided that you have satisfied its requirements.
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL
);
31 #include <ipxe/vsprintf.h>
35 #define CHAR_LEN 0 /**< "hh" length modifier */
36 #define SHORT_LEN 1 /**< "h" length modifier */
37 #define INT_LEN 2 /**< no length modifier */
38 #define LONG_LEN 3 /**< "l" length modifier */
39 #define LONGLONG_LEN 4 /**< "ll" length modifier */
40 #define SIZE_T_LEN 5 /**< "z" length modifier */
42 static uint8_t type_sizes
[] = {
43 [CHAR_LEN
] = sizeof ( char ),
44 [SHORT_LEN
] = sizeof ( short ),
45 [INT_LEN
] = sizeof ( int ),
46 [LONG_LEN
] = sizeof ( long ),
47 [LONGLONG_LEN
] = sizeof ( long long ),
48 [SIZE_T_LEN
] = sizeof ( size_t ),
52 * Use lower-case for hexadecimal digits
54 * Note that this value is set to 0x20 since that makes for very
55 * efficient calculations. (Bitwise-ORing with @c LCASE converts to a
56 * lower-case character, for example.)
61 * Use "alternate form"
63 * For hexadecimal numbers, this means to add a "0x" or "0X" prefix to
71 * Note that this value is set to 0x10 since that allows the pad
72 * character to be calculated as @c 0x20|(flags&ZPAD)
77 * Format a hexadecimal number
79 * @v end End of buffer to contain number
80 * @v num Number to format
81 * @v width Minimum field width
82 * @v flags Format flags
83 * @ret ptr End of buffer
85 * Fills a buffer in reverse order with a formatted hexadecimal
86 * number. The number will be zero-padded to the specified width.
87 * Lower-case and "alternate form" (i.e. "0x" prefix) flags may be
90 * There must be enough space in the buffer to contain the largest
91 * number that this function can format.
93 static char * format_hex ( char *end
, unsigned long long num
, int width
,
96 int case_mod
= ( flags
& LCASE
);
97 int pad
= ( ( flags
& ZPAD
) | ' ' );
99 /* Generate the number */
101 *(--ptr
) = "0123456789ABCDEF"[ num
& 0xf ] | case_mod
;
106 while ( ( end
- ptr
) < width
)
109 /* Add "0x" or "0X" if alternate form specified */
110 if ( flags
& ALT_FORM
) {
111 *(--ptr
) = 'X' | case_mod
;
119 * Format a decimal number
121 * @v end End of buffer to contain number
122 * @v num Number to format
123 * @v width Minimum field width
124 * @v flags Format flags
125 * @ret ptr End of buffer
127 * Fills a buffer in reverse order with a formatted decimal number.
128 * The number will be space-padded to the specified width.
130 * There must be enough space in the buffer to contain the largest
131 * number that this function can format.
133 static char * format_decimal ( char *end
, signed long num
, int width
,
137 int zpad
= ( flags
& ZPAD
);
138 int pad
= ( zpad
| ' ' );
140 /* Generate the number */
146 *(--ptr
) = '0' + ( num
% 10 );
150 /* Add "-" if necessary */
151 if ( negative
&& ( ! zpad
) )
155 while ( ( end
- ptr
) < width
)
158 /* Add "-" if necessary */
159 if ( negative
&& zpad
)
166 char *format_unsigned_decimal(char *end
, unsigned long long num
, int width
, int flags
)
169 int zpad
= ( flags
& ZPAD
);
170 int pad
= ( zpad
| ' ' );
173 *(--ptr
) = '0' + ( num
% 10 );
178 while ( ( end
- ptr
) < width
)
185 * Print character via a printf context
190 * Call's the printf_context::handler() method and increments
191 * printf_context::len.
193 static inline void cputchar ( struct printf_context
*ctx
, unsigned char c
) {
194 ctx
->handler ( ctx
, c
);
199 * Write a formatted string to a printf context
202 * @v fmt Format string
203 * @v args Arguments corresponding to the format string
204 * @ret len Length of formatted string
206 size_t vcprintf ( struct printf_context
*ctx
, const char *fmt
, va_list args
) {
211 char tmp_buf
[32]; /* 32 is enough for all numerical formats.
212 * Insane width fields could overflow this buffer. */
215 /* Initialise context */
218 for ( ; *fmt
; fmt
++ ) {
219 /* Pass through ordinary characters */
221 cputchar ( ctx
, *fmt
);
225 /* Process flag characters */
230 } else if ( *fmt
== '0' ) {
233 /* End of flag characters */
237 /* Process field width */
240 if ( ( ( unsigned ) ( *fmt
- '0' ) ) < 10 ) {
241 width
= ( width
* 10 ) + ( *fmt
- '0' );
246 /* We don't do floating point */
247 /* Process length modifier */
248 length
= &type_sizes
[INT_LEN
];
252 } else if ( *fmt
== 'l' ) {
254 } else if ( *fmt
== 'z' ) {
255 length
= &type_sizes
[SIZE_T_LEN
];
260 /* Process conversion specifier */
261 ptr
= tmp_buf
+ sizeof ( tmp_buf
) - 1;
265 if ( length
< &type_sizes
[LONG_LEN
] ) {
266 cputchar ( ctx
, va_arg ( args
, unsigned int ) );
271 wc
= va_arg ( args
, wint_t );
272 len
= wcrtomb ( tmp_buf
, wc
, NULL
);
276 } else if ( *fmt
== 's' ) {
277 if ( length
< &type_sizes
[LONG_LEN
] ) {
278 ptr
= va_arg ( args
, char * );
282 wptr
= va_arg ( args
, wchar_t * );
286 } else if ( *fmt
== 'p' ) {
289 ptrval
= ( intptr_t ) va_arg ( args
, void * );
290 ptr
= format_hex ( ptr
, ptrval
, width
,
291 ( ALT_FORM
| LCASE
) );
292 } else if ( ( *fmt
& ~0x20 ) == 'X' ) {
293 unsigned long long hex
;
295 flags
|= ( *fmt
& 0x20 ); /* LCASE */
296 if ( *length
>= sizeof ( unsigned long long ) ) {
297 hex
= va_arg ( args
, unsigned long long );
298 } else if ( *length
>= sizeof ( unsigned long ) ) {
299 hex
= va_arg ( args
, unsigned long );
301 hex
= va_arg ( args
, unsigned int );
303 ptr
= format_hex ( ptr
, hex
, width
, flags
);
304 } else if ( ( *fmt
== 'd' ) || ( *fmt
== 'i' ) ){
307 if ( *length
>= sizeof ( signed long ) ) {
308 decimal
= va_arg ( args
, signed long );
310 decimal
= va_arg ( args
, signed int );
312 ptr
= format_decimal ( ptr
, decimal
, width
, flags
);
313 } else if ( ( *fmt
== 'u' ) || ( *fmt
== 'U' )){
314 unsigned long long decimal
;
315 if ( *length
>= sizeof ( unsigned long long ) ) {
316 decimal
= va_arg ( args
, unsigned long long );
317 } else if ( *length
>= sizeof ( unsigned long ) ) {
318 decimal
= va_arg ( args
, unsigned long );
320 decimal
= va_arg ( args
, unsigned int );
322 ptr
= format_unsigned_decimal( ptr
, decimal
, width
, flags
);
326 /* Write out conversion result */
327 if ( wptr
== NULL
) {
328 for ( ; *ptr
; ptr
++ ) {
329 cputchar ( ctx
, *ptr
);
332 for ( ; *wptr
; wptr
++ ) {
333 size_t len
= wcrtomb ( tmp_buf
, *wptr
, NULL
);
334 for ( ptr
= tmp_buf
; len
-- ; ptr
++ ) {
335 cputchar ( ctx
, *ptr
);
344 /** Context used by vsnprintf() and friends */
345 struct sputc_context
{
346 struct printf_context ctx
;
347 /** Buffer for formatted string (used by printf_sputc()) */
349 /** Buffer length (used by printf_sputc()) */
354 * Write character to buffer
359 static void printf_sputc ( struct printf_context
*ctx
, unsigned int c
) {
360 struct sputc_context
* sctx
=
361 container_of ( ctx
, struct sputc_context
, ctx
);
363 if ( ctx
->len
< sctx
->max_len
)
364 sctx
->buf
[ctx
->len
] = c
;
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 args Arguments corresponding to the format string
374 * @ret len Length of formatted string
376 * If the buffer is too small to contain the string, the returned
377 * length is the length that would have been written had enough space
380 int vsnprintf ( char *buf
, size_t size
, const char *fmt
, va_list args
) {
381 struct sputc_context sctx
;
385 /* Hand off to vcprintf */
386 sctx
.ctx
.handler
= printf_sputc
;
389 len
= vcprintf ( &sctx
.ctx
, fmt
, args
);
391 /* Add trailing NUL */
403 * Write a formatted string to a buffer
405 * @v buf Buffer into which to write the string
406 * @v size Size of buffer
407 * @v fmt Format string
408 * @v ... Arguments corresponding to the format string
409 * @ret len Length of formatted string
411 int snprintf ( char *buf
, size_t size
, const char *fmt
, ... ) {
415 va_start ( args
, fmt
);
416 i
= vsnprintf ( buf
, size
, fmt
, args
);
422 * Version of vsnprintf() that accepts a signed buffer size
424 * @v buf Buffer into which to write the string
425 * @v size Size of buffer
426 * @v fmt Format string
427 * @v args Arguments corresponding to the format string
428 * @ret len Length of formatted string
430 int vssnprintf ( char *buf
, ssize_t ssize
, const char *fmt
, va_list args
) {
432 /* Treat negative buffer size as zero buffer size */
436 /* Hand off to vsnprintf */
437 return vsnprintf ( buf
, ssize
, fmt
, args
);
441 * Version of vsnprintf() that accepts a signed buffer size
443 * @v buf Buffer into which to write the string
444 * @v size Size of buffer
445 * @v fmt Format string
446 * @v ... Arguments corresponding to the format string
447 * @ret len Length of formatted string
449 int ssnprintf ( char *buf
, ssize_t ssize
, const char *fmt
, ... ) {
453 /* Hand off to vssnprintf */
454 va_start ( args
, fmt
);
455 len
= vssnprintf ( buf
, ssize
, fmt
, args
);
461 * Write character to console
466 static void printf_putchar ( struct printf_context
*ctx __unused
,
472 * Write a formatted string to the console
474 * @v fmt Format string
475 * @v args Arguments corresponding to the format string
476 * @ret len Length of formatted string
478 int vprintf ( const char *fmt
, va_list args
) {
479 struct printf_context ctx
;
481 /* Hand off to vcprintf */
482 ctx
.handler
= printf_putchar
;
483 return vcprintf ( &ctx
, fmt
, args
);
487 * Write a formatted string to the console.
489 * @v fmt Format string
490 * @v ... Arguments corresponding to the format string
491 * @ret len Length of formatted string
493 int printf ( const char *fmt
, ... ) {
497 va_start ( args
, fmt
);
498 i
= vprintf ( fmt
, args
);