]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - IPXE/ipxe-3fe683e/src/core/vsprintf.c
Add German language (#57)
[Ventoy.git] / IPXE / ipxe-3fe683e / src / core / 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 * 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.
22 */
23
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
26 #include <stddef.h>
27 #include <stdarg.h>
28 #include <stdio.h>
29 #include <errno.h>
30 #include <wchar.h>
31 #include <ipxe/vsprintf.h>
32
33 /** @file */
34
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 */
41
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 ),
49 };
50
51 /**
52 * Use lower-case for hexadecimal digits
53 *
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.)
57 */
58 #define LCASE 0x20
59
60 /**
61 * Use "alternate form"
62 *
63 * For hexadecimal numbers, this means to add a "0x" or "0X" prefix to
64 * the number.
65 */
66 #define ALT_FORM 0x02
67
68 /**
69 * Use zero padding
70 *
71 * Note that this value is set to 0x10 since that allows the pad
72 * character to be calculated as @c 0x20|(flags&ZPAD)
73 */
74 #define ZPAD 0x10
75
76 /**
77 * Format a hexadecimal number
78 *
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
84 *
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
88 * set.
89 *
90 * There must be enough space in the buffer to contain the largest
91 * number that this function can format.
92 */
93 static char * format_hex ( char *end, unsigned long long num, int width,
94 int flags ) {
95 char *ptr = end;
96 int case_mod = ( flags & LCASE );
97 int pad = ( ( flags & ZPAD ) | ' ' );
98
99 /* Generate the number */
100 do {
101 *(--ptr) = "0123456789ABCDEF"[ num & 0xf ] | case_mod;
102 num >>= 4;
103 } while ( num );
104
105 /* Pad to width */
106 while ( ( end - ptr ) < width )
107 *(--ptr) = pad;
108
109 /* Add "0x" or "0X" if alternate form specified */
110 if ( flags & ALT_FORM ) {
111 *(--ptr) = 'X' | case_mod;
112 *(--ptr) = '0';
113 }
114
115 return ptr;
116 }
117
118 /**
119 * Format a decimal number
120 *
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
126 *
127 * Fills a buffer in reverse order with a formatted decimal number.
128 * The number will be space-padded to the specified width.
129 *
130 * There must be enough space in the buffer to contain the largest
131 * number that this function can format.
132 */
133 static char * format_decimal ( char *end, signed long num, int width,
134 int flags ) {
135 char *ptr = end;
136 int negative = 0;
137 int zpad = ( flags & ZPAD );
138 int pad = ( zpad | ' ' );
139
140 /* Generate the number */
141 if ( num < 0 ) {
142 negative = 1;
143 num = -num;
144 }
145 do {
146 *(--ptr) = '0' + ( num % 10 );
147 num /= 10;
148 } while ( num );
149
150 /* Add "-" if necessary */
151 if ( negative && ( ! zpad ) )
152 *(--ptr) = '-';
153
154 /* Pad to width */
155 while ( ( end - ptr ) < width )
156 *(--ptr) = pad;
157
158 /* Add "-" if necessary */
159 if ( negative && zpad )
160 *ptr = '-';
161
162 return ptr;
163 }
164
165 #define ZPAD 0x10
166 char *format_unsigned_decimal(char *end, unsigned long long num, int width, int flags)
167 {
168 char *ptr = end;
169 int zpad = ( flags & ZPAD );
170 int pad = ( zpad | ' ' );
171
172 do {
173 *(--ptr) = '0' + ( num % 10 );
174 num /= 10;
175 } while ( num );
176
177 /* Pad to width */
178 while ( ( end - ptr ) < width )
179 *(--ptr) = pad;
180
181 return ptr;
182 }
183
184 /**
185 * Print character via a printf context
186 *
187 * @v ctx Context
188 * @v c Character
189 *
190 * Call's the printf_context::handler() method and increments
191 * printf_context::len.
192 */
193 static inline void cputchar ( struct printf_context *ctx, unsigned char c ) {
194 ctx->handler ( ctx, c );
195 ++ctx->len;
196 }
197
198 /**
199 * Write a formatted string to a printf context
200 *
201 * @v ctx Context
202 * @v fmt Format string
203 * @v args Arguments corresponding to the format string
204 * @ret len Length of formatted string
205 */
206 size_t vcprintf ( struct printf_context *ctx, const char *fmt, va_list args ) {
207 int flags;
208 int width;
209 uint8_t *length;
210 char *ptr;
211 char tmp_buf[32]; /* 32 is enough for all numerical formats.
212 * Insane width fields could overflow this buffer. */
213 wchar_t *wptr;
214
215 /* Initialise context */
216 ctx->len = 0;
217
218 for ( ; *fmt ; fmt++ ) {
219 /* Pass through ordinary characters */
220 if ( *fmt != '%' ) {
221 cputchar ( ctx, *fmt );
222 continue;
223 }
224 fmt++;
225 /* Process flag characters */
226 flags = 0;
227 for ( ; ; fmt++ ) {
228 if ( *fmt == '#' ) {
229 flags |= ALT_FORM;
230 } else if ( *fmt == '0' ) {
231 flags |= ZPAD;
232 } else {
233 /* End of flag characters */
234 break;
235 }
236 }
237 /* Process field width */
238 width = 0;
239 for ( ; ; fmt++ ) {
240 if ( ( ( unsigned ) ( *fmt - '0' ) ) < 10 ) {
241 width = ( width * 10 ) + ( *fmt - '0' );
242 } else {
243 break;
244 }
245 }
246 /* We don't do floating point */
247 /* Process length modifier */
248 length = &type_sizes[INT_LEN];
249 for ( ; ; fmt++ ) {
250 if ( *fmt == 'h' ) {
251 length--;
252 } else if ( *fmt == 'l' ) {
253 length++;
254 } else if ( *fmt == 'z' ) {
255 length = &type_sizes[SIZE_T_LEN];
256 } else {
257 break;
258 }
259 }
260 /* Process conversion specifier */
261 ptr = tmp_buf + sizeof ( tmp_buf ) - 1;
262 *ptr = '\0';
263 wptr = NULL;
264 if ( *fmt == 'c' ) {
265 if ( length < &type_sizes[LONG_LEN] ) {
266 cputchar ( ctx, va_arg ( args, unsigned int ) );
267 } else {
268 wchar_t wc;
269 size_t len;
270
271 wc = va_arg ( args, wint_t );
272 len = wcrtomb ( tmp_buf, wc, NULL );
273 tmp_buf[len] = '\0';
274 ptr = tmp_buf;
275 }
276 } else if ( *fmt == 's' ) {
277 if ( length < &type_sizes[LONG_LEN] ) {
278 ptr = va_arg ( args, char * );
279 if ( ! ptr )
280 ptr = "<NULL>";
281 } else {
282 wptr = va_arg ( args, wchar_t * );
283 if ( ! wptr )
284 ptr = "<NULL>";
285 }
286 } else if ( *fmt == 'p' ) {
287 intptr_t ptrval;
288
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;
294
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 );
300 } else {
301 hex = va_arg ( args, unsigned int );
302 }
303 ptr = format_hex ( ptr, hex, width, flags );
304 } else if ( ( *fmt == 'd' ) || ( *fmt == 'i' ) ){
305 signed long decimal;
306
307 if ( *length >= sizeof ( signed long ) ) {
308 decimal = va_arg ( args, signed long );
309 } else {
310 decimal = va_arg ( args, signed int );
311 }
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 );
319 } else {
320 decimal = va_arg ( args, unsigned int );
321 }
322 ptr = format_unsigned_decimal( ptr, decimal, width, flags );
323 } else {
324 *(--ptr) = *fmt;
325 }
326 /* Write out conversion result */
327 if ( wptr == NULL ) {
328 for ( ; *ptr ; ptr++ ) {
329 cputchar ( ctx, *ptr );
330 }
331 } else {
332 for ( ; *wptr ; wptr++ ) {
333 size_t len = wcrtomb ( tmp_buf, *wptr, NULL );
334 for ( ptr = tmp_buf ; len-- ; ptr++ ) {
335 cputchar ( ctx, *ptr );
336 }
337 }
338 }
339 }
340
341 return ctx->len;
342 }
343
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()) */
348 char *buf;
349 /** Buffer length (used by printf_sputc()) */
350 size_t max_len;
351 };
352
353 /**
354 * Write character to buffer
355 *
356 * @v ctx Context
357 * @v c Character
358 */
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 );
362
363 if ( ctx->len < sctx->max_len )
364 sctx->buf[ctx->len] = c;
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 args Arguments corresponding to the format string
374 * @ret len Length of formatted string
375 *
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
378 * been available.
379 */
380 int vsnprintf ( char *buf, size_t size, const char *fmt, va_list args ) {
381 struct sputc_context sctx;
382 size_t len;
383 size_t end;
384
385 /* Hand off to vcprintf */
386 sctx.ctx.handler = printf_sputc;
387 sctx.buf = buf;
388 sctx.max_len = size;
389 len = vcprintf ( &sctx.ctx, fmt, args );
390
391 /* Add trailing NUL */
392 if ( size ) {
393 end = size - 1;
394 if ( len < end )
395 end = len;
396 buf[end] = '\0';
397 }
398
399 return len;
400 }
401
402 /**
403 * Write a formatted string to a buffer
404 *
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
410 */
411 int snprintf ( char *buf, size_t size, const char *fmt, ... ) {
412 va_list args;
413 int i;
414
415 va_start ( args, fmt );
416 i = vsnprintf ( buf, size, fmt, args );
417 va_end ( args );
418 return i;
419 }
420
421 /**
422 * Version of vsnprintf() that accepts a signed buffer size
423 *
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
429 */
430 int vssnprintf ( char *buf, ssize_t ssize, const char *fmt, va_list args ) {
431
432 /* Treat negative buffer size as zero buffer size */
433 if ( ssize < 0 )
434 ssize = 0;
435
436 /* Hand off to vsnprintf */
437 return vsnprintf ( buf, ssize, fmt, args );
438 }
439
440 /**
441 * Version of vsnprintf() that accepts a signed buffer size
442 *
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
448 */
449 int ssnprintf ( char *buf, ssize_t ssize, const char *fmt, ... ) {
450 va_list args;
451 int len;
452
453 /* Hand off to vssnprintf */
454 va_start ( args, fmt );
455 len = vssnprintf ( buf, ssize, fmt, args );
456 va_end ( args );
457 return len;
458 }
459
460 /**
461 * Write character to console
462 *
463 * @v ctx Context
464 * @v c Character
465 */
466 static void printf_putchar ( struct printf_context *ctx __unused,
467 unsigned int c ) {
468 putchar ( c );
469 }
470
471 /**
472 * Write a formatted string to the console
473 *
474 * @v fmt Format string
475 * @v args Arguments corresponding to the format string
476 * @ret len Length of formatted string
477 */
478 int vprintf ( const char *fmt, va_list args ) {
479 struct printf_context ctx;
480
481 /* Hand off to vcprintf */
482 ctx.handler = printf_putchar;
483 return vcprintf ( &ctx, fmt, args );
484 }
485
486 /**
487 * Write a formatted string to the console.
488 *
489 * @v fmt Format string
490 * @v ... Arguments corresponding to the format string
491 * @ret len Length of formatted string
492 */
493 int printf ( const char *fmt, ... ) {
494 va_list args;
495 int i;
496
497 va_start ( args, fmt );
498 i = vprintf ( fmt, args );
499 va_end ( args );
500 return i;
501 }