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