00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 FILE_LICENCE ( GPL2_OR_LATER );
00020
00021 #include <stddef.h>
00022 #include <stdarg.h>
00023 #include <stdio.h>
00024 #include <console.h>
00025 #include <errno.h>
00026 #include <gpxe/vsprintf.h>
00027
00028
00029
00030 #define CHAR_LEN 0
00031 #define SHORT_LEN 1
00032 #define INT_LEN 2
00033 #define LONG_LEN 3
00034 #define LONGLONG_LEN 4
00035 #define SIZE_T_LEN 5
00036
00037 static uint8_t type_sizes[] = {
00038 [CHAR_LEN] = sizeof ( char ),
00039 [SHORT_LEN] = sizeof ( short ),
00040 [INT_LEN] = sizeof ( int ),
00041 [LONG_LEN] = sizeof ( long ),
00042 [LONGLONG_LEN] = sizeof ( long long ),
00043 [SIZE_T_LEN] = sizeof ( size_t ),
00044 };
00045
00046
00047
00048
00049
00050
00051
00052
00053 #define LCASE 0x20
00054
00055
00056
00057
00058
00059
00060
00061 #define ALT_FORM 0x02
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079 static char * format_hex ( char *end, unsigned long long num, int width,
00080 int flags ) {
00081 char *ptr = end;
00082 int case_mod;
00083
00084
00085 case_mod = flags & LCASE;
00086 do {
00087 *(--ptr) = "0123456789ABCDEF"[ num & 0xf ] | case_mod;
00088 num >>= 4;
00089 } while ( num );
00090
00091
00092 while ( ( end - ptr ) < width )
00093 *(--ptr) = '0';
00094
00095
00096 if ( flags & ALT_FORM ) {
00097 *(--ptr) = 'X' | case_mod;
00098 *(--ptr) = '0';
00099 }
00100
00101 return ptr;
00102 }
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118 static char * format_decimal ( char *end, signed long num, int width ) {
00119 char *ptr = end;
00120 int negative = 0;
00121
00122
00123 if ( num < 0 ) {
00124 negative = 1;
00125 num = -num;
00126 }
00127 do {
00128 *(--ptr) = '0' + ( num % 10 );
00129 num /= 10;
00130 } while ( num );
00131
00132
00133 if ( negative )
00134 *(--ptr) = '-';
00135
00136
00137 while ( ( end - ptr ) < width )
00138 *(--ptr) = ' ';
00139
00140 return ptr;
00141 }
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152 static inline void cputchar ( struct printf_context *ctx, unsigned int c ) {
00153 ctx->handler ( ctx, c );
00154 ++ctx->len;
00155 }
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165 size_t vcprintf ( struct printf_context *ctx, const char *fmt, va_list args ) {
00166 int flags;
00167 int width;
00168 uint8_t *length;
00169 char *ptr;
00170 char tmp_buf[32];
00171
00172
00173
00174 ctx->len = 0;
00175
00176 for ( ; *fmt ; fmt++ ) {
00177
00178 if ( *fmt != '%' ) {
00179 cputchar ( ctx, *fmt );
00180 continue;
00181 }
00182 fmt++;
00183
00184 flags = 0;
00185 for ( ; ; fmt++ ) {
00186 if ( *fmt == '#' ) {
00187 flags |= ALT_FORM;
00188 } else if ( *fmt == '0' ) {
00189
00190 } else {
00191
00192 break;
00193 }
00194 }
00195
00196 width = 0;
00197 for ( ; ; fmt++ ) {
00198 if ( ( ( unsigned ) ( *fmt - '0' ) ) < 10 ) {
00199 width = ( width * 10 ) + ( *fmt - '0' );
00200 } else {
00201 break;
00202 }
00203 }
00204
00205
00206 length = &type_sizes[INT_LEN];
00207 for ( ; ; fmt++ ) {
00208 if ( *fmt == 'h' ) {
00209 length--;
00210 } else if ( *fmt == 'l' ) {
00211 length++;
00212 } else if ( *fmt == 'z' ) {
00213 length = &type_sizes[SIZE_T_LEN];
00214 } else {
00215 break;
00216 }
00217 }
00218
00219 ptr = tmp_buf + sizeof ( tmp_buf ) - 1;
00220 *ptr = '\0';
00221 if ( *fmt == 'c' ) {
00222 cputchar ( ctx, va_arg ( args, unsigned int ) );
00223 } else if ( *fmt == 's' ) {
00224 ptr = va_arg ( args, char * );
00225 if ( ! ptr )
00226 ptr = "<NULL>";
00227 } else if ( *fmt == 'p' ) {
00228 intptr_t ptrval;
00229
00230 ptrval = ( intptr_t ) va_arg ( args, void * );
00231 ptr = format_hex ( ptr, ptrval, width,
00232 ( ALT_FORM | LCASE ) );
00233 } else if ( ( *fmt & ~0x20 ) == 'X' ) {
00234 unsigned long long hex;
00235
00236 flags |= ( *fmt & 0x20 );
00237 if ( *length >= sizeof ( unsigned long long ) ) {
00238 hex = va_arg ( args, unsigned long long );
00239 } else if ( *length >= sizeof ( unsigned long ) ) {
00240 hex = va_arg ( args, unsigned long );
00241 } else {
00242 hex = va_arg ( args, unsigned int );
00243 }
00244 ptr = format_hex ( ptr, hex, width, flags );
00245 } else if ( ( *fmt == 'd' ) || ( *fmt == 'i' ) ){
00246 signed long decimal;
00247
00248 if ( *length >= sizeof ( signed long ) ) {
00249 decimal = va_arg ( args, signed long );
00250 } else {
00251 decimal = va_arg ( args, signed int );
00252 }
00253 ptr = format_decimal ( ptr, decimal, width );
00254 } else {
00255 *(--ptr) = *fmt;
00256 }
00257
00258 for ( ; *ptr ; ptr++ ) {
00259 cputchar ( ctx, *ptr );
00260 }
00261 }
00262
00263 return ctx->len;
00264 }
00265
00266
00267 struct sputc_context {
00268 struct printf_context ctx;
00269
00270 char *buf;
00271
00272 size_t max_len;
00273 };
00274
00275
00276
00277
00278
00279
00280
00281 static void printf_sputc ( struct printf_context *ctx, unsigned int c ) {
00282 struct sputc_context * sctx =
00283 container_of ( ctx, struct sputc_context, ctx );
00284
00285 if ( ctx->len < sctx->max_len )
00286 sctx->buf[ctx->len] = c;
00287 }
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302 int vsnprintf ( char *buf, size_t size, const char *fmt, va_list args ) {
00303 struct sputc_context sctx;
00304 size_t len;
00305 size_t end;
00306
00307
00308 sctx.ctx.handler = printf_sputc;
00309 sctx.buf = buf;
00310 sctx.max_len = size;
00311 len = vcprintf ( &sctx.ctx, fmt, args );
00312
00313
00314 if ( size ) {
00315 end = size - 1;
00316 if ( len < end )
00317 end = len;
00318 buf[end] = '\0';
00319 }
00320
00321 return len;
00322 }
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333 int snprintf ( char *buf, size_t size, const char *fmt, ... ) {
00334 va_list args;
00335 int i;
00336
00337 va_start ( args, fmt );
00338 i = vsnprintf ( buf, size, fmt, args );
00339 va_end ( args );
00340 return i;
00341 }
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352 int vssnprintf ( char *buf, ssize_t ssize, const char *fmt, va_list args ) {
00353
00354
00355 if ( ssize < 0 )
00356 ssize = 0;
00357
00358
00359 return vsnprintf ( buf, ssize, fmt, args );
00360 }
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371 int ssnprintf ( char *buf, ssize_t ssize, const char *fmt, ... ) {
00372 va_list args;
00373 int len;
00374
00375
00376 va_start ( args, fmt );
00377 len = vssnprintf ( buf, ssize, fmt, args );
00378 va_end ( args );
00379 return len;
00380 }
00381
00382
00383
00384
00385
00386
00387
00388 static void printf_putchar ( struct printf_context *ctx __unused,
00389 unsigned int c ) {
00390 putchar ( c );
00391 }
00392
00393
00394
00395
00396
00397
00398
00399
00400 int vprintf ( const char *fmt, va_list args ) {
00401 struct printf_context ctx;
00402
00403
00404 ctx.handler = printf_putchar;
00405 return vcprintf ( &ctx, fmt, args );
00406 }
00407
00408
00409
00410
00411
00412
00413
00414
00415 int printf ( const char *fmt, ... ) {
00416 va_list args;
00417 int i;
00418
00419 va_start ( args, fmt );
00420 i = vprintf ( fmt, args );
00421 va_end ( args );
00422 return i;
00423 }