"Fossies" - the Fresh Open Source Software Archive

Member "tnftp-20200705/libnetbsd/snprintf.c" (5 Jul 2020, 17491 Bytes) of package /linux/privat/tnftp-20200705.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "snprintf.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 20151004_vs_20200705.

    1 /* $NetBSD: snprintf.c,v 1.7 2020/07/05 10:08:59 lukem Exp $ */
    2 
    3 /*
    4  * Copyright Patrick Powell 1995
    5  * This code is based on code written by Patrick Powell (papowell@astart.com)
    6  * It may be used for any purpose as long as this notice remains intact
    7  * on all source code distributions
    8  */
    9 
   10 /**************************************************************
   11  * Original:
   12  * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
   13  * A bombproof version of doprnt (dopr) included.
   14  * Sigh.  This sort of thing is always nasty do deal with.  Note that
   15  * the version here does not include floating point...
   16  *
   17  * snprintf() is used instead of sprintf() as it does limit checks
   18  * for string length.  This covers a nasty loophole.
   19  *
   20  * The other functions are there to prevent NULL pointers from
   21  * causing nast effects.
   22  *
   23  * More Recently:
   24  *  Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43
   25  *  This was ugly.  It is still ugly.  I opted out of floating point
   26  *  numbers, but the formatter understands just about everything
   27  *  from the normal C string format, at least as far as I can tell from
   28  *  the Solaris 2.5 printf(3S) man page.
   29  *
   30  *  Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1
   31  *    Ok, added some minimal floating point support, which means this
   32  *    probably requires libm on most operating systems.  Don't yet
   33  *    support the exponent (e,E) and sigfig (g,G).  Also, fmtint()
   34  *    was pretty badly broken, it just wasn't being exercised in ways
   35  *    which showed it, so that's been fixed.  Also, formated the code
   36  *    to mutt conventions, and removed dead code left over from the
   37  *    original.  Also, there is now a builtin-test, just compile with:
   38  *           gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
   39  *    and run snprintf for results.
   40  *
   41  *  Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i
   42  *    The PGP code was using unsigned hexadecimal formats.
   43  *    Unfortunately, unsigned formats simply didn't work.
   44  *
   45  *  Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8
   46  *    The original code assumed that both snprintf() and vsnprintf() were
   47  *    missing.  Some systems only have snprintf() but not vsnprintf(), so
   48  *    the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
   49  *
   50  *  Andrew Tridgell (tridge@samba.org) Oct 1998
   51  *    fixed handling of %.0f
   52  *    added test for HAVE_LONG_DOUBLE
   53  *
   54  *  Luke Mewburn <lukem@NetBSD.org>, Thu Sep 30 23:28:21 EST 1999
   55  *  cleaned up formatting, autoconf tests
   56  *  added long long support
   57  *
   58  **************************************************************/
   59 
   60 #include "tnftp.h"
   61 
   62 
   63 #if defined(HAVE_LONG_DOUBLE)
   64 #define LDOUBLE long double
   65 #else
   66 #define LDOUBLE double
   67 #endif
   68 
   69 #if defined(HAVE_LONG_LONG_INT)
   70 #define LLONG long long
   71 #else
   72 #define LLONG long
   73 #endif
   74 
   75 static void dopr(char *buffer, size_t maxlen, size_t *retlen,
   76             const char *format, va_list args);
   77 static void fmtstr(char *buffer, size_t * currlen, size_t maxlen,
   78             char *value, int min, int max, int flags);
   79 static void fmtint(char *buffer, size_t * currlen, size_t maxlen,
   80             LLONG value, int base, int min, int max, int flags);
   81 static void fmtfp(char *buffer, size_t * currlen, size_t maxlen,
   82             LDOUBLE fvalue, int min, int max, int flags);
   83 static void dopr_outch(char *buffer, size_t * currlen, size_t maxlen, int c);
   84 
   85 /*
   86  * dopr(): poor man's version of doprintf
   87  */
   88 
   89 /* format read states */
   90 #define DP_S_DEFAULT    0
   91 #define DP_S_FLAGS  1
   92 #define DP_S_MIN    2
   93 #define DP_S_DOT    3
   94 #define DP_S_MAX    4
   95 #define DP_S_MOD    5
   96 #define DP_S_CONV   6
   97 #define DP_S_DONE   7
   98 
   99 /* format flags - Bits */
  100 #define DP_F_MINUS  (1 << 0)
  101 #define DP_F_PLUS   (1 << 1)
  102 #define DP_F_SPACE  (1 << 2)
  103 #define DP_F_NUM    (1 << 3)
  104 #define DP_F_ZERO   (1 << 4)
  105 #define DP_F_UP     (1 << 5)
  106 #define DP_F_UNSIGNED   (1 << 6)
  107 
  108 /* Conversion Flags */
  109 #define DP_C_SHORT  1
  110 #define DP_C_LONG   2
  111 #define DP_C_LDOUBLE    3
  112 #define DP_C_LLONG  4
  113 
  114 #define char_to_int(p) (p - '0')
  115 
  116 static void
  117 dopr(char *buffer, size_t maxlen, size_t *retlen, const char *format,
  118     va_list args)
  119 {
  120     char     ch;
  121     LLONG    value;
  122     LDOUBLE  fvalue;
  123     char    *strvalue;
  124     int  min;
  125     int  max;
  126     int  state;
  127     int  flags;
  128     int  cflags;
  129     size_t   currlen;
  130 
  131     state = DP_S_DEFAULT;
  132     flags = currlen = cflags = min = 0;
  133     max = -1;
  134     ch = *format++;
  135 
  136     while (state != DP_S_DONE) {
  137         if ((ch == '\0') || (currlen >= maxlen))
  138             state = DP_S_DONE;
  139 
  140         switch (state) {
  141         case DP_S_DEFAULT:
  142             if (ch == '%')
  143                 state = DP_S_FLAGS;
  144             else
  145                 dopr_outch(buffer, &currlen, maxlen, ch);
  146             ch = *format++;
  147             break;
  148         case DP_S_FLAGS:
  149             switch (ch) {
  150             case '-':
  151                 flags |= DP_F_MINUS;
  152                 ch = *format++;
  153                 break;
  154             case '+':
  155                 flags |= DP_F_PLUS;
  156                 ch = *format++;
  157                 break;
  158             case ' ':
  159                 flags |= DP_F_SPACE;
  160                 ch = *format++;
  161                 break;
  162             case '#':
  163                 flags |= DP_F_NUM;
  164                 ch = *format++;
  165                 break;
  166             case '0':
  167                 flags |= DP_F_ZERO;
  168                 ch = *format++;
  169                 break;
  170             default:
  171                 state = DP_S_MIN;
  172                 break;
  173             }
  174             break;
  175         case DP_S_MIN:
  176             if (isdigit((unsigned char) ch)) {
  177                 min = 10 * min + char_to_int(ch);
  178                 ch = *format++;
  179             } else if (ch == '*') {
  180                 min = va_arg(args, int);
  181                 ch = *format++;
  182                 state = DP_S_DOT;
  183             } else
  184                 state = DP_S_DOT;
  185             break;
  186         case DP_S_DOT:
  187             if (ch == '.') {
  188                 state = DP_S_MAX;
  189                 ch = *format++;
  190             } else
  191                 state = DP_S_MOD;
  192             break;
  193         case DP_S_MAX:
  194             if (isdigit((unsigned char) ch)) {
  195                 if (max < 0)
  196                     max = 0;
  197                 max = 10 * max + char_to_int(ch);
  198                 ch = *format++;
  199             } else if (ch == '*') {
  200                 max = va_arg(args, int);
  201                 ch = *format++;
  202                 state = DP_S_MOD;
  203             } else
  204                 state = DP_S_MOD;
  205             break;
  206         case DP_S_MOD:
  207             switch (ch) {
  208             case 'h':
  209                 cflags = DP_C_SHORT;
  210                 ch = *format++;
  211                 break;
  212             case 'l':
  213                 if (*format == 'l') {
  214                     cflags = DP_C_LLONG;
  215                     format++;
  216                 } else
  217                     cflags = DP_C_LONG;
  218                 ch = *format++;
  219                 break;
  220             case 'q':
  221                 cflags = DP_C_LLONG;
  222                 ch = *format++;
  223                 break;
  224             case 'L':
  225                 cflags = DP_C_LDOUBLE;
  226                 ch = *format++;
  227                 break;
  228             default:
  229                 break;
  230             }
  231             state = DP_S_CONV;
  232             break;
  233         case DP_S_CONV:
  234             switch (ch) {
  235             case 'd':
  236             case 'i':
  237                 switch (cflags) {
  238                 case DP_C_SHORT:
  239                     value = va_arg(args, int);
  240                     break;
  241                 case DP_C_LONG:
  242                     value = va_arg(args, long int);
  243                     break;
  244                 case DP_C_LLONG:
  245                     value = va_arg(args, LLONG);
  246                     break;
  247                 default:
  248                     value = va_arg(args, int);
  249                     break;
  250                 }
  251                 fmtint(buffer, &currlen, maxlen, value, 10,
  252                     min, max, flags);
  253                 break;
  254             case 'X':
  255                 flags |= DP_F_UP;
  256                 /* FALLTHROUGH */
  257             case 'x':
  258             case 'o':
  259             case 'u':
  260                 flags |= DP_F_UNSIGNED;
  261                 switch (cflags) {
  262                 case DP_C_SHORT:
  263                     value = va_arg(args, unsigned int);
  264                     break;
  265                 case DP_C_LONG:
  266                     value = (LLONG) va_arg(args,
  267                         unsigned long int);
  268                     break;
  269                 case DP_C_LLONG:
  270                     value = va_arg(args, unsigned LLONG);
  271                     break;
  272                 default:
  273                     value = (LLONG) va_arg(args,
  274                         unsigned int);
  275                     break;
  276                 }
  277                 fmtint(buffer, &currlen, maxlen, value,
  278                     ch == 'o' ? 8 : (ch == 'u' ? 10 : 16),
  279                     min, max, flags);
  280                 break;
  281             case 'f':
  282                 if (cflags == DP_C_LDOUBLE)
  283                     fvalue = va_arg(args, LDOUBLE);
  284                 else
  285                     fvalue = va_arg(args, double);
  286                 /* um, floating point? */
  287                 fmtfp(buffer, &currlen, maxlen, fvalue, min,
  288                     max, flags);
  289                 break;
  290             case 'E':
  291                 flags |= DP_F_UP;
  292             case 'e':
  293                 if (cflags == DP_C_LDOUBLE)
  294                     fvalue = va_arg(args, LDOUBLE);
  295                 else
  296                     fvalue = va_arg(args, double);
  297                 break;
  298             case 'G':
  299                 flags |= DP_F_UP;
  300             case 'g':
  301                 if (cflags == DP_C_LDOUBLE)
  302                     fvalue = va_arg(args, LDOUBLE);
  303                 else
  304                     fvalue = va_arg(args, double);
  305                 break;
  306             case 'c':
  307                 dopr_outch(buffer, &currlen, maxlen,
  308                     va_arg(args, int));
  309                 break;
  310             case 's':
  311                 strvalue = va_arg(args, char *);
  312                 if (max < 0)
  313                     max = maxlen;   /* ie, no max */
  314                 fmtstr(buffer, &currlen, maxlen, strvalue,
  315                     min, max, flags);
  316                 break;
  317             case 'p':
  318                 value = (long)va_arg(args, void *);
  319                 fmtint(buffer, &currlen, maxlen,
  320                     value, 16, min, max, flags);
  321                 break;
  322             case 'n':
  323 /* XXX */
  324                 if (cflags == DP_C_SHORT) {
  325                     short int *num;
  326                     num = va_arg(args, short int *);
  327                     *num = currlen;
  328                 } else if (cflags == DP_C_LONG) { /* XXX */
  329                     long int *num;
  330                     num = va_arg(args, long int *);
  331                     *num = (long int) currlen;
  332                 } else if (cflags == DP_C_LLONG) { /* XXX */
  333                     LLONG *num;
  334                     num = va_arg(args, LLONG *);
  335                     *num = (LLONG) currlen;
  336                 } else {
  337                     int    *num;
  338                     num = va_arg(args, int *);
  339                     *num = currlen;
  340                 }
  341                 break;
  342             case '%':
  343                 dopr_outch(buffer, &currlen, maxlen, ch);
  344                 break;
  345             case 'w':
  346                 /* not supported yet, treat as next char */
  347                 ch = *format++;
  348                 break;
  349             default:
  350                 /* Unknown, skip */
  351                 break;
  352             }
  353             ch = *format++;
  354             state = DP_S_DEFAULT;
  355             flags = cflags = min = 0;
  356             max = -1;
  357             break;
  358         case DP_S_DONE:
  359             break;
  360         default:
  361             /* hmm? */
  362             break;  /* some picky compilers need this */
  363         }
  364     }
  365     if (currlen >= maxlen - 1)
  366         currlen = maxlen - 1;
  367     buffer[currlen] = '\0';
  368     *retlen = currlen;
  369 }
  370 
  371 static void
  372 fmtstr(char *buffer, size_t *currlen, size_t maxlen, char *value,
  373     int min, int max, int flags)
  374 {
  375     int padlen, strln;  /* amount to pad */
  376     int cnt = 0;
  377 
  378     if (value == 0) {
  379         value = "<NULL>";
  380     }
  381     for (strln = 0; value[strln]; ++strln)
  382         ;   /* strlen */
  383     padlen = min - strln;
  384     if (padlen < 0)
  385         padlen = 0;
  386     if (flags & DP_F_MINUS)
  387         padlen = -padlen;   /* Left Justify */
  388 
  389     while ((padlen > 0) && (cnt < max)) {
  390         dopr_outch(buffer, currlen, maxlen, ' ');
  391         --padlen;
  392         ++cnt;
  393     }
  394     while (*value && (cnt < max)) {
  395         dopr_outch(buffer, currlen, maxlen, *value++);
  396         ++cnt;
  397     }
  398     while ((padlen < 0) && (cnt < max)) {
  399         dopr_outch(buffer, currlen, maxlen, ' ');
  400         ++padlen;
  401         ++cnt;
  402     }
  403 }
  404 /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
  405 
  406 static void
  407 fmtint(char *buffer, size_t *currlen, size_t maxlen, LLONG value, int base,
  408     int min, int max, int flags)
  409 {
  410     int     signvalue = 0;
  411     unsigned LLONG  uvalue;
  412     char        convert[20];
  413     int     place = 0;
  414     int     spadlen = 0;    /* amount to space pad */
  415     int     zpadlen = 0;    /* amount to zero pad */
  416     int     caps = 0;
  417 
  418     if (max < 0)
  419         max = 0;
  420 
  421     uvalue = value;
  422 
  423     if (!(flags & DP_F_UNSIGNED)) {
  424         if (value < 0) {
  425             signvalue = '-';
  426             uvalue = -value;
  427         } else if (flags & DP_F_PLUS)   /* Do a sign (+/i) */
  428             signvalue = '+';
  429         else if (flags & DP_F_SPACE)
  430             signvalue = ' ';
  431     }
  432     if (flags & DP_F_UP)
  433         caps = 1;   /* Should characters be upper case? */
  434 
  435     do {
  436         convert[place++] =
  437             (caps ? "0123456789ABCDEF" : "0123456789abcdef")
  438             [uvalue % (unsigned) base];
  439         uvalue = (uvalue / (unsigned) base);
  440     } while (uvalue && (place < 20));
  441     if (place == 20)
  442         place--;
  443     convert[place] = 0;
  444 
  445     zpadlen = max - place;
  446     spadlen = min - MAX(max, place) - (signvalue ? 1 : 0);
  447     if (zpadlen < 0)
  448         zpadlen = 0;
  449     if (spadlen < 0)
  450         spadlen = 0;
  451     if (flags & DP_F_ZERO) {
  452         zpadlen = MAX(zpadlen, spadlen);
  453         spadlen = 0;
  454     }
  455     if (flags & DP_F_MINUS)
  456         spadlen = -spadlen; /* Left Justifty */
  457 
  458 #ifdef DEBUG_SNPRINTF
  459     printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
  460         zpadlen, spadlen, min, max, place);
  461 #endif
  462 
  463     /* Spaces */
  464     while (spadlen > 0) {
  465         dopr_outch(buffer, currlen, maxlen, ' ');
  466         --spadlen;
  467     }
  468 
  469     /* Sign */
  470     if (signvalue)
  471         dopr_outch(buffer, currlen, maxlen, signvalue);
  472 
  473     /* Zeros */
  474     if (zpadlen > 0) {
  475         while (zpadlen > 0) {
  476             dopr_outch(buffer, currlen, maxlen, '0');
  477             --zpadlen;
  478         }
  479     }
  480     /* Digits */
  481     while (place > 0)
  482         dopr_outch(buffer, currlen, maxlen, convert[--place]);
  483 
  484     /* Left Justified spaces */
  485     while (spadlen < 0) {
  486         dopr_outch(buffer, currlen, maxlen, ' ');
  487         ++spadlen;
  488     }
  489 }
  490 
  491 static LDOUBLE
  492 abs_val(LDOUBLE value)
  493 {
  494     LDOUBLE result = value;
  495 
  496     if (value < 0)
  497         result = -value;
  498 
  499     return result;
  500 }
  501 
  502 static LDOUBLE
  503 sn_pow10(int exp)
  504 {
  505     LDOUBLE result = 1;
  506 
  507     while (exp) {
  508         result *= 10;
  509         exp--;
  510     }
  511 
  512     return result;
  513 }
  514 
  515 static long
  516 sn_round(LDOUBLE value)
  517 {
  518     long    intpart;
  519 
  520     intpart = (long) value;
  521     value = value - intpart;
  522     if (value >= 0.5)
  523         intpart++;
  524 
  525     return intpart;
  526 }
  527 
  528 static void
  529 fmtfp(char *buffer, size_t *currlen, size_t maxlen, LDOUBLE fvalue,
  530     int min, int max, int flags)
  531 {
  532     int signvalue = 0;
  533     LDOUBLE ufvalue;
  534     char    iconvert[20];
  535     char    fconvert[20];
  536     int iplace = 0;
  537     int fplace = 0;
  538     int padlen = 0; /* amount to pad */
  539     int zpadlen = 0;
  540     int caps = 0;
  541     long    intpart;
  542     long    fracpart;
  543 
  544     /* AIX manpage says the default is 0, but Solaris says the default is
  545      * 6, and sprintf on AIX defaults to 6 */
  546     if (max < 0)
  547         max = 6;
  548 
  549     ufvalue = abs_val(fvalue);
  550 
  551     if (fvalue < 0)
  552         signvalue = '-';
  553     else if (flags & DP_F_PLUS) /* Do a sign (+/i) */
  554         signvalue = '+';
  555     else if (flags & DP_F_SPACE)
  556         signvalue = ' ';
  557 
  558 #if 0
  559     if (flags & DP_F_UP)
  560         caps = 1;   /* Should characters be upper case? */
  561 #endif
  562 
  563     intpart = (long) ufvalue;
  564 
  565     /* Sorry, we only support 9 digits past the decimal because of our
  566      * conversion method */
  567     if (max > 9)
  568         max = 9;
  569 
  570     /* We "cheat" by converting the fractional part to integer by
  571      * multiplying by a factor of 10 */
  572     fracpart = sn_round((sn_pow10(max)) * (ufvalue - intpart));
  573 
  574     if (fracpart >= sn_pow10(max)) {
  575         intpart++;
  576         fracpart -= sn_pow10(max);
  577     }
  578 #ifdef DEBUG_SNPRINTF
  579     printf("fmtfp: %g %d.%d min=%d max=%d\n",
  580         (double) fvalue, intpart, fracpart, min, max);
  581 #endif
  582 
  583     /* Convert integer part */
  584     do {
  585         iconvert[iplace++] =
  586             (caps ? "0123456789ABCDEF"
  587               : "0123456789abcdef")[intpart % 10];
  588         intpart = (intpart / 10);
  589     } while (intpart && (iplace < 20));
  590     if (iplace == 20)
  591         iplace--;
  592     iconvert[iplace] = 0;
  593 
  594     /* Convert fractional part */
  595     do {
  596         fconvert[fplace++] =
  597             (caps ? "0123456789ABCDEF"
  598               : "0123456789abcdef")[fracpart % 10];
  599         fracpart = (fracpart / 10);
  600     } while (fracpart && (fplace < 20));
  601     if (fplace == 20)
  602         fplace--;
  603     fconvert[fplace] = 0;
  604 
  605     /* -1 for decimal point, another -1 if we are printing a sign */
  606     padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
  607     zpadlen = max - fplace;
  608     if (zpadlen < 0)
  609         zpadlen = 0;
  610     if (padlen < 0)
  611         padlen = 0;
  612     if (flags & DP_F_MINUS)
  613         padlen = -padlen;   /* Left Justifty */
  614 
  615     if ((flags & DP_F_ZERO) && (padlen > 0)) {
  616         if (signvalue) {
  617             dopr_outch(buffer, currlen, maxlen, signvalue);
  618             --padlen;
  619             signvalue = 0;
  620         }
  621         while (padlen > 0) {
  622             dopr_outch(buffer, currlen, maxlen, '0');
  623             --padlen;
  624         }
  625     }
  626     while (padlen > 0) {
  627         dopr_outch(buffer, currlen, maxlen, ' ');
  628         --padlen;
  629     }
  630     if (signvalue)
  631         dopr_outch(buffer, currlen, maxlen, signvalue);
  632 
  633     while (iplace > 0)
  634         dopr_outch(buffer, currlen, maxlen, iconvert[--iplace]);
  635 
  636 
  637 #ifdef DEBUG_SNPRINTF
  638     printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);
  639 #endif
  640 
  641     /*
  642          * Decimal point.  This should probably use locale to find the correct
  643          * char to print out.
  644          */
  645     if (max > 0) {
  646         dopr_outch(buffer, currlen, maxlen, '.');
  647 
  648         while (fplace > 0)
  649             dopr_outch(buffer, currlen, maxlen, fconvert[--fplace]);
  650     }
  651     while (zpadlen > 0) {
  652         dopr_outch(buffer, currlen, maxlen, '0');
  653         --zpadlen;
  654     }
  655 
  656     while (padlen < 0) {
  657         dopr_outch(buffer, currlen, maxlen, ' ');
  658         ++padlen;
  659     }
  660 }
  661 
  662 static void
  663 dopr_outch(char *buffer, size_t *currlen, size_t maxlen, int c)
  664 {
  665     if (*currlen < maxlen)
  666         buffer[(*currlen)++] = (char)c;
  667 }
  668 
  669 int
  670 vsnprintf(char *str, size_t count, const char *fmt, va_list args)
  671 {
  672     size_t retlen;
  673 
  674     str[0] = 0;
  675     dopr(str, count, &retlen, fmt, args);
  676     return (retlen);
  677 }
  678 
  679 /* VARARGS3 */
  680 int
  681 snprintf(char *str, size_t count, const char *fmt, ...)
  682 {
  683     va_list  ap;
  684     int  rv;
  685 
  686     va_start(ap, fmt);
  687     rv = vsnprintf(str, count, fmt, ap);
  688     va_end(ap);
  689     return (rv);
  690 }
  691 
  692 
  693 #ifdef TEST_SNPRINTF
  694 #ifndef LONG_STRING
  695 #define LONG_STRING 1024
  696 #endif
  697 
  698 int
  699 main(int argc, char *argv[])
  700 {
  701     char     buf1[LONG_STRING];
  702     char     buf2[LONG_STRING];
  703     char    *fp_fmt[] = {
  704             "%-1.5f",
  705             "%1.5f",
  706             "%123.9f",
  707             "%10.5f",
  708             "% 10.5f",
  709             "%+22.9f",
  710             "%+4.9f",
  711             "%01.3f",
  712             "%4f",
  713             "%3.1f",
  714             "%3.2f",
  715             "%.0f",
  716             "%.1f",
  717             NULL
  718          };
  719     double   fp_nums[] = {
  720             -1.5, 134.21, 91340.2, 341.1234, 0203.9,
  721             0.96, 0.996, 0.9996, 1.996, 4.136,
  722             0
  723          };
  724     char    *int_fmt[] = {
  725             "%-1.5d",
  726             "%1.5d",
  727             "%123.9d",
  728             "%5.5d",
  729             "%10.5d",
  730             "% 10.5d",
  731             "%+22.33d",
  732             "%01.3d",
  733             "%4d",
  734 #if defined(HAVE_LONG_LONG_INT)
  735             "%12lld",
  736 #endif
  737             NULL
  738          };
  739     LLONG    int_nums[] = {
  740             -1, 134, 91340, 341, 0203,
  741             4294967290,
  742             4294967297,
  743             0
  744          };
  745     int  x, y;
  746     int  fail = 0;
  747     int  num = 0;
  748     int  len;
  749 
  750     printf("Testing snprintf format codes against system sprintf...\n");
  751 
  752     for (x = 0; fp_fmt[x] != NULL; x++) {
  753         printf("testing %s\n", fp_fmt[x]);
  754         for (y = 0; fp_nums[y] != 0; y++) {
  755             snprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]);
  756             sprintf(buf2, fp_fmt[x], fp_nums[y]);
  757             if (strcmp(buf1, buf2)) {
  758                 printf("snprintf doesn't match Format: %s\n",
  759                     fp_fmt[x]);
  760                 printf("\tsnprintf = %s\n\tsprintf  = %s\n",
  761                     buf1, buf2);
  762                 fail++;
  763             }
  764             num++;
  765         }
  766     }
  767 
  768     for (x = 0; int_fmt[x] != NULL; x++) {
  769         printf("testing %s\n", int_fmt[x]);
  770         for (y = 0; int_nums[y] != 0; y++) {
  771             len = snprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]);
  772 printf("got %d >%s< (%d)\n", len, buf1, (int)strlen(buf1));
  773             sprintf(buf2, int_fmt[x], int_nums[y]);
  774             if (strcmp(buf1, buf2)) {
  775                 printf("snprintf doesn't match Format: %s\n",
  776                     int_fmt[x]);
  777                 printf("\tsnprintf = %s\n\tsprintf  = %s\n",
  778                     buf1, buf2);
  779                 fail++;
  780             }
  781             num++;
  782         }
  783     }
  784 
  785     printf("%d tests failed out of %d.\n", fail, num);
  786     exit(0);
  787 }
  788 #endif /* TEST_SNPRINTF */