home *** CD-ROM | disk | FTP | other *** search
/ PC Online 1999 April / PCO0499.ISO / filesbbs / os2 / apach134.arj / APACH134.ZIP / src / ap / ap_snprintf.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-01-01  |  23.7 KB  |  1,026 lines

  1. /* ====================================================================
  2.  * Copyright (c) 1995-1999 The Apache Group.  All rights reserved.
  3.  *
  4.  * Redistribution and use in source and binary forms, with or without
  5.  * modification, are permitted provided that the following conditions
  6.  * are met:
  7.  *
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer. 
  10.  *
  11.  * 2. Redistributions in binary form must reproduce the above copyright
  12.  *    notice, this list of conditions and the following disclaimer in
  13.  *    the documentation and/or other materials provided with the
  14.  *    distribution.
  15.  *
  16.  * 3. All advertising materials mentioning features or use of this
  17.  *    software must display the following acknowledgment:
  18.  *    "This product includes software developed by the Apache Group
  19.  *    for use in the Apache HTTP server project (http://www.apache.org/)."
  20.  *
  21.  * 4. The names "Apache Server" and "Apache Group" must not be used to
  22.  *    endorse or promote products derived from this software without
  23.  *    prior written permission. For written permission, please contact
  24.  *    apache@apache.org.
  25.  *
  26.  * 5. Products derived from this software may not be called "Apache"
  27.  *    nor may "Apache" appear in their names without prior written
  28.  *    permission of the Apache Group.
  29.  *
  30.  * 6. Redistributions of any form whatsoever must retain the following
  31.  *    acknowledgment:
  32.  *    "This product includes software developed by the Apache Group
  33.  *    for use in the Apache HTTP server project (http://www.apache.org/)."
  34.  *
  35.  * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
  36.  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  37.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  38.  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR
  39.  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  40.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  41.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  42.  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  43.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  44.  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  45.  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  46.  * OF THE POSSIBILITY OF SUCH DAMAGE.
  47.  * ====================================================================
  48.  *
  49.  * This software consists of voluntary contributions made by many
  50.  * individuals on behalf of the Apache Group and was originally based
  51.  * on public domain software written at the National Center for
  52.  * Supercomputing Applications, University of Illinois, Urbana-Champaign.
  53.  * For more information on the Apache Group and the Apache HTTP server
  54.  * project, please see <http://www.apache.org/>.
  55.  *
  56.  * This code is based on, and used with the permission of, the
  57.  * SIO stdio-replacement strx_* functions by Panos Tsirigotis
  58.  * <panos@alumni.cs.colorado.edu> for xinetd.
  59.  */
  60.  
  61. #include "httpd.h"
  62.  
  63. #include <stdio.h>
  64. #include <ctype.h>
  65. #include <sys/types.h>
  66. #include <stdarg.h>
  67. #include <string.h>
  68. #include <stdlib.h>
  69. #include <math.h>
  70.  
  71. typedef enum {
  72.     NO = 0, YES = 1
  73. } boolean_e;
  74.  
  75. #ifndef FALSE
  76. #define FALSE            0
  77. #endif
  78. #ifndef TRUE
  79. #define TRUE            1
  80. #endif
  81. #define NUL            '\0'
  82. #define INT_NULL        ((int *)0)
  83. #define WIDE_INT        long
  84.  
  85. typedef WIDE_INT wide_int;
  86. typedef unsigned WIDE_INT u_wide_int;
  87. typedef int bool_int;
  88.  
  89. #define S_NULL            "(null)"
  90. #define S_NULL_LEN        6
  91.  
  92. #define FLOAT_DIGITS        6
  93. #define EXPONENT_LENGTH        10
  94.  
  95. /*
  96.  * NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions
  97.  *
  98.  * XXX: this is a magic number; do not decrease it
  99.  */
  100. #define NUM_BUF_SIZE        512
  101.  
  102. /*
  103.  * cvt.c - IEEE floating point formatting routines for FreeBSD
  104.  * from GNU libc-4.6.27.  Modified to be thread safe.
  105.  */
  106.  
  107. /*
  108.  *    ap_ecvt converts to decimal
  109.  *      the number of digits is specified by ndigit
  110.  *      decpt is set to the position of the decimal point
  111.  *      sign is set to 0 for positive, 1 for negative
  112.  */
  113.  
  114. #define    NDIG    80
  115.  
  116. /* buf must have at least NDIG bytes */
  117. static char *ap_cvt(double arg, int ndigits, int *decpt, int *sign, int eflag, char *buf)
  118. {
  119.     register int r2;
  120.     double fi, fj;
  121.     register char *p, *p1;
  122.  
  123.     if (ndigits >= NDIG - 1)
  124.     ndigits = NDIG - 2;
  125.     r2 = 0;
  126.     *sign = 0;
  127.     p = &buf[0];
  128.     if (arg < 0) {
  129.     *sign = 1;
  130.     arg = -arg;
  131.     }
  132.     arg = modf(arg, &fi);
  133.     p1 = &buf[NDIG];
  134.     /*
  135.      * Do integer part
  136.      */
  137.     if (fi != 0) {
  138.     p1 = &buf[NDIG];
  139.     while (fi != 0) {
  140.         fj = modf(fi / 10, &fi);
  141.         *--p1 = (int) ((fj + .03) * 10) + '0';
  142.         r2++;
  143.     }
  144.     while (p1 < &buf[NDIG])
  145.         *p++ = *p1++;
  146.     }
  147.     else if (arg > 0) {
  148.     while ((fj = arg * 10) < 1) {
  149.         arg = fj;
  150.         r2--;
  151.     }
  152.     }
  153.     p1 = &buf[ndigits];
  154.     if (eflag == 0)
  155.     p1 += r2;
  156.     *decpt = r2;
  157.     if (p1 < &buf[0]) {
  158.     buf[0] = '\0';
  159.     return (buf);
  160.     }
  161.     while (p <= p1 && p < &buf[NDIG]) {
  162.     arg *= 10;
  163.     arg = modf(arg, &fj);
  164.     *p++ = (int) fj + '0';
  165.     }
  166.     if (p1 >= &buf[NDIG]) {
  167.     buf[NDIG - 1] = '\0';
  168.     return (buf);
  169.     }
  170.     p = p1;
  171.     *p1 += 5;
  172.     while (*p1 > '9') {
  173.     *p1 = '0';
  174.     if (p1 > buf)
  175.         ++ * --p1;
  176.     else {
  177.         *p1 = '1';
  178.         (*decpt)++;
  179.         if (eflag == 0) {
  180.         if (p > buf)
  181.             *p = '0';
  182.         p++;
  183.         }
  184.     }
  185.     }
  186.     *p = '\0';
  187.     return (buf);
  188. }
  189.  
  190. static char *ap_ecvt(double arg, int ndigits, int *decpt, int *sign, char *buf)
  191. {
  192.     return (ap_cvt(arg, ndigits, decpt, sign, 1, buf));
  193. }
  194.  
  195. static char *ap_fcvt(double arg, int ndigits, int *decpt, int *sign, char *buf)
  196. {
  197.     return (ap_cvt(arg, ndigits, decpt, sign, 0, buf));
  198. }
  199.  
  200. /*
  201.  * ap_gcvt  - Floating output conversion to
  202.  * minimal length string
  203.  */
  204.  
  205. static char *ap_gcvt(double number, int ndigit, char *buf, boolean_e altform)
  206. {
  207.     int sign, decpt;
  208.     register char *p1, *p2;
  209.     register int i;
  210.     char buf1[NDIG];
  211.  
  212.     p1 = ap_ecvt(number, ndigit, &decpt, &sign, buf1);
  213.     p2 = buf;
  214.     if (sign)
  215.     *p2++ = '-';
  216.     for (i = ndigit - 1; i > 0 && p1[i] == '0'; i--)
  217.     ndigit--;
  218.     if ((decpt >= 0 && decpt - ndigit > 4)
  219.     || (decpt < 0 && decpt < -3)) {        /* use E-style */
  220.     decpt--;
  221.     *p2++ = *p1++;
  222.     *p2++ = '.';
  223.     for (i = 1; i < ndigit; i++)
  224.         *p2++ = *p1++;
  225.     *p2++ = 'e';
  226.     if (decpt < 0) {
  227.         decpt = -decpt;
  228.         *p2++ = '-';
  229.     }
  230.     else
  231.         *p2++ = '+';
  232.     if (decpt / 100 > 0)
  233.         *p2++ = decpt / 100 + '0';
  234.     if (decpt / 10 > 0)
  235.         *p2++ = (decpt % 100) / 10 + '0';
  236.     *p2++ = decpt % 10 + '0';
  237.     }
  238.     else {
  239.     if (decpt <= 0) {
  240.         if (*p1 != '0')
  241.         *p2++ = '.';
  242.         while (decpt < 0) {
  243.         decpt++;
  244.         *p2++ = '0';
  245.         }
  246.     }
  247.     for (i = 1; i <= ndigit; i++) {
  248.         *p2++ = *p1++;
  249.         if (i == decpt)
  250.         *p2++ = '.';
  251.     }
  252.     if (ndigit < decpt) {
  253.         while (ndigit++ < decpt)
  254.         *p2++ = '0';
  255.         *p2++ = '.';
  256.     }
  257.     }
  258.     if (p2[-1] == '.' && !altform)
  259.     p2--;
  260.     *p2 = '\0';
  261.     return (buf);
  262. }
  263.  
  264. /*
  265.  * The INS_CHAR macro inserts a character in the buffer and writes
  266.  * the buffer back to disk if necessary
  267.  * It uses the char pointers sp and bep:
  268.  *      sp points to the next available character in the buffer
  269.  *      bep points to the end-of-buffer+1
  270.  * While using this macro, note that the nextb pointer is NOT updated.
  271.  *
  272.  * NOTE: Evaluation of the c argument should not have any side-effects
  273.  */
  274. #define INS_CHAR(c, sp, bep, cc)                \
  275.         {                            \
  276.         if (sp >= bep) {                \
  277.             vbuff->curpos = sp;                         \
  278.             if (flush_func(vbuff))            \
  279.             return -1;                \
  280.             sp = vbuff->curpos;                \
  281.             bep = vbuff->endpos;            \
  282.         }                         \
  283.         *sp++ = (c);                    \
  284.         cc++;                         \
  285.         }
  286.  
  287. #define NUM( c )            ( c - '0' )
  288.  
  289. #define STR_TO_DEC( str, num )        \
  290.     num = NUM( *str++ ) ;        \
  291.     while ( ap_isdigit( *str ) )        \
  292.     {                    \
  293.     num *= 10 ;            \
  294.     num += NUM( *str++ ) ;        \
  295.     }
  296.  
  297. /*
  298.  * This macro does zero padding so that the precision
  299.  * requirement is satisfied. The padding is done by
  300.  * adding '0's to the left of the string that is going
  301.  * to be printed.
  302.  */
  303. #define FIX_PRECISION( adjust, precision, s, s_len )    \
  304.     if ( adjust )                    \
  305.     while ( s_len < precision )            \
  306.     {                        \
  307.         *--s = '0' ;                \
  308.         s_len++ ;                    \
  309.     }
  310.  
  311. /*
  312.  * Macro that does padding. The padding is done by printing
  313.  * the character ch.
  314.  */
  315. #define PAD( width, len, ch )    do        \
  316.     {                    \
  317.         INS_CHAR( ch, sp, bep, cc ) ;    \
  318.         width-- ;                \
  319.     }                    \
  320.     while ( width > len )
  321.  
  322. /*
  323.  * Prefix the character ch to the string str
  324.  * Increase length
  325.  * Set the has_prefix flag
  326.  */
  327. #define PREFIX( str, length, ch )     *--str = ch ; length++ ; has_prefix = YES
  328.  
  329.  
  330. /*
  331.  * Convert num to its decimal format.
  332.  * Return value:
  333.  *   - a pointer to a string containing the number (no sign)
  334.  *   - len contains the length of the string
  335.  *   - is_negative is set to TRUE or FALSE depending on the sign
  336.  *     of the number (always set to FALSE if is_unsigned is TRUE)
  337.  *
  338.  * The caller provides a buffer for the string: that is the buf_end argument
  339.  * which is a pointer to the END of the buffer + 1 (i.e. if the buffer
  340.  * is declared as buf[ 100 ], buf_end should be &buf[ 100 ])
  341.  */
  342. static char *conv_10(register wide_int num, register bool_int is_unsigned,
  343.              register bool_int *is_negative, char *buf_end,
  344.              register int *len)
  345. {
  346.     register char *p = buf_end;
  347.     register u_wide_int magnitude;
  348.  
  349.     if (is_unsigned) {
  350.     magnitude = (u_wide_int) num;
  351.     *is_negative = FALSE;
  352.     }
  353.     else {
  354.     *is_negative = (num < 0);
  355.  
  356.     /*
  357.      * On a 2's complement machine, negating the most negative integer 
  358.      * results in a number that cannot be represented as a signed integer.
  359.      * Here is what we do to obtain the number's magnitude:
  360.      *      a. add 1 to the number
  361.      *      b. negate it (becomes positive)
  362.      *      c. convert it to unsigned
  363.      *      d. add 1
  364.      */
  365.     if (*is_negative) {
  366.         wide_int t = num + 1;
  367.  
  368.         magnitude = ((u_wide_int) -t) + 1;
  369.     }
  370.     else
  371.         magnitude = (u_wide_int) num;
  372.     }
  373.  
  374.     /*
  375.      * We use a do-while loop so that we write at least 1 digit 
  376.      */
  377.     do {
  378.     register u_wide_int new_magnitude = magnitude / 10;
  379.  
  380.     *--p = (char) (magnitude - new_magnitude * 10 + '0');
  381.     magnitude = new_magnitude;
  382.     }
  383.     while (magnitude);
  384.  
  385.     *len = buf_end - p;
  386.     return (p);
  387. }
  388.  
  389.  
  390.  
  391. static char *conv_in_addr(struct in_addr *ia, char *buf_end, int *len)
  392. {
  393.     unsigned addr = ntohl(ia->s_addr);
  394.     char *p = buf_end;
  395.     bool_int is_negative;
  396.     int sub_len;
  397.  
  398.     p = conv_10((addr & 0x000000FF)      , TRUE, &is_negative, p, &sub_len);
  399.     *--p = '.';
  400.     p = conv_10((addr & 0x0000FF00) >>  8, TRUE, &is_negative, p, &sub_len);
  401.     *--p = '.';
  402.     p = conv_10((addr & 0x00FF0000) >> 16, TRUE, &is_negative, p, &sub_len);
  403.     *--p = '.';
  404.     p = conv_10((addr & 0xFF000000) >> 24, TRUE, &is_negative, p, &sub_len);
  405.  
  406.     *len = buf_end - p;
  407.     return (p);
  408. }
  409.  
  410.  
  411.  
  412. static char *conv_sockaddr_in(struct sockaddr_in *si, char *buf_end, int *len)
  413. {
  414.     char *p = buf_end;
  415.     bool_int is_negative;
  416.     int sub_len;
  417.  
  418.     p = conv_10(ntohs(si->sin_port), TRUE, &is_negative, p, &sub_len);
  419.     *--p = ':';
  420.     p = conv_in_addr(&si->sin_addr, p, &sub_len);
  421.  
  422.     *len = buf_end - p;
  423.     return (p);
  424. }
  425.  
  426.  
  427.  
  428. /*
  429.  * Convert a floating point number to a string formats 'f', 'e' or 'E'.
  430.  * The result is placed in buf, and len denotes the length of the string
  431.  * The sign is returned in the is_negative argument (and is not placed
  432.  * in buf).
  433.  */
  434. static char *conv_fp(register char format, register double num,
  435.     boolean_e add_dp, int precision, bool_int *is_negative,
  436.     char *buf, int *len)
  437. {
  438.     register char *s = buf;
  439.     register char *p;
  440.     int decimal_point;
  441.     char buf1[NDIG];
  442.  
  443.     if (format == 'f')
  444.     p = ap_fcvt(num, precision, &decimal_point, is_negative, buf1);
  445.     else            /* either e or E format */
  446.     p = ap_ecvt(num, precision + 1, &decimal_point, is_negative, buf1);
  447.  
  448.     /*
  449.      * Check for Infinity and NaN
  450.      */
  451.     if (ap_isalpha(*p)) {
  452.     *len = strlen(strcpy(buf, p));
  453.     *is_negative = FALSE;
  454.     return (buf);
  455.     }
  456.  
  457.     if (format == 'f') {
  458.     if (decimal_point <= 0) {
  459.         *s++ = '0';
  460.         if (precision > 0) {
  461.         *s++ = '.';
  462.         while (decimal_point++ < 0)
  463.             *s++ = '0';
  464.         }
  465.         else if (add_dp)
  466.         *s++ = '.';
  467.     }
  468.     else {
  469.         while (decimal_point-- > 0)
  470.         *s++ = *p++;
  471.         if (precision > 0 || add_dp)
  472.         *s++ = '.';
  473.     }
  474.     }
  475.     else {
  476.     *s++ = *p++;
  477.     if (precision > 0 || add_dp)
  478.         *s++ = '.';
  479.     }
  480.  
  481.     /*
  482.      * copy the rest of p, the NUL is NOT copied
  483.      */
  484.     while (*p)
  485.     *s++ = *p++;
  486.  
  487.     if (format != 'f') {
  488.     char temp[EXPONENT_LENGTH];    /* for exponent conversion */
  489.     int t_len;
  490.     bool_int exponent_is_negative;
  491.  
  492.     *s++ = format;        /* either e or E */
  493.     decimal_point--;
  494.     if (decimal_point != 0) {
  495.         p = conv_10((wide_int) decimal_point, FALSE, &exponent_is_negative,
  496.             &temp[EXPONENT_LENGTH], &t_len);
  497.         *s++ = exponent_is_negative ? '-' : '+';
  498.  
  499.         /*
  500.          * Make sure the exponent has at least 2 digits
  501.          */
  502.         if (t_len == 1)
  503.         *s++ = '0';
  504.         while (t_len--)
  505.         *s++ = *p++;
  506.     }
  507.     else {
  508.         *s++ = '+';
  509.         *s++ = '0';
  510.         *s++ = '0';
  511.     }
  512.     }
  513.  
  514.     *len = s - buf;
  515.     return (buf);
  516. }
  517.  
  518.  
  519. /*
  520.  * Convert num to a base X number where X is a power of 2. nbits determines X.
  521.  * For example, if nbits is 3, we do base 8 conversion
  522.  * Return value:
  523.  *      a pointer to a string containing the number
  524.  *
  525.  * The caller provides a buffer for the string: that is the buf_end argument
  526.  * which is a pointer to the END of the buffer + 1 (i.e. if the buffer
  527.  * is declared as buf[ 100 ], buf_end should be &buf[ 100 ])
  528.  */
  529. static char *conv_p2(register u_wide_int num, register int nbits,
  530.              char format, char *buf_end, register int *len)
  531. {
  532.     register int mask = (1 << nbits) - 1;
  533.     register char *p = buf_end;
  534.     static const char low_digits[] = "0123456789abcdef";
  535.     static const char upper_digits[] = "0123456789ABCDEF";
  536.     register const char *digits = (format == 'X') ? upper_digits : low_digits;
  537.  
  538.     do {
  539.     *--p = digits[num & mask];
  540.     num >>= nbits;
  541.     }
  542.     while (num);
  543.  
  544.     *len = buf_end - p;
  545.     return (p);
  546. }
  547.  
  548.  
  549. /*
  550.  * Do format conversion placing the output in buffer
  551.  */
  552. API_EXPORT(int) ap_vformatter(int (*flush_func)(ap_vformatter_buff *),
  553.     ap_vformatter_buff *vbuff, const char *fmt, va_list ap)
  554. {
  555.     register char *sp;
  556.     register char *bep;
  557.     register int cc = 0;
  558.     register int i;
  559.  
  560.     register char *s = NULL;
  561.     char *q;
  562.     int s_len;
  563.  
  564.     register int min_width = 0;
  565.     int precision = 0;
  566.     enum {
  567.     LEFT, RIGHT
  568.     } adjust;
  569.     char pad_char;
  570.     char prefix_char;
  571.  
  572.     double fp_num;
  573.     wide_int i_num = (wide_int) 0;
  574.     u_wide_int ui_num;
  575.  
  576.     char num_buf[NUM_BUF_SIZE];
  577.     char char_buf[2];        /* for printing %% and %<unknown> */
  578.  
  579.     /*
  580.      * Flag variables
  581.      */
  582.     boolean_e is_long;
  583.     boolean_e alternate_form;
  584.     boolean_e print_sign;
  585.     boolean_e print_blank;
  586.     boolean_e adjust_precision;
  587.     boolean_e adjust_width;
  588.     bool_int is_negative;
  589.  
  590.     sp = vbuff->curpos;
  591.     bep = vbuff->endpos;
  592.  
  593.     while (*fmt) {
  594.     if (*fmt != '%') {
  595.         INS_CHAR(*fmt, sp, bep, cc);
  596.     }
  597.     else {
  598.         /*
  599.          * Default variable settings
  600.          */
  601.         adjust = RIGHT;
  602.         alternate_form = print_sign = print_blank = NO;
  603.         pad_char = ' ';
  604.         prefix_char = NUL;
  605.  
  606.         fmt++;
  607.  
  608.         /*
  609.          * Try to avoid checking for flags, width or precision
  610.          */
  611.         if (!ap_islower(*fmt)) {
  612.         /*
  613.          * Recognize flags: -, #, BLANK, +
  614.          */
  615.         for (;; fmt++) {
  616.             if (*fmt == '-')
  617.             adjust = LEFT;
  618.             else if (*fmt == '+')
  619.             print_sign = YES;
  620.             else if (*fmt == '#')
  621.             alternate_form = YES;
  622.             else if (*fmt == ' ')
  623.             print_blank = YES;
  624.             else if (*fmt == '0')
  625.             pad_char = '0';
  626.             else
  627.             break;
  628.         }
  629.  
  630.         /*
  631.          * Check if a width was specified
  632.          */
  633.         if (ap_isdigit(*fmt)) {
  634.             STR_TO_DEC(fmt, min_width);
  635.             adjust_width = YES;
  636.         }
  637.         else if (*fmt == '*') {
  638.             min_width = va_arg(ap, int);
  639.             fmt++;
  640.             adjust_width = YES;
  641.             if (min_width < 0) {
  642.             adjust = LEFT;
  643.             min_width = -min_width;
  644.             }
  645.         }
  646.         else
  647.             adjust_width = NO;
  648.  
  649.         /*
  650.          * Check if a precision was specified
  651.          *
  652.          * XXX: an unreasonable amount of precision may be specified
  653.          * resulting in overflow of num_buf. Currently we
  654.          * ignore this possibility.
  655.          */
  656.         if (*fmt == '.') {
  657.             adjust_precision = YES;
  658.             fmt++;
  659.             if (ap_isdigit(*fmt)) {
  660.             STR_TO_DEC(fmt, precision);
  661.             }
  662.             else if (*fmt == '*') {
  663.             precision = va_arg(ap, int);
  664.             fmt++;
  665.             if (precision < 0)
  666.                 precision = 0;
  667.             }
  668.             else
  669.             precision = 0;
  670.         }
  671.         else
  672.             adjust_precision = NO;
  673.         }
  674.         else
  675.         adjust_precision = adjust_width = NO;
  676.  
  677.         /*
  678.          * Modifier check
  679.          */
  680.         if (*fmt == 'l') {
  681.         is_long = YES;
  682.         fmt++;
  683.         }
  684.         else {
  685.         if (*fmt == 'h')  /* "short" backward compatibility */
  686.             ++fmt;
  687.         is_long = NO;
  688.         }
  689.  
  690.         /*
  691.          * Argument extraction and printing.
  692.          * First we determine the argument type.
  693.          * Then, we convert the argument to a string.
  694.          * On exit from the switch, s points to the string that
  695.          * must be printed, s_len has the length of the string
  696.          * The precision requirements, if any, are reflected in s_len.
  697.          *
  698.          * NOTE: pad_char may be set to '0' because of the 0 flag.
  699.          *   It is reset to ' ' by non-numeric formats
  700.          */
  701.         switch (*fmt) {
  702.         case 'u':
  703.         if (is_long)
  704.             i_num = va_arg(ap, u_wide_int);
  705.         else
  706.             i_num = (wide_int) va_arg(ap, unsigned int);
  707.         s = conv_10(i_num, 1, &is_negative,
  708.                 &num_buf[NUM_BUF_SIZE], &s_len);
  709.         FIX_PRECISION(adjust_precision, precision, s, s_len);
  710.         break;
  711.  
  712.         case 'd':
  713.         case 'i':
  714.         if (is_long)
  715.             i_num = va_arg(ap, wide_int);
  716.         else
  717.             i_num = (wide_int) va_arg(ap, int);
  718.         s = conv_10(i_num, 0, &is_negative,
  719.                 &num_buf[NUM_BUF_SIZE], &s_len);
  720.         FIX_PRECISION(adjust_precision, precision, s, s_len);
  721.  
  722.         if (is_negative)
  723.             prefix_char = '-';
  724.         else if (print_sign)
  725.             prefix_char = '+';
  726.         else if (print_blank)
  727.             prefix_char = ' ';
  728.         break;
  729.  
  730.  
  731.         case 'o':
  732.         if (is_long)
  733.             ui_num = va_arg(ap, u_wide_int);
  734.         else
  735.             ui_num = (u_wide_int) va_arg(ap, unsigned int);
  736.         s = conv_p2(ui_num, 3, *fmt,
  737.                 &num_buf[NUM_BUF_SIZE], &s_len);
  738.         FIX_PRECISION(adjust_precision, precision, s, s_len);
  739.         if (alternate_form && *s != '0') {
  740.             *--s = '0';
  741.             s_len++;
  742.         }
  743.         break;
  744.  
  745.  
  746.         case 'x':
  747.         case 'X':
  748.         if (is_long)
  749.             ui_num = (u_wide_int) va_arg(ap, u_wide_int);
  750.         else
  751.             ui_num = (u_wide_int) va_arg(ap, unsigned int);
  752.         s = conv_p2(ui_num, 4, *fmt,
  753.                 &num_buf[NUM_BUF_SIZE], &s_len);
  754.         FIX_PRECISION(adjust_precision, precision, s, s_len);
  755.         if (alternate_form && i_num != 0) {
  756.             *--s = *fmt;    /* 'x' or 'X' */
  757.             *--s = '0';
  758.             s_len += 2;
  759.         }
  760.         break;
  761.  
  762.  
  763.         case 's':
  764.         s = va_arg(ap, char *);
  765.         if (s != NULL) {
  766.             s_len = strlen(s);
  767.             if (adjust_precision && precision < s_len)
  768.             s_len = precision;
  769.         }
  770.         else {
  771.             s = S_NULL;
  772.             s_len = S_NULL_LEN;
  773.         }
  774.         pad_char = ' ';
  775.         break;
  776.  
  777.  
  778.         case 'f':
  779.         case 'e':
  780.         case 'E':
  781.         fp_num = va_arg(ap, double);
  782.         /*
  783.          * * We use &num_buf[ 1 ], so that we have room for the sign
  784.          */
  785.         s = conv_fp(*fmt, fp_num, alternate_form,
  786.             (adjust_precision == NO) ? FLOAT_DIGITS : precision,
  787.                 &is_negative, &num_buf[1], &s_len);
  788.         if (is_negative)
  789.             prefix_char = '-';
  790.         else if (print_sign)
  791.             prefix_char = '+';
  792.         else if (print_blank)
  793.             prefix_char = ' ';
  794.         break;
  795.  
  796.  
  797.         case 'g':
  798.         case 'G':
  799.         if (adjust_precision == NO)
  800.             precision = FLOAT_DIGITS;
  801.         else if (precision == 0)
  802.             precision = 1;
  803.         /*
  804.          * * We use &num_buf[ 1 ], so that we have room for the sign
  805.          */
  806.         s = ap_gcvt(va_arg(ap, double), precision, &num_buf[1],
  807.                     alternate_form);
  808.         if (*s == '-')
  809.             prefix_char = *s++;
  810.         else if (print_sign)
  811.             prefix_char = '+';
  812.         else if (print_blank)
  813.             prefix_char = ' ';
  814.  
  815.         s_len = strlen(s);
  816.  
  817.         if (alternate_form && (q = strchr(s, '.')) == NULL) {
  818.             s[s_len++] = '.';
  819.             s[s_len] = '\0'; /* delimit for following strchr() */
  820.         }
  821.         if (*fmt == 'G' && (q = strchr(s, 'e')) != NULL)
  822.             *q = 'E';
  823.         break;
  824.  
  825.  
  826.         case 'c':
  827.         char_buf[0] = (char) (va_arg(ap, int));
  828.         s = &char_buf[0];
  829.         s_len = 1;
  830.         pad_char = ' ';
  831.         break;
  832.  
  833.  
  834.         case '%':
  835.         char_buf[0] = '%';
  836.         s = &char_buf[0];
  837.         s_len = 1;
  838.         pad_char = ' ';
  839.         break;
  840.  
  841.  
  842.         case 'n':
  843.         *(va_arg(ap, int *)) = cc;
  844.         break;
  845.  
  846.         /*
  847.          * This is where we extend the printf format, with a second
  848.          * type specifier
  849.          */
  850.         case 'p':
  851.         switch(*++fmt) {
  852.             /*
  853.              * If the pointer size is equal to the size of an unsigned
  854.              * integer we convert the pointer to a hex number, otherwise 
  855.              * we print "%p" to indicate that we don't handle "%p".
  856.              */
  857.         case 'p':
  858.             ui_num = (u_wide_int) va_arg(ap, void *);
  859.  
  860.             if (sizeof(char *) <= sizeof(u_wide_int))
  861.                 s = conv_p2(ui_num, 4, 'x',
  862.                         &num_buf[NUM_BUF_SIZE], &s_len);
  863.             else {
  864.             s = "%p";
  865.             s_len = 2;
  866.             prefix_char = NUL;
  867.             }
  868.             pad_char = ' ';
  869.             break;
  870.  
  871.             /* print a struct sockaddr_in as a.b.c.d:port */
  872.         case 'I':
  873.             {
  874.             struct sockaddr_in *si;
  875.  
  876.             si = va_arg(ap, struct sockaddr_in *);
  877.             if (si != NULL) {
  878.                 s = conv_sockaddr_in(si, &num_buf[NUM_BUF_SIZE], &s_len);
  879.                 if (adjust_precision && precision < s_len)
  880.                 s_len = precision;
  881.             }
  882.             else {
  883.                 s = S_NULL;
  884.                 s_len = S_NULL_LEN;
  885.             }
  886.             pad_char = ' ';
  887.             }
  888.             break;
  889.  
  890.             /* print a struct in_addr as a.b.c.d */
  891.         case 'A':
  892.             {
  893.             struct in_addr *ia;
  894.  
  895.             ia = va_arg(ap, struct in_addr *);
  896.             if (ia != NULL) {
  897.                 s = conv_in_addr(ia, &num_buf[NUM_BUF_SIZE], &s_len);
  898.                 if (adjust_precision && precision < s_len)
  899.                 s_len = precision;
  900.             }
  901.             else {
  902.                 s = S_NULL;
  903.                 s_len = S_NULL_LEN;
  904.             }
  905.             pad_char = ' ';
  906.             }
  907.             break;
  908.  
  909.         case NUL:
  910.             /* if %p ends the string, oh well ignore it */
  911.             continue;
  912.  
  913.         default:
  914.             s = "bogus %p";
  915.             s_len = 8;
  916.             prefix_char = NUL;
  917.             break;
  918.         }
  919.         break;
  920.  
  921.         case NUL:
  922.         /*
  923.          * The last character of the format string was %.
  924.          * We ignore it.
  925.          */
  926.         continue;
  927.  
  928.  
  929.         /*
  930.          * The default case is for unrecognized %'s.
  931.          * We print %<char> to help the user identify what
  932.          * option is not understood.
  933.          * This is also useful in case the user wants to pass
  934.          * the output of format_converter to another function
  935.          * that understands some other %<char> (like syslog).
  936.          * Note that we can't point s inside fmt because the
  937.          * unknown <char> could be preceded by width etc.
  938.          */
  939.         default:
  940.         char_buf[0] = '%';
  941.         char_buf[1] = *fmt;
  942.         s = char_buf;
  943.         s_len = 2;
  944.         pad_char = ' ';
  945.         break;
  946.         }
  947.  
  948.         if (prefix_char != NUL && s != S_NULL && s != char_buf) {
  949.         *--s = prefix_char;
  950.         s_len++;
  951.         }
  952.  
  953.         if (adjust_width && adjust == RIGHT && min_width > s_len) {
  954.         if (pad_char == '0' && prefix_char != NUL) {
  955.             INS_CHAR(*s, sp, bep, cc);
  956.             s++;
  957.             s_len--;
  958.             min_width--;
  959.         }
  960.         PAD(min_width, s_len, pad_char);
  961.         }
  962.  
  963.         /*
  964.          * Print the string s. 
  965.          */
  966.         for (i = s_len; i != 0; i--) {
  967.         INS_CHAR(*s, sp, bep, cc);
  968.         s++;
  969.         }
  970.  
  971.         if (adjust_width && adjust == LEFT && min_width > s_len)
  972.         PAD(min_width, s_len, pad_char);
  973.     }
  974.     fmt++;
  975.     }
  976.     vbuff->curpos = sp;
  977.     return cc;
  978. }
  979.  
  980.  
  981. static int snprintf_flush(ap_vformatter_buff *vbuff)
  982. {
  983.     /* if the buffer fills we have to abort immediately, there is no way
  984.      * to "flush" an ap_snprintf... there's nowhere to flush it to.
  985.      */
  986.     return -1;
  987. }
  988.  
  989.  
  990. API_EXPORT(int) ap_snprintf(char *buf, size_t len, const char *format,...)
  991. {
  992.     int cc;
  993.     va_list ap;
  994.     ap_vformatter_buff vbuff;
  995.  
  996.     if (len == 0)
  997.     return 0;
  998.  
  999.     /* save one byte for nul terminator */
  1000.     vbuff.curpos = buf;
  1001.     vbuff.endpos = buf + len - 1;
  1002.     va_start(ap, format);
  1003.     cc = ap_vformatter(snprintf_flush, &vbuff, format, ap);
  1004.     va_end(ap);
  1005.     *vbuff.curpos = '\0';
  1006.     return (cc == -1) ? len : cc;
  1007. }
  1008.  
  1009.  
  1010. API_EXPORT(int) ap_vsnprintf(char *buf, size_t len, const char *format,
  1011.                  va_list ap)
  1012. {
  1013.     int cc;
  1014.     ap_vformatter_buff vbuff;
  1015.  
  1016.     if (len == 0)
  1017.     return 0;
  1018.  
  1019.     /* save one byte for nul terminator */
  1020.     vbuff.curpos = buf;
  1021.     vbuff.endpos = buf + len - 1;
  1022.     cc = ap_vformatter(snprintf_flush, &vbuff, format, ap);
  1023.     *vbuff.curpos = '\0';
  1024.     return (cc == -1) ? len : cc;
  1025. }
  1026.