Jabber WindowGram Client (JWGC)

Introduction Screenshots Installation Downloads
Documentation Browse Source Resources Project Site

Stable Version
-none-

Latest Version
beta5



Main Page | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

snprintf.c

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


Last updated at Tue Dec 18 21:07:42 PST 2007. This site and project hosted by...SourceForge.net Logo
Source Perspective by Fisheye