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