Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Compound List | File List | Namespace Members | Compound Members | File Members | Related Pages | Examples

vos/corelibs/vos/snprintf.cc

Go to the documentation of this file.
00001 /*
00002  * Copyright Patrick Powell 1995
00003  * This code is based on code written by Patrick Powell (papowell@astart.com)
00004  * It may be used for any purpose as long as this notice remains intact
00005  * on all source code distributions
00006  */
00007 
00008 /**************************************************************
00009  * Original:
00010  * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
00011  * A bombproof version of doprnt (dopr) included.
00012  * Sigh.  This sort of thing is always nasty do deal with.  Note that
00013  * the version here does not include floating point...
00014  *
00015  * snprintf() is used instead of sprintf() as it does limit checks
00016  * for string length.  This covers a nasty loophole.
00017  *
00018  * The other functions are there to prevent NULL pointers from
00019  * causing nast effects.
00020  *
00021  * More Recently:
00022  *  Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43
00023  *  This was ugly.  It is still ugly.  I opted out of floating point
00024  *  numbers, but the formatter understands just about everything
00025  *  from the normal C string format, at least as far as I can tell from
00026  *  the Solaris 2.5 printf(3S) man page.
00027  *
00028  *  Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1
00029  *    Ok, added some minimal floating point support, which means this
00030  *    probably requires libm on most operating systems.  Don't yet
00031  *    support the exponent (e,E) and sigfig (g,G).  Also, fmtint()
00032  *    was pretty badly broken, it just wasn't being exercised in ways
00033  *    which showed it, so that's been fixed.  Also, formated the code
00034  *    to mutt conventions, and removed dead code left over from the
00035  *    original.  Also, there is now a builtin-test, just compile with:
00036  *           gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
00037  *    and run snprintf for results.
00038  *
00039  *  Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i
00040  *    The PGP code was using unsigned hexadecimal formats.
00041  *    Unfortunately, unsigned formats simply didn't work.
00042  *
00043  *  Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8
00044  *    The original code assumed that both snprintf() and vsnprintf() were
00045  *    missing.  Some systems only have snprintf() but not vsnprintf(), so
00046  *    the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
00047  *
00048  *  Andrew Tridgell (tridge@samba.org) Oct 1998
00049  *    fixed handling of %.0f
00050  *    added test for HAVE_LONG_DOUBLE
00051  *
00052  *  Russ Allbery <rra@stanford.edu> 2000-08-26
00053  *    fixed return value to comply with C99
00054  *    fixed handling of snprintf(NULL, ...)
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 /* Define this as a fall through, HAVE_STDARG_H is probably already set */
00071 
00072 #define HAVE_VARARGS_H
00073 
00074 /* varargs declarations: */
00075 
00076 #if defined(HAVE_STDARG_H)
00077 # include <stdarg.h>
00078 # define HAVE_STDARGS    /* let's hope that works everywhere (mj) */
00079 # define VA_LOCAL_DECL   va_list ap
00080 # define VA_START(f)     va_start(ap, f)
00081 # define VA_SHIFT(v,t)  ;   /* no-op for ANSI */
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)      /* f is ignored! */
00089 #  define VA_SHIFT(v,t) v = va_arg(ap,t)
00090 #  define VA_END        va_end(ap)
00091 # else
00092 /*XX ** NO VARARGS ** XX*/
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  * dopr(): poor man's version of doprintf
00127  */
00128 
00129 /* format read states */
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 /* format flags - Bits */
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 /* Conversion Flags */
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       /* Currently, we don't support Long Long, bummer */
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     /* um, floating point? */
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     /* not supported yet, treat as next char */
00387     ch = *format++;
00388     break;
00389       default:
00390     /* Unknown, skip */
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       /* hmm? */
00402       break; /* some picky compilers need this */
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;     /* amount to pad */
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); /* strlen */
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; /* Left Justify */
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 /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
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; /* amount to space pad */
00464   int zpadlen = 0; /* amount to zero pad */
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)  /* Do a sign (+/i) */
00481     signvalue = '+';
00482     else
00483       if (flags & DP_F_SPACE)
00484     signvalue = ' ';
00485   }
00486 
00487   if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
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; /* Left Justifty */
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   /* Spaces */
00516   while (spadlen > 0)
00517   {
00518     total += dopr_outch (buffer, currlen, maxlen, ' ');
00519     --spadlen;
00520   }
00521 
00522   /* Sign */
00523   if (signvalue)
00524     total += dopr_outch (buffer, currlen, maxlen, signvalue);
00525 
00526   /* Zeros */
00527   if (zpadlen > 0)
00528   {
00529     while (zpadlen > 0)
00530     {
00531       total += dopr_outch (buffer, currlen, maxlen, '0');
00532       --zpadlen;
00533     }
00534   }
00535 
00536   /* Digits */
00537   while (place > 0)
00538     total += dopr_outch (buffer, currlen, maxlen, convert[--place]);
00539 
00540   /* Left Justified spaces */
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; /* amount to pad */
00594   int zpadlen = 0;
00595   int caps = 0;
00596   int total = 0;
00597   long intpart;
00598   long fracpart;
00599 
00600   /*
00601    * AIX manpage says the default is 0, but Solaris says the default
00602    * is 6, and sprintf on AIX defaults to 6
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)  /* Do a sign (+/i) */
00613       signvalue = '+';
00614     else
00615       if (flags & DP_F_SPACE)
00616     signvalue = ' ';
00617 
00618 #if 0
00619   if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
00620 #endif
00621 
00622   intpart = (long)ufvalue;
00623 
00624   /*
00625    * Sorry, we only support 9 digits past the decimal because of our
00626    * conversion method
00627    */
00628   if (max > 9)
00629     max = 9;
00630 
00631   /* We "cheat" by converting the fractional part to integer by
00632    * multiplying by a factor of 10
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   /* Convert integer part */
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   /* Convert fractional part */
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   /* -1 for decimal point, another -1 if we are printing a sign */
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; /* Left Justifty */
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    * Decimal point.  This should probably use locale to find the correct
00701    * char to print out.
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 /* !HAVE_VSNPRINTF */
00741 
00742 #ifndef HAVE_SNPRINTF
00743 /* VARARGS3 */
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 /* !HAVE_SNPRINTF */
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 /* SNPRINTF_TEST */
00843 
00844 #endif /* !HAVE_SNPRINTF */

Generated on Tue Aug 12 03:55:42 2003 for Interreality Project - VOS by doxygen 1.3.2