snprintf.c
上传用户:liugui
上传日期:2007-01-04
资源大小:822k
文件大小:21k
源码类别:

代理服务器

开发平台:

Unix_Linux

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