"Fossies" - the Fresh Open Source Software Archive

Member "apr-1.7.0/strings/apr_snprintf.c" (5 Oct 2018, 43973 Bytes) of package /linux/www/apr-1.7.0.tar.bz2:


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 "apr_snprintf.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.6.5_vs_1.7.0.

    1 /* Licensed to the Apache Software Foundation (ASF) under one or more
    2  * contributor license agreements.  See the NOTICE file distributed with
    3  * this work for additional information regarding copyright ownership.
    4  * The ASF licenses this file to You under the Apache License, Version 2.0
    5  * (the "License"); you may not use this file except in compliance with
    6  * the License.  You may obtain a copy of the License at
    7  *
    8  *     http://www.apache.org/licenses/LICENSE-2.0
    9  *
   10  * Unless required by applicable law or agreed to in writing, software
   11  * distributed under the License is distributed on an "AS IS" BASIS,
   12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   13  * See the License for the specific language governing permissions and
   14  * limitations under the License.
   15  */
   16 
   17 #include "apr.h"
   18 #include "apr_private.h"
   19 
   20 #include "apr_lib.h"
   21 #include "apr_strings.h"
   22 #include "apr_network_io.h"
   23 #include "apr_portable.h"
   24 #include "apr_errno.h"
   25 #include <math.h>
   26 #if APR_HAVE_CTYPE_H
   27 #include <ctype.h>
   28 #endif
   29 #if APR_HAVE_NETINET_IN_H
   30 #include <netinet/in.h>
   31 #endif
   32 #if APR_HAVE_SYS_SOCKET_H
   33 #include <sys/socket.h>
   34 #endif
   35 #if APR_HAVE_ARPA_INET_H
   36 #include <arpa/inet.h>
   37 #endif
   38 #if APR_HAVE_LIMITS_H
   39 #include <limits.h>
   40 #endif
   41 #if APR_HAVE_STRING_H
   42 #include <string.h>
   43 #endif
   44 
   45 typedef enum {
   46     NO = 0, YES = 1
   47 } boolean_e;
   48 
   49 #ifndef FALSE
   50 #define FALSE 0
   51 #endif
   52 #ifndef TRUE
   53 #define TRUE 1
   54 #endif
   55 #define NUL '\0'
   56 
   57 static const char null_string[] = "(null)";
   58 #define S_NULL ((char *)null_string)
   59 #define S_NULL_LEN 6
   60 
   61 #define FLOAT_DIGITS 6
   62 #define EXPONENT_LENGTH 10
   63 
   64 /*
   65  * NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions
   66  *
   67  * NOTICE: this is a magic number; do not decrease it
   68  */
   69 #define NUM_BUF_SIZE 512
   70 
   71 /*
   72  * cvt - IEEE floating point formatting routines.
   73  *       Derived from UNIX V7, Copyright(C) Caldera International Inc.
   74  */
   75 
   76 /*
   77  *    apr_ecvt converts to decimal
   78  *      the number of digits is specified by ndigit
   79  *      decpt is set to the position of the decimal point
   80  *      sign is set to 0 for positive, 1 for negative
   81  */
   82 
   83 #define NDIG 80
   84 
   85 /* buf must have at least NDIG bytes */
   86 static char *apr_cvt(double arg, int ndigits, int *decpt, int *sign, 
   87                      int eflag, char *buf)
   88 {
   89     register int r2;
   90     double fi, fj;
   91     register char *p, *p1;
   92     
   93     if (ndigits >= NDIG - 1)
   94         ndigits = NDIG - 2;
   95     r2 = 0;
   96     *sign = 0;
   97     p = &buf[0];
   98     if (arg < 0) {
   99         *sign = 1;
  100         arg = -arg;
  101     }
  102     arg = modf(arg, &fi);
  103     /*
  104      * Do integer part
  105      */
  106     if (fi != 0) {
  107         p1 = &buf[NDIG];
  108         while (p1 > &buf[0] && fi != 0) {
  109             fj = modf(fi / 10, &fi);
  110             *--p1 = (int) ((fj + .03) * 10) + '0';
  111             r2++;
  112         }
  113         while (p1 < &buf[NDIG])
  114             *p++ = *p1++;
  115     }
  116     else if (arg > 0) {
  117         while ((fj = arg * 10) < 1) {
  118             arg = fj;
  119             r2--;
  120         }
  121     }
  122     p1 = &buf[ndigits];
  123     if (eflag == 0)
  124         p1 += r2;
  125     if (p1 < &buf[0]) {
  126         *decpt = -ndigits;
  127         buf[0] = '\0';
  128         return (buf);
  129     }
  130     *decpt = r2;
  131     while (p <= p1 && p < &buf[NDIG]) {
  132         arg *= 10;
  133         arg = modf(arg, &fj);
  134         *p++ = (int) fj + '0';
  135     }
  136     if (p1 >= &buf[NDIG]) {
  137         buf[NDIG - 1] = '\0';
  138         return (buf);
  139     }
  140     p = p1;
  141     *p1 += 5;
  142     while (*p1 > '9') {
  143         *p1 = '0';
  144         if (p1 > buf)
  145             ++ * --p1;
  146         else {
  147             *p1 = '1';
  148             (*decpt)++;
  149             if (eflag == 0) {
  150                 if (p > buf)
  151                     *p = '0';
  152                 p++;
  153             }
  154         }
  155     }
  156     *p = '\0';
  157     return (buf);
  158 }
  159 
  160 static char *apr_ecvt(double arg, int ndigits, int *decpt, int *sign, char *buf)
  161 {
  162     return (apr_cvt(arg, ndigits, decpt, sign, 1, buf));
  163 }
  164 
  165 static char *apr_fcvt(double arg, int ndigits, int *decpt, int *sign, char *buf)
  166 {
  167     return (apr_cvt(arg, ndigits, decpt, sign, 0, buf));
  168 }
  169 
  170 /*
  171  * apr_gcvt  - Floating output conversion to
  172  * minimal length string
  173  */
  174 
  175 static char *apr_gcvt(double number, int ndigit, char *buf, boolean_e altform)
  176 {
  177     int sign, decpt;
  178     register char *p1, *p2;
  179     register int i;
  180     char buf1[NDIG];
  181 
  182     p1 = apr_ecvt(number, ndigit, &decpt, &sign, buf1);
  183     p2 = buf;
  184     if (sign)
  185         *p2++ = '-';
  186     for (i = ndigit - 1; i > 0 && p1[i] == '0'; i--)
  187         ndigit--;
  188     if ((decpt >= 0 && decpt - ndigit > 4)
  189         || (decpt < 0 && decpt < -3)) {                /* use E-style */
  190         decpt--;
  191         *p2++ = *p1++;
  192         *p2++ = '.';
  193         for (i = 1; i < ndigit; i++)
  194             *p2++ = *p1++;
  195         *p2++ = 'e';
  196         if (decpt < 0) {
  197             decpt = -decpt;
  198             *p2++ = '-';
  199         }
  200         else
  201             *p2++ = '+';
  202         if (decpt / 100 > 0)
  203             *p2++ = decpt / 100 + '0';
  204         if (decpt / 10 > 0)
  205             *p2++ = (decpt % 100) / 10 + '0';
  206         *p2++ = decpt % 10 + '0';
  207     }
  208     else {
  209         if (decpt <= 0) {
  210             if (*p1 != '0')
  211                 *p2++ = '.';
  212             while (decpt < 0) {
  213                 decpt++;
  214                 *p2++ = '0';
  215             }
  216         }
  217         for (i = 1; i <= ndigit; i++) {
  218             *p2++ = *p1++;
  219             if (i == decpt)
  220                 *p2++ = '.';
  221         }
  222         if (ndigit < decpt) {
  223             while (ndigit++ < decpt)
  224                 *p2++ = '0';
  225             *p2++ = '.';
  226         }
  227     }
  228     if (p2[-1] == '.' && !altform)
  229         p2--;
  230     *p2 = '\0';
  231     return (buf);
  232 }
  233 
  234 /*
  235  * The INS_CHAR macro inserts a character in the buffer and writes
  236  * the buffer back to disk if necessary
  237  * It uses the char pointers sp and bep:
  238  *      sp points to the next available character in the buffer
  239  *      bep points to the end-of-buffer+1
  240  * While using this macro, note that the nextb pointer is NOT updated.
  241  *
  242  * NOTE: Evaluation of the c argument should not have any side-effects
  243  */
  244 #define INS_CHAR(c, sp, bep, cc)                    \
  245 {                                                   \
  246     if (sp) {                                       \
  247         if (sp >= bep) {                            \
  248             vbuff->curpos = sp;                     \
  249             if (flush_func(vbuff))                  \
  250                 return -1;                          \
  251             sp = vbuff->curpos;                     \
  252             bep = vbuff->endpos;                    \
  253         }                                           \
  254         *sp++ = (c);                                \
  255     }                                               \
  256     cc++;                                           \
  257 }
  258 
  259 #define NUM(c) (c - '0')
  260 
  261 #define STR_TO_DEC(str, num)                        \
  262     num = NUM(*str++);                              \
  263     while (apr_isdigit(*str))                       \
  264     {                                               \
  265         num *= 10 ;                                 \
  266         num += NUM(*str++);                         \
  267     }
  268 
  269 /*
  270  * This macro does zero padding so that the precision
  271  * requirement is satisfied. The padding is done by
  272  * adding '0's to the left of the string that is going
  273  * to be printed. We don't allow precision to be large
  274  * enough that we continue past the start of s.
  275  *
  276  * NOTE: this makes use of the magic info that s is
  277  * always based on num_buf with a size of NUM_BUF_SIZE.
  278  */
  279 #define FIX_PRECISION(adjust, precision, s, s_len)  \
  280     if (adjust) {                                   \
  281         apr_size_t p = (precision + 1 < NUM_BUF_SIZE) \
  282                      ? precision : NUM_BUF_SIZE - 1;  \
  283         while (s_len < p)                           \
  284         {                                           \
  285             *--s = '0';                             \
  286             s_len++;                                \
  287         }                                           \
  288     }
  289 
  290 /*
  291  * Macro that does padding. The padding is done by printing
  292  * the character ch.
  293  */
  294 #define PAD(width, len, ch)                         \
  295 do                                                  \
  296 {                                                   \
  297     INS_CHAR(ch, sp, bep, cc);                      \
  298     width--;                                        \
  299 }                                                   \
  300 while (width > len)
  301 
  302 /*
  303  * Prefix the character ch to the string str
  304  * Increase length
  305  * Set the has_prefix flag
  306  */
  307 #define PREFIX(str, length, ch)                     \
  308     *--str = ch;                                    \
  309     length++;                                       \
  310     has_prefix=YES;
  311 
  312 
  313 /*
  314  * Convert num to its decimal format.
  315  * Return value:
  316  *   - a pointer to a string containing the number (no sign)
  317  *   - len contains the length of the string
  318  *   - is_negative is set to TRUE or FALSE depending on the sign
  319  *     of the number (always set to FALSE if is_unsigned is TRUE)
  320  *
  321  * The caller provides a buffer for the string: that is the buf_end argument
  322  * which is a pointer to the END of the buffer + 1 (i.e. if the buffer
  323  * is declared as buf[ 100 ], buf_end should be &buf[ 100 ])
  324  *
  325  * Note: we have 2 versions. One is used when we need to use quads
  326  * (conv_10_quad), the other when we don't (conv_10). We're assuming the
  327  * latter is faster.
  328  */
  329 static char *conv_10(register apr_int32_t num, register int is_unsigned,
  330                      register int *is_negative, char *buf_end,
  331                      register apr_size_t *len)
  332 {
  333     register char *p = buf_end;
  334     register apr_uint32_t magnitude = num;
  335 
  336     if (is_unsigned) {
  337         *is_negative = FALSE;
  338     }
  339     else {
  340         *is_negative = (num < 0);
  341 
  342         /*
  343          * On a 2's complement machine, negating the most negative integer 
  344          * results in a number that cannot be represented as a signed integer.
  345          * Here is what we do to obtain the number's magnitude:
  346          *      a. add 1 to the number
  347          *      b. negate it (becomes positive)
  348          *      c. convert it to unsigned
  349          *      d. add 1
  350          */
  351         if (*is_negative) {
  352             apr_int32_t t = num + 1;
  353             magnitude = ((apr_uint32_t) -t) + 1;
  354         }
  355     }
  356 
  357     /*
  358      * We use a do-while loop so that we write at least 1 digit 
  359      */
  360     do {
  361         register apr_uint32_t new_magnitude = magnitude / 10;
  362 
  363         *--p = (char) (magnitude - new_magnitude * 10 + '0');
  364         magnitude = new_magnitude;
  365     }
  366     while (magnitude);
  367 
  368     *len = buf_end - p;
  369     return (p);
  370 }
  371 
  372 static char *conv_10_quad(apr_int64_t num, register int is_unsigned,
  373                      register int *is_negative, char *buf_end,
  374                      register apr_size_t *len)
  375 {
  376     register char *p = buf_end;
  377     apr_uint64_t magnitude = num;
  378 
  379     /*
  380      * We see if we can use the faster non-quad version by checking the
  381      * number against the largest long value it can be. If <=, we
  382      * punt to the quicker version.
  383      */
  384     if ((magnitude <= APR_UINT32_MAX && is_unsigned)
  385         || (num <= APR_INT32_MAX && num >= APR_INT32_MIN && !is_unsigned))
  386             return(conv_10((apr_int32_t)num, is_unsigned, is_negative, buf_end, len));
  387 
  388     if (is_unsigned) {
  389         *is_negative = FALSE;
  390     }
  391     else {
  392         *is_negative = (num < 0);
  393 
  394         /*
  395          * On a 2's complement machine, negating the most negative integer 
  396          * results in a number that cannot be represented as a signed integer.
  397          * Here is what we do to obtain the number's magnitude:
  398          *      a. add 1 to the number
  399          *      b. negate it (becomes positive)
  400          *      c. convert it to unsigned
  401          *      d. add 1
  402          */
  403         if (*is_negative) {
  404             apr_int64_t t = num + 1;
  405             magnitude = ((apr_uint64_t) -t) + 1;
  406         }
  407     }
  408 
  409     /*
  410      * We use a do-while loop so that we write at least 1 digit 
  411      */
  412     do {
  413         apr_uint64_t new_magnitude = magnitude / 10;
  414 
  415         *--p = (char) (magnitude - new_magnitude * 10 + '0');
  416         magnitude = new_magnitude;
  417     }
  418     while (magnitude);
  419 
  420     *len = buf_end - p;
  421     return (p);
  422 }
  423 
  424 static char *conv_in_addr(struct in_addr *ia, char *buf_end, apr_size_t *len)
  425 {
  426     unsigned addr = ntohl(ia->s_addr);
  427     char *p = buf_end;
  428     int is_negative;
  429     apr_size_t sub_len;
  430 
  431     p = conv_10((addr & 0x000000FF)      , TRUE, &is_negative, p, &sub_len);
  432     *--p = '.';
  433     p = conv_10((addr & 0x0000FF00) >>  8, TRUE, &is_negative, p, &sub_len);
  434     *--p = '.';
  435     p = conv_10((addr & 0x00FF0000) >> 16, TRUE, &is_negative, p, &sub_len);
  436     *--p = '.';
  437     p = conv_10((addr & 0xFF000000) >> 24, TRUE, &is_negative, p, &sub_len);
  438 
  439     *len = buf_end - p;
  440     return (p);
  441 }
  442 
  443 
  444 /* Must be passed a buffer of size NUM_BUF_SIZE where buf_end points
  445  * to 1 byte past the end of the buffer. */
  446 static char *conv_apr_sockaddr(apr_sockaddr_t *sa, char *buf_end, apr_size_t *len)
  447 {
  448     char *p = buf_end;
  449     int is_negative;
  450     apr_size_t sub_len;
  451     char *ipaddr_str;
  452 
  453     p = conv_10(sa->port, TRUE, &is_negative, p, &sub_len);
  454     *--p = ':';
  455     ipaddr_str = buf_end - NUM_BUF_SIZE;
  456     if (apr_sockaddr_ip_getbuf(ipaddr_str, sa->addr_str_len, sa)) {
  457         /* Should only fail if the buffer is too small, which it
  458          * should not be; but fail safe anyway: */
  459         *--p = '?';
  460         *len = buf_end - p;
  461         return p;
  462     }
  463     sub_len = strlen(ipaddr_str);
  464 #if APR_HAVE_IPV6
  465     if (sa->family == APR_INET6 &&
  466         !IN6_IS_ADDR_V4MAPPED(&sa->sa.sin6.sin6_addr)) {
  467         *(p - 1) = ']';
  468         p -= sub_len + 2;
  469         *p = '[';
  470         memcpy(p + 1, ipaddr_str, sub_len);
  471     }
  472     else
  473 #endif
  474     {
  475         p -= sub_len;
  476         memcpy(p, ipaddr_str, sub_len);
  477     }
  478 
  479     *len = buf_end - p;
  480     return (p);
  481 }
  482 
  483 
  484 
  485 #if APR_HAS_THREADS
  486 static char *conv_os_thread_t(apr_os_thread_t *tid, char *buf_end, apr_size_t *len)
  487 {
  488     union {
  489         apr_os_thread_t tid;
  490         apr_uint64_t u64;
  491         apr_uint32_t u32;
  492     } u;
  493     int is_negative;
  494 
  495     u.tid = *tid;
  496     switch(sizeof(u.tid)) {
  497     case sizeof(apr_int32_t):
  498         return conv_10(u.u32, TRUE, &is_negative, buf_end, len);
  499     case sizeof(apr_int64_t):
  500         return conv_10_quad(u.u64, TRUE, &is_negative, buf_end, len);
  501     default:
  502         /* not implemented; stick 0 in the buffer */
  503         return conv_10(0, TRUE, &is_negative, buf_end, len);
  504     }
  505 }
  506 #endif
  507 
  508 
  509 
  510 /*
  511  * Convert a floating point number to a string formats 'f', 'e' or 'E'.
  512  * The result is placed in buf, and len denotes the length of the string
  513  * The sign is returned in the is_negative argument (and is not placed
  514  * in buf).
  515  */
  516 static char *conv_fp(register char format, register double num,
  517     boolean_e add_dp, int precision, int *is_negative,
  518     char *buf, apr_size_t *len)
  519 {
  520     register char *s = buf;
  521     register char *p;
  522     int decimal_point;
  523     char buf1[NDIG];
  524 
  525     if (format == 'f')
  526         p = apr_fcvt(num, precision, &decimal_point, is_negative, buf1);
  527     else /* either e or E format */
  528         p = apr_ecvt(num, precision + 1, &decimal_point, is_negative, buf1);
  529 
  530     /*
  531      * Check for Infinity and NaN
  532      */
  533     if (apr_isalpha(*p)) {
  534         *len = strlen(p);
  535         memcpy(buf, p, *len + 1);
  536         *is_negative = FALSE;
  537         return (buf);
  538     }
  539 
  540     if (format == 'f') {
  541         if (decimal_point <= 0) {
  542             *s++ = '0';
  543             if (precision > 0) {
  544                 *s++ = '.';
  545                 while (decimal_point++ < 0)
  546                     *s++ = '0';
  547             }
  548             else if (add_dp)
  549                 *s++ = '.';
  550         }
  551         else {
  552             while (decimal_point-- > 0)
  553                 *s++ = *p++;
  554             if (precision > 0 || add_dp)
  555                 *s++ = '.';
  556         }
  557     }
  558     else {
  559         *s++ = *p++;
  560         if (precision > 0 || add_dp)
  561             *s++ = '.';
  562     }
  563 
  564     /*
  565      * copy the rest of p, the NUL is NOT copied
  566      */
  567     while (*p)
  568         *s++ = *p++;
  569 
  570     if (format != 'f') {
  571         char temp[EXPONENT_LENGTH];        /* for exponent conversion */
  572         apr_size_t t_len;
  573         int exponent_is_negative;
  574 
  575         *s++ = format;                /* either e or E */
  576         decimal_point--;
  577         if (decimal_point != 0) {
  578             p = conv_10((apr_int32_t) decimal_point, FALSE, &exponent_is_negative,
  579                         &temp[EXPONENT_LENGTH], &t_len);
  580             *s++ = exponent_is_negative ? '-' : '+';
  581 
  582             /*
  583              * Make sure the exponent has at least 2 digits
  584              */
  585             if (t_len == 1)
  586                 *s++ = '0';
  587             while (t_len--)
  588                 *s++ = *p++;
  589         }
  590         else {
  591             *s++ = '+';
  592             *s++ = '0';
  593             *s++ = '0';
  594         }
  595     }
  596 
  597     *len = s - buf;
  598     return (buf);
  599 }
  600 
  601 
  602 /*
  603  * Convert num to a base X number where X is a power of 2. nbits determines X.
  604  * For example, if nbits is 3, we do base 8 conversion
  605  * Return value:
  606  *      a pointer to a string containing the number
  607  *
  608  * The caller provides a buffer for the string: that is the buf_end argument
  609  * which is a pointer to the END of the buffer + 1 (i.e. if the buffer
  610  * is declared as buf[ 100 ], buf_end should be &buf[ 100 ])
  611  *
  612  * As with conv_10, we have a faster version which is used when
  613  * the number isn't quad size.
  614  */
  615 static char *conv_p2(register apr_uint32_t num, register int nbits,
  616                      char format, char *buf_end, register apr_size_t *len)
  617 {
  618     register int mask = (1 << nbits) - 1;
  619     register char *p = buf_end;
  620     static const char low_digits[] = "0123456789abcdef";
  621     static const char upper_digits[] = "0123456789ABCDEF";
  622     register const char *digits = (format == 'X') ? upper_digits : low_digits;
  623 
  624     do {
  625         *--p = digits[num & mask];
  626         num >>= nbits;
  627     }
  628     while (num);
  629 
  630     *len = buf_end - p;
  631     return (p);
  632 }
  633 
  634 static char *conv_p2_quad(apr_uint64_t num, register int nbits,
  635                      char format, char *buf_end, register apr_size_t *len)
  636 {
  637     register int mask = (1 << nbits) - 1;
  638     register char *p = buf_end;
  639     static const char low_digits[] = "0123456789abcdef";
  640     static const char upper_digits[] = "0123456789ABCDEF";
  641     register const char *digits = (format == 'X') ? upper_digits : low_digits;
  642 
  643     if (num <= APR_UINT32_MAX)
  644         return(conv_p2((apr_uint32_t)num, nbits, format, buf_end, len));
  645 
  646     do {
  647         *--p = digits[num & mask];
  648         num >>= nbits;
  649     }
  650     while (num);
  651 
  652     *len = buf_end - p;
  653     return (p);
  654 }
  655 
  656 #if APR_HAS_THREADS
  657 static char *conv_os_thread_t_hex(apr_os_thread_t *tid, char *buf_end, apr_size_t *len)
  658 {
  659     union {
  660         apr_os_thread_t tid;
  661         apr_uint64_t u64;
  662         apr_uint32_t u32;
  663     } u;
  664     int is_negative;
  665 
  666     u.tid = *tid;
  667     switch(sizeof(u.tid)) {
  668     case sizeof(apr_int32_t):
  669         return conv_p2(u.u32, 4, 'x', buf_end, len);
  670     case sizeof(apr_int64_t):
  671         return conv_p2_quad(u.u64, 4, 'x', buf_end, len);
  672     default:
  673         /* not implemented; stick 0 in the buffer */
  674         return conv_10(0, TRUE, &is_negative, buf_end, len);
  675     }
  676 }
  677 #endif
  678 
  679 /*
  680  * Do format conversion placing the output in buffer
  681  */
  682 APR_DECLARE(int) apr_vformatter(int (*flush_func)(apr_vformatter_buff_t *),
  683     apr_vformatter_buff_t *vbuff, const char *fmt, va_list ap)
  684 {
  685     register char *sp;
  686     register char *bep;
  687     register int cc = 0;
  688     register apr_size_t i;
  689 
  690     register char *s = NULL;
  691     char *q;
  692     apr_size_t s_len = 0;
  693 
  694     register apr_size_t min_width = 0;
  695     apr_size_t precision = 0;
  696     enum {
  697         LEFT, RIGHT
  698     } adjust;
  699     char pad_char;
  700     char prefix_char;
  701 
  702     double fp_num;
  703     apr_int64_t i_quad = 0;
  704     apr_uint64_t ui_quad;
  705     apr_int32_t i_num = 0;
  706     apr_uint32_t ui_num = 0;
  707 
  708     char num_buf[NUM_BUF_SIZE];
  709     char char_buf[2];                /* for printing %% and %<unknown> */
  710 
  711     enum var_type_enum {
  712             IS_QUAD, IS_LONG, IS_SHORT, IS_INT
  713     };
  714     enum var_type_enum var_type = IS_INT;
  715 
  716     /*
  717      * Flag variables
  718      */
  719     boolean_e alternate_form;
  720     boolean_e print_sign;
  721     boolean_e print_blank;
  722     boolean_e adjust_precision;
  723     boolean_e adjust_width;
  724     int is_negative;
  725 
  726     sp = vbuff->curpos;
  727     bep = vbuff->endpos;
  728 
  729     while (*fmt) {
  730         if (*fmt != '%') {
  731             INS_CHAR(*fmt, sp, bep, cc);
  732         }
  733         else {
  734             /*
  735              * Default variable settings
  736              */
  737             boolean_e print_something = YES;
  738             adjust = RIGHT;
  739             alternate_form = print_sign = print_blank = NO;
  740             pad_char = ' ';
  741             prefix_char = NUL;
  742 
  743             fmt++;
  744 
  745             /*
  746              * Try to avoid checking for flags, width or precision
  747              */
  748             if (!apr_islower(*fmt)) {
  749                 /*
  750                  * Recognize flags: -, #, BLANK, +
  751                  */
  752                 for (;; fmt++) {
  753                     if (*fmt == '-')
  754                         adjust = LEFT;
  755                     else if (*fmt == '+')
  756                         print_sign = YES;
  757                     else if (*fmt == '#')
  758                         alternate_form = YES;
  759                     else if (*fmt == ' ')
  760                         print_blank = YES;
  761                     else if (*fmt == '0')
  762                         pad_char = '0';
  763                     else
  764                         break;
  765                 }
  766 
  767                 /*
  768                  * Check if a width was specified
  769                  */
  770                 if (apr_isdigit(*fmt)) {
  771                     STR_TO_DEC(fmt, min_width);
  772                     adjust_width = YES;
  773                 }
  774                 else if (*fmt == '*') {
  775                     int v = va_arg(ap, int);
  776                     fmt++;
  777                     adjust_width = YES;
  778                     if (v < 0) {
  779                         adjust = LEFT;
  780                         min_width = (apr_size_t)(-v);
  781                     }
  782                     else
  783                         min_width = (apr_size_t)v;
  784                 }
  785                 else
  786                     adjust_width = NO;
  787 
  788                 /*
  789                  * Check if a precision was specified
  790                  */
  791                 if (*fmt == '.') {
  792                     adjust_precision = YES;
  793                     fmt++;
  794                     if (apr_isdigit(*fmt)) {
  795                         STR_TO_DEC(fmt, precision);
  796                     }
  797                     else if (*fmt == '*') {
  798                         int v = va_arg(ap, int);
  799                         fmt++;
  800                         precision = (v < 0) ? 0 : (apr_size_t)v;
  801                     }
  802                     else
  803                         precision = 0;
  804                 }
  805                 else
  806                     adjust_precision = NO;
  807             }
  808             else
  809                 adjust_precision = adjust_width = NO;
  810 
  811             /*
  812              * Modifier check.  In same cases, APR_OFF_T_FMT can be
  813              * "lld" and APR_INT64_T_FMT can be "ld" (that is, off_t is
  814              * "larger" than int64). Check that case 1st.
  815              * Note that if APR_OFF_T_FMT is "d",
  816              * the first if condition is never true. If APR_INT64_T_FMT
  817              * is "d' then the second if condition is never true.
  818              */
  819             if ((sizeof(APR_OFF_T_FMT) > sizeof(APR_INT64_T_FMT)) &&
  820                 ((sizeof(APR_OFF_T_FMT) == 4 &&
  821                  fmt[0] == APR_OFF_T_FMT[0] &&
  822                  fmt[1] == APR_OFF_T_FMT[1]) ||
  823                 (sizeof(APR_OFF_T_FMT) == 3 &&
  824                  fmt[0] == APR_OFF_T_FMT[0]) ||
  825                 (sizeof(APR_OFF_T_FMT) > 4 &&
  826                  strncmp(fmt, APR_OFF_T_FMT, 
  827                          sizeof(APR_OFF_T_FMT) - 2) == 0))) {
  828                 /* Need to account for trailing 'd' and null in sizeof() */
  829                 var_type = IS_QUAD;
  830                 fmt += (sizeof(APR_OFF_T_FMT) - 2);
  831             }
  832             else if ((sizeof(APR_INT64_T_FMT) == 4 &&
  833                  fmt[0] == APR_INT64_T_FMT[0] &&
  834                  fmt[1] == APR_INT64_T_FMT[1]) ||
  835                 (sizeof(APR_INT64_T_FMT) == 3 &&
  836                  fmt[0] == APR_INT64_T_FMT[0]) ||
  837                 (sizeof(APR_INT64_T_FMT) > 4 &&
  838                  strncmp(fmt, APR_INT64_T_FMT, 
  839                          sizeof(APR_INT64_T_FMT) - 2) == 0)) {
  840                 /* Need to account for trailing 'd' and null in sizeof() */
  841                 var_type = IS_QUAD;
  842                 fmt += (sizeof(APR_INT64_T_FMT) - 2);
  843             }
  844             else if (*fmt == 'q') {
  845                 var_type = IS_QUAD;
  846                 fmt++;
  847             }
  848             else if (*fmt == 'l') {
  849                 var_type = IS_LONG;
  850                 fmt++;
  851             }
  852             else if (*fmt == 'h') {
  853                 var_type = IS_SHORT;
  854                 fmt++;
  855             }
  856             else {
  857                 var_type = IS_INT;
  858             }
  859 
  860             /*
  861              * Argument extraction and printing.
  862              * First we determine the argument type.
  863              * Then, we convert the argument to a string.
  864              * On exit from the switch, s points to the string that
  865              * must be printed, s_len has the length of the string
  866              * The precision requirements, if any, are reflected in s_len.
  867              *
  868              * NOTE: pad_char may be set to '0' because of the 0 flag.
  869              *   It is reset to ' ' by non-numeric formats
  870              */
  871             switch (*fmt) {
  872             case 'u':
  873                 if (var_type == IS_QUAD) {
  874                     i_quad = va_arg(ap, apr_uint64_t);
  875                     s = conv_10_quad(i_quad, 1, &is_negative,
  876                             &num_buf[NUM_BUF_SIZE], &s_len);
  877                 }
  878                 else {
  879                     if (var_type == IS_LONG)
  880                         i_num = (apr_int32_t) va_arg(ap, apr_uint32_t);
  881                     else if (var_type == IS_SHORT)
  882                         i_num = (apr_int32_t) (unsigned short) va_arg(ap, unsigned int);
  883                     else
  884                         i_num = (apr_int32_t) va_arg(ap, unsigned int);
  885                     s = conv_10(i_num, 1, &is_negative,
  886                             &num_buf[NUM_BUF_SIZE], &s_len);
  887                 }
  888                 FIX_PRECISION(adjust_precision, precision, s, s_len);
  889                 break;
  890 
  891             case 'd':
  892             case 'i':
  893                 if (var_type == IS_QUAD) {
  894                     i_quad = va_arg(ap, apr_int64_t);
  895                     s = conv_10_quad(i_quad, 0, &is_negative,
  896                             &num_buf[NUM_BUF_SIZE], &s_len);
  897                 }
  898                 else {
  899                     if (var_type == IS_LONG)
  900                         i_num = va_arg(ap, apr_int32_t);
  901                     else if (var_type == IS_SHORT)
  902                         i_num = (short) va_arg(ap, int);
  903                     else
  904                         i_num = va_arg(ap, int);
  905                     s = conv_10(i_num, 0, &is_negative,
  906                             &num_buf[NUM_BUF_SIZE], &s_len);
  907                 }
  908                 FIX_PRECISION(adjust_precision, precision, s, s_len);
  909 
  910                 if (is_negative)
  911                     prefix_char = '-';
  912                 else if (print_sign)
  913                     prefix_char = '+';
  914                 else if (print_blank)
  915                     prefix_char = ' ';
  916                 break;
  917 
  918 
  919             case 'o':
  920                 if (var_type == IS_QUAD) {
  921                     ui_quad = va_arg(ap, apr_uint64_t);
  922                     s = conv_p2_quad(ui_quad, 3, *fmt,
  923                             &num_buf[NUM_BUF_SIZE], &s_len);
  924                 }
  925                 else {
  926                     if (var_type == IS_LONG)
  927                         ui_num = va_arg(ap, apr_uint32_t);
  928                     else if (var_type == IS_SHORT)
  929                         ui_num = (unsigned short) va_arg(ap, unsigned int);
  930                     else
  931                         ui_num = va_arg(ap, unsigned int);
  932                     s = conv_p2(ui_num, 3, *fmt,
  933                             &num_buf[NUM_BUF_SIZE], &s_len);
  934                 }
  935                 FIX_PRECISION(adjust_precision, precision, s, s_len);
  936                 if (alternate_form && *s != '0') {
  937                     *--s = '0';
  938                     s_len++;
  939                 }
  940                 break;
  941 
  942 
  943             case 'x':
  944             case 'X':
  945                 if (var_type == IS_QUAD) {
  946                     ui_quad = va_arg(ap, apr_uint64_t);
  947                     s = conv_p2_quad(ui_quad, 4, *fmt,
  948                             &num_buf[NUM_BUF_SIZE], &s_len);
  949                 }
  950                 else {
  951                     if (var_type == IS_LONG)
  952                         ui_num = va_arg(ap, apr_uint32_t);
  953                     else if (var_type == IS_SHORT)
  954                         ui_num = (unsigned short) va_arg(ap, unsigned int);
  955                     else
  956                         ui_num = va_arg(ap, unsigned int);
  957                     s = conv_p2(ui_num, 4, *fmt,
  958                             &num_buf[NUM_BUF_SIZE], &s_len);
  959                 }
  960                 FIX_PRECISION(adjust_precision, precision, s, s_len);
  961                 if (alternate_form && ui_num != 0) {
  962                     *--s = *fmt;        /* 'x' or 'X' */
  963                     *--s = '0';
  964                     s_len += 2;
  965                 }
  966                 break;
  967 
  968 
  969             case 's':
  970                 s = va_arg(ap, char *);
  971                 if (s != NULL) {
  972                     if (!adjust_precision) {
  973                         s_len = strlen(s);
  974                     }
  975                     else {
  976                         /* From the C library standard in section 7.9.6.1:
  977                          * ...if the precision is specified, no more then
  978                          * that many characters are written.  If the
  979                          * precision is not specified or is greater
  980                          * than the size of the array, the array shall
  981                          * contain a null character.
  982                          *
  983                          * My reading is is precision is specified and
  984                          * is less then or equal to the size of the
  985                          * array, no null character is required.  So
  986                          * we can't do a strlen.
  987                          *
  988                          * This figures out the length of the string
  989                          * up to the precision.  Once it's long enough
  990                          * for the specified precision, we don't care
  991                          * anymore.
  992                          *
  993                          * NOTE: you must do the length comparison
  994                          * before the check for the null character.
  995                          * Otherwise, you'll check one beyond the
  996                          * last valid character.
  997                          */
  998                         const char *walk;
  999 
 1000                         for (walk = s, s_len = 0;
 1001                              (s_len < precision) && (*walk != '\0');
 1002                              ++walk, ++s_len);
 1003                     }
 1004                 }
 1005                 else {
 1006                     s = S_NULL;
 1007                     s_len = S_NULL_LEN;
 1008                 }
 1009                 pad_char = ' ';
 1010                 break;
 1011 
 1012 
 1013             case 'f':
 1014             case 'e':
 1015             case 'E':
 1016                 fp_num = va_arg(ap, double);
 1017                 /*
 1018                  * We use &num_buf[ 1 ], so that we have room for the sign
 1019                  */
 1020                 s = NULL;
 1021 #ifdef HAVE_ISNAN
 1022                 if (isnan(fp_num)) {
 1023                     s = "nan";
 1024                     s_len = 3;
 1025                 }
 1026 #endif
 1027 #ifdef HAVE_ISINF
 1028                 if (!s && isinf(fp_num)) {
 1029                     s = "inf";
 1030                     s_len = 3;
 1031                 }
 1032 #endif
 1033                 if (!s) {
 1034                     s = conv_fp(*fmt, fp_num, alternate_form,
 1035                                 (int)((adjust_precision == NO) ? FLOAT_DIGITS : precision),
 1036                                 &is_negative, &num_buf[1], &s_len);
 1037                     if (is_negative)
 1038                         prefix_char = '-';
 1039                     else if (print_sign)
 1040                         prefix_char = '+';
 1041                     else if (print_blank)
 1042                         prefix_char = ' ';
 1043                 }
 1044                 break;
 1045 
 1046 
 1047             case 'g':
 1048             case 'G':
 1049                 if (adjust_precision == NO)
 1050                     precision = FLOAT_DIGITS;
 1051                 else if (precision == 0)
 1052                     precision = 1;
 1053                 /*
 1054                  * * We use &num_buf[ 1 ], so that we have room for the sign
 1055                  */
 1056                 s = apr_gcvt(va_arg(ap, double), (int) precision, &num_buf[1],
 1057                             alternate_form);
 1058                 if (*s == '-')
 1059                     prefix_char = *s++;
 1060                 else if (print_sign)
 1061                     prefix_char = '+';
 1062                 else if (print_blank)
 1063                     prefix_char = ' ';
 1064 
 1065                 s_len = strlen(s);
 1066 
 1067                 if (alternate_form && (q = strchr(s, '.')) == NULL) {
 1068                     s[s_len++] = '.';
 1069                     s[s_len] = '\0'; /* delimit for following strchr() */
 1070                 }
 1071                 if (*fmt == 'G' && (q = strchr(s, 'e')) != NULL)
 1072                     *q = 'E';
 1073                 break;
 1074 
 1075 
 1076             case 'c':
 1077                 char_buf[0] = (char) (va_arg(ap, int));
 1078                 s = &char_buf[0];
 1079                 s_len = 1;
 1080                 pad_char = ' ';
 1081                 break;
 1082 
 1083 
 1084             case '%':
 1085                 char_buf[0] = '%';
 1086                 s = &char_buf[0];
 1087                 s_len = 1;
 1088                 pad_char = ' ';
 1089                 break;
 1090 
 1091 
 1092             case 'n':
 1093                 if (var_type == IS_QUAD)
 1094                     *(va_arg(ap, apr_int64_t *)) = cc;
 1095                 else if (var_type == IS_LONG)
 1096                     *(va_arg(ap, long *)) = cc;
 1097                 else if (var_type == IS_SHORT)
 1098                     *(va_arg(ap, short *)) = cc;
 1099                 else
 1100                     *(va_arg(ap, int *)) = cc;
 1101                 print_something = NO;
 1102                 break;
 1103 
 1104                 /*
 1105                  * This is where we extend the printf format, with a second
 1106                  * type specifier
 1107                  */
 1108             case 'p':
 1109                 switch(*++fmt) {
 1110                 /*
 1111                  * If the pointer size is equal to or smaller than the size
 1112                  * of the largest unsigned int, we convert the pointer to a
 1113                  * hex number, otherwise we print "%p" to indicate that we
 1114                  * don't handle "%p".
 1115                  */
 1116                 case 'p':
 1117 #if APR_SIZEOF_VOIDP == 8
 1118                     if (sizeof(void *) <= sizeof(apr_uint64_t)) {
 1119                         ui_quad = (apr_uint64_t) va_arg(ap, void *);
 1120                         s = conv_p2_quad(ui_quad, 4, 'x',
 1121                                 &num_buf[NUM_BUF_SIZE], &s_len);
 1122                     }
 1123 #else
 1124                     if (sizeof(void *) <= sizeof(apr_uint32_t)) {
 1125                         ui_num = (apr_uint32_t) va_arg(ap, void *);
 1126                         s = conv_p2(ui_num, 4, 'x',
 1127                                 &num_buf[NUM_BUF_SIZE], &s_len);
 1128                     }
 1129 #endif
 1130                     else {
 1131                         s = "%p";
 1132                         s_len = 2;
 1133                         prefix_char = NUL;
 1134                     }
 1135                     pad_char = ' ';
 1136                     break;
 1137 
 1138                 /* print an apr_sockaddr_t as a.b.c.d:port */
 1139                 case 'I':
 1140                 {
 1141                     apr_sockaddr_t *sa;
 1142 
 1143                     sa = va_arg(ap, apr_sockaddr_t *);
 1144                     if (sa != NULL) {
 1145                         s = conv_apr_sockaddr(sa, &num_buf[NUM_BUF_SIZE], &s_len);
 1146                         if (adjust_precision && precision < s_len)
 1147                             s_len = precision;
 1148                     }
 1149                     else {
 1150                         s = S_NULL;
 1151                         s_len = S_NULL_LEN;
 1152                     }
 1153                     pad_char = ' ';
 1154                 }
 1155                 break;
 1156 
 1157                 /* print a struct in_addr as a.b.c.d */
 1158                 case 'A':
 1159                 {
 1160                     struct in_addr *ia;
 1161 
 1162                     ia = va_arg(ap, struct in_addr *);
 1163                     if (ia != NULL) {
 1164                         s = conv_in_addr(ia, &num_buf[NUM_BUF_SIZE], &s_len);
 1165                         if (adjust_precision && precision < s_len)
 1166                             s_len = precision;
 1167                     }
 1168                     else {
 1169                         s = S_NULL;
 1170                         s_len = S_NULL_LEN;
 1171                     }
 1172                     pad_char = ' ';
 1173                 }
 1174                 break;
 1175 
 1176                 /* print the error for an apr_status_t */
 1177                 case 'm':
 1178                 {
 1179                     apr_status_t *mrv;
 1180 
 1181                     mrv = va_arg(ap, apr_status_t *);
 1182                     if (mrv != NULL) {
 1183                         s = apr_strerror(*mrv, num_buf, NUM_BUF_SIZE-1);
 1184                         s_len = strlen(s);
 1185                     }
 1186                     else {
 1187                         s = S_NULL;
 1188                         s_len = S_NULL_LEN;
 1189                     }
 1190                     pad_char = ' ';
 1191                 }
 1192                 break;
 1193 
 1194                 case 'T':
 1195 #if APR_HAS_THREADS
 1196                 {
 1197                     apr_os_thread_t *tid;
 1198 
 1199                     tid = va_arg(ap, apr_os_thread_t *);
 1200                     if (tid != NULL) {
 1201                         s = conv_os_thread_t(tid, &num_buf[NUM_BUF_SIZE], &s_len);
 1202                         if (adjust_precision && precision < s_len)
 1203                             s_len = precision;
 1204                     }
 1205                     else {
 1206                         s = S_NULL;
 1207                         s_len = S_NULL_LEN;
 1208                     }
 1209                     pad_char = ' ';
 1210                 }
 1211 #else
 1212                     char_buf[0] = '0';
 1213                     s = &char_buf[0];
 1214                     s_len = 1;
 1215                     pad_char = ' ';
 1216 #endif
 1217                     break;
 1218 
 1219                 case 't':
 1220 #if APR_HAS_THREADS
 1221                 {
 1222                     apr_os_thread_t *tid;
 1223 
 1224                     tid = va_arg(ap, apr_os_thread_t *);
 1225                     if (tid != NULL) {
 1226                         s = conv_os_thread_t_hex(tid, &num_buf[NUM_BUF_SIZE], &s_len);
 1227                         if (adjust_precision && precision < s_len)
 1228                             s_len = precision;
 1229                     }
 1230                     else {
 1231                         s = S_NULL;
 1232                         s_len = S_NULL_LEN;
 1233                     }
 1234                     pad_char = ' ';
 1235                 }
 1236 #else
 1237                     char_buf[0] = '0';
 1238                     s = &char_buf[0];
 1239                     s_len = 1;
 1240                     pad_char = ' ';
 1241 #endif
 1242                     break;
 1243 
 1244                 case 'B':
 1245                 case 'F':
 1246                 case 'S':
 1247                 {
 1248                     char buf[5];
 1249                     apr_off_t size = 0;
 1250 
 1251                     if (*fmt == 'B') {
 1252                         apr_uint32_t *arg = va_arg(ap, apr_uint32_t *);
 1253                         size = (arg) ? *arg : 0;
 1254                     }
 1255                     else if (*fmt == 'F') {
 1256                         apr_off_t *arg = va_arg(ap, apr_off_t *);
 1257                         size = (arg) ? *arg : 0;
 1258                     }
 1259                     else {
 1260                         apr_size_t *arg = va_arg(ap, apr_size_t *);
 1261                         size = (arg) ? *arg : 0;
 1262                     }
 1263 
 1264                     s = apr_strfsize(size, buf);
 1265                     s_len = strlen(s);
 1266                     pad_char = ' ';
 1267                 }
 1268                 break;
 1269 
 1270                 case NUL:
 1271                     /* if %p ends the string, oh well ignore it */
 1272                     continue;
 1273 
 1274                 default:
 1275                     s = "bogus %p";
 1276                     s_len = 8;
 1277                     prefix_char = NUL;
 1278                     (void)va_arg(ap, void *); /* skip the bogus argument on the stack */
 1279                     break;
 1280                 }
 1281                 break;
 1282 
 1283             case NUL:
 1284                 /*
 1285                  * The last character of the format string was %.
 1286                  * We ignore it.
 1287                  */
 1288                 continue;
 1289 
 1290 
 1291                 /*
 1292                  * The default case is for unrecognized %'s.
 1293                  * We print %<char> to help the user identify what
 1294                  * option is not understood.
 1295                  * This is also useful in case the user wants to pass
 1296                  * the output of format_converter to another function
 1297                  * that understands some other %<char> (like syslog).
 1298                  * Note that we can't point s inside fmt because the
 1299                  * unknown <char> could be preceded by width etc.
 1300                  */
 1301             default:
 1302                 char_buf[0] = '%';
 1303                 char_buf[1] = *fmt;
 1304                 s = char_buf;
 1305                 s_len = 2;
 1306                 pad_char = ' ';
 1307                 break;
 1308             }
 1309 
 1310             if (prefix_char != NUL && s != S_NULL && s != char_buf) {
 1311                 *--s = prefix_char;
 1312                 s_len++;
 1313             }
 1314 
 1315             if (adjust_width && adjust == RIGHT && min_width > s_len) {
 1316                 if (pad_char == '0' && prefix_char != NUL) {
 1317                     INS_CHAR(*s, sp, bep, cc);
 1318                     s++;
 1319                     s_len--;
 1320                     min_width--;
 1321                 }
 1322                 PAD(min_width, s_len, pad_char);
 1323             }
 1324 
 1325             /*
 1326              * Print the string s. 
 1327              */
 1328             if (print_something == YES) {
 1329                 for (i = s_len; i != 0; i--) {
 1330                     INS_CHAR(*s, sp, bep, cc);
 1331                     s++;
 1332                 }
 1333             }
 1334 
 1335             if (adjust_width && adjust == LEFT && min_width > s_len)
 1336                 PAD(min_width, s_len, pad_char);
 1337         }
 1338         fmt++;
 1339     }
 1340     vbuff->curpos = sp;
 1341 
 1342     return cc;
 1343 }
 1344 
 1345 
 1346 static int snprintf_flush(apr_vformatter_buff_t *vbuff)
 1347 {
 1348     /* if the buffer fills we have to abort immediately, there is no way
 1349      * to "flush" an apr_snprintf... there's nowhere to flush it to.
 1350      */
 1351     return -1;
 1352 }
 1353 
 1354 
 1355 APR_DECLARE_NONSTD(int) apr_snprintf(char *buf, apr_size_t len, 
 1356                                      const char *format, ...)
 1357 {
 1358     int cc;
 1359     va_list ap;
 1360     apr_vformatter_buff_t vbuff;
 1361 
 1362     if (len == 0) {
 1363         /* NOTE: This is a special case; we just want to return the number
 1364          * of chars that would be written (minus \0) if the buffer
 1365          * size was infinite. We leverage the fact that INS_CHAR
 1366          * just does actual inserts iff the buffer pointer is non-NULL.
 1367          * In this case, we don't care what buf is; it can be NULL, since
 1368          * we don't touch it at all.
 1369          */
 1370         vbuff.curpos = NULL;
 1371         vbuff.endpos = NULL;
 1372     } else {
 1373         /* save one byte for nul terminator */
 1374         vbuff.curpos = buf;
 1375         vbuff.endpos = buf + len - 1;
 1376     }
 1377     va_start(ap, format);
 1378     cc = apr_vformatter(snprintf_flush, &vbuff, format, ap);
 1379     va_end(ap);
 1380     if (len != 0) {
 1381         *vbuff.curpos = '\0';
 1382     }
 1383     return (cc == -1) ? (int)len - 1 : cc;
 1384 }
 1385 
 1386 
 1387 APR_DECLARE(int) apr_vsnprintf(char *buf, apr_size_t len, const char *format,
 1388                                va_list ap)
 1389 {
 1390     int cc;
 1391     apr_vformatter_buff_t vbuff;
 1392 
 1393     if (len == 0) {
 1394         /* See above note */
 1395         vbuff.curpos = NULL;
 1396         vbuff.endpos = NULL;
 1397     } else {
 1398         /* save one byte for nul terminator */
 1399         vbuff.curpos = buf;
 1400         vbuff.endpos = buf + len - 1;
 1401     }
 1402     cc = apr_vformatter(snprintf_flush, &vbuff, format, ap);
 1403     if (len != 0) {
 1404         *vbuff.curpos = '\0';
 1405     }
 1406     return (cc == -1) ? (int)len - 1 : cc;
 1407 }