#include "main.h"
#include "snprintf.h"
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <varargs.h>
Go to the source code of this file.
Defines | |
#define | VA_LOCAL_DECL va_list ap |
#define | VA_START(f) va_start(ap) |
#define | VA_SHIFT(v, t) v = va_arg(ap,t) |
#define | VA_END va_end(ap) |
#define | LDOUBLE double |
#define | DP_S_DEFAULT 0 |
#define | DP_S_FLAGS 1 |
#define | DP_S_MIN 2 |
#define | DP_S_DOT 3 |
#define | DP_S_MAX 4 |
#define | DP_S_MOD 5 |
#define | DP_S_CONV 6 |
#define | DP_S_DONE 7 |
#define | DP_F_MINUS (1 << 0) |
#define | DP_F_PLUS (1 << 1) |
#define | DP_F_SPACE (1 << 2) |
#define | DP_F_NUM (1 << 3) |
#define | DP_F_ZERO (1 << 4) |
#define | DP_F_UP (1 << 5) |
#define | DP_F_UNSIGNED (1 << 6) |
#define | DP_C_SHORT 1 |
#define | DP_C_LONG 2 |
#define | DP_C_LDOUBLE 3 |
#define | char_to_int(p) (p - '0') |
#define | MAX(p, q) ((p >= q) ? p : q) |
Functions | |
static void | dopr (char *buffer, size_t maxlen, const char *format, va_list args) |
static void | fmtstr (char *buffer, size_t *currlen, size_t maxlen, char *value, int flags, int min, int max) |
static void | fmtint (char *buffer, size_t *currlen, size_t maxlen, long value, int base, int min, int max, int flags) |
static void | fmtfp (char *buffer, size_t *currlen, size_t maxlen, double fvalue, int min, int max, int flags) |
static void | dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c) |
static double | abs_val (double value) |
static double | pow10 (int exp) |
static long | round (double value) |
int | egg_vsnprintf (char *str, size_t count, const char *fmt, va_list args) |
int | egg_snprintf (va_alist) |
#define char_to_int | ( | p | ) | (p - '0') |
Definition at line 154 of file snprintf.c.
Referenced by dopr().
#define DP_C_LDOUBLE 3 |
Definition at line 152 of file snprintf.c.
Referenced by dopr().
#define DP_C_LONG 2 |
Definition at line 151 of file snprintf.c.
Referenced by dopr().
#define DP_C_SHORT 1 |
Definition at line 150 of file snprintf.c.
Referenced by dopr().
#define DP_F_MINUS (1 << 0) |
#define DP_F_NUM (1 << 3) |
Definition at line 144 of file snprintf.c.
Referenced by dopr().
#define DP_F_PLUS (1 << 1) |
Definition at line 142 of file snprintf.c.
#define DP_F_SPACE (1 << 2) |
Definition at line 143 of file snprintf.c.
#define DP_F_UNSIGNED (1 << 6) |
Definition at line 147 of file snprintf.c.
#define DP_F_UP (1 << 5) |
Definition at line 146 of file snprintf.c.
#define DP_F_ZERO (1 << 4) |
Definition at line 145 of file snprintf.c.
#define DP_S_CONV 6 |
Definition at line 137 of file snprintf.c.
Referenced by dopr().
#define DP_S_DEFAULT 0 |
Definition at line 131 of file snprintf.c.
Referenced by dopr().
#define DP_S_DONE 7 |
Definition at line 138 of file snprintf.c.
Referenced by dopr().
#define DP_S_DOT 3 |
Definition at line 134 of file snprintf.c.
Referenced by dopr().
#define DP_S_FLAGS 1 |
Definition at line 132 of file snprintf.c.
Referenced by dopr().
#define DP_S_MAX 4 |
Definition at line 135 of file snprintf.c.
Referenced by dopr().
#define DP_S_MIN 2 |
Definition at line 133 of file snprintf.c.
Referenced by dopr().
#define DP_S_MOD 5 |
Definition at line 136 of file snprintf.c.
Referenced by dopr().
#define LDOUBLE double |
#define MAX | ( | p, | |||
q | ) | ((p >= q) ? p : q) |
Definition at line 159 of file snprintf.c.
Referenced by fmtint().
#define VA_END va_end(ap) |
Definition at line 108 of file snprintf.c.
Referenced by egg_snprintf().
#define VA_LOCAL_DECL va_list ap |
Definition at line 105 of file snprintf.c.
Referenced by egg_snprintf().
#define VA_SHIFT | ( | v, | |||
t | ) | v = va_arg(ap,t) |
Definition at line 107 of file snprintf.c.
Referenced by egg_snprintf().
#define VA_START | ( | f | ) | va_start(ap) |
Definition at line 106 of file snprintf.c.
Referenced by egg_snprintf().
static double abs_val | ( | double | value | ) | [static] |
Definition at line 539 of file snprintf.c.
References LDOUBLE.
Referenced by fmtfp().
00540 { 00541 LDOUBLE result = value; 00542 00543 if (value < 0) 00544 result = -value; 00545 00546 return result; 00547 }
static void dopr | ( | char * | buffer, | |
size_t | maxlen, | |||
const char * | format, | |||
va_list | args | |||
) | [static] |
Definition at line 161 of file snprintf.c.
References char_to_int, dopr_outch(), DP_C_LDOUBLE, DP_C_LONG, DP_C_SHORT, DP_F_MINUS, DP_F_NUM, DP_F_PLUS, DP_F_SPACE, DP_F_UNSIGNED, DP_F_UP, DP_F_ZERO, DP_S_CONV, DP_S_DEFAULT, DP_S_DONE, DP_S_DOT, DP_S_FLAGS, DP_S_MAX, DP_S_MIN, DP_S_MOD, egg_isdigit, fmtfp(), fmtint(), fmtstr(), and LDOUBLE.
Referenced by egg_vsnprintf().
00162 { 00163 char ch; 00164 long value; 00165 LDOUBLE fvalue; 00166 char *strvalue; 00167 int min; 00168 int max; 00169 int state; 00170 int flags; 00171 int cflags; 00172 size_t currlen; 00173 00174 state = DP_S_DEFAULT; 00175 currlen = flags = cflags = min = 0; 00176 max = -1; 00177 ch = *format++; 00178 00179 while (state != DP_S_DONE) { 00180 if ((ch == '\0') || (currlen >= maxlen)) 00181 state = DP_S_DONE; 00182 00183 switch (state) { 00184 case DP_S_DEFAULT: 00185 if (ch == '%') 00186 state = DP_S_FLAGS; 00187 else 00188 dopr_outch(buffer, &currlen, maxlen, ch); 00189 ch = *format++; 00190 break; 00191 case DP_S_FLAGS: 00192 switch (ch) { 00193 case '-': 00194 flags |= DP_F_MINUS; 00195 ch = *format++; 00196 break; 00197 case '+': 00198 flags |= DP_F_PLUS; 00199 ch = *format++; 00200 break; 00201 case ' ': 00202 flags |= DP_F_SPACE; 00203 ch = *format++; 00204 break; 00205 case '#': 00206 flags |= DP_F_NUM; 00207 ch = *format++; 00208 break; 00209 case '0': 00210 flags |= DP_F_ZERO; 00211 ch = *format++; 00212 break; 00213 default: 00214 state = DP_S_MIN; 00215 break; 00216 } 00217 break; 00218 case DP_S_MIN: 00219 if (egg_isdigit(ch)) { 00220 min = 10 * min + char_to_int(ch); 00221 ch = *format++; 00222 } else if (ch == '*') { 00223 min = va_arg(args, int); 00224 00225 ch = *format++; 00226 state = DP_S_DOT; 00227 } else 00228 state = DP_S_DOT; 00229 break; 00230 case DP_S_DOT: 00231 if (ch == '.') { 00232 state = DP_S_MAX; 00233 ch = *format++; 00234 } else 00235 state = DP_S_MOD; 00236 break; 00237 case DP_S_MAX: 00238 if (egg_isdigit(ch)) { 00239 if (max < 0) 00240 max = 0; 00241 max = 10 * max + char_to_int(ch); 00242 ch = *format++; 00243 } else if (ch == '*') { 00244 max = va_arg(args, int); 00245 00246 ch = *format++; 00247 state = DP_S_MOD; 00248 } else 00249 state = DP_S_MOD; 00250 break; 00251 case DP_S_MOD: 00252 /* Currently, we don't support Long Long, bummer */ 00253 switch (ch) { 00254 case 'h': 00255 cflags = DP_C_SHORT; 00256 ch = *format++; 00257 break; 00258 case 'l': 00259 cflags = DP_C_LONG; 00260 ch = *format++; 00261 break; 00262 case 'L': 00263 cflags = DP_C_LDOUBLE; 00264 ch = *format++; 00265 break; 00266 default: 00267 break; 00268 } 00269 state = DP_S_CONV; 00270 break; 00271 case DP_S_CONV: 00272 switch (ch) { 00273 case 'd': 00274 case 'i': 00275 if (cflags == DP_C_SHORT) 00276 value = va_arg(args, int); 00277 00278 else if (cflags == DP_C_LONG) 00279 value = va_arg(args, long int); 00280 00281 else 00282 value = va_arg(args, int); 00283 00284 fmtint(buffer, &currlen, maxlen, value, 10, min, max, flags); 00285 break; 00286 case 'o': 00287 flags |= DP_F_UNSIGNED; 00288 if (cflags == DP_C_SHORT) 00289 value = va_arg(args, unsigned int); 00290 00291 else if (cflags == DP_C_LONG) 00292 value = va_arg(args, unsigned long int); 00293 00294 else 00295 value = va_arg(args, unsigned int); 00296 00297 fmtint(buffer, &currlen, maxlen, value, 8, min, max, flags); 00298 break; 00299 case 'u': 00300 flags |= DP_F_UNSIGNED; 00301 if (cflags == DP_C_SHORT) 00302 value = va_arg(args, unsigned int); 00303 00304 else if (cflags == DP_C_LONG) 00305 value = va_arg(args, unsigned long int); 00306 00307 else 00308 value = va_arg(args, unsigned int); 00309 00310 fmtint(buffer, &currlen, maxlen, value, 10, min, max, flags); 00311 break; 00312 case 'X': 00313 flags |= DP_F_UP; 00314 case 'x': 00315 flags |= DP_F_UNSIGNED; 00316 if (cflags == DP_C_SHORT) 00317 value = va_arg(args, unsigned int); 00318 00319 else if (cflags == DP_C_LONG) 00320 value = va_arg(args, unsigned long int); 00321 00322 else 00323 value = va_arg(args, unsigned int); 00324 00325 fmtint(buffer, &currlen, maxlen, value, 16, min, max, flags); 00326 break; 00327 case 'f': 00328 if (cflags == DP_C_LDOUBLE) 00329 fvalue = va_arg(args, LDOUBLE); 00330 else 00331 fvalue = va_arg(args, double); 00332 00333 /* um, floating point? */ 00334 fmtfp(buffer, &currlen, maxlen, fvalue, min, max, flags); 00335 break; 00336 case 'E': 00337 flags |= DP_F_UP; 00338 case 'e': 00339 if (cflags == DP_C_LDOUBLE) 00340 fvalue = va_arg(args, LDOUBLE); 00341 else 00342 fvalue = va_arg(args, double); 00343 00344 break; 00345 case 'G': 00346 flags |= DP_F_UP; 00347 case 'g': 00348 if (cflags == DP_C_LDOUBLE) 00349 fvalue = va_arg(args, LDOUBLE); 00350 else 00351 fvalue = va_arg(args, double); 00352 00353 break; 00354 case 'c': 00355 dopr_outch(buffer, &currlen, maxlen, va_arg(args, int)); 00356 00357 break; 00358 case 's': 00359 strvalue = va_arg(args, char *); 00360 00361 if (max < 0) 00362 max = maxlen; /* ie, no max */ 00363 fmtstr(buffer, &currlen, maxlen, strvalue, flags, min, max); 00364 break; 00365 case 'p': 00366 strvalue = va_arg(args, void *); 00367 00368 fmtint(buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags); 00369 break; 00370 case 'n': 00371 if (cflags == DP_C_SHORT) { 00372 short int *num; 00373 num = va_arg(args, short int *); 00374 00375 *num = currlen; 00376 } else if (cflags == DP_C_LONG) { 00377 long int *num; 00378 num = va_arg(args, long int *); 00379 00380 *num = currlen; 00381 } else { 00382 int *num; 00383 num = va_arg(args, int *); 00384 00385 *num = currlen; 00386 } 00387 break; 00388 case '%': 00389 dopr_outch(buffer, &currlen, maxlen, ch); 00390 break; 00391 case 'w': 00392 /* not supported yet, treat as next char */ 00393 ch = *format++; 00394 break; 00395 default: 00396 /* Unknown, skip */ 00397 break; 00398 } 00399 ch = *format++; 00400 state = DP_S_DEFAULT; 00401 flags = cflags = min = 0; 00402 max = -1; 00403 break; 00404 case DP_S_DONE: 00405 break; 00406 default: 00407 /* hmm? */ 00408 break; /* some picky compilers need this */ 00409 } 00410 } 00411 if (currlen < maxlen - 1) 00412 buffer[currlen] = '\0'; 00413 else 00414 buffer[maxlen - 1] = '\0'; 00415 }
int egg_snprintf | ( | va_alist | ) |
Definition at line 721 of file snprintf.c.
References egg_vsnprintf, VA_END, VA_LOCAL_DECL, VA_SHIFT, VA_START, and void().
00724 { 00725 # ifndef HAVE_STDARGS 00726 char *str; 00727 size_t count; 00728 char *fmt; 00729 # endif 00730 VA_LOCAL_DECL; 00731 00732 VA_START(fmt); 00733 VA_SHIFT(str, char *); 00734 00735 VA_SHIFT(count, size_t); 00736 VA_SHIFT(fmt, char *); 00737 00738 (void) egg_vsnprintf(str, count, fmt, ap); 00739 VA_END; 00740 return (strlen(str)); 00741 }
int egg_vsnprintf | ( | char * | str, | |
size_t | count, | |||
const char * | fmt, | |||
va_list | args | |||
) |
Definition at line 709 of file snprintf.c.
References dopr().
static void fmtfp | ( | char * | buffer, | |
size_t * | currlen, | |||
size_t | maxlen, | |||
double | fvalue, | |||
int | min, | |||
int | max, | |||
int | flags | |||
) | [static] |
Definition at line 573 of file snprintf.c.
References abs_val(), dopr_outch(), DP_F_MINUS, DP_F_PLUS, DP_F_SPACE, DP_F_UP, DP_F_ZERO, LDOUBLE, pow10(), and round().
Referenced by dopr().
00575 { 00576 int signvalue = 0; 00577 LDOUBLE ufvalue; 00578 char iconvert[20]; 00579 char fconvert[20]; 00580 int iplace = 0; 00581 int fplace = 0; 00582 int padlen = 0; /* amount to pad */ 00583 int zpadlen = 0; 00584 int caps = 0; 00585 long intpart; 00586 long fracpart; 00587 00588 /* 00589 * AIX manpage says the default is 0, but Solaris says the default 00590 * is 6, and sprintf on AIX defaults to 6 00591 */ 00592 if (max < 0) 00593 max = 6; 00594 00595 ufvalue = abs_val(fvalue); 00596 00597 if (fvalue < 0) 00598 signvalue = '-'; 00599 else if (flags & DP_F_PLUS) /* Do a sign (+/i) */ 00600 signvalue = '+'; 00601 else if (flags & DP_F_SPACE) 00602 signvalue = ' '; 00603 00604 #if 0 00605 if (flags & DP_F_UP) 00606 caps = 1; /* Should characters be upper case? */ 00607 #endif 00608 00609 intpart = ufvalue; 00610 00611 /* 00612 * Sorry, we only support 9 digits past the decimal because of our 00613 * conversion method 00614 */ 00615 if (max > 9) 00616 max = 9; 00617 00618 /* We "cheat" by converting the fractional part to integer by 00619 * multiplying by a factor of 10 00620 */ 00621 fracpart = round((pow10(max)) * (ufvalue - intpart)); 00622 00623 if (fracpart >= pow10(max)) { 00624 intpart++; 00625 fracpart -= pow10(max); 00626 } 00627 00628 /* Convert integer part */ 00629 do { 00630 iconvert[iplace++] = 00631 (caps ? "0123456789ABCDEF" : "0123456789abcdef")[intpart % 10]; 00632 intpart = (intpart / 10); 00633 } 00634 while (intpart && (iplace < 20)); 00635 if (iplace == 20) 00636 iplace--; 00637 iconvert[iplace] = 0; 00638 00639 /* Convert fractional part */ 00640 do { 00641 fconvert[fplace++] = 00642 (caps ? "0123456789ABCDEF" : "0123456789abcdef")[fracpart % 10]; 00643 fracpart = (fracpart / 10); 00644 } 00645 while (fracpart && (fplace < 20)); 00646 if (fplace == 20) 00647 fplace--; 00648 fconvert[fplace] = 0; 00649 00650 /* -1 for decimal point, another -1 if we are printing a sign */ 00651 padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0); 00652 zpadlen = max - fplace; 00653 if (zpadlen < 0) 00654 zpadlen = 0; 00655 if (padlen < 0) 00656 padlen = 0; 00657 if (flags & DP_F_MINUS) 00658 padlen = -padlen; /* Left Justifty */ 00659 00660 if ((flags & DP_F_ZERO) && (padlen > 0)) { 00661 if (signvalue) { 00662 dopr_outch(buffer, currlen, maxlen, signvalue); 00663 --padlen; 00664 signvalue = 0; 00665 } 00666 while (padlen > 0) { 00667 dopr_outch(buffer, currlen, maxlen, '0'); 00668 --padlen; 00669 } 00670 } 00671 while (padlen > 0) { 00672 dopr_outch(buffer, currlen, maxlen, ' '); 00673 --padlen; 00674 } 00675 if (signvalue) 00676 dopr_outch(buffer, currlen, maxlen, signvalue); 00677 00678 while (iplace > 0) 00679 dopr_outch(buffer, currlen, maxlen, iconvert[--iplace]); 00680 00681 /* 00682 * Decimal point. This should probably use locale to find the correct 00683 * char to print out. 00684 */ 00685 if (max > 0) { 00686 dopr_outch(buffer, currlen, maxlen, '.'); 00687 00688 while (fplace > 0) 00689 dopr_outch(buffer, currlen, maxlen, fconvert[--fplace]); 00690 } 00691 00692 while (zpadlen > 0) { 00693 dopr_outch(buffer, currlen, maxlen, '0'); 00694 --zpadlen; 00695 } 00696 00697 while (padlen < 0) { 00698 dopr_outch(buffer, currlen, maxlen, ' '); 00699 ++padlen; 00700 } 00701 }
static void fmtint | ( | char * | buffer, | |
size_t * | currlen, | |||
size_t | maxlen, | |||
long | value, | |||
int | base, | |||
int | min, | |||
int | max, | |||
int | flags | |||
) | [static] |
Definition at line 452 of file snprintf.c.
References dopr_outch(), DP_F_MINUS, DP_F_PLUS, DP_F_SPACE, DP_F_UNSIGNED, DP_F_UP, DP_F_ZERO, and MAX.
Referenced by dopr().
00454 { 00455 int signvalue = 0; 00456 unsigned long uvalue; 00457 char convert[20]; 00458 int place = 0; 00459 int spadlen = 0; /* amount to space pad */ 00460 int zpadlen = 0; /* amount to zero pad */ 00461 int caps = 0; 00462 00463 if (max < 0) 00464 max = 0; 00465 00466 uvalue = value; 00467 00468 if (!(flags & DP_F_UNSIGNED)) { 00469 if (value < 0) { 00470 signvalue = '-'; 00471 uvalue = -value; 00472 } else if (flags & DP_F_PLUS) /* Do a sign (+/i) */ 00473 signvalue = '+'; 00474 else if (flags & DP_F_SPACE) 00475 signvalue = ' '; 00476 } 00477 00478 if (flags & DP_F_UP) 00479 caps = 1; /* Should characters be upper case? */ 00480 00481 do { 00482 convert[place++] = (caps ? "0123456789ABCDEF" : "0123456789abcdef") 00483 [uvalue % (unsigned) base]; 00484 uvalue = (uvalue / (unsigned) base); 00485 } 00486 while (uvalue && (place < 20)); 00487 if (place == 20) 00488 place--; 00489 convert[place] = 0; 00490 00491 zpadlen = max - place; 00492 spadlen = min - MAX(max, place) - (signvalue ? 1 : 0); 00493 if (zpadlen < 0) 00494 zpadlen = 0; 00495 if (spadlen < 0) 00496 spadlen = 0; 00497 if (flags & DP_F_ZERO) { 00498 zpadlen = MAX(zpadlen, spadlen); 00499 spadlen = 0; 00500 } 00501 if (flags & DP_F_MINUS) 00502 spadlen = -spadlen; /* Left Justifty */ 00503 00504 #ifdef DEBUG_SNPRINTF 00505 dprint(1, 00506 (debugfile, "zpad: %d, spad: %d, min: %d, max: %d, place: %d\n", 00507 zpadlen, spadlen, min, max, place)); 00508 #endif 00509 00510 /* Spaces */ 00511 while (spadlen > 0) { 00512 dopr_outch(buffer, currlen, maxlen, ' '); 00513 --spadlen; 00514 } 00515 00516 /* Sign */ 00517 if (signvalue) 00518 dopr_outch(buffer, currlen, maxlen, signvalue); 00519 00520 /* Zeros */ 00521 if (zpadlen > 0) { 00522 while (zpadlen > 0) { 00523 dopr_outch(buffer, currlen, maxlen, '0'); 00524 --zpadlen; 00525 } 00526 } 00527 00528 /* Digits */ 00529 while (place > 0) 00530 dopr_outch(buffer, currlen, maxlen, convert[--place]); 00531 00532 /* Left Justified spaces */ 00533 while (spadlen < 0) { 00534 dopr_outch(buffer, currlen, maxlen, ' '); 00535 ++spadlen; 00536 } 00537 }
static void fmtstr | ( | char * | buffer, | |
size_t * | currlen, | |||
size_t | maxlen, | |||
char * | value, | |||
int | flags, | |||
int | min, | |||
int | max | |||
) | [static] |
Definition at line 417 of file snprintf.c.
References dopr_outch(), and DP_F_MINUS.
Referenced by dopr().
00419 { 00420 int padlen, strln; /* amount to pad */ 00421 int cnt = 0; 00422 00423 if (value == 0) { 00424 value = "<NULL>"; 00425 } 00426 00427 for (strln = 0; value[strln]; ++strln); /* strlen */ 00428 padlen = min - strln; 00429 if (padlen < 0) 00430 padlen = 0; 00431 if (flags & DP_F_MINUS) 00432 padlen = -padlen; /* Left Justify */ 00433 00434 while ((padlen > 0) && (cnt < max)) { 00435 dopr_outch(buffer, currlen, maxlen, ' '); 00436 --padlen; 00437 ++cnt; 00438 } 00439 while (*value && (cnt < max)) { 00440 dopr_outch(buffer, currlen, maxlen, *value++); 00441 ++cnt; 00442 } 00443 while ((padlen < 0) && (cnt < max)) { 00444 dopr_outch(buffer, currlen, maxlen, ' '); 00445 ++padlen; 00446 ++cnt; 00447 } 00448 }
static double pow10 | ( | int | exp | ) | [static] |
Definition at line 549 of file snprintf.c.
References LDOUBLE.
Referenced by fmtfp().
00550 { 00551 LDOUBLE result = 1; 00552 00553 while (exp) { 00554 result *= 10; 00555 exp--; 00556 } 00557 00558 return result; 00559 }
static long round | ( | double | value | ) | [static] |
Definition at line 561 of file snprintf.c.
Referenced by fmtfp().
00562 { 00563 long intpart; 00564 00565 intpart = value; 00566 value = value - intpart; 00567 if (value >= 0.5) 00568 intpart++; 00569 00570 return intpart; 00571 }