iPXE
vsprintf.c
Go to the documentation of this file.
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
24FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25FILE_SECBOOT ( PERMITTED );
26
27#include <stddef.h>
28#include <stdarg.h>
29#include <stdio.h>
30#include <errno.h>
31#include <wchar.h>
32#include <ipxe/vsprintf.h>
33
34/** @file */
35
36#define CHAR_LEN 0 /**< "hh" length modifier */
37#define SHORT_LEN 1 /**< "h" length modifier */
38#define INT_LEN 2 /**< no length modifier */
39#define LONG_LEN 3 /**< "l" length modifier */
40#define LONGLONG_LEN 4 /**< "ll" length modifier */
41#define SIZE_T_LEN 5 /**< "z" length modifier */
42
43static uint8_t type_sizes[] = {
44 [CHAR_LEN] = sizeof ( char ),
45 [SHORT_LEN] = sizeof ( short ),
46 [INT_LEN] = sizeof ( int ),
47 [LONG_LEN] = sizeof ( long ),
48 [LONGLONG_LEN] = sizeof ( long long ),
49 [SIZE_T_LEN] = sizeof ( size_t ),
50};
51
52/**
53 * Use lower-case for hexadecimal digits
54 *
55 * Note that this value is set to 0x20 since that makes for very
56 * efficient calculations. (Bitwise-ORing with @c LCASE converts to a
57 * lower-case character, for example.)
58 */
59#define LCASE 0x20
60
61/**
62 * Use "alternate form"
63 *
64 * For hexadecimal numbers, this means to add a "0x" or "0X" prefix to
65 * the number.
66 */
67#define ALT_FORM 0x02
68
69/**
70 * Use zero padding
71 *
72 * Note that this value is set to 0x10 since that allows the pad
73 * character to be calculated as @c 0x20|(flags&ZPAD)
74 */
75#define ZPAD 0x10
76
77/**
78 * Format a hexadecimal number
79 *
80 * @v end End of buffer to contain number
81 * @v num Number to format
82 * @v width Minimum field width
83 * @v flags Format flags
84 * @ret ptr End of buffer
85 *
86 * Fills a buffer in reverse order with a formatted hexadecimal
87 * number. The number will be zero-padded to the specified width.
88 * Lower-case and "alternate form" (i.e. "0x" prefix) flags may be
89 * set.
90 *
91 * There must be enough space in the buffer to contain the largest
92 * number that this function can format.
93 */
94static char * format_hex ( char *end, unsigned long long num, int width,
95 int flags ) {
96 char *ptr = end;
97 int case_mod = ( flags & LCASE );
98 int pad = ( ( flags & ZPAD ) | ' ' );
99
100 /* Generate the number */
101 do {
102 *(--ptr) = "0123456789ABCDEF"[ num & 0xf ] | case_mod;
103 num >>= 4;
104 } while ( num );
105
106 /* Pad to width */
107 while ( ( end - ptr ) < width )
108 *(--ptr) = pad;
109
110 /* Add "0x" or "0X" if alternate form specified */
111 if ( flags & ALT_FORM ) {
112 *(--ptr) = 'X' | case_mod;
113 *(--ptr) = '0';
114 }
115
116 return ptr;
117}
118
119/**
120 * Format a decimal number
121 *
122 * @v end End of buffer to contain number
123 * @v num Number to format
124 * @v width Minimum field width
125 * @v flags Format flags
126 * @ret ptr End of buffer
127 *
128 * Fills a buffer in reverse order with a formatted decimal number.
129 * The number will be space-padded to the specified width.
130 *
131 * There must be enough space in the buffer to contain the largest
132 * number that this function can format.
133 */
134static char * format_decimal ( char *end, signed long num, int width,
135 int flags ) {
136 char *ptr = end;
137 int negative = 0;
138 int zpad = ( flags & ZPAD );
139 int pad = ( zpad | ' ' );
140
141 /* Generate the number */
142 if ( num < 0 ) {
143 negative = 1;
144 num = -num;
145 }
146 do {
147 *(--ptr) = '0' + ( num % 10 );
148 num /= 10;
149 } while ( num );
150
151 /* Add "-" if necessary */
152 if ( negative && ( ! zpad ) )
153 *(--ptr) = '-';
154
155 /* Pad to width */
156 while ( ( end - ptr ) < width )
157 *(--ptr) = pad;
158
159 /* Add "-" if necessary */
160 if ( negative && zpad )
161 *ptr = '-';
162
163 return ptr;
164}
165
166/**
167 * Print character via a printf context
168 *
169 * @v ctx Context
170 * @v c Character
171 *
172 * Call's the printf_context::handler() method and increments
173 * printf_context::len.
174 */
175static inline void cputchar ( struct printf_context *ctx, unsigned char c ) {
176 ctx->handler ( ctx, c );
177 ++ctx->len;
178}
179
180/**
181 * Write a formatted string to a printf context
182 *
183 * @v ctx Context
184 * @v fmt Format string
185 * @v args Arguments corresponding to the format string
186 * @ret len Length of formatted string
187 */
188size_t vcprintf ( struct printf_context *ctx, const char *fmt, va_list args ) {
189 int flags;
190 int width;
192 char *ptr;
193 char tmp_buf[32]; /* 32 is enough for all numerical formats.
194 * Insane width fields could overflow this buffer. */
195 wchar_t *wptr;
196
197 /* Initialise context */
198 ctx->len = 0;
199
200 for ( ; *fmt ; fmt++ ) {
201 /* Pass through ordinary characters */
202 if ( *fmt != '%' ) {
203 cputchar ( ctx, *fmt );
204 continue;
205 }
206 fmt++;
207 /* Process flag characters */
208 flags = 0;
209 for ( ; ; fmt++ ) {
210 if ( *fmt == '#' ) {
211 flags |= ALT_FORM;
212 } else if ( *fmt == '0' ) {
213 flags |= ZPAD;
214 } else {
215 /* End of flag characters */
216 break;
217 }
218 }
219 /* Process field width */
220 width = 0;
221 for ( ; ; fmt++ ) {
222 if ( ( ( unsigned ) ( *fmt - '0' ) ) < 10 ) {
223 width = ( width * 10 ) + ( *fmt - '0' );
224 } else {
225 break;
226 }
227 }
228 /* We don't do floating point */
229 /* Process length modifier */
231 for ( ; ; fmt++ ) {
232 if ( *fmt == 'h' ) {
233 length--;
234 } else if ( *fmt == 'l' ) {
235 length++;
236 } else if ( *fmt == 'z' ) {
238 } else {
239 break;
240 }
241 }
242 /* Process conversion specifier */
243 ptr = tmp_buf + sizeof ( tmp_buf ) - 1;
244 *ptr = '\0';
245 wptr = NULL;
246 if ( *fmt == 'c' ) {
247 if ( length < &type_sizes[LONG_LEN] ) {
248 cputchar ( ctx, va_arg ( args, unsigned int ) );
249 } else {
250 wchar_t wc;
251 size_t len;
252
253 wc = va_arg ( args, wint_t );
254 len = wcrtomb ( tmp_buf, wc, NULL );
255 tmp_buf[len] = '\0';
256 ptr = tmp_buf;
257 }
258 } else if ( *fmt == 's' ) {
259 if ( length < &type_sizes[LONG_LEN] ) {
260 ptr = va_arg ( args, char * );
261 if ( ! ptr )
262 ptr = "<NULL>";
263 } else {
264 wptr = va_arg ( args, wchar_t * );
265 if ( ! wptr )
266 ptr = "<NULL>";
267 }
268 } else if ( *fmt == 'p' ) {
269 intptr_t ptrval;
270
271 ptrval = ( intptr_t ) va_arg ( args, void * );
272 ptr = format_hex ( ptr, ptrval, width,
273 ( ALT_FORM | LCASE ) );
274 } else if ( ( *fmt & ~0x20 ) == 'X' ) {
275 unsigned long long hex;
276
277 flags |= ( *fmt & 0x20 ); /* LCASE */
278 if ( *length >= sizeof ( unsigned long long ) ) {
279 hex = va_arg ( args, unsigned long long );
280 } else if ( *length >= sizeof ( unsigned long ) ) {
281 hex = va_arg ( args, unsigned long );
282 } else {
283 hex = va_arg ( args, unsigned int );
284 }
285 ptr = format_hex ( ptr, hex, width, flags );
286 } else if ( ( *fmt == 'd' ) || ( *fmt == 'i' ) ){
287 signed long decimal;
288
289 if ( *length >= sizeof ( signed long ) ) {
290 decimal = va_arg ( args, signed long );
291 } else {
292 decimal = va_arg ( args, signed int );
293 }
294 ptr = format_decimal ( ptr, decimal, width, flags );
295 } else {
296 *(--ptr) = *fmt;
297 }
298 /* Write out conversion result */
299 if ( wptr == NULL ) {
300 for ( ; *ptr ; ptr++ ) {
301 cputchar ( ctx, *ptr );
302 }
303 } else {
304 for ( ; *wptr ; wptr++ ) {
305 size_t len = wcrtomb ( tmp_buf, *wptr, NULL );
306 for ( ptr = tmp_buf ; len-- ; ptr++ ) {
307 cputchar ( ctx, *ptr );
308 }
309 }
310 }
311 }
312
313 return ctx->len;
314}
315
316/** Context used by vsnprintf() and friends */
319 /** Buffer for formatted string (used by printf_sputc()) */
320 char *buf;
321 /** Buffer length (used by printf_sputc()) */
322 size_t max_len;
323};
324
325/**
326 * Write character to buffer
327 *
328 * @v ctx Context
329 * @v c Character
330 */
331static void printf_sputc ( struct printf_context *ctx, unsigned int c ) {
332 struct sputc_context * sctx =
333 container_of ( ctx, struct sputc_context, ctx );
334
335 if ( ctx->len < sctx->max_len )
336 sctx->buf[ctx->len] = c;
337}
338
339/**
340 * Write a formatted string to a buffer
341 *
342 * @v buf Buffer into which to write the string
343 * @v size Size of buffer
344 * @v fmt Format string
345 * @v args Arguments corresponding to the format string
346 * @ret len Length of formatted string
347 *
348 * If the buffer is too small to contain the string, the returned
349 * length is the length that would have been written had enough space
350 * been available.
351 */
352int vsnprintf ( char *buf, size_t size, const char *fmt, va_list args ) {
353 struct sputc_context sctx;
354 size_t len;
355 size_t end;
356
357 /* Hand off to vcprintf */
358 sctx.ctx.handler = printf_sputc;
359 sctx.buf = buf;
360 sctx.max_len = size;
361 len = vcprintf ( &sctx.ctx, fmt, args );
362
363 /* Add trailing NUL */
364 if ( size ) {
365 end = size - 1;
366 if ( len < end )
367 end = len;
368 buf[end] = '\0';
369 }
370
371 return len;
372}
373
374/**
375 * Write a formatted string to a buffer
376 *
377 * @v buf Buffer into which to write the string
378 * @v size Size of buffer
379 * @v fmt Format string
380 * @v ... Arguments corresponding to the format string
381 * @ret len Length of formatted string
382 */
383int snprintf ( char *buf, size_t size, const char *fmt, ... ) {
384 va_list args;
385 int i;
386
387 va_start ( args, fmt );
388 i = vsnprintf ( buf, size, fmt, args );
389 va_end ( args );
390 return i;
391}
392
393/**
394 * Version of vsnprintf() that accepts a signed buffer size
395 *
396 * @v buf Buffer into which to write the string
397 * @v size Size of buffer
398 * @v fmt Format string
399 * @v args Arguments corresponding to the format string
400 * @ret len Length of formatted string
401 */
402int vssnprintf ( char *buf, ssize_t ssize, const char *fmt, va_list args ) {
403
404 /* Treat negative buffer size as zero buffer size */
405 if ( ssize < 0 )
406 ssize = 0;
407
408 /* Hand off to vsnprintf */
409 return vsnprintf ( buf, ssize, fmt, args );
410}
411
412/**
413 * Version of vsnprintf() that accepts a signed buffer size
414 *
415 * @v buf Buffer into which to write the string
416 * @v size Size of buffer
417 * @v fmt Format string
418 * @v ... Arguments corresponding to the format string
419 * @ret len Length of formatted string
420 */
421int ssnprintf ( char *buf, ssize_t ssize, const char *fmt, ... ) {
422 va_list args;
423 int len;
424
425 /* Hand off to vssnprintf */
426 va_start ( args, fmt );
427 len = vssnprintf ( buf, ssize, fmt, args );
428 va_end ( args );
429 return len;
430}
431
432/**
433 * Write character to console
434 *
435 * @v ctx Context
436 * @v c Character
437 */
439 unsigned int c ) {
440 putchar ( c );
441}
442
443/**
444 * Write a formatted string to the console
445 *
446 * @v fmt Format string
447 * @v args Arguments corresponding to the format string
448 * @ret len Length of formatted string
449 */
450int vprintf ( const char *fmt, va_list args ) {
451 struct printf_context ctx;
452
453 /* Hand off to vcprintf */
454 ctx.handler = printf_putchar;
455 return vcprintf ( &ctx, fmt, args );
456}
457
458/**
459 * Write a formatted string to the console.
460 *
461 * @v fmt Format string
462 * @v ... Arguments corresponding to the format string
463 * @ret len Length of formatted string
464 */
465int printf ( const char *fmt, ... ) {
466 va_list args;
467 int i;
468
469 va_start ( args, fmt );
470 i = vprintf ( fmt, args );
471 va_end ( args );
472 return i;
473}
#define NULL
NULL pointer (VOID *)
Definition Base.h:322
struct golan_eq_context ctx
Definition CIB_PRM.h:0
u32 pad[9]
Padding.
Definition ar9003_mac.h:23
unsigned long intptr_t
Definition stdint.h:21
unsigned char uint8_t
Definition stdint.h:10
signed long ssize_t
Definition stdint.h:7
int putchar(int character)
Write a single character to each console device.
Definition console.c:29
ring len
Length.
Definition dwmac.h:226
uint8_t flags
Flags.
Definition ena.h:7
Error codes.
#define __unused
Declare a variable or data structure as unused.
Definition compiler.h:573
uint16_t size
Buffer size.
Definition dwmac.h:3
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:896
#define FILE_SECBOOT(_status)
Declare a file's UEFI Secure Boot permission status.
Definition compiler.h:926
uint32_t num
Definition multiboot.h:0
uint32_t end
Ending offset.
Definition netvsc.h:7
char hex[8]
Count (as an eight-digit hex value)
Definition pccrd.h:1
u16 length
Definition sky2.h:1
#define va_arg(ap, type)
Definition stdarg.h:9
#define va_end(ap)
Definition stdarg.h:10
#define va_start(ap, last)
Definition stdarg.h:8
__builtin_va_list va_list
Definition stdarg.h:7
#define container_of(ptr, type, field)
Get containing structure.
Definition stddef.h:36
__WINT_TYPE__ wint_t
Definition stddef.h:51
A printf context.
Definition vsprintf.h:48
void(* handler)(struct printf_context *ctx, unsigned int c)
Character handler.
Definition vsprintf.h:58
Context used by vsnprintf() and friends.
Definition vsprintf.c:317
struct printf_context ctx
Definition vsprintf.c:318
char * buf
Buffer for formatted string (used by printf_sputc())
Definition vsprintf.c:320
size_t max_len
Buffer length (used by printf_sputc())
Definition vsprintf.c:322
static uint8_t type_sizes[]
Definition vsprintf.c:43
#define SHORT_LEN
"h" length modifier
Definition vsprintf.c:37
#define CHAR_LEN
"hh" length modifier
Definition vsprintf.c:36
int ssnprintf(char *buf, ssize_t ssize, const char *fmt,...)
Version of vsnprintf() that accepts a signed buffer size.
Definition vsprintf.c:421
static void cputchar(struct printf_context *ctx, unsigned char c)
Print character via a printf context.
Definition vsprintf.c:175
#define LONGLONG_LEN
"ll" length modifier
Definition vsprintf.c:40
static char * format_hex(char *end, unsigned long long num, int width, int flags)
Format a hexadecimal number.
Definition vsprintf.c:94
int printf(const char *fmt,...)
Write a formatted string to the console.
Definition vsprintf.c:465
static char * format_decimal(char *end, signed long num, int width, int flags)
Format a decimal number.
Definition vsprintf.c:134
#define ALT_FORM
Use "alternate form".
Definition vsprintf.c:67
#define ZPAD
Use zero padding.
Definition vsprintf.c:75
#define LCASE
Use lower-case for hexadecimal digits.
Definition vsprintf.c:59
#define SIZE_T_LEN
"z" length modifier
Definition vsprintf.c:41
#define LONG_LEN
"l" length modifier
Definition vsprintf.c:39
int vssnprintf(char *buf, ssize_t ssize, const char *fmt, va_list args)
Version of vsnprintf() that accepts a signed buffer size.
Definition vsprintf.c:402
static void printf_sputc(struct printf_context *ctx, unsigned int c)
Write character to buffer.
Definition vsprintf.c:331
static void printf_putchar(struct printf_context *ctx __unused, unsigned int c)
Write character to console.
Definition vsprintf.c:438
int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
Write a formatted string to a buffer.
Definition vsprintf.c:352
int vprintf(const char *fmt, va_list args)
Write a formatted string to the console.
Definition vsprintf.c:450
#define INT_LEN
no length modifier
Definition vsprintf.c:38
int snprintf(char *buf, size_t size, const char *fmt,...)
Write a formatted string to a buffer.
Definition vsprintf.c:383
size_t vcprintf(struct printf_context *ctx, const char *fmt, va_list args)
Write a formatted string to a printf context.
Definition vsprintf.c:188
printf() and friends
int ssize_t ssize
Definition vsprintf.h:73
int ssize_t const char * fmt
Definition vsprintf.h:73
static wchar_t wc
Definition wchar.h:23