00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "main.h"
00025 #include "snprintf.h"
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085 #include <string.h>
00086 #include <ctype.h>
00087 #include <sys/types.h>
00088
00089 #ifndef HAVE_VSNPRINTF
00090
00091
00092
00093 #if defined(__STDC__)
00094 # ifdef HAVE_STDARG_H
00095 # include <stdarg.h>
00096 # endif
00097 # define HAVE_STDARGS
00098 # define VA_LOCAL_DECL va_list ap
00099 # define VA_START(f) va_start(ap, f)
00100 # define VA_SHIFT(v,t) ;
00101 # define VA_END va_end(ap)
00102 #else
00103 # include <varargs.h>
00104 # undef HAVE_STDARGS
00105 # define VA_LOCAL_DECL va_list ap
00106 # define VA_START(f) va_start(ap)
00107 # define VA_SHIFT(v,t) v = va_arg(ap,t)
00108 # define VA_END va_end(ap)
00109 #endif
00110
00111 #ifdef HAVE_LONG_DOUBLE
00112 #define LDOUBLE long double
00113 #else
00114 #define LDOUBLE double
00115 #endif
00116
00117 static void dopr(char *buffer, size_t maxlen, const char *format, va_list args);
00118 static void fmtstr(char *buffer, size_t *currlen, size_t maxlen, char *value,
00119 int flags, int min, int max);
00120 static void fmtint(char *buffer, size_t *currlen, size_t maxlen, long value,
00121 int base, int min, int max, int flags);
00122 static void fmtfp(char *buffer, size_t *currlen, size_t maxlen, LDOUBLE fvalue,
00123 int min, int max, int flags);
00124 static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);
00125
00126
00127
00128
00129
00130
00131 #define DP_S_DEFAULT 0
00132 #define DP_S_FLAGS 1
00133 #define DP_S_MIN 2
00134 #define DP_S_DOT 3
00135 #define DP_S_MAX 4
00136 #define DP_S_MOD 5
00137 #define DP_S_CONV 6
00138 #define DP_S_DONE 7
00139
00140
00141 #define DP_F_MINUS (1 << 0)
00142 #define DP_F_PLUS (1 << 1)
00143 #define DP_F_SPACE (1 << 2)
00144 #define DP_F_NUM (1 << 3)
00145 #define DP_F_ZERO (1 << 4)
00146 #define DP_F_UP (1 << 5)
00147 #define DP_F_UNSIGNED (1 << 6)
00148
00149
00150 #define DP_C_SHORT 1
00151 #define DP_C_LONG 2
00152 #define DP_C_LDOUBLE 3
00153
00154 #define char_to_int(p) (p - '0')
00155
00156 #ifdef MAX
00157 # undef MAX
00158 #endif
00159 #define MAX(p,q) ((p >= q) ? p : q)
00160
00161 static void dopr(char *buffer, size_t maxlen, const char *format, va_list args)
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
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
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;
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
00393 ch = *format++;
00394 break;
00395 default:
00396
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
00408 break;
00409 }
00410 }
00411 if (currlen < maxlen - 1)
00412 buffer[currlen] = '\0';
00413 else
00414 buffer[maxlen - 1] = '\0';
00415 }
00416
00417 static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
00418 char *value, int flags, int min, int max)
00419 {
00420 int padlen, strln;
00421 int cnt = 0;
00422
00423 if (value == 0) {
00424 value = "<NULL>";
00425 }
00426
00427 for (strln = 0; value[strln]; ++strln);
00428 padlen = min - strln;
00429 if (padlen < 0)
00430 padlen = 0;
00431 if (flags & DP_F_MINUS)
00432 padlen = -padlen;
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 }
00449
00450
00451
00452 static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
00453 long value, int base, int min, int max, int flags)
00454 {
00455 int signvalue = 0;
00456 unsigned long uvalue;
00457 char convert[20];
00458 int place = 0;
00459 int spadlen = 0;
00460 int zpadlen = 0;
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)
00473 signvalue = '+';
00474 else if (flags & DP_F_SPACE)
00475 signvalue = ' ';
00476 }
00477
00478 if (flags & DP_F_UP)
00479 caps = 1;
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;
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
00511 while (spadlen > 0) {
00512 dopr_outch(buffer, currlen, maxlen, ' ');
00513 --spadlen;
00514 }
00515
00516
00517 if (signvalue)
00518 dopr_outch(buffer, currlen, maxlen, signvalue);
00519
00520
00521 if (zpadlen > 0) {
00522 while (zpadlen > 0) {
00523 dopr_outch(buffer, currlen, maxlen, '0');
00524 --zpadlen;
00525 }
00526 }
00527
00528
00529 while (place > 0)
00530 dopr_outch(buffer, currlen, maxlen, convert[--place]);
00531
00532
00533 while (spadlen < 0) {
00534 dopr_outch(buffer, currlen, maxlen, ' ');
00535 ++spadlen;
00536 }
00537 }
00538
00539 static LDOUBLE abs_val(LDOUBLE value)
00540 {
00541 LDOUBLE result = value;
00542
00543 if (value < 0)
00544 result = -value;
00545
00546 return result;
00547 }
00548
00549 static LDOUBLE pow10(int exp)
00550 {
00551 LDOUBLE result = 1;
00552
00553 while (exp) {
00554 result *= 10;
00555 exp--;
00556 }
00557
00558 return result;
00559 }
00560
00561 static long round(LDOUBLE value)
00562 {
00563 long intpart;
00564
00565 intpart = value;
00566 value = value - intpart;
00567 if (value >= 0.5)
00568 intpart++;
00569
00570 return intpart;
00571 }
00572
00573 static void fmtfp(char *buffer, size_t *currlen, size_t maxlen,
00574 LDOUBLE fvalue, int min, int max, int flags)
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;
00583 int zpadlen = 0;
00584 int caps = 0;
00585 long intpart;
00586 long fracpart;
00587
00588
00589
00590
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)
00600 signvalue = '+';
00601 else if (flags & DP_F_SPACE)
00602 signvalue = ' ';
00603
00604 #if 0
00605 if (flags & DP_F_UP)
00606 caps = 1;
00607 #endif
00608
00609 intpart = ufvalue;
00610
00611
00612
00613
00614
00615 if (max > 9)
00616 max = 9;
00617
00618
00619
00620
00621 fracpart = round((pow10(max)) * (ufvalue - intpart));
00622
00623 if (fracpart >= pow10(max)) {
00624 intpart++;
00625 fracpart -= pow10(max);
00626 }
00627
00628
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
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
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;
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
00683
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 }
00702
00703 static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
00704 {
00705 if (*currlen < maxlen)
00706 buffer[(*currlen)++] = c;
00707 }
00708
00709 int egg_vsnprintf(char *str, size_t count, const char *fmt, va_list args)
00710 {
00711 str[0] = 0;
00712 dopr(str, count, fmt, args);
00713 return (strlen(str));
00714 }
00715 #endif
00716
00717 #ifndef HAVE_SNPRINTF
00718 # ifdef HAVE_STDARGS
00719 int egg_snprintf(char *str, size_t count, const char *fmt, ...)
00720 # else
00721 int egg_snprintf(va_alist)
00722 va_dcl
00723 # endif
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 }
00742 #endif