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