snprintf.c

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  **************************************************************/
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           /* let's hope that works everywhere (mj) */
00069 # define VA_LOCAL_DECL   va_list ap
00070 # define VA_START(f)     va_start(ap, f)
00071 # define VA_SHIFT(v,t)  ;       /* no-op for ANSI */
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)  /* f is ignored! */
00078 #  define VA_SHIFT(v,t) v = va_arg(ap,t)
00079 #  define VA_END        va_end(ap)
00080 #else
00081 /*
00082  * XX ** NO VARARGS ** XX
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  * dopr(): poor man's version of doprintf
00109  */
00110 
00111 /*
00112  * format read states 
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  * format flags - Bits 
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  * Conversion Flags 
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              * Currently, we don't support Long Long, bummer 
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                  * um, floating point? 
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;       /* ie, no max */
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                  * not supported yet, treat as next char 
00365                  */
00366                 ch = *format++;
00367                 break;
00368             default:
00369                 /*
00370                  * Unknown, skip 
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              * hmm? 
00384              */
00385             break;              /* some picky compilers need this */
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;      /* amount to pad */
00399     int             cnt = 0;
00400 
00401     if (value == 0) {
00402         value = "<NULL>";
00403     }
00404 
00405     for (strln = 0; value[strln]; ++strln);     /* strlen */
00406     padlen = min - strln;
00407     if (padlen < 0)
00408         padlen = 0;
00409     if (flags & DP_F_MINUS)
00410         padlen = -padlen;       /* Left Justify */
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  * Have to handle DP_F_NUM (ie 0x and 0 alternates) 
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;        /* amount to space pad */
00441     int             zpadlen = 0;        /* amount to zero pad */
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)   /* Do a sign (+/i) */
00454             signvalue = '+';
00455         else if (flags & DP_F_SPACE)
00456             signvalue = ' ';
00457     }
00458 
00459     if (flags & DP_F_UP)
00460         caps = 1;               /* Should characters be upper case? */
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;     /* Left Justifty */
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      * Spaces 
00492      */
00493     while (spadlen > 0) {
00494         dopr_outch(buffer, currlen, maxlen, ' ');
00495         --spadlen;
00496     }
00497 
00498     /*
00499      * Sign 
00500      */
00501     if (signvalue)
00502         dopr_outch(buffer, currlen, maxlen, signvalue);
00503 
00504     /*
00505      * Zeros 
00506      */
00507     if (zpadlen > 0) {
00508         while (zpadlen > 0) {
00509             dopr_outch(buffer, currlen, maxlen, '0');
00510             --zpadlen;
00511         }
00512     }
00513 
00514     /*
00515      * Digits 
00516      */
00517     while (place > 0)
00518         dopr_outch(buffer, currlen, maxlen, convert[--place]);
00519 
00520     /*
00521      * Left Justified spaces 
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; /* amount to pad */
00577     int             zpadlen = 0;
00578     int             caps = 0;
00579     long            intpart;
00580     long            fracpart;
00581 
00582     /*
00583      * AIX manpage says the default is 0, but Solaris says the default
00584      * is 6, and sprintf on AIX defaults to 6
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) /* Do a sign (+/i) */
00594         signvalue = '+';
00595     else if (flags & DP_F_SPACE)
00596         signvalue = ' ';
00597 
00598 #if 0
00599     if (flags & DP_F_UP)
00600         caps = 1;               /* Should characters be upper case? */
00601 #endif
00602 
00603     intpart = ufvalue;
00604 
00605     /*
00606      * Sorry, we only support 9 digits past the decimal because of our 
00607      * conversion method
00608      */
00609     if (max > 9)
00610         max = 9;
00611 
00612     /*
00613      * We "cheat" by converting the fractional part to integer by
00614      * * multiplying by a factor of 10
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      * Convert integer part 
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      * Convert fractional part 
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      * -1 for decimal point, another -1 if we are printing a sign 
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;       /* Left Justifty */
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      * Decimal point.  This should probably use locale to find the correct
00687      * char to print out.
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                          /* !HAVE_VSNPRINTF */
00723 
00724 #ifndef HAVE_SNPRINTF
00725 /*
00726  * VARARGS3 
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                          /* !HAVE_SNPRINTF */
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                          /* SNPRINTF_TEST */
00830 
00831 #endif                          /* !HAVE_SNPRINTF */

net-snmpに対してSat Sep 5 13:14:27 2009に生成されました。  doxygen 1.4.7