00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
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 #include <net-snmp/net-snmp-config.h>
00055
00056 #if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF)
00057
00058 #if HAVE_STRING_H
00059 #include <string.h>
00060 #else
00061 #include <strings.h>
00062 #endif
00063 #include <ctype.h>
00064 #include <sys/types.h>
00065
00066 #if HAVE_STDARG_H
00067 # include <stdarg.h>
00068 # define HAVE_STDARGS
00069 # define VA_LOCAL_DECL va_list ap
00070 # define VA_START(f) va_start(ap, f)
00071 # define VA_SHIFT(v,t) ;
00072 # define VA_END va_end(ap)
00073 #elif HAVE_VARARGS_H
00074 # include <varargs.h>
00075 # undef HAVE_STDARGS
00076 # define VA_LOCAL_DECL va_list ap
00077 # define VA_START(f) va_start(ap)
00078 # define VA_SHIFT(v,t) v = va_arg(ap,t)
00079 # define VA_END va_end(ap)
00080 #else
00081
00082
00083
00084 #endif
00085
00086 #ifdef HAVE_LONG_DOUBLE
00087 #define LDOUBLE long double
00088 #else
00089 #define LDOUBLE double
00090 #endif
00091
00092 int snprintf(char *str, size_t count, const char *fmt, ...);
00093 int vsnprintf(char *str, size_t count, const char *fmt,
00094 va_list arg);
00095
00096 static void dopr(char *buffer, size_t maxlen, const char *format,
00097 va_list args);
00098 static void fmtstr(char *buffer, size_t * currlen, size_t maxlen,
00099 char *value, int flags, int min, int max);
00100 static void fmtint(char *buffer, size_t * currlen, size_t maxlen,
00101 long value, int base, int min, int max, int flags);
00102 static void fmtfp(char *buffer, size_t * currlen, size_t maxlen,
00103 LDOUBLE fvalue, int min, int max, int flags);
00104 static void dopr_outch(char *buffer, size_t * currlen, size_t maxlen,
00105 char c);
00106
00107
00108
00109
00110
00111
00112
00113
00114 #define DP_S_DEFAULT 0
00115 #define DP_S_FLAGS 1
00116 #define DP_S_MIN 2
00117 #define DP_S_DOT 3
00118 #define DP_S_MAX 4
00119 #define DP_S_MOD 5
00120 #define DP_S_CONV 6
00121 #define DP_S_DONE 7
00122
00123
00124
00125
00126 #define DP_F_MINUS (1 << 0)
00127 #define DP_F_PLUS (1 << 1)
00128 #define DP_F_SPACE (1 << 2)
00129 #define DP_F_NUM (1 << 3)
00130 #define DP_F_ZERO (1 << 4)
00131 #define DP_F_UP (1 << 5)
00132 #define DP_F_UNSIGNED (1 << 6)
00133
00134
00135
00136
00137 #define DP_C_SHORT 1
00138 #define DP_C_LONG 2
00139 #define DP_C_LDOUBLE 3
00140
00141 #define char_to_int(p) (p - '0')
00142 #define MAX(p,q) ((p >= q) ? p : q)
00143
00144 static void
00145 dopr(char *buffer, size_t maxlen, const char *format, va_list args)
00146 {
00147 char ch;
00148 long value;
00149 LDOUBLE fvalue;
00150 char *strvalue;
00151 int min;
00152 int max;
00153 int state;
00154 int flags;
00155 int cflags;
00156 size_t currlen;
00157
00158 state = DP_S_DEFAULT;
00159 currlen = flags = cflags = min = 0;
00160 max = -1;
00161 ch = *format++;
00162
00163 while (state != DP_S_DONE) {
00164 if ((ch == '\0') || (currlen >= maxlen))
00165 state = DP_S_DONE;
00166
00167 switch (state) {
00168 case DP_S_DEFAULT:
00169 if (ch == '%')
00170 state = DP_S_FLAGS;
00171 else
00172 dopr_outch(buffer, &currlen, maxlen, ch);
00173 ch = *format++;
00174 break;
00175 case DP_S_FLAGS:
00176 switch (ch) {
00177 case '-':
00178 flags |= DP_F_MINUS;
00179 ch = *format++;
00180 break;
00181 case '+':
00182 flags |= DP_F_PLUS;
00183 ch = *format++;
00184 break;
00185 case ' ':
00186 flags |= DP_F_SPACE;
00187 ch = *format++;
00188 break;
00189 case '#':
00190 flags |= DP_F_NUM;
00191 ch = *format++;
00192 break;
00193 case '0':
00194 flags |= DP_F_ZERO;
00195 ch = *format++;
00196 break;
00197 default:
00198 state = DP_S_MIN;
00199 break;
00200 }
00201 break;
00202 case DP_S_MIN:
00203 if (isdigit(ch)) {
00204 min = 10 * min + char_to_int(ch);
00205 ch = *format++;
00206 } else if (ch == '*') {
00207 min = va_arg(args, int);
00208 ch = *format++;
00209 state = DP_S_DOT;
00210 } else
00211 state = DP_S_DOT;
00212 break;
00213 case DP_S_DOT:
00214 if (ch == '.') {
00215 state = DP_S_MAX;
00216 ch = *format++;
00217 } else
00218 state = DP_S_MOD;
00219 break;
00220 case DP_S_MAX:
00221 if (isdigit(ch)) {
00222 if (max < 0)
00223 max = 0;
00224 max = 10 * max + char_to_int(ch);
00225 ch = *format++;
00226 } else if (ch == '*') {
00227 max = va_arg(args, int);
00228 ch = *format++;
00229 state = DP_S_MOD;
00230 } else
00231 state = DP_S_MOD;
00232 break;
00233 case DP_S_MOD:
00234
00235
00236
00237 switch (ch) {
00238 case 'h':
00239 cflags = DP_C_SHORT;
00240 ch = *format++;
00241 break;
00242 case 'l':
00243 cflags = DP_C_LONG;
00244 ch = *format++;
00245 break;
00246 case 'L':
00247 cflags = DP_C_LDOUBLE;
00248 ch = *format++;
00249 break;
00250 default:
00251 break;
00252 }
00253 state = DP_S_CONV;
00254 break;
00255 case DP_S_CONV:
00256 switch (ch) {
00257 case 'd':
00258 case 'i':
00259 if (cflags == DP_C_SHORT)
00260 value = va_arg(args, short int);
00261 else if (cflags == DP_C_LONG)
00262 value = va_arg(args, long int);
00263 else
00264 value = va_arg(args, int);
00265 fmtint(buffer, &currlen, maxlen, value, 10, min, max,
00266 flags);
00267 break;
00268 case 'o':
00269 flags |= DP_F_UNSIGNED;
00270 if (cflags == DP_C_SHORT)
00271 value = va_arg(args, unsigned short int);
00272 else if (cflags == DP_C_LONG)
00273 value = va_arg(args, unsigned long int);
00274 else
00275 value = va_arg(args, unsigned int);
00276 fmtint(buffer, &currlen, maxlen, value, 8, min, max,
00277 flags);
00278 break;
00279 case 'u':
00280 flags |= DP_F_UNSIGNED;
00281 if (cflags == DP_C_SHORT)
00282 value = va_arg(args, unsigned short int);
00283 else if (cflags == DP_C_LONG)
00284 value = va_arg(args, unsigned long int);
00285 else
00286 value = va_arg(args, unsigned int);
00287 fmtint(buffer, &currlen, maxlen, value, 10, min, max,
00288 flags);
00289 break;
00290 case 'X':
00291 flags |= DP_F_UP;
00292 case 'x':
00293 flags |= DP_F_UNSIGNED;
00294 if (cflags == DP_C_SHORT)
00295 value = va_arg(args, unsigned short int);
00296 else if (cflags == DP_C_LONG)
00297 value = va_arg(args, unsigned long int);
00298 else
00299 value = va_arg(args, unsigned int);
00300 fmtint(buffer, &currlen, maxlen, value, 16, min, max,
00301 flags);
00302 break;
00303 case 'f':
00304 if (cflags == DP_C_LDOUBLE)
00305 fvalue = va_arg(args, LDOUBLE);
00306 else
00307 fvalue = va_arg(args, double);
00308
00309
00310
00311 fmtfp(buffer, &currlen, maxlen, fvalue, min, max, flags);
00312 break;
00313 case 'E':
00314 flags |= DP_F_UP;
00315 case 'e':
00316 if (cflags == DP_C_LDOUBLE)
00317 fvalue = va_arg(args, LDOUBLE);
00318 else
00319 fvalue = va_arg(args, double);
00320 break;
00321 case 'G':
00322 flags |= DP_F_UP;
00323 case 'g':
00324 if (cflags == DP_C_LDOUBLE)
00325 fvalue = va_arg(args, LDOUBLE);
00326 else
00327 fvalue = va_arg(args, double);
00328 break;
00329 case 'c':
00330 dopr_outch(buffer, &currlen, maxlen, va_arg(args, int));
00331 break;
00332 case 's':
00333 strvalue = va_arg(args, char *);
00334 if (max < 0)
00335 max = maxlen;
00336 fmtstr(buffer, &currlen, maxlen, strvalue, flags, min,
00337 max);
00338 break;
00339 case 'p':
00340 strvalue = (char *) va_arg(args, void *);
00341 fmtint(buffer, &currlen, maxlen, (long) strvalue, 16, min,
00342 max, flags);
00343 break;
00344 case 'n':
00345 if (cflags == DP_C_SHORT) {
00346 short int *num;
00347 num = va_arg(args, short int *);
00348 *num = currlen;
00349 } else if (cflags == DP_C_LONG) {
00350 long int *num;
00351 num = va_arg(args, long int *);
00352 *num = currlen;
00353 } else {
00354 int *num;
00355 num = va_arg(args, int *);
00356 *num = currlen;
00357 }
00358 break;
00359 case '%':
00360 dopr_outch(buffer, &currlen, maxlen, ch);
00361 break;
00362 case 'w':
00363
00364
00365
00366 ch = *format++;
00367 break;
00368 default:
00369
00370
00371
00372 break;
00373 }
00374 ch = *format++;
00375 state = DP_S_DEFAULT;
00376 flags = cflags = min = 0;
00377 max = -1;
00378 break;
00379 case DP_S_DONE:
00380 break;
00381 default:
00382
00383
00384
00385 break;
00386 }
00387 }
00388 if (currlen < maxlen - 1)
00389 buffer[currlen] = '\0';
00390 else
00391 buffer[maxlen - 1] = '\0';
00392 }
00393
00394 static void
00395 fmtstr(char *buffer, size_t * currlen, size_t maxlen,
00396 char *value, int flags, int min, int max)
00397 {
00398 int padlen, strln;
00399 int cnt = 0;
00400
00401 if (value == 0) {
00402 value = "<NULL>";
00403 }
00404
00405 for (strln = 0; value[strln]; ++strln);
00406 padlen = min - strln;
00407 if (padlen < 0)
00408 padlen = 0;
00409 if (flags & DP_F_MINUS)
00410 padlen = -padlen;
00411
00412 while ((padlen > 0) && (cnt < max)) {
00413 dopr_outch(buffer, currlen, maxlen, ' ');
00414 --padlen;
00415 ++cnt;
00416 }
00417 while (*value && (cnt < max)) {
00418 dopr_outch(buffer, currlen, maxlen, *value++);
00419 ++cnt;
00420 }
00421 while ((padlen < 0) && (cnt < max)) {
00422 dopr_outch(buffer, currlen, maxlen, ' ');
00423 ++padlen;
00424 ++cnt;
00425 }
00426 }
00427
00428
00429
00430
00431
00432 static void
00433 fmtint(char *buffer, size_t * currlen, size_t maxlen,
00434 long value, int base, int min, int max, int flags)
00435 {
00436 int signvalue = 0;
00437 unsigned long uvalue;
00438 char convert[20];
00439 int place = 0;
00440 int spadlen = 0;
00441 int zpadlen = 0;
00442 int caps = 0;
00443
00444 if (max < 0)
00445 max = 0;
00446
00447 uvalue = value;
00448
00449 if (!(flags & DP_F_UNSIGNED)) {
00450 if (value < 0) {
00451 signvalue = '-';
00452 uvalue = -value;
00453 } else if (flags & DP_F_PLUS)
00454 signvalue = '+';
00455 else if (flags & DP_F_SPACE)
00456 signvalue = ' ';
00457 }
00458
00459 if (flags & DP_F_UP)
00460 caps = 1;
00461
00462 do {
00463 convert[place++] = (caps ? "0123456789ABCDEF" : "0123456789abcdef")
00464 [uvalue % (unsigned) base];
00465 uvalue = (uvalue / (unsigned) base);
00466 } while (uvalue && (place < 20));
00467 if (place == 20)
00468 place--;
00469 convert[place] = 0;
00470
00471 zpadlen = max - place;
00472 spadlen = min - MAX(max, place) - (signvalue ? 1 : 0);
00473 if (zpadlen < 0)
00474 zpadlen = 0;
00475 if (spadlen < 0)
00476 spadlen = 0;
00477 if (flags & DP_F_ZERO) {
00478 zpadlen = MAX(zpadlen, spadlen);
00479 spadlen = 0;
00480 }
00481 if (flags & DP_F_MINUS)
00482 spadlen = -spadlen;
00483
00484 #ifdef DEBUG_SNPRINTF
00485 dprint(1,
00486 (debugfile, "zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
00487 zpadlen, spadlen, min, max, place));
00488 #endif
00489
00490
00491
00492
00493 while (spadlen > 0) {
00494 dopr_outch(buffer, currlen, maxlen, ' ');
00495 --spadlen;
00496 }
00497
00498
00499
00500
00501 if (signvalue)
00502 dopr_outch(buffer, currlen, maxlen, signvalue);
00503
00504
00505
00506
00507 if (zpadlen > 0) {
00508 while (zpadlen > 0) {
00509 dopr_outch(buffer, currlen, maxlen, '0');
00510 --zpadlen;
00511 }
00512 }
00513
00514
00515
00516
00517 while (place > 0)
00518 dopr_outch(buffer, currlen, maxlen, convert[--place]);
00519
00520
00521
00522
00523 while (spadlen < 0) {
00524 dopr_outch(buffer, currlen, maxlen, ' ');
00525 ++spadlen;
00526 }
00527 }
00528
00529 static LDOUBLE
00530 abs_val(LDOUBLE value)
00531 {
00532 LDOUBLE result = value;
00533
00534 if (value < 0)
00535 result = -value;
00536
00537 return result;
00538 }
00539
00540 static LDOUBLE
00541 pow10(int exp)
00542 {
00543 LDOUBLE result = 1;
00544
00545 while (exp) {
00546 result *= 10;
00547 exp--;
00548 }
00549
00550 return result;
00551 }
00552
00553 static long
00554 round(LDOUBLE value)
00555 {
00556 long intpart;
00557
00558 intpart = value;
00559 value = value - intpart;
00560 if (value >= 0.5)
00561 intpart++;
00562
00563 return intpart;
00564 }
00565
00566 static void
00567 fmtfp(char *buffer, size_t * currlen, size_t maxlen,
00568 LDOUBLE fvalue, int min, int max, int flags)
00569 {
00570 int signvalue = 0;
00571 LDOUBLE ufvalue;
00572 char iconvert[20];
00573 char fconvert[20];
00574 int iplace = 0;
00575 int fplace = 0;
00576 int padlen = 0;
00577 int zpadlen = 0;
00578 int caps = 0;
00579 long intpart;
00580 long fracpart;
00581
00582
00583
00584
00585
00586 if (max < 0)
00587 max = 6;
00588
00589 ufvalue = abs_val(fvalue);
00590
00591 if (fvalue < 0)
00592 signvalue = '-';
00593 else if (flags & DP_F_PLUS)
00594 signvalue = '+';
00595 else if (flags & DP_F_SPACE)
00596 signvalue = ' ';
00597
00598 #if 0
00599 if (flags & DP_F_UP)
00600 caps = 1;
00601 #endif
00602
00603 intpart = ufvalue;
00604
00605
00606
00607
00608
00609 if (max > 9)
00610 max = 9;
00611
00612
00613
00614
00615
00616 fracpart = round((pow10(max)) * (ufvalue - intpart));
00617
00618 if (fracpart >= pow10(max)) {
00619 intpart++;
00620 fracpart -= pow10(max);
00621 }
00622 #ifdef DEBUG_SNPRINTF
00623 dprint(1,
00624 (debugfile, "fmtfp: %f =? %d.%d\n", fvalue, intpart, fracpart));
00625 #endif
00626
00627
00628
00629
00630 do {
00631 iconvert[iplace++] =
00632 (caps ? "0123456789ABCDEF" : "0123456789abcdef")[intpart % 10];
00633 intpart = (intpart / 10);
00634 } while (intpart && (iplace < 20));
00635 if (iplace == 20)
00636 iplace--;
00637 iconvert[iplace] = 0;
00638
00639
00640
00641
00642 do {
00643 fconvert[fplace++] =
00644 (caps ? "0123456789ABCDEF" : "0123456789abcdef")[fracpart %
00645 10];
00646 fracpart = (fracpart / 10);
00647 } while (fracpart && (fplace < 20));
00648 if (fplace == 20)
00649 fplace--;
00650 fconvert[fplace] = 0;
00651
00652
00653
00654
00655 padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
00656 zpadlen = max - fplace;
00657 if (zpadlen < 0)
00658 zpadlen = 0;
00659 if (padlen < 0)
00660 padlen = 0;
00661 if (flags & DP_F_MINUS)
00662 padlen = -padlen;
00663
00664 if ((flags & DP_F_ZERO) && (padlen > 0)) {
00665 if (signvalue) {
00666 dopr_outch(buffer, currlen, maxlen, signvalue);
00667 --padlen;
00668 signvalue = 0;
00669 }
00670 while (padlen > 0) {
00671 dopr_outch(buffer, currlen, maxlen, '0');
00672 --padlen;
00673 }
00674 }
00675 while (padlen > 0) {
00676 dopr_outch(buffer, currlen, maxlen, ' ');
00677 --padlen;
00678 }
00679 if (signvalue)
00680 dopr_outch(buffer, currlen, maxlen, signvalue);
00681
00682 while (iplace > 0)
00683 dopr_outch(buffer, currlen, maxlen, iconvert[--iplace]);
00684
00685
00686
00687
00688
00689 if (max > 0) {
00690 dopr_outch(buffer, currlen, maxlen, '.');
00691
00692 while (fplace > 0)
00693 dopr_outch(buffer, currlen, maxlen, fconvert[--fplace]);
00694 }
00695
00696 while (zpadlen > 0) {
00697 dopr_outch(buffer, currlen, maxlen, '0');
00698 --zpadlen;
00699 }
00700
00701 while (padlen < 0) {
00702 dopr_outch(buffer, currlen, maxlen, ' ');
00703 ++padlen;
00704 }
00705 }
00706
00707 static void
00708 dopr_outch(char *buffer, size_t * currlen, size_t maxlen, char c)
00709 {
00710 if (*currlen < maxlen)
00711 buffer[(*currlen)++] = c;
00712 }
00713
00714 #ifndef HAVE_VSNPRINTF
00715 int
00716 vsnprintf(char *str, size_t count, const char *fmt, va_list args)
00717 {
00718 str[0] = 0;
00719 dopr(str, count, fmt, args);
00720 return (strlen(str));
00721 }
00722 #endif
00723
00724 #ifndef HAVE_SNPRINTF
00725
00726
00727
00728 #ifdef HAVE_STDARGS
00729 int
00730 snprintf(char *str, size_t count, const char *fmt, ...)
00731 #else
00732 int
00733 snprintf(va_alist)
00734 va_dcl
00735 #endif
00736 {
00737 #ifndef HAVE_STDARGS
00738 char *str;
00739 size_t count;
00740 char *fmt;
00741 #endif
00742 VA_LOCAL_DECL;
00743
00744 VA_START(fmt);
00745 VA_SHIFT(str, char *);
00746 VA_SHIFT(count, size_t);
00747 VA_SHIFT(fmt, char *);
00748 (void) vsnprintf(str, count, fmt, ap);
00749 VA_END;
00750 return (strlen(str));
00751 }
00752 #endif
00753
00754 #ifdef TEST_SNPRINTF
00755 #ifndef LONG_STRING
00756 #define LONG_STRING 1024
00757 #endif
00758 int
00759 main(void)
00760 {
00761 char buf1[LONG_STRING];
00762 char buf2[LONG_STRING];
00763 char *fp_fmt[] = {
00764 "%-1.5f",
00765 "%1.5f",
00766 "%123.9f",
00767 "%10.5f",
00768 "% 10.5f",
00769 "%+22.9f",
00770 "%+4.9f",
00771 "%01.3f",
00772 "%4f",
00773 "%3.1f",
00774 "%3.2f",
00775 "%.0f",
00776 "%.1f",
00777 NULL
00778 };
00779 double fp_nums[] =
00780 { -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996,
00781 0.9996, 1.996, 4.136, 0
00782 };
00783 char *int_fmt[] = {
00784 "%-1.5d",
00785 "%1.5d",
00786 "%123.9d",
00787 "%5.5d",
00788 "%10.5d",
00789 "% 10.5d",
00790 "%+22.33d",
00791 "%01.3d",
00792 "%4d",
00793 NULL
00794 };
00795 long int_nums[] = { -1, 134, 91340, 341, 0203, 0 };
00796 int x, y;
00797 int fail = 0;
00798 int num = 0;
00799
00800 printf("Testing snprintf format codes against system sprintf...\n");
00801
00802 for (x = 0; fp_fmt[x] != NULL; x++)
00803 for (y = 0; fp_nums[y] != 0; y++) {
00804 snprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]);
00805 sprintf(buf2, fp_fmt[x], fp_nums[y]);
00806 if (strcmp(buf1, buf2)) {
00807 printf
00808 ("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
00809 fp_fmt[x], buf1, buf2);
00810 fail++;
00811 }
00812 num++;
00813 }
00814
00815 for (x = 0; int_fmt[x] != NULL; x++)
00816 for (y = 0; int_nums[y] != 0; y++) {
00817 snprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]);
00818 sprintf(buf2, int_fmt[x], int_nums[y]);
00819 if (strcmp(buf1, buf2)) {
00820 printf
00821 ("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
00822 int_fmt[x], buf1, buf2);
00823 fail++;
00824 }
00825 num++;
00826 }
00827 printf("%d tests failed out of %d.\n", fail, num);
00828 }
00829 #endif
00830
00831 #endif