modules_k/xmpp/xsnprintf.c

Go to the documentation of this file.
00001 /* ====================================================================
00002  * $Id$
00003  *
00004  * Copyright (c) 1995-1998 The Apache Group.  All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  *
00010  * 1. Redistributions of source code must retain the above copyright
00011  *    notice, this list of conditions and the following disclaimer. 
00012  *
00013  * 2. Redistributions in binary form must reproduce the above copyright
00014  *    notice, this list of conditions and the following disclaimer in
00015  *    the documentation and/or other materials provided with the
00016  *    distribution.
00017  *
00018  * 3. All advertising materials mentioning features or use of this
00019  *    software must display the following acknowledgment:
00020  *    "This product includes software developed by the Apache Group
00021  *    for use in the Apache HTTP server project (http://www.apache.org/)."
00022  *
00023  * 4. The names "Apache Server" and "Apache Group" must not be used to
00024  *    endorse or promote products derived from this software without
00025  *    prior written permission.
00026  *
00027  * 5. Redistributions of any form whatsoever must retain the following
00028  *    acknowledgment:
00029  *    "This product includes software developed by the Apache Group
00030  *    for use in the Apache HTTP server project (http://www.apache.org/)."
00031  *
00032  * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
00033  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00034  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00035  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR
00036  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00037  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00038  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00039  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00040  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
00041  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00042  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
00043  * OF THE POSSIBILITY OF SUCH DAMAGE.
00044  * ====================================================================
00045  *
00046  * This software consists of voluntary contributions made by many
00047  * individuals on behalf of the Apache Group and was originally based
00048  * on public domain software written at the National Center for
00049  * Supercomputing Applications, University of Illinois, Urbana-Champaign.
00050  * For more information on the Apache Group and the Apache HTTP server
00051  * project, please see <http://www.apache.org/>.
00052  *
00053  * This code is based on, and used with the permission of, the
00054  * SIO stdio-replacement strx_* functions by Panos Tsirigotis
00055  * <panos@alumni.cs.colorado.edu> for xinetd.
00056  */
00057 
00063 #include "xode.h"
00064 
00065 #if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF)
00066 
00067 #include <stdio.h>
00068 #include <ctype.h>
00069 #include <sys/types.h>
00070 #include <stdarg.h>
00071 #include <string.h>
00072 #include <stdlib.h>
00073 #include <math.h>
00074 
00075 
00076 #ifdef HAVE_GCVT
00077 
00078 #define ap_ecvt ecvt
00079 #define ap_fcvt fcvt
00080 #define ap_gcvt gcvt
00081 
00082 #else
00083 
00084 /*
00085 * cvt.c - IEEE floating point formatting routines for FreeBSD
00086 * from GNU libc-4.6.27
00087 */
00088 
00089 /*
00090 *    ap_ecvt converts to decimal
00091 *      the number of digits is specified by ndigit
00092 *      decpt is set to the position of the decimal point
00093 *      sign is set to 0 for positive, 1 for negative
00094 */
00095 
00096 #define NDIG    80
00097 
00098 static char *
00099 ap_cvt(double arg, int ndigits, int *decpt, int *sign, int eflag)
00100 {
00101     register int r2;
00102     double fi, fj;
00103     register char *p, *p1;
00104     static char buf[NDIG];
00105 
00106     if (ndigits >= NDIG - 1)
00107         ndigits = NDIG - 2;
00108     r2 = 0;
00109     *sign = 0;
00110     p = &buf[0];
00111     if (arg < 0) {
00112         *sign = 1;
00113         arg = -arg;
00114     }
00115     arg = modf(arg, &fi);
00116     p1 = &buf[NDIG];
00117     /*
00118     * Do integer part
00119     */
00120     if (fi != 0) {
00121         p1 = &buf[NDIG];
00122         while (fi != 0) {
00123             fj = modf(fi / 10, &fi);
00124             *--p1 = (int) ((fj + .03) * 10) + '0';
00125             r2++;
00126         }
00127         while (p1 < &buf[NDIG])
00128             *p++ = *p1++;
00129     } else if (arg > 0) {
00130         while ((fj = arg * 10) < 1) {
00131             arg = fj;
00132             r2--;
00133         }
00134     }
00135     p1 = &buf[ndigits];
00136     if (eflag == 0)
00137         p1 += r2;
00138     *decpt = r2;
00139     if (p1 < &buf[0]) {
00140         buf[0] = '\0';
00141         return (buf);
00142     }
00143     while (p <= p1 && p < &buf[NDIG]) {
00144         arg *= 10;
00145         arg = modf(arg, &fj);
00146         *p++ = (int) fj + '0';
00147     }
00148     if (p1 >= &buf[NDIG]) {
00149         buf[NDIG - 1] = '\0';
00150         return (buf);
00151     }
00152     p = p1;
00153     *p1 += 5;
00154     while (*p1 > '9') {
00155         *p1 = '0';
00156         if (p1 > buf)
00157             ++ * --p1;
00158         else {
00159             *p1 = '1';
00160             (*decpt)++;
00161             if (eflag == 0) {
00162                 if (p > buf)
00163                     *p = '0';
00164                 p++;
00165             }
00166         }
00167     }
00168     *p = '\0';
00169     return (buf);
00170 }
00171 
00172 static char *
00173 ap_ecvt(double arg, int ndigits, int *decpt, int *sign)
00174 {
00175     return (ap_cvt(arg, ndigits, decpt, sign, 1));
00176 }
00177 
00178 static char *
00179 ap_fcvt(double arg, int ndigits, int *decpt, int *sign)
00180 {
00181     return (ap_cvt(arg, ndigits, decpt, sign, 0));
00182 }
00183 
00184 /*
00185 * ap_gcvt  - Floating output conversion to
00186 * minimal length string
00187 */
00188 
00189 static char *
00190 ap_gcvt(double number, int ndigit, char *buf)
00191 {
00192     int sign, decpt;
00193     register char *p1, *p2;
00194     int i;
00195 
00196     p1 = ap_ecvt(number, ndigit, &decpt, &sign);
00197     p2 = buf;
00198     if (sign)
00199         *p2++ = '-';
00200     for (i = ndigit - 1; i > 0 && p1[i] == '0'; i--)
00201         ndigit--;
00202     if ((decpt >= 0 && decpt - ndigit > 4)
00203             || (decpt < 0 && decpt < -3)) {     /* use E-style */
00204         decpt--;
00205         *p2++ = *p1++;
00206         *p2++ = '.';
00207         for (i = 1; i < ndigit; i++)
00208             *p2++ = *p1++;
00209         *p2++ = 'e';
00210         if (decpt < 0) {
00211             decpt = -decpt;
00212             *p2++ = '-';
00213         } else
00214             *p2++ = '+';
00215         if (decpt / 100 > 0)
00216             *p2++ = decpt / 100 + '0';
00217         if (decpt / 10 > 0)
00218             *p2++ = (decpt % 100) / 10 + '0';
00219         *p2++ = decpt % 10 + '0';
00220     } else {
00221         if (decpt <= 0) {
00222             if (*p1 != '0')
00223                 *p2++ = '.';
00224             while (decpt < 0) {
00225                 decpt++;
00226                 *p2++ = '0';
00227             }
00228         }
00229         for (i = 1; i <= ndigit; i++) {
00230             *p2++ = *p1++;
00231             if (i == decpt)
00232                 *p2++ = '.';
00233         }
00234         if (ndigit < decpt) {
00235             while (ndigit++ < decpt)
00236                 *p2++ = '0';
00237             *p2++ = '.';
00238         }
00239     }
00240     if (p2[-1] == '.')
00241         p2--;
00242     *p2 = '\0';
00243     return (buf);
00244 }
00245 
00246 #endif                          /* HAVE_CVT */
00247 
00248 typedef enum {
00249     NO = 0, YES = 1
00250 } boolean_e;
00251 
00252 #define FALSE           0
00253 #define TRUE            1
00254 #define NUL         '\0'
00255 #define INT_NULL        ((int *)0)
00256 #define WIDE_INT        long
00257 
00258 typedef WIDE_INT wide_int;
00259 typedef unsigned WIDE_INT u_wide_int;
00260 typedef int bool_int;
00261 
00262 #define S_NULL          "(null)"
00263 #define S_NULL_LEN      6
00264 
00265 #define FLOAT_DIGITS        6
00266 #define EXPONENT_LENGTH     10
00267 
00268 /*
00269  * NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions
00270  *
00271  * XXX: this is a magic number; do not decrease it
00272  */
00273 #define NUM_BUF_SIZE        512
00274 
00275 
00276 /*
00277  * Descriptor for buffer area
00278  */
00279 struct buf_area {
00280     char *buf_end;
00281     char *nextb;                /* pointer to next byte to read/write   */
00282 };
00283 
00284 typedef struct buf_area buffy;
00285 
00286 /*
00287  * The INS_CHAR macro inserts a character in the buffer and writes
00288  * the buffer back to disk if necessary
00289  * It uses the char pointers sp and bep:
00290  *      sp points to the next available character in the buffer
00291  *      bep points to the end-of-buffer+1
00292  * While using this macro, note that the nextb pointer is NOT updated.
00293  *
00294  * NOTE: Evaluation of the c argument should not have any side-effects
00295  */
00296 #define INS_CHAR( c, sp, bep, cc )  \
00297         {               \
00298         if ( sp < bep )     \
00299         {           \
00300             *sp++ = c ;     \
00301             cc++ ;      \
00302         }           \
00303         }
00304 
00305 #define NUM( c )            ( c - '0' )
00306 
00307 #define STR_TO_DEC( str, num )      \
00308     num = NUM( *str++ ) ;       \
00309     while ( isdigit((int)*str ) )       \
00310     {                   \
00311     num *= 10 ;         \
00312     num += NUM( *str++ ) ;      \
00313     }
00314 
00315 /*
00316  * This macro does zero padding so that the precision
00317  * requirement is satisfied. The padding is done by
00318  * adding '0's to the left of the string that is going
00319  * to be printed.
00320  */
00321 #define FIX_PRECISION( adjust, precision, s, s_len )    \
00322     if ( adjust )                   \
00323     while ( s_len < precision )         \
00324     {                       \
00325         *--s = '0' ;                \
00326         s_len++ ;                   \
00327     }
00328 
00329 /*
00330  * Macro that does padding. The padding is done by printing
00331  * the character ch.
00332  */
00333 #define PAD( width, len, ch )   do      \
00334     {                   \
00335         INS_CHAR( ch, sp, bep, cc ) ;   \
00336         width-- ;               \
00337     }                   \
00338     while ( width > len )
00339 
00340 /*
00341  * Prefix the character ch to the string str
00342  * Increase length
00343  * Set the has_prefix flag
00344  */
00345 #define PREFIX( str, length, ch )    *--str = ch ; length++ ; has_prefix = YES
00346 
00347 
00348 /*
00349  * Convert num to its decimal format.
00350  * Return value:
00351  *   - a pointer to a string containing the number (no sign)
00352  *   - len contains the length of the string
00353  *   - is_negative is set to TRUE or FALSE depending on the sign
00354  *     of the number (always set to FALSE if is_unsigned is TRUE)
00355  *
00356  * The caller provides a buffer for the string: that is the buf_end argument
00357  * which is a pointer to the END of the buffer + 1 (i.e. if the buffer
00358  * is declared as buf[ 100 ], buf_end should be &buf[ 100 ])
00359  */
00360 static char *
00361 conv_10(register wide_int num, register bool_int is_unsigned,
00362         register bool_int * is_negative, char *buf_end, register int *len)
00363 {
00364     register char *p = buf_end;
00365     register u_wide_int magnitude;
00366 
00367     if (is_unsigned) {
00368         magnitude = (u_wide_int) num;
00369         *is_negative = FALSE;
00370     } else {
00371         *is_negative = (num < 0);
00372 
00373         /*
00374          * On a 2's complement machine, negating the most negative integer 
00375          * results in a number that cannot be represented as a signed integer.
00376          * Here is what we do to obtain the number's magnitude:
00377          *      a. add 1 to the number
00378          *      b. negate it (becomes positive)
00379          *      c. convert it to unsigned
00380          *      d. add 1
00381          */
00382         if (*is_negative) {
00383             wide_int t = num + 1;
00384 
00385             magnitude = ((u_wide_int) - t) + 1;
00386         } else
00387             magnitude = (u_wide_int) num;
00388     }
00389 
00390     /*
00391      * We use a do-while loop so that we write at least 1 digit 
00392      */
00393     do {
00394         register u_wide_int new_magnitude = magnitude / 10;
00395 
00396         *--p = magnitude - new_magnitude * 10 + '0';
00397         magnitude = new_magnitude;
00398     }
00399     while (magnitude);
00400 
00401     *len = buf_end - p;
00402     return (p);
00403 }
00404 
00405 
00406 
00407 /*
00408  * Convert a floating point number to a string formats 'f', 'e' or 'E'.
00409  * The result is placed in buf, and len denotes the length of the string
00410  * The sign is returned in the is_negative argument (and is not placed
00411  * in buf).
00412  */
00413 static char *
00414 conv_fp(register char format, register double num,
00415         boolean_e add_dp, int precision, bool_int * is_negative, char *buf, int *len)
00416 {
00417     register char *s = buf;
00418     register char *p;
00419     int decimal_point;
00420 
00421     if (format == 'f')
00422         p = ap_fcvt(num, precision, &decimal_point, is_negative);
00423     else                        /* either e or E format */
00424         p = ap_ecvt(num, precision + 1, &decimal_point, is_negative);
00425 
00426     /*
00427      * Check for Infinity and NaN
00428      */
00429     if (isalpha((int)*p)) {
00430         *len = strlen(strcpy(buf, p));
00431         *is_negative = FALSE;
00432         return (buf);
00433     }
00434     if (format == 'f') {
00435         if (decimal_point <= 0) {
00436             *s++ = '0';
00437             if (precision > 0) {
00438                 *s++ = '.';
00439                 while (decimal_point++ < 0)
00440                     *s++ = '0';
00441             } else if (add_dp) {
00442                 *s++ = '.';
00443             }
00444         } else {
00445             while (decimal_point-- > 0) {
00446                 *s++ = *p++;
00447             }
00448             if (precision > 0 || add_dp) {
00449                 *s++ = '.';
00450             }
00451         }
00452     } else {
00453         *s++ = *p++;
00454         if (precision > 0 || add_dp)
00455             *s++ = '.';
00456     }
00457 
00458     /*
00459      * copy the rest of p, the NUL is NOT copied
00460      */
00461     while (*p)
00462         *s++ = *p++;
00463 
00464     if (format != 'f') {
00465         char temp[EXPONENT_LENGTH];     /* for exponent conversion */
00466         int t_len;
00467         bool_int exponent_is_negative;
00468 
00469         *s++ = format;          /* either e or E */
00470         decimal_point--;
00471         if (decimal_point != 0) {
00472             p = conv_10((wide_int) decimal_point, FALSE, &exponent_is_negative,
00473                         &temp[EXPONENT_LENGTH], &t_len);
00474             *s++ = exponent_is_negative ? '-' : '+';
00475 
00476             /*
00477              * Make sure the exponent has at least 2 digits
00478              */
00479             if (t_len == 1)
00480                 *s++ = '0';
00481             while (t_len--)
00482                 *s++ = *p++;
00483         } else {
00484             *s++ = '+';
00485             *s++ = '0';
00486             *s++ = '0';
00487         }
00488     }
00489     *len = s - buf;
00490     return (buf);
00491 }
00492 
00493 
00494 /*
00495  * Convert num to a base X number where X is a power of 2. nbits determines X.
00496  * For example, if nbits is 3, we do base 8 conversion
00497  * Return value:
00498  *      a pointer to a string containing the number
00499  *
00500  * The caller provides a buffer for the string: that is the buf_end argument
00501  * which is a pointer to the END of the buffer + 1 (i.e. if the buffer
00502  * is declared as buf[ 100 ], buf_end should be &buf[ 100 ])
00503  */
00504 static char *
00505 conv_p2(register u_wide_int num, register int nbits,
00506         char format, char *buf_end, register int *len)
00507 {
00508     register int mask = (1 << nbits) - 1;
00509     register char *p = buf_end;
00510     static char low_digits[] = "0123456789abcdef";
00511     static char upper_digits[] = "0123456789ABCDEF";
00512     register char *digits = (format == 'X') ? upper_digits : low_digits;
00513 
00514     do {
00515         *--p = digits[num & mask];
00516         num >>= nbits;
00517     }
00518     while (num);
00519 
00520     *len = buf_end - p;
00521     return (p);
00522 }
00523 
00524 
00525 /*
00526  * Do format conversion placing the output in buffer
00527  */
00528 static int format_converter(register buffy * odp, const char *fmt,
00529                             va_list ap)
00530 {
00531     register char *sp;
00532     register char *bep;
00533     register int cc = 0;
00534     register int i;
00535 
00536     register char *s = NULL;
00537     char *q;
00538     int s_len;
00539 
00540     register int min_width = 0;
00541     int precision = 0;
00542     enum {
00543         LEFT, RIGHT
00544     } adjust;
00545     char pad_char;
00546     char prefix_char;
00547 
00548     double fp_num;
00549     wide_int i_num = (wide_int) 0;
00550     u_wide_int ui_num;
00551 
00552     char num_buf[NUM_BUF_SIZE];
00553     char char_buf[2];           /* for printing %% and %<unknown> */
00554 
00555     /*
00556      * Flag variables
00557      */
00558     boolean_e is_long;
00559     boolean_e alternate_form;
00560     boolean_e print_sign;
00561     boolean_e print_blank;
00562     boolean_e adjust_precision;
00563     boolean_e adjust_width;
00564     bool_int is_negative;
00565 
00566     s_len = 0;
00567 
00568     sp = odp->nextb;
00569     bep = odp->buf_end;
00570 
00571     while (*fmt) {
00572         if (*fmt != '%') {
00573             INS_CHAR(*fmt, sp, bep, cc);
00574         } else {
00575             /*
00576              * Default variable settings
00577              */
00578             adjust = RIGHT;
00579             alternate_form = print_sign = print_blank = NO;
00580             pad_char = ' ';
00581             prefix_char = NUL;
00582 
00583             fmt++;
00584 
00585             /*
00586              * Try to avoid checking for flags, width or precision
00587              */
00588             if (isascii((int)*fmt) && !islower((int)*fmt)) {
00589                 /*
00590                  * Recognize flags: -, #, BLANK, +
00591                  */
00592                 for (;; fmt++) {
00593                     if (*fmt == '-')
00594                         adjust = LEFT;
00595                     else if (*fmt == '+')
00596                         print_sign = YES;
00597                     else if (*fmt == '#')
00598                         alternate_form = YES;
00599                     else if (*fmt == ' ')
00600                         print_blank = YES;
00601                     else if (*fmt == '0')
00602                         pad_char = '0';
00603                     else
00604                         break;
00605                 }
00606 
00607                 /*
00608                  * Check if a width was specified
00609                  */
00610                 if (isdigit((int)*fmt)) {
00611                     STR_TO_DEC(fmt, min_width);
00612                     adjust_width = YES;
00613                 } else if (*fmt == '*') {
00614                     min_width = va_arg(ap, int);
00615                     fmt++;
00616                     adjust_width = YES;
00617                     if (min_width < 0) {
00618                         adjust = LEFT;
00619                         min_width = -min_width;
00620                     }
00621                 } else
00622                     adjust_width = NO;
00623 
00624                 /*
00625                  * Check if a precision was specified
00626                  *
00627                  * XXX: an unreasonable amount of precision may be specified
00628                  * resulting in overflow of num_buf. Currently we
00629                  * ignore this possibility.
00630                  */
00631                 if (*fmt == '.') {
00632                     adjust_precision = YES;
00633                     fmt++;
00634                     if (isdigit((int)*fmt)) {
00635                         STR_TO_DEC(fmt, precision);
00636                     } else if (*fmt == '*') {
00637                         precision = va_arg(ap, int);
00638                         fmt++;
00639                         if (precision < 0)
00640                             precision = 0;
00641                     } else
00642                         precision = 0;
00643                 } else
00644                     adjust_precision = NO;
00645             } else
00646                 adjust_precision = adjust_width = NO;
00647 
00648             /*
00649              * Modifier check
00650              */
00651             if (*fmt == 'l') {
00652                 is_long = YES;
00653                 fmt++;
00654             } else
00655                 is_long = NO;
00656 
00657             /*
00658              * Argument extraction and printing.
00659              * First we determine the argument type.
00660              * Then, we convert the argument to a string.
00661              * On exit from the switch, s points to the string that
00662              * must be printed, s_len has the length of the string
00663              * The precision requirements, if any, are reflected in s_len.
00664              *
00665              * NOTE: pad_char may be set to '0' because of the 0 flag.
00666              *   It is reset to ' ' by non-numeric formats
00667              */
00668             switch (*fmt) {
00669             case 'u':
00670                 if (is_long)
00671                     i_num = va_arg(ap, u_wide_int);
00672                 else
00673                     i_num = (wide_int) va_arg(ap, unsigned int);
00674                 /*
00675                  * The rest also applies to other integer formats, so fall
00676                  * into that case.
00677                  */
00678             case 'd':
00679             case 'i':
00680                 /*
00681                  * Get the arg if we haven't already.
00682                  */
00683                 if ((*fmt) != 'u') {
00684                     if (is_long)
00685                         i_num = va_arg(ap, wide_int);
00686                     else
00687                         i_num = (wide_int) va_arg(ap, int);
00688                 };
00689                 s = conv_10(i_num, (*fmt) == 'u', &is_negative,
00690                             &num_buf[NUM_BUF_SIZE], &s_len);
00691                 FIX_PRECISION(adjust_precision, precision, s, s_len);
00692 
00693                 if (*fmt != 'u') {
00694                     if (is_negative)
00695                         prefix_char = '-';
00696                     else if (print_sign)
00697                         prefix_char = '+';
00698                     else if (print_blank)
00699                         prefix_char = ' ';
00700                 }
00701                 break;
00702 
00703 
00704             case 'o':
00705                 if (is_long)
00706                     ui_num = va_arg(ap, u_wide_int);
00707                 else
00708                     ui_num = (u_wide_int) va_arg(ap, unsigned int);
00709                 s = conv_p2(ui_num, 3, *fmt,
00710                             &num_buf[NUM_BUF_SIZE], &s_len);
00711                 FIX_PRECISION(adjust_precision, precision, s, s_len);
00712                 if (alternate_form && *s != '0') {
00713                     *--s = '0';
00714                     s_len++;
00715                 }
00716                 break;
00717 
00718 
00719             case 'x':
00720             case 'X':
00721                 if (is_long)
00722                     ui_num = (u_wide_int) va_arg(ap, u_wide_int);
00723                 else
00724                     ui_num = (u_wide_int) va_arg(ap, unsigned int);
00725                 s = conv_p2(ui_num, 4, *fmt,
00726                             &num_buf[NUM_BUF_SIZE], &s_len);
00727                 FIX_PRECISION(adjust_precision, precision, s, s_len);
00728                 if (alternate_form && i_num != 0) {
00729                     *--s = *fmt;    /* 'x' or 'X' */
00730                     *--s = '0';
00731                     s_len += 2;
00732                 }
00733                 break;
00734 
00735 
00736             case 's':
00737                 s = va_arg(ap, char *);
00738                 if (s != NULL) {
00739                     s_len = strlen(s);
00740                     if (adjust_precision && precision < s_len)
00741                         s_len = precision;
00742                 } else {
00743                     s = S_NULL;
00744                     s_len = S_NULL_LEN;
00745                 }
00746                 pad_char = ' ';
00747                 break;
00748 
00749 
00750             case 'f':
00751             case 'e':
00752             case 'E':
00753                 fp_num = va_arg(ap, double);
00754 
00755                 s = conv_fp(*fmt, fp_num, alternate_form,
00756                             (adjust_precision == NO) ? FLOAT_DIGITS : precision,
00757                             &is_negative, &num_buf[1], &s_len);
00758                 if (is_negative)
00759                     prefix_char = '-';
00760                 else if (print_sign)
00761                     prefix_char = '+';
00762                 else if (print_blank)
00763                     prefix_char = ' ';
00764                 break;
00765 
00766 
00767             case 'g':
00768             case 'G':
00769                 if (adjust_precision == NO)
00770                     precision = FLOAT_DIGITS;
00771                 else if (precision == 0)
00772                     precision = 1;
00773                 /*
00774                  * * We use &num_buf[ 1 ], so that we have room for the sign
00775                  */
00776                 s = ap_gcvt(va_arg(ap, double), precision, &num_buf[1]);
00777                 if (*s == '-')
00778                     prefix_char = *s++;
00779                 else if (print_sign)
00780                     prefix_char = '+';
00781                 else if (print_blank)
00782                     prefix_char = ' ';
00783 
00784                 s_len = strlen(s);
00785 
00786                 if (alternate_form && (q = strchr(s, '.')) == NULL)
00787                     s[s_len++] = '.';
00788                 if (*fmt == 'G' && (q = strchr(s, 'e')) != NULL)
00789                     *q = 'E';
00790                 break;
00791 
00792 
00793             case 'c':
00794                 char_buf[0] = (char) (va_arg(ap, int));
00795                 s = &char_buf[0];
00796                 s_len = 1;
00797                 pad_char = ' ';
00798                 break;
00799 
00800 
00801             case '%':
00802                 char_buf[0] = '%';
00803                 s = &char_buf[0];
00804                 s_len = 1;
00805                 pad_char = ' ';
00806                 break;
00807 
00808 
00809             case 'n':
00810                 *(va_arg(ap, int *)) = cc;
00811                 break;
00812 
00813                 /*
00814                  * Always extract the argument as a "char *" pointer. We 
00815                  * should be using "void *" but there are still machines 
00816                  * that don't understand it.
00817                  * If the pointer size is equal to the size of an unsigned
00818                  * integer we convert the pointer to a hex number, otherwise 
00819                  * we print "%p" to indicate that we don't handle "%p".
00820                  */
00821             case 'p':
00822                 ui_num = (u_wide_int) va_arg(ap, char *);
00823 
00824                 if (sizeof(char *) <= sizeof(u_wide_int))
00825                     s = conv_p2(ui_num, 4, 'x',
00826                                 &num_buf[NUM_BUF_SIZE], &s_len);
00827                 else {
00828                     s = "%p";
00829                     s_len = 2;
00830                 }
00831                 pad_char = ' ';
00832                 break;
00833 
00834 
00835             case NUL:
00836                 /*
00837                  * The last character of the format string was %.
00838                  * We ignore it.
00839                  */
00840                 continue;
00841 
00842 
00843                 /*
00844                  * The default case is for unrecognized %'s.
00845                  * We print %<char> to help the user identify what
00846                  * option is not understood.
00847                  * This is also useful in case the user wants to pass
00848                  * the output of format_converter to another function
00849                  * that understands some other %<char> (like syslog).
00850                  * Note that we can't point s inside fmt because the
00851                  * unknown <char> could be preceded by width etc.
00852                  */
00853             default:
00854                 char_buf[0] = '%';
00855                 char_buf[1] = *fmt;
00856                 s = char_buf;
00857                 s_len = 2;
00858                 pad_char = ' ';
00859                 break;
00860             }
00861 
00862             if (prefix_char != NUL) {
00863                 *--s = prefix_char;
00864                 s_len++;
00865             }
00866             if (adjust_width && adjust == RIGHT && min_width > s_len) {
00867                 if (pad_char == '0' && prefix_char != NUL) {
00868                     INS_CHAR(*s, sp, bep, cc)
00869                     s++;
00870                     s_len--;
00871                     min_width--;
00872                 }
00873                 PAD(min_width, s_len, pad_char);
00874             }
00875             /*
00876              * Print the string s. 
00877              */
00878             for (i = s_len; i != 0; i--) {
00879                 INS_CHAR(*s, sp, bep, cc);
00880                 s++;
00881             }
00882 
00883             if (adjust_width && adjust == LEFT && min_width > s_len)
00884                 PAD(min_width, s_len, pad_char);
00885         }
00886         fmt++;
00887     }
00888     odp->nextb = sp;
00889     return (cc);
00890 }
00891 
00892 
00893 /*
00894  * This is the general purpose conversion function.
00895  */
00896 static void strx_printv(int *ccp, char *buf, size_t len, const char *format,
00897                         va_list ap)
00898 {
00899     buffy od;
00900     int cc;
00901 
00902     /*
00903      * First initialize the descriptor
00904      * Notice that if no length is given, we initialize buf_end to the
00905      * highest possible address.
00906      */
00907     od.buf_end = len ? &buf[len] : (char *) ~0;
00908     od.nextb = buf;
00909 
00910     /*
00911      * Do the conversion
00912      */
00913     cc = format_converter(&od, format, ap);
00914     if (len == 0 || od.nextb <= od.buf_end)
00915         *(od.nextb) = '\0';
00916     if (ccp)
00917         *ccp = cc;
00918 }
00919 
00920 
00921 int ap_snprintf(char *buf, size_t len, const char *format,...)
00922 {
00923     int cc;
00924     va_list ap;
00925 
00926     va_start(ap, format);
00927     strx_printv(&cc, buf, (len - 1), format, ap);
00928     va_end(ap);
00929     return (cc);
00930 }
00931 
00932 
00933 int ap_vsnprintf(char *buf, size_t len, const char *format, va_list ap)
00934 {
00935     int cc;
00936 
00937     strx_printv(&cc, buf, (len - 1), format, ap);
00938     return (cc);
00939 }
00940 
00941 #endif                          /* HAVE_SNPRINTF */