These changes are the raw update to qemu-2.6.
[kvmfornfv.git] / qemu / roms / ipxe / 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 /**
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 */
229                 length = &type_sizes[INT_LEN];
230                 for ( ; ; fmt++ ) {
231                         if ( *fmt == 'h' ) {
232                                 length--;
233                         } else if ( *fmt == 'l' ) {
234                                 length++;
235                         } else if ( *fmt == 'z' ) {
236                                 length = &type_sizes[SIZE_T_LEN];
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                         } else {
261                                 wptr = va_arg ( args, wchar_t * );
262                         }
263                         if ( ( ptr == NULL ) && ( wptr == NULL ) )
264                                 ptr = "<NULL>";
265                 } else if ( *fmt == 'p' ) {
266                         intptr_t ptrval;
267
268                         ptrval = ( intptr_t ) va_arg ( args, void * );
269                         ptr = format_hex ( ptr, ptrval, width, 
270                                            ( ALT_FORM | LCASE ) );
271                 } else if ( ( *fmt & ~0x20 ) == 'X' ) {
272                         unsigned long long hex;
273
274                         flags |= ( *fmt & 0x20 ); /* LCASE */
275                         if ( *length >= sizeof ( unsigned long long ) ) {
276                                 hex = va_arg ( args, unsigned long long );
277                         } else if ( *length >= sizeof ( unsigned long ) ) {
278                                 hex = va_arg ( args, unsigned long );
279                         } else {
280                                 hex = va_arg ( args, unsigned int );
281                         }
282                         ptr = format_hex ( ptr, hex, width, flags );
283                 } else if ( ( *fmt == 'd' ) || ( *fmt == 'i' ) ){
284                         signed long decimal;
285
286                         if ( *length >= sizeof ( signed long ) ) {
287                                 decimal = va_arg ( args, signed long );
288                         } else {
289                                 decimal = va_arg ( args, signed int );
290                         }
291                         ptr = format_decimal ( ptr, decimal, width, flags );
292                 } else {
293                         *(--ptr) = *fmt;
294                 }
295                 /* Write out conversion result */
296                 if ( wptr == NULL ) {
297                         for ( ; *ptr ; ptr++ ) {
298                                 cputchar ( ctx, *ptr );
299                         }
300                 } else {
301                         for ( ; *wptr ; wptr++ ) {
302                                 size_t len = wcrtomb ( tmp_buf, *wptr, NULL );
303                                 for ( ptr = tmp_buf ; len-- ; ptr++ ) {
304                                         cputchar ( ctx, *ptr );
305                                 }
306                         }
307                 }
308         }
309
310         return ctx->len;
311 }
312
313 /** Context used by vsnprintf() and friends */
314 struct sputc_context {
315         struct printf_context ctx;
316         /** Buffer for formatted string (used by printf_sputc()) */
317         char *buf;
318         /** Buffer length (used by printf_sputc()) */
319         size_t max_len; 
320 };
321
322 /**
323  * Write character to buffer
324  *
325  * @v ctx               Context
326  * @v c                 Character
327  */
328 static void printf_sputc ( struct printf_context *ctx, unsigned int c ) {
329         struct sputc_context * sctx =
330                 container_of ( ctx, struct sputc_context, ctx );
331
332         if ( ctx->len < sctx->max_len )
333                 sctx->buf[ctx->len] = c;
334 }
335
336 /**
337  * Write a formatted string to a buffer
338  *
339  * @v buf               Buffer into which to write the string
340  * @v size              Size of buffer
341  * @v fmt               Format string
342  * @v args              Arguments corresponding to the format string
343  * @ret len             Length of formatted string
344  *
345  * If the buffer is too small to contain the string, the returned
346  * length is the length that would have been written had enough space
347  * been available.
348  */
349 int vsnprintf ( char *buf, size_t size, const char *fmt, va_list args ) {
350         struct sputc_context sctx;
351         size_t len;
352         size_t end;
353
354         /* Hand off to vcprintf */
355         sctx.ctx.handler = printf_sputc;
356         sctx.buf = buf;
357         sctx.max_len = size;
358         len = vcprintf ( &sctx.ctx, fmt, args );
359
360         /* Add trailing NUL */
361         if ( size ) {
362                 end = size - 1;
363                 if ( len < end )
364                         end = len;
365                 buf[end] = '\0';
366         }
367
368         return len;
369 }
370
371 /**
372  * Write a formatted string to a buffer
373  *
374  * @v buf               Buffer into which to write the string
375  * @v size              Size of buffer
376  * @v fmt               Format string
377  * @v ...               Arguments corresponding to the format string
378  * @ret len             Length of formatted string
379  */
380 int snprintf ( char *buf, size_t size, const char *fmt, ... ) {
381         va_list args;
382         int i;
383
384         va_start ( args, fmt );
385         i = vsnprintf ( buf, size, fmt, args );
386         va_end ( args );
387         return i;
388 }
389
390 /**
391  * Version of vsnprintf() that accepts a signed buffer size
392  *
393  * @v buf               Buffer into which to write the string
394  * @v size              Size of buffer
395  * @v fmt               Format string
396  * @v args              Arguments corresponding to the format string
397  * @ret len             Length of formatted string
398  */
399 int vssnprintf ( char *buf, ssize_t ssize, const char *fmt, va_list args ) {
400
401         /* Treat negative buffer size as zero buffer size */
402         if ( ssize < 0 )
403                 ssize = 0;
404
405         /* Hand off to vsnprintf */
406         return vsnprintf ( buf, ssize, fmt, args );
407 }
408
409 /**
410  * Version of vsnprintf() that accepts a signed buffer size
411  *
412  * @v buf               Buffer into which to write the string
413  * @v size              Size of buffer
414  * @v fmt               Format string
415  * @v ...               Arguments corresponding to the format string
416  * @ret len             Length of formatted string
417  */
418 int ssnprintf ( char *buf, ssize_t ssize, const char *fmt, ... ) {
419         va_list args;
420         int len;
421
422         /* Hand off to vssnprintf */
423         va_start ( args, fmt );
424         len = vssnprintf ( buf, ssize, fmt, args );
425         va_end ( args );
426         return len;
427 }
428
429 /**
430  * Write character to console
431  *
432  * @v ctx               Context
433  * @v c                 Character
434  */
435 static void printf_putchar ( struct printf_context *ctx __unused,
436                              unsigned int c ) {
437         putchar ( c );
438 }
439
440 /**
441  * Write a formatted string to the console
442  *
443  * @v fmt               Format string
444  * @v args              Arguments corresponding to the format string
445  * @ret len             Length of formatted string
446  */
447 int vprintf ( const char *fmt, va_list args ) {
448         struct printf_context ctx;
449
450         /* Hand off to vcprintf */
451         ctx.handler = printf_putchar;   
452         return vcprintf ( &ctx, fmt, args );    
453 }
454
455 /**
456  * Write a formatted string to the console.
457  *
458  * @v fmt               Format string
459  * @v ...               Arguments corresponding to the format string
460  * @ret len             Length of formatted string
461  */
462 int printf ( const char *fmt, ... ) {
463         va_list args;
464         int i;
465
466         va_start ( args, fmt );
467         i = vprintf ( fmt, args );
468         va_end ( args );
469         return i;
470 }