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 
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 /**
166  * Print character via a printf context
167  *
168  * @v ctx Context
169  * @v c Character
170  *
171  * Call's the printf_context::handler() method and increments
172  * printf_context::len.
173  */
174 static inline void cputchar ( struct printf_context *ctx, unsigned char c ) {
175  ctx->handler ( ctx, c );
176  ++ctx->len;
177 }
178 
179 /**
180  * Write a formatted string to a printf context
181  *
182  * @v ctx Context
183  * @v fmt Format string
184  * @v args Arguments corresponding to the format string
185  * @ret len Length of formatted string
186  */
187 size_t vcprintf ( struct printf_context *ctx, const char *fmt, va_list args ) {
188  int flags;
189  int width;
190  uint8_t *length;
191  char *ptr;
192  char tmp_buf[32]; /* 32 is enough for all numerical formats.
193  * Insane width fields could overflow this buffer. */
194  wchar_t *wptr;
195 
196  /* Initialise context */
197  ctx->len = 0;
198 
199  for ( ; *fmt ; fmt++ ) {
200  /* Pass through ordinary characters */
201  if ( *fmt != '%' ) {
202  cputchar ( ctx, *fmt );
203  continue;
204  }
205  fmt++;
206  /* Process flag characters */
207  flags = 0;
208  for ( ; ; fmt++ ) {
209  if ( *fmt == '#' ) {
210  flags |= ALT_FORM;
211  } else if ( *fmt == '0' ) {
212  flags |= ZPAD;
213  } else {
214  /* End of flag characters */
215  break;
216  }
217  }
218  /* Process field width */
219  width = 0;
220  for ( ; ; fmt++ ) {
221  if ( ( ( unsigned ) ( *fmt - '0' ) ) < 10 ) {
222  width = ( width * 10 ) + ( *fmt - '0' );
223  } else {
224  break;
225  }
226  }
227  /* We don't do floating point */
228  /* Process length modifier */
230  for ( ; ; fmt++ ) {
231  if ( *fmt == 'h' ) {
232  length--;
233  } else if ( *fmt == 'l' ) {
234  length++;
235  } else if ( *fmt == 'z' ) {
237  } else {
238  break;
239  }
240  }
241  /* Process conversion specifier */
242  ptr = tmp_buf + sizeof ( tmp_buf ) - 1;
243  *ptr = '\0';
244  wptr = NULL;
245  if ( *fmt == 'c' ) {
246  if ( length < &type_sizes[LONG_LEN] ) {
247  cputchar ( ctx, va_arg ( args, unsigned int ) );
248  } else {
249  wchar_t wc;
250  size_t len;
251 
252  wc = va_arg ( args, wint_t );
253  len = wcrtomb ( tmp_buf, wc, NULL );
254  tmp_buf[len] = '\0';
255  ptr = tmp_buf;
256  }
257  } else if ( *fmt == 's' ) {
258  if ( length < &type_sizes[LONG_LEN] ) {
259  ptr = va_arg ( args, char * );
260  if ( ! ptr )
261  ptr = "<NULL>";
262  } else {
263  wptr = va_arg ( args, wchar_t * );
264  if ( ! wptr )
265  ptr = "<NULL>";
266  }
267  } else if ( *fmt == 'p' ) {
268  intptr_t ptrval;
269 
270  ptrval = ( intptr_t ) va_arg ( args, void * );
271  ptr = format_hex ( ptr, ptrval, width,
272  ( ALT_FORM | LCASE ) );
273  } else if ( ( *fmt & ~0x20 ) == 'X' ) {
274  unsigned long long hex;
275 
276  flags |= ( *fmt & 0x20 ); /* LCASE */
277  if ( *length >= sizeof ( unsigned long long ) ) {
278  hex = va_arg ( args, unsigned long long );
279  } else if ( *length >= sizeof ( unsigned long ) ) {
280  hex = va_arg ( args, unsigned long );
281  } else {
282  hex = va_arg ( args, unsigned int );
283  }
284  ptr = format_hex ( ptr, hex, width, flags );
285  } else if ( ( *fmt == 'd' ) || ( *fmt == 'i' ) ){
286  signed long decimal;
287 
288  if ( *length >= sizeof ( signed long ) ) {
289  decimal = va_arg ( args, signed long );
290  } else {
291  decimal = va_arg ( args, signed int );
292  }
293  ptr = format_decimal ( ptr, decimal, width, flags );
294  } else {
295  *(--ptr) = *fmt;
296  }
297  /* Write out conversion result */
298  if ( wptr == NULL ) {
299  for ( ; *ptr ; ptr++ ) {
300  cputchar ( ctx, *ptr );
301  }
302  } else {
303  for ( ; *wptr ; wptr++ ) {
304  size_t len = wcrtomb ( tmp_buf, *wptr, NULL );
305  for ( ptr = tmp_buf ; len-- ; ptr++ ) {
306  cputchar ( ctx, *ptr );
307  }
308  }
309  }
310  }
311 
312  return ctx->len;
313 }
314 
315 /** Context used by vsnprintf() and friends */
318  /** Buffer for formatted string (used by printf_sputc()) */
319  char *buf;
320  /** Buffer length (used by printf_sputc()) */
321  size_t max_len;
322 };
323 
324 /**
325  * Write character to buffer
326  *
327  * @v ctx Context
328  * @v c Character
329  */
330 static void printf_sputc ( struct printf_context *ctx, unsigned int c ) {
331  struct sputc_context * sctx =
332  container_of ( ctx, struct sputc_context, ctx );
333 
334  if ( ctx->len < sctx->max_len )
335  sctx->buf[ctx->len] = c;
336 }
337 
338 /**
339  * Write a formatted string to a buffer
340  *
341  * @v buf Buffer into which to write the string
342  * @v size Size of buffer
343  * @v fmt Format string
344  * @v args Arguments corresponding to the format string
345  * @ret len Length of formatted string
346  *
347  * If the buffer is too small to contain the string, the returned
348  * length is the length that would have been written had enough space
349  * been available.
350  */
351 int vsnprintf ( char *buf, size_t size, const char *fmt, va_list args ) {
352  struct sputc_context sctx;
353  size_t len;
354  size_t end;
355 
356  /* Hand off to vcprintf */
357  sctx.ctx.handler = printf_sputc;
358  sctx.buf = buf;
359  sctx.max_len = size;
360  len = vcprintf ( &sctx.ctx, fmt, args );
361 
362  /* Add trailing NUL */
363  if ( size ) {
364  end = size - 1;
365  if ( len < end )
366  end = len;
367  buf[end] = '\0';
368  }
369 
370  return len;
371 }
372 
373 /**
374  * Write a formatted string to a buffer
375  *
376  * @v buf Buffer into which to write the string
377  * @v size Size of buffer
378  * @v fmt Format string
379  * @v ... Arguments corresponding to the format string
380  * @ret len Length of formatted string
381  */
382 int snprintf ( char *buf, size_t size, const char *fmt, ... ) {
383  va_list args;
384  int i;
385 
386  va_start ( args, fmt );
387  i = vsnprintf ( buf, size, fmt, args );
388  va_end ( args );
389  return i;
390 }
391 
392 /**
393  * Version of vsnprintf() that accepts a signed buffer size
394  *
395  * @v buf Buffer into which to write the string
396  * @v size Size of buffer
397  * @v fmt Format string
398  * @v args Arguments corresponding to the format string
399  * @ret len Length of formatted string
400  */
401 int vssnprintf ( char *buf, ssize_t ssize, const char *fmt, va_list args ) {
402 
403  /* Treat negative buffer size as zero buffer size */
404  if ( ssize < 0 )
405  ssize = 0;
406 
407  /* Hand off to vsnprintf */
408  return vsnprintf ( buf, ssize, fmt, args );
409 }
410 
411 /**
412  * Version of vsnprintf() that accepts a signed buffer size
413  *
414  * @v buf Buffer into which to write the string
415  * @v size Size of buffer
416  * @v fmt Format string
417  * @v ... Arguments corresponding to the format string
418  * @ret len Length of formatted string
419  */
420 int ssnprintf ( char *buf, ssize_t ssize, const char *fmt, ... ) {
421  va_list args;
422  int len;
423 
424  /* Hand off to vssnprintf */
425  va_start ( args, fmt );
426  len = vssnprintf ( buf, ssize, fmt, args );
427  va_end ( args );
428  return len;
429 }
430 
431 /**
432  * Write character to console
433  *
434  * @v ctx Context
435  * @v c Character
436  */
438  unsigned int c ) {
439  putchar ( c );
440 }
441 
442 /**
443  * Write a formatted string to the console
444  *
445  * @v fmt Format string
446  * @v args Arguments corresponding to the format string
447  * @ret len Length of formatted string
448  */
449 int vprintf ( const char *fmt, va_list args ) {
450  struct printf_context ctx;
451 
452  /* Hand off to vcprintf */
453  ctx.handler = printf_putchar;
454  return vcprintf ( &ctx, fmt, args );
455 }
456 
457 /**
458  * Write a formatted string to the console.
459  *
460  * @v fmt Format string
461  * @v ... Arguments corresponding to the format string
462  * @ret len Length of formatted string
463  */
464 int printf ( const char *fmt, ... ) {
465  va_list args;
466  int i;
467 
468  va_start ( args, fmt );
469  i = vprintf ( fmt, args );
470  va_end ( args );
471  return i;
472 }
uint32_t c
Definition: md4.c:30
u16 length
Definition: sky2.h:9
#define CHAR_LEN
"hh" length modifier
Definition: vsprintf.c:35
static wchar_t wc
Definition: wchar.h:22
#define ALT_FORM
Use "alternate form".
Definition: vsprintf.c:66
static void cputchar(struct printf_context *ctx, unsigned char c)
Print character via a printf context.
Definition: vsprintf.c:174
#define va_end(ap)
Definition: stdarg.h:9
int printf(const char *fmt,...)
Write a formatted string to the console.
Definition: vsprintf.c:464
static char * format_decimal(char *end, signed long num, int width, int flags)
Format a decimal number.
Definition: vsprintf.c:133
void(* handler)(struct printf_context *ctx, unsigned int c)
Character handler.
Definition: vsprintf.h:57
Error codes.
printf() and friends
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
char hex[8]
Count (as an eight-digit hex value)
Definition: pccrd.h:12
static void printf_putchar(struct printf_context *ctx __unused, unsigned int c)
Write character to console.
Definition: vsprintf.c:437
#define INT_LEN
no length modifier
Definition: vsprintf.c:37
u32 pad[9]
Padding.
Definition: ar9003_mac.h:90
unsigned long intptr_t
Definition: stdint.h:21
#define LCASE
Use lower-case for hexadecimal digits.
Definition: vsprintf.c:58
struct printf_context ctx
Definition: vsprintf.c:317
#define LONG_LEN
"l" length modifier
Definition: vsprintf.c:38
int ssnprintf(char *buf, ssize_t ssize, const char *fmt,...)
Version of vsnprintf() that accepts a signed buffer size.
Definition: vsprintf.c:420
#define SIZE_T_LEN
"z" length modifier
Definition: vsprintf.c:40
#define va_arg(ap, type)
Definition: stdarg.h:8
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:401
#define container_of(ptr, type, field)
Get containing structure.
Definition: stddef.h:35
char unsigned long * num
Definition: xenstore.h:17
#define ZPAD
Use zero padding.
Definition: vsprintf.c:74
#define SHORT_LEN
"h" length modifier
Definition: vsprintf.c:36
static char * format_hex(char *end, unsigned long long num, int width, int flags)
Format a hexadecimal number.
Definition: vsprintf.c:93
struct golan_eq_context ctx
Definition: CIB_PRM.h:28
static uint8_t type_sizes[]
Definition: vsprintf.c:42
unsigned char uint8_t
Definition: stdint.h:10
#define __unused
Declare a variable or data structure as unused.
Definition: compiler.h:573
A printf context.
Definition: vsprintf.h:47
int ssize_t ssize
Definition: vsprintf.h:72
uint32_t len
Length.
Definition: ena.h:14
__builtin_va_list va_list
Definition: stdarg.h:6
#define LONGLONG_LEN
"ll" length modifier
Definition: vsprintf.c:39
size_t max_len
Buffer length (used by printf_sputc())
Definition: vsprintf.c:321
uint32_t end
Ending offset.
Definition: netvsc.h:18
uint8_t size
Entry size (in 32-bit words)
Definition: ena.h:16
int ssize_t const char * fmt
Definition: vsprintf.h:72
int snprintf(char *buf, size_t size, const char *fmt,...)
Write a formatted string to a buffer.
Definition: vsprintf.c:382
int vprintf(const char *fmt, va_list args)
Write a formatted string to the console.
Definition: vsprintf.c:449
Context used by vsnprintf() and friends.
Definition: vsprintf.c:316
signed long ssize_t
Definition: stdint.h:7
#define va_start(ap, last)
Definition: stdarg.h:7
char * buf
Buffer for formatted string (used by printf_sputc())
Definition: vsprintf.c:319
static void printf_sputc(struct printf_context *ctx, unsigned int c)
Write character to buffer.
Definition: vsprintf.c:330
#define NULL
NULL pointer (VOID *)
Definition: Base.h:321
int putchar(int character)
Write a single character to each console device.
Definition: console.c:28
size_t vcprintf(struct printf_context *ctx, const char *fmt, va_list args)
Write a formatted string to a printf context.
Definition: vsprintf.c:187
__WINT_TYPE__ wint_t
Definition: stddef.h:50
int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
Write a formatted string to a buffer.
Definition: vsprintf.c:351
uint8_t flags
Flags.
Definition: ena.h:18