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