00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include "mem.h"
00018 #include "printf.h"
00019 #include "str.h"
00020
00021 enum __printf_flags {
00022 PFL_ALT = 0x01,
00023 PFL_ZERO = 0x02,
00024 PFL_LEFT = 0x04,
00025 PFL_BLANK = 0x08,
00026 PFL_SIGN = 0x10,
00027 PFL_UPPER = 0x20,
00028 PFL_SIGNED = 0x40,
00029 };
00030
00031 enum __printf_rank {
00032 PFR_CHAR,
00033 PFR_SHORT,
00034 PFR_INT,
00035 PFR_LONG,
00036 PFR_LLONG,
00037 };
00038
00039 #define PFR_MIN PFR_CHAR
00040 #define PFR_MAX PFR_LLONG
00041
00042 enum __printf_state {
00043 PFS_NORMAL,
00044 PFS_FLAGS,
00045 PFS_WIDTH,
00046 PFS_PREC,
00047 PFS_MOD,
00048 PFS_CONV,
00049 };
00050
00051 typedef struct {
00052 unsigned int f;
00053 int l;
00054 int p;
00055 int s;
00056 unsigned int w;
00057 } __printf_t;
00058
00059 #define EMIT(C) { if (idx < size - 1) { *str++ = C; } idx++; }
00060
00061 static
00062 int __printf_int(char *str, int size, unsigned long long int val,
00063 int base, __printf_t f)
00064 {
00065 static const char lcdigits[] = "0123456789abcdef";
00066 static const char ucdigits[] = "0123456789ABCDEF";
00067 const char *digits;
00068
00069 int idx = 0, ndigits = 0, nchars, minus = 0;
00070 unsigned long long int tmpval;
00071
00072
00073 digits = (f.f & PFL_UPPER) ? ucdigits : lcdigits;
00074
00075
00076 if (f.f & PFL_SIGNED && (signed long long int) val < 0) {
00077 minus = 1;
00078 val = (unsigned long long int) (-(signed long long int) val);
00079 }
00080
00081
00082 tmpval = val;
00083
00084 while (tmpval) {
00085 tmpval /= base;
00086 ndigits++;
00087 }
00088
00089
00090 if (val == 0)
00091 ndigits = 1;
00092
00093
00094 nchars = f.p > ndigits ? f.p : ndigits;
00095
00096
00097 if (minus || (f.f & (PFL_SIGN | PFL_BLANK)))
00098 nchars++;
00099
00100
00101 if (f.f & PFL_ALT) {
00102 if (base == 16)
00103 nchars += 2;
00104 else if (base == 8 && val != 0)
00105 nchars += 1;
00106 }
00107
00108
00109 if ((f.f & (PFL_LEFT|PFL_ZERO)) == 0) {
00110 while (f.w > nchars) {
00111 EMIT(' ')
00112 f.w--;
00113 }
00114 }
00115
00116
00117 if ((f.f & PFL_ZERO) > 0) {
00118 while (f.w > nchars) {
00119 EMIT('0')
00120 f.w--;
00121 }
00122 }
00123
00124
00125 if (minus)
00126 EMIT('-')
00127
00128 else if (f.f & PFL_SIGN)
00129 EMIT('+')
00130
00131 else if (f.f & PFL_BLANK)
00132 EMIT(' ')
00133
00134 if (f.f & PFL_ALT) {
00135 if (base == 16) {
00136 EMIT('0')
00137 EMIT((f.f & PFL_UPPER) ? 'X' : 'x');
00138 }
00139
00140 else if (base == 8 && val != 0)
00141 EMIT('0')
00142 }
00143
00144
00145 while (f.p > ndigits) {
00146 EMIT('0')
00147 f.p--;
00148 }
00149
00150
00151 str += ndigits;
00152
00153 do {
00154 if (idx < size)
00155 *--str = digits[val % base];
00156
00157 idx++;
00158 } while ((val /= base));
00159
00160 str += ndigits;
00161
00162
00163 if ((f.f & PFL_LEFT) > 0) {
00164 while (f.w > nchars) {
00165 EMIT(' ')
00166 f.w--;
00167 }
00168 }
00169
00170 return idx;
00171 }
00172
00173
00174
00175
00176
00177
00178
00179 int _lucid_vsnprintf(char *str, int size, const char *fmt, va_list _ap)
00180 {
00181
00182 int i;
00183
00184
00185 const char *p;
00186
00187
00188 int idx = 0;
00189
00190
00191 const char *ccp = fmt;
00192
00193
00194 char c;
00195
00196
00197 __printf_t f;
00198
00199
00200 union {
00201
00202 signed long long int d;
00203
00204
00205 unsigned long long int u;
00206
00207
00208 double f;
00209
00210
00211 int c;
00212
00213
00214 const char *s;
00215
00216
00217 void *p;
00218
00219
00220 int *n;
00221 } arg;
00222
00223
00224 int base;
00225
00226
00227 int len;
00228
00229
00230 va_list ap;
00231 va_copy(ap, _ap);
00232
00233
00234 f.f = 0;
00235 f.l = PFR_INT;
00236 f.p = -1;
00237 f.s = PFS_NORMAL;
00238 f.w = 0;
00239
00240 if (size > 0)
00241 mem_set(str, 0, size);
00242
00243 while ((c = *fmt++)) {
00244 switch (f.s) {
00245 case PFS_NORMAL:
00246 if (c == '%') {
00247 f.f = 0;
00248 f.l = PFR_INT;
00249 f.p = -1;
00250 f.s = PFS_FLAGS;
00251 f.w = 0;
00252 ccp = &c;
00253 }
00254
00255 else
00256 EMIT(c)
00257
00258 break;
00259
00260 case PFS_FLAGS:
00261 switch (c) {
00262 case '#':
00263 f.f |= PFL_ALT;
00264 break;
00265
00266 case '0':
00267 if (!(f.f & PFL_LEFT))
00268 f.f |= PFL_ZERO;
00269 break;
00270
00271 case '-':
00272 f.f &= ~PFL_ZERO;
00273 f.f |= PFL_LEFT;
00274 break;
00275
00276 case ' ':
00277 f.f |= PFL_BLANK;
00278 break;
00279
00280 case '+':
00281 f.f &= ~PFL_BLANK;
00282 f.f |= PFL_SIGN;
00283 break;
00284
00285 default:
00286 f.s = PFS_WIDTH;
00287 fmt--;
00288 break;
00289 }
00290
00291 break;
00292
00293 case PFS_WIDTH:
00294 if (c == '-') {
00295 f.f &= PFL_ZERO;
00296 f.f |= PFL_LEFT;
00297 }
00298
00299 else if (c >= '0' && c <= '9')
00300 f.w = f.w * 10 + (c - '0');
00301
00302 else if (c == '*') {
00303 f.w = va_arg(ap, int);
00304
00305 if (f.w < 0) {
00306 f.w = -f.w;
00307 f.f &= PFL_ZERO;
00308 f.f |= PFL_LEFT;
00309 }
00310 }
00311
00312 else if (c == '.') {
00313 f.p = 0;
00314 f.s = PFS_PREC;
00315 }
00316
00317 else {
00318 f.s = PFS_MOD;
00319 fmt--;
00320 }
00321
00322 break;
00323
00324 case PFS_PREC:
00325 if (c >= '0' && c <= '9')
00326 f.p = f.p * 10 + (c - '0');
00327
00328 else if (c == '*') {
00329 f.p = va_arg(ap, int);
00330
00331 if (f.p < 0)
00332 f.p = 0;
00333 }
00334
00335 else {
00336 f.s = PFS_MOD;
00337 fmt--;
00338 }
00339
00340 break;
00341
00342 case PFS_MOD:
00343 switch (c) {
00344 case 'h':
00345 f.l--;
00346 break;
00347
00348 case 'l':
00349 f.l++;
00350 break;
00351
00352 default:
00353 f.s = PFS_CONV;
00354 fmt--;
00355 break;
00356 }
00357
00358 break;
00359
00360 case PFS_CONV:
00361 f.s = PFS_NORMAL;
00362
00363 if (f.l > PFR_MAX)
00364 f.l = PFR_MAX;
00365
00366 if (f.l < PFR_MIN)
00367 f.l = PFR_MIN;
00368
00369 switch (c) {
00370 case 'P':
00371 f.f |= PFL_UPPER;
00372
00373 case 'p':
00374 base = 16;
00375 f.p = (8 * sizeof(void *) + 3)/4;
00376 f.f |= PFL_ALT;
00377
00378 arg.u = (unsigned long long int) (unsigned long int) va_arg(ap, void *);
00379
00380 goto is_integer;
00381
00382 case 'd':
00383 case 'i':
00384 base = 10;
00385 f.f |= PFL_SIGNED;
00386
00387 switch (f.l) {
00388 case PFR_CHAR:
00389 arg.d = (signed char) va_arg(ap, signed int);
00390 break;
00391
00392 case PFR_SHORT:
00393 arg.d = (signed short int) va_arg(ap, signed int);
00394 break;
00395
00396 case PFR_INT:
00397 arg.d = (signed int) va_arg(ap, signed int);
00398 break;
00399
00400 case PFR_LONG:
00401 arg.d = (signed long int) va_arg(ap, signed long int);
00402 break;
00403
00404 case PFR_LLONG:
00405 arg.d = (signed long long int) va_arg(ap, signed long long int);
00406 break;
00407
00408 default:
00409 arg.d = (signed long long int) va_arg(ap, signed int);
00410 break;
00411 }
00412
00413 arg.u = (unsigned long long int) arg.d;
00414
00415 goto is_integer;
00416
00417 case 'o':
00418 base = 8;
00419 goto is_unsigned;
00420
00421 case 'u':
00422 base = 10;
00423 goto is_unsigned;
00424
00425 case 'X':
00426 f.f |= PFL_UPPER;
00427
00428 case 'x':
00429 base = 16;
00430 goto is_unsigned;
00431
00432 is_unsigned:
00433 switch (f.l) {
00434 case PFR_CHAR:
00435 arg.u = (unsigned char) va_arg(ap, unsigned int);
00436 break;
00437
00438 case PFR_SHORT:
00439 arg.u = (unsigned short int) va_arg(ap, unsigned int);
00440 break;
00441
00442 case PFR_INT:
00443 arg.u = (unsigned int) va_arg(ap, unsigned int);
00444 break;
00445
00446 case PFR_LONG:
00447 arg.u = (unsigned long int) va_arg(ap, unsigned long int);
00448 break;
00449
00450 case PFR_LLONG:
00451 arg.u = (unsigned long long int) va_arg(ap, unsigned long long int);
00452 break;
00453
00454 default:
00455 arg.u = (unsigned long long int) va_arg(ap, unsigned int);
00456 break;
00457 }
00458
00459 is_integer:
00460 len = __printf_int(str, size, arg.u, base, f);
00461
00462 str += len;
00463 idx += len;
00464 break;
00465
00466 case 'c':
00467 arg.c = (char) va_arg(ap, int);
00468 EMIT(arg.c)
00469 break;
00470
00471 case 's':
00472 arg.s = va_arg(ap, const char *);
00473 arg.s = arg.s ? arg.s : "(null)";
00474 len = str_len(arg.s);
00475
00476 is_string:
00477 if (f.p != -1 && len > f.p)
00478 len = f.p;
00479
00480 if ((f.f & (PFL_LEFT|PFL_ZERO)) == 0) {
00481 while (f.w > len) {
00482 EMIT(' ')
00483 f.w--;
00484 }
00485 }
00486
00487 if ((f.f & PFL_ZERO) > 0) {
00488 while (f.w > len) {
00489 EMIT('0')
00490 f.w--;
00491 }
00492 }
00493
00494 for (i = len; i; i--)
00495 EMIT(*arg.s++)
00496
00497 if ((f.f & PFL_LEFT) > 0) {
00498 while (f.w > len) {
00499 EMIT(' ')
00500 f.w--;
00501 }
00502 }
00503
00504 break;
00505
00506 case 'n':
00507 arg.n = va_arg(ap, int *);
00508 *arg.n = idx;
00509
00510 break;
00511
00512 case '%':
00513 EMIT(c)
00514 break;
00515
00516 default:
00517
00518 f.w = 0;
00519 f.p = -1;
00520
00521 arg.s = ccp;
00522 len = str_len(arg.s);
00523 fmt = ccp + len;
00524
00525 p = str_chr(arg.s + 1, '%', len - 1);
00526
00527 if (p != 0) {
00528 len = p - arg.s - 1;
00529 fmt = p - 1;
00530 }
00531
00532 goto is_string;
00533 }
00534
00535 break;
00536 }
00537 }
00538
00539 va_end(ap);
00540
00541 return idx;
00542 }