]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - wimboot/wimboot-2.7.3/src/ipxe/vsprintf.c
1.1.07 release
[Ventoy.git] / wimboot / wimboot-2.7.3 / src / ipxe / vsprintf.c
1 /*
2 * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
3 *
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.
8 *
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.
13 *
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
17 * 02110-1301, USA.
18 */
19
20 FILE_LICENCE ( GPL2_OR_LATER );
21
22 #include <stddef.h>
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include <errno.h>
26 #include <wchar.h>
27 #include <ipxe/vsprintf.h>
28
29 /** @file */
30
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 */
37
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 ),
45 };
46
47 /**
48 * Use lower-case for hexadecimal digits
49 *
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.)
53 */
54 #define LCASE 0x20
55
56 /**
57 * Use "alternate form"
58 *
59 * For hexadecimal numbers, this means to add a "0x" or "0X" prefix to
60 * the number.
61 */
62 #define ALT_FORM 0x02
63
64 /**
65 * Use zero padding
66 *
67 * Note that this value is set to 0x10 since that allows the pad
68 * character to be calculated as @c 0x20|(flags&ZPAD)
69 */
70 #define ZPAD 0x10
71
72 /**
73 * Format a hexadecimal number
74 *
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
80 *
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
84 * set.
85 *
86 * There must be enough space in the buffer to contain the largest
87 * number that this function can format.
88 */
89 static char * format_hex ( char *end, unsigned long long num, int width,
90 int flags ) {
91 char *ptr = end;
92 int case_mod = ( flags & LCASE );
93 int pad = ( ( flags & ZPAD ) | ' ' );
94
95 /* Generate the number */
96 do {
97 *(--ptr) = "0123456789ABCDEF"[ num & 0xf ] | case_mod;
98 num >>= 4;
99 } while ( num );
100
101 /* Pad to width */
102 while ( ( end - ptr ) < width )
103 *(--ptr) = pad;
104
105 /* Add "0x" or "0X" if alternate form specified */
106 if ( flags & ALT_FORM ) {
107 *(--ptr) = 'X' | case_mod;
108 *(--ptr) = '0';
109 }
110
111 return ptr;
112 }
113
114 /**
115 * Format a decimal number
116 *
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
122 *
123 * Fills a buffer in reverse order with a formatted decimal number.
124 * The number will be space-padded to the specified width.
125 *
126 * There must be enough space in the buffer to contain the largest
127 * number that this function can format.
128 */
129 static char * format_decimal ( char *end, signed long num, int width,
130 int flags ) {
131 char *ptr = end;
132 int negative = 0;
133 int zpad = ( flags & ZPAD );
134 int pad = ( zpad | ' ' );
135
136 /* Generate the number */
137 if ( num < 0 ) {
138 negative = 1;
139 num = -num;
140 }
141 do {
142 *(--ptr) = '0' + ( num % 10 );
143 num /= 10;
144 } while ( num );
145
146 /* Add "-" if necessary */
147 if ( negative && ( ! zpad ) )
148 *(--ptr) = '-';
149
150 /* Pad to width */
151 while ( ( end - ptr ) < width )
152 *(--ptr) = pad;
153
154 /* Add "-" if necessary */
155 if ( negative && zpad )
156 *ptr = '-';
157
158 return ptr;
159 }
160
161 /**
162 * Print character via a printf context
163 *
164 * @v ctx Context
165 * @v c Character
166 *
167 * Call's the printf_context::handler() method and increments
168 * printf_context::len.
169 */
170 static inline void cputchar ( struct printf_context *ctx, unsigned int c ) {
171 ctx->handler ( ctx, c );
172 ++ctx->len;
173 }
174
175 /**
176 * Write a formatted string to a printf context
177 *
178 * @v ctx Context
179 * @v fmt Format string
180 * @v args Arguments corresponding to the format string
181 * @ret len Length of formatted string
182 */
183 size_t vcprintf ( struct printf_context *ctx, const char *fmt, va_list args ) {
184 int flags;
185 int width;
186 uint8_t *length;
187 char *ptr;
188 char tmp_buf[32]; /* 32 is enough for all numerical formats.
189 * Insane width fields could overflow this buffer. */
190 wchar_t *wptr;
191
192 /* Initialise context */
193 ctx->len = 0;
194
195 for ( ; *fmt ; fmt++ ) {
196 /* Pass through ordinary characters */
197 if ( *fmt != '%' ) {
198 cputchar ( ctx, *fmt );
199 continue;
200 }
201 fmt++;
202 /* Process flag characters */
203 flags = 0;
204 for ( ; ; fmt++ ) {
205 if ( *fmt == '#' ) {
206 flags |= ALT_FORM;
207 } else if ( *fmt == '0' ) {
208 flags |= ZPAD;
209 } else {
210 /* End of flag characters */
211 break;
212 }
213 }
214 /* Process field width */
215 width = 0;
216 for ( ; ; fmt++ ) {
217 if ( ( ( unsigned ) ( *fmt - '0' ) ) < 10 ) {
218 width = ( width * 10 ) + ( *fmt - '0' );
219 } else {
220 break;
221 }
222 }
223 /* We don't do floating point */
224 /* Process length modifier */
225 length = &type_sizes[INT_LEN];
226 for ( ; ; fmt++ ) {
227 if ( *fmt == 'h' ) {
228 length--;
229 } else if ( *fmt == 'l' ) {
230 length++;
231 } else if ( *fmt == 'z' ) {
232 length = &type_sizes[SIZE_T_LEN];
233 } else {
234 break;
235 }
236 }
237 /* Process conversion specifier */
238 ptr = tmp_buf + sizeof ( tmp_buf ) - 1;
239 *ptr = '\0';
240 wptr = NULL;
241 if ( *fmt == 'c' ) {
242 if ( length < &type_sizes[LONG_LEN] ) {
243 cputchar ( ctx, va_arg ( args, unsigned int ) );
244 } else {
245 wchar_t wc;
246 size_t len;
247
248 wc = va_arg ( args, wint_t );
249 len = wcrtomb ( tmp_buf, wc, NULL );
250 tmp_buf[len] = '\0';
251 ptr = tmp_buf;
252 }
253 } else if ( *fmt == 's' ) {
254 if ( length < &type_sizes[LONG_LEN] ) {
255 ptr = va_arg ( args, char * );
256 } else {
257 wptr = va_arg ( args, wchar_t * );
258 }
259 if ( ( ptr == NULL ) && ( wptr == NULL ) )
260 ptr = "<NULL>";
261 } else if ( *fmt == 'p' ) {
262 intptr_t ptrval;
263
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;
269
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 );
275 } else {
276 hex = va_arg ( args, unsigned int );
277 }
278 ptr = format_hex ( ptr, hex, width, flags );
279 } else if ( ( *fmt == 'd' ) || ( *fmt == 'i' ) ){
280 signed long decimal;
281
282 if ( *length >= sizeof ( signed long ) ) {
283 decimal = va_arg ( args, signed long );
284 } else {
285 decimal = va_arg ( args, signed int );
286 }
287 ptr = format_decimal ( ptr, decimal, width, flags );
288 } else {
289 *(--ptr) = *fmt;
290 }
291 /* Write out conversion result */
292 if ( wptr == NULL ) {
293 for ( ; *ptr ; ptr++ ) {
294 cputchar ( ctx, *ptr );
295 }
296 } else {
297 for ( ; *wptr ; wptr++ ) {
298 size_t len = wcrtomb ( tmp_buf, *wptr, NULL );
299 for ( ptr = tmp_buf ; len-- ; ptr++ ) {
300 cputchar ( ctx, *ptr );
301 }
302 }
303 }
304 }
305
306 return ctx->len;
307 }
308
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()) */
313 char *buf;
314 /** Buffer length (used by printf_sputc()) */
315 size_t max_len;
316 };
317
318 /**
319 * Write character to buffer
320 *
321 * @v ctx Context
322 * @v c Character
323 */
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 );
327
328 if ( ctx->len < sctx->max_len )
329 sctx->buf[ctx->len] = c;
330 }
331
332 /**
333 * Write a formatted string to a buffer
334 *
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
340 *
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
343 * been available.
344 */
345 int vsnprintf ( char *buf, size_t size, const char *fmt, va_list args ) {
346 struct sputc_context sctx;
347 size_t len;
348 size_t end;
349
350 /* Hand off to vcprintf */
351 sctx.ctx.handler = printf_sputc;
352 sctx.buf = buf;
353 sctx.max_len = size;
354 len = vcprintf ( &sctx.ctx, fmt, args );
355
356 /* Add trailing NUL */
357 if ( size ) {
358 end = size - 1;
359 if ( len < end )
360 end = len;
361 buf[end] = '\0';
362 }
363
364 return len;
365 }
366
367 /**
368 * Write a formatted string to a buffer
369 *
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
375 */
376 int snprintf ( char *buf, size_t size, const char *fmt, ... ) {
377 va_list args;
378 int i;
379
380 va_start ( args, fmt );
381 i = vsnprintf ( buf, size, fmt, args );
382 va_end ( args );
383 return i;
384 }
385
386 /**
387 * Version of vsnprintf() that accepts a signed buffer size
388 *
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
394 */
395 int vssnprintf ( char *buf, ssize_t ssize, const char *fmt, va_list args ) {
396
397 /* Treat negative buffer size as zero buffer size */
398 if ( ssize < 0 )
399 ssize = 0;
400
401 /* Hand off to vsnprintf */
402 return vsnprintf ( buf, ssize, fmt, args );
403 }
404
405 /**
406 * Version of vsnprintf() that accepts a signed buffer size
407 *
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
413 */
414 int ssnprintf ( char *buf, ssize_t ssize, const char *fmt, ... ) {
415 va_list args;
416 int len;
417
418 /* Hand off to vssnprintf */
419 va_start ( args, fmt );
420 len = vssnprintf ( buf, ssize, fmt, args );
421 va_end ( args );
422 return len;
423 }
424
425 /**
426 * Write character to console
427 *
428 * @v ctx Context
429 * @v c Character
430 */
431 static void printf_putchar ( struct printf_context *ctx __unused,
432 unsigned int c ) {
433 putchar ( c );
434 }
435
436 /**
437 * Write a formatted string to the console
438 *
439 * @v fmt Format string
440 * @v args Arguments corresponding to the format string
441 * @ret len Length of formatted string
442 */
443 int vprintf ( const char *fmt, va_list args ) {
444 struct printf_context ctx;
445
446 /* Hand off to vcprintf */
447 ctx.handler = printf_putchar;
448 return vcprintf ( &ctx, fmt, args );
449 }
450
451 /**
452 * Write a formatted string to the console.
453 *
454 * @v fmt Format string
455 * @v ... Arguments corresponding to the format string
456 * @ret len Length of formatted string
457 */
458 int printf ( const char *fmt, ... ) {
459 va_list args;
460 int i;
461
462 va_start ( args, fmt );
463 i = vprintf ( fmt, args );
464 va_end ( args );
465 return i;
466 }