snprintf.c
上传用户:wxp200602
上传日期:2007-10-30
资源大小:4028k
文件大小:23k
源码类别:

SNMP编程

开发平台:

Unix_Linux

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