Home | History | Annotate | Line # | Download | only in dist
      1 /* Licensed to the Apache Software Foundation (ASF) under one or more
      2  * contributor license agreements.  See the NOTICE file distributed with
      3  * this work for additional information regarding copyright ownership.
      4  * The ASF licenses this file to You under the Apache License, Version 2.0
      5  * (the "License"); you may not use this file except in compliance with
      6  * the License.  You may obtain a copy of the License at
      7  *
      8  *     http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 /*
     18  * This code is based on, and used with the permission of, the
     19  * SIO stdio-replacement strx_* functions by Panos Tsirigotis
     20  * <panos (at) alumni.cs.colorado.edu> for xinetd.
     21  */
     22 
     23 #include "config.h"
     24 #include <stdio.h>
     25 #include <ctype.h>
     26 #include <sys/types.h>
     27 #include <stdarg.h>
     28 #include <string.h>
     29 #include <stdlib.h>
     30 #include <math.h>
     31 #include <netinet/in.h>
     32 
     33 #ifdef HAVE_LIMITS_H
     34 #include <limits.h>
     35 #endif
     36 
     37 typedef struct {
     38     char *curpos;
     39     char *endpos;
     40 } ap_vformatter_buff;
     41 
     42 
     43 #define API_EXPORT(type) type
     44 #define API_EXPORT_NONSTD(type) type
     45 
     46 #define ap_isalnum(c) (isalnum(((unsigned char)(c))))
     47 #define ap_isalpha(c) (isalpha(((unsigned char)(c))))
     48 #define ap_iscntrl(c) (iscntrl(((unsigned char)(c))))
     49 #define ap_isdigit(c) (isdigit(((unsigned char)(c))))
     50 #define ap_isgraph(c) (isgraph(((unsigned char)(c))))
     51 #define ap_islower(c) (islower(((unsigned char)(c))))
     52 #define ap_isprint(c) (isprint(((unsigned char)(c))))
     53 #define ap_ispunct(c) (ispunct(((unsigned char)(c))))
     54 #define ap_isspace(c) (isspace(((unsigned char)(c))))
     55 #define ap_isupper(c) (isupper(((unsigned char)(c))))
     56 #define ap_isxdigit(c) (isxdigit(((unsigned char)(c))))
     57 #define ap_tolower(c) (tolower(((unsigned char)(c))))
     58 #define ap_toupper(c) (toupper(((unsigned char)(c))))
     59 
     60 
     61 typedef enum {
     62     NO = 0, YES = 1
     63 } boolean_e;
     64 
     65 #ifndef FALSE
     66 #define FALSE			0
     67 #endif
     68 #ifndef TRUE
     69 #define TRUE			1
     70 #endif
     71 #ifndef AP_LONGEST_LONG
     72 #define AP_LONGEST_LONG		long
     73 #endif
     74 #define NUL			'\0'
     75 #define WIDE_INT		long
     76 #define WIDEST_INT		AP_LONGEST_LONG
     77 
     78 typedef WIDE_INT wide_int;
     79 typedef unsigned WIDE_INT u_wide_int;
     80 typedef WIDEST_INT widest_int;
     81 #ifdef __TANDEM
     82 /* Although Tandem supports "long long" there is no unsigned variant. */
     83 typedef unsigned long       u_widest_int;
     84 #else
     85 typedef unsigned WIDEST_INT u_widest_int;
     86 #endif
     87 typedef int bool_int;
     88 
     89 #define S_NULL			"(null)"
     90 #define S_NULL_LEN		6
     91 
     92 #define FLOAT_DIGITS		6
     93 #define EXPONENT_LENGTH		10
     94 
     95 /*
     96  * NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions
     97  *
     98  * XXX: this is a magic number; do not decrease it
     99  */
    100 #define NUM_BUF_SIZE		512
    101 
    102 /*
    103  * cvt.c - IEEE floating point formatting routines for FreeBSD
    104  * from GNU libc-4.6.27.  Modified to be thread safe.
    105  */
    106 
    107 /*
    108  *    ap_ecvt converts to decimal
    109  *      the number of digits is specified by ndigit
    110  *      decpt is set to the position of the decimal point
    111  *      sign is set to 0 for positive, 1 for negative
    112  */
    113 
    114 #define	NDIG	80
    115 
    116 /* buf must have at least NDIG bytes */
    117 static char *ap_cvt(double arg, int ndigits, int *decpt, int *sign, int eflag, char *buf)
    118 {
    119     register int r2;
    120     double fi, fj;
    121     register char *p, *p1;
    122 
    123     if (ndigits >= NDIG - 1)
    124 	ndigits = NDIG - 2;
    125     r2 = 0;
    126     *sign = 0;
    127     p = &buf[0];
    128     if (arg < 0) {
    129 	*sign = 1;
    130 	arg = -arg;
    131     }
    132     arg = modf(arg, &fi);
    133     p1 = &buf[NDIG];
    134     /*
    135      * Do integer part
    136      */
    137     if (fi != 0) {
    138 	p1 = &buf[NDIG];
    139 	while (p1 > &buf[0] && fi != 0) {
    140 	    fj = modf(fi / 10, &fi);
    141 	    *--p1 = (int) ((fj + .03) * 10) + '0';
    142 	    r2++;
    143 	}
    144 	while (p1 < &buf[NDIG])
    145 	    *p++ = *p1++;
    146     }
    147     else if (arg > 0) {
    148 	while ((fj = arg * 10) < 1) {
    149 	    arg = fj;
    150 	    r2--;
    151 	}
    152     }
    153     p1 = &buf[ndigits];
    154     if (eflag == 0)
    155 	p1 += r2;
    156     *decpt = r2;
    157     if (p1 < &buf[0]) {
    158 	buf[0] = '\0';
    159 	return (buf);
    160     }
    161     while (p <= p1 && p < &buf[NDIG]) {
    162 	arg *= 10;
    163 	arg = modf(arg, &fj);
    164 	*p++ = (int) fj + '0';
    165     }
    166     if (p1 >= &buf[NDIG]) {
    167 	buf[NDIG - 1] = '\0';
    168 	return (buf);
    169     }
    170     p = p1;
    171     *p1 += 5;
    172     while (*p1 > '9') {
    173 	*p1 = '0';
    174 	if (p1 > buf)
    175 	    ++ * --p1;
    176 	else {
    177 	    *p1 = '1';
    178 	    (*decpt)++;
    179 	    if (eflag == 0) {
    180 		if (p > buf)
    181 		    *p = '0';
    182 		p++;
    183 	    }
    184 	}
    185     }
    186     *p = '\0';
    187     return (buf);
    188 }
    189 
    190 static char *ap_ecvt(double arg, int ndigits, int *decpt, int *sign, char *buf)
    191 {
    192     return (ap_cvt(arg, ndigits, decpt, sign, 1, buf));
    193 }
    194 
    195 static char *ap_fcvt(double arg, int ndigits, int *decpt, int *sign, char *buf)
    196 {
    197     return (ap_cvt(arg, ndigits, decpt, sign, 0, buf));
    198 }
    199 
    200 /*
    201  * ap_gcvt  - Floating output conversion to
    202  * minimal length string
    203  */
    204 
    205 static char *ap_gcvt(double number, int ndigit, char *buf, boolean_e altform)
    206 {
    207     int sign, decpt;
    208     register char *p1, *p2;
    209     register int i;
    210     char buf1[NDIG];
    211 
    212     p1 = ap_ecvt(number, ndigit, &decpt, &sign, buf1);
    213     p2 = buf;
    214     if (sign)
    215 	*p2++ = '-';
    216     for (i = ndigit - 1; i > 0 && p1[i] == '0'; i--)
    217 	ndigit--;
    218     if ((decpt >= 0 && decpt - ndigit > 4)
    219 	|| (decpt < 0 && decpt < -3)) {		/* use E-style */
    220 	decpt--;
    221 	*p2++ = *p1++;
    222 	*p2++ = '.';
    223 	for (i = 1; i < ndigit; i++)
    224 	    *p2++ = *p1++;
    225 	*p2++ = 'e';
    226 	if (decpt < 0) {
    227 	    decpt = -decpt;
    228 	    *p2++ = '-';
    229 	}
    230 	else
    231 	    *p2++ = '+';
    232 	if (decpt / 100 > 0)
    233 	    *p2++ = decpt / 100 + '0';
    234 	if (decpt / 10 > 0)
    235 	    *p2++ = (decpt % 100) / 10 + '0';
    236 	*p2++ = decpt % 10 + '0';
    237     }
    238     else {
    239 	if (decpt <= 0) {
    240 	    if (*p1 != '0')
    241 		*p2++ = '.';
    242 	    while (decpt < 0) {
    243 		decpt++;
    244 		*p2++ = '0';
    245 	    }
    246 	}
    247 	for (i = 1; i <= ndigit; i++) {
    248 	    *p2++ = *p1++;
    249 	    if (i == decpt)
    250 		*p2++ = '.';
    251 	}
    252 	if (ndigit < decpt) {
    253 	    while (ndigit++ < decpt)
    254 		*p2++ = '0';
    255 	    *p2++ = '.';
    256 	}
    257     }
    258     if (p2[-1] == '.' && !altform)
    259 	p2--;
    260     *p2 = '\0';
    261     return (buf);
    262 }
    263 
    264 /*
    265  * The INS_CHAR macro inserts a character in the buffer and writes
    266  * the buffer back to disk if necessary
    267  * It uses the char pointers sp and bep:
    268  *      sp points to the next available character in the buffer
    269  *      bep points to the end-of-buffer+1
    270  * While using this macro, note that the nextb pointer is NOT updated.
    271  *
    272  * NOTE: Evaluation of the c argument should not have any side-effects
    273  */
    274 #define INS_CHAR(c, sp, bep, cc)				\
    275 	    {							\
    276 		if (sp >= bep) {				\
    277 		    vbuff->curpos = sp;                         \
    278 		    if (flush_func(vbuff))			\
    279 			return -1;				\
    280 		    sp = vbuff->curpos;				\
    281 		    bep = vbuff->endpos;			\
    282 		} 						\
    283 		*sp++ = (c);					\
    284 		cc++; 						\
    285 	    }
    286 
    287 #define NUM( c )			( c - '0' )
    288 
    289 #define STR_TO_DEC( str, num )		\
    290     num = NUM( *str++ ) ;		\
    291     while ( ap_isdigit( *str ) )		\
    292     {					\
    293 	num *= 10 ;			\
    294 	num += NUM( *str++ ) ;		\
    295     }
    296 
    297 /*
    298  * This macro does zero padding so that the precision
    299  * requirement is satisfied. The padding is done by
    300  * adding '0's to the left of the string that is going
    301  * to be printed. We don't allow precision to be large
    302  * enough that we continue past the start of s.
    303  *
    304  * NOTE: this makes use of the magic info that s is
    305  * always based on num_buf with a size of NUM_BUF_SIZE.
    306  */
    307 #define FIX_PRECISION( adjust, precision, s, s_len )	\
    308     if ( adjust ) {					\
    309         int p = precision < NUM_BUF_SIZE - 1 ? precision : NUM_BUF_SIZE - 1; \
    310 	while ( s_len < p )				\
    311 	{						\
    312 	    *--s = '0' ;				\
    313 	    s_len++ ;					\
    314 	}						\
    315     }
    316 
    317 /*
    318  * Macro that does padding. The padding is done by printing
    319  * the character ch.
    320  */
    321 #define PAD( width, len, ch )	do		\
    322 	{					\
    323 	    INS_CHAR( ch, sp, bep, cc ) ;	\
    324 	    width-- ;				\
    325 	}					\
    326 	while ( width > len )
    327 
    328 /*
    329  * Prefix the character ch to the string str
    330  * Increase length
    331  * Set the has_prefix flag
    332  */
    333 #define PREFIX( str, length, ch )	 *--str = ch ; length++ ; has_prefix = YES
    334 
    335 
    336 /*
    337  * Convert num to its decimal format.
    338  * Return value:
    339  *   - a pointer to a string containing the number (no sign)
    340  *   - len contains the length of the string
    341  *   - is_negative is set to TRUE or FALSE depending on the sign
    342  *     of the number (always set to FALSE if is_unsigned is TRUE)
    343  *
    344  * The caller provides a buffer for the string: that is the buf_end argument
    345  * which is a pointer to the END of the buffer + 1 (i.e. if the buffer
    346  * is declared as buf[ 100 ], buf_end should be &buf[ 100 ])
    347  *
    348  * Note: we have 2 versions. One is used when we need to use quads
    349  * (conv_10_quad), the other when we don't (conv_10). We're assuming the
    350  * latter is faster.
    351  */
    352 static char *conv_10(register wide_int num, register bool_int is_unsigned,
    353 		     register bool_int *is_negative, char *buf_end,
    354 		     register int *len)
    355 {
    356     register char *p = buf_end;
    357     register u_wide_int magnitude;
    358 
    359     if (is_unsigned) {
    360 	magnitude = (u_wide_int) num;
    361 	*is_negative = FALSE;
    362     }
    363     else {
    364 	*is_negative = (num < 0);
    365 
    366 	/*
    367 	 * On a 2's complement machine, negating the most negative integer
    368 	 * results in a number that cannot be represented as a signed integer.
    369 	 * Here is what we do to obtain the number's magnitude:
    370 	 *      a. add 1 to the number
    371 	 *      b. negate it (becomes positive)
    372 	 *      c. convert it to unsigned
    373 	 *      d. add 1
    374 	 */
    375 	if (*is_negative) {
    376 	    wide_int t = num + 1;
    377 
    378 	    magnitude = ((u_wide_int) -t) + 1;
    379 	}
    380 	else
    381 	    magnitude = (u_wide_int) num;
    382     }
    383 
    384     /*
    385      * We use a do-while loop so that we write at least 1 digit
    386      */
    387     do {
    388 	register u_wide_int new_magnitude = magnitude / 10;
    389 
    390 	*--p = (char) (magnitude - new_magnitude * 10 + '0');
    391 	magnitude = new_magnitude;
    392     }
    393     while (magnitude);
    394 
    395     *len = buf_end - p;
    396     return (p);
    397 }
    398 
    399 static char *conv_10_quad(widest_int num, register bool_int is_unsigned,
    400 		     register bool_int *is_negative, char *buf_end,
    401 		     register int *len)
    402 {
    403     register char *p = buf_end;
    404     u_widest_int magnitude;
    405 
    406     /*
    407      * We see if we can use the faster non-quad version by checking the
    408      * number against the largest long value it can be. If <=, we
    409      * punt to the quicker version.
    410      */
    411     if ((num <= ULONG_MAX && is_unsigned) || (num <= LONG_MAX && !is_unsigned))
    412     	return(conv_10( (wide_int)num, is_unsigned, is_negative,
    413 	       buf_end, len));
    414 
    415     if (is_unsigned) {
    416 	magnitude = (u_widest_int) num;
    417 	*is_negative = FALSE;
    418     }
    419     else {
    420 	*is_negative = (num < 0);
    421 
    422 	/*
    423 	 * On a 2's complement machine, negating the most negative integer
    424 	 * results in a number that cannot be represented as a signed integer.
    425 	 * Here is what we do to obtain the number's magnitude:
    426 	 *      a. add 1 to the number
    427 	 *      b. negate it (becomes positive)
    428 	 *      c. convert it to unsigned
    429 	 *      d. add 1
    430 	 */
    431 	if (*is_negative) {
    432 	    widest_int t = num + 1;
    433 
    434 	    magnitude = ((u_widest_int) -t) + 1;
    435 	}
    436 	else
    437 	    magnitude = (u_widest_int) num;
    438     }
    439 
    440     /*
    441      * We use a do-while loop so that we write at least 1 digit
    442      */
    443     do {
    444 	u_widest_int new_magnitude = magnitude / 10;
    445 
    446 	*--p = (char) (magnitude - new_magnitude * 10 + '0');
    447 	magnitude = new_magnitude;
    448     }
    449     while (magnitude);
    450 
    451     *len = buf_end - p;
    452     return (p);
    453 }
    454 
    455 
    456 
    457 static char *conv_in_addr(struct in_addr *ia, char *buf_end, int *len)
    458 {
    459     unsigned addr = ntohl(ia->s_addr);
    460     char *p = buf_end;
    461     bool_int is_negative;
    462     int sub_len;
    463 
    464     p = conv_10((addr & 0x000000FF)      , TRUE, &is_negative, p, &sub_len);
    465     *--p = '.';
    466     p = conv_10((addr & 0x0000FF00) >>  8, TRUE, &is_negative, p, &sub_len);
    467     *--p = '.';
    468     p = conv_10((addr & 0x00FF0000) >> 16, TRUE, &is_negative, p, &sub_len);
    469     *--p = '.';
    470     p = conv_10((addr & 0xFF000000) >> 24, TRUE, &is_negative, p, &sub_len);
    471 
    472     *len = buf_end - p;
    473     return (p);
    474 }
    475 
    476 
    477 
    478 static char *conv_sockaddr_in(struct sockaddr_in *si, char *buf_end, int *len)
    479 {
    480     char *p = buf_end;
    481     bool_int is_negative;
    482     int sub_len;
    483 
    484     p = conv_10(ntohs(si->sin_port), TRUE, &is_negative, p, &sub_len);
    485     *--p = ':';
    486     p = conv_in_addr(&si->sin_addr, p, &sub_len);
    487 
    488     *len = buf_end - p;
    489     return (p);
    490 }
    491 
    492 
    493 
    494 /*
    495  * Convert a floating point number to a string formats 'f', 'e' or 'E'.
    496  * The result is placed in buf, and len denotes the length of the string
    497  * The sign is returned in the is_negative argument (and is not placed
    498  * in buf).
    499  */
    500 static char *conv_fp(register char format, register double num,
    501     boolean_e add_dp, int precision, bool_int *is_negative,
    502     char *buf, int *len)
    503 {
    504     register char *s = buf;
    505     register char *p;
    506     int decimal_point;
    507     char buf1[NDIG];
    508 
    509     if (format == 'f')
    510 	p = ap_fcvt(num, precision, &decimal_point, is_negative, buf1);
    511     else			/* either e or E format */
    512 	p = ap_ecvt(num, precision + 1, &decimal_point, is_negative, buf1);
    513 
    514     /*
    515      * Check for Infinity and NaN
    516      */
    517     if (ap_isalpha(*p)) {
    518 	*len = strlen(strcpy(buf, p));
    519 	*is_negative = FALSE;
    520 	return (buf);
    521     }
    522 
    523     if (format == 'f') {
    524 	if (decimal_point <= 0) {
    525 	    *s++ = '0';
    526 	    if (precision > 0) {
    527 		*s++ = '.';
    528 		while (decimal_point++ < 0)
    529 		    *s++ = '0';
    530 	    }
    531 	    else if (add_dp)
    532 		*s++ = '.';
    533 	}
    534 	else {
    535 	    while (decimal_point-- > 0)
    536 		*s++ = *p++;
    537 	    if (precision > 0 || add_dp)
    538 		*s++ = '.';
    539 	}
    540     }
    541     else {
    542 	*s++ = *p++;
    543 	if (precision > 0 || add_dp)
    544 	    *s++ = '.';
    545     }
    546 
    547     /*
    548      * copy the rest of p, the NUL is NOT copied
    549      */
    550     while (*p)
    551 	*s++ = *p++;
    552 
    553     if (format != 'f') {
    554 	char temp[EXPONENT_LENGTH];	/* for exponent conversion */
    555 	int t_len;
    556 	bool_int exponent_is_negative;
    557 
    558 	*s++ = format;		/* either e or E */
    559 	decimal_point--;
    560 	if (decimal_point != 0) {
    561 	    p = conv_10((wide_int) decimal_point, FALSE, &exponent_is_negative,
    562 			&temp[EXPONENT_LENGTH], &t_len);
    563 	    *s++ = exponent_is_negative ? '-' : '+';
    564 
    565 	    /*
    566 	     * Make sure the exponent has at least 2 digits
    567 	     */
    568 	    if (t_len == 1)
    569 		*s++ = '0';
    570 	    while (t_len--)
    571 		*s++ = *p++;
    572 	}
    573 	else {
    574 	    *s++ = '+';
    575 	    *s++ = '0';
    576 	    *s++ = '0';
    577 	}
    578     }
    579 
    580     *len = s - buf;
    581     return (buf);
    582 }
    583 
    584 
    585 /*
    586  * Convert num to a base X number where X is a power of 2. nbits determines X.
    587  * For example, if nbits is 3, we do base 8 conversion
    588  * Return value:
    589  *      a pointer to a string containing the number
    590  *
    591  * The caller provides a buffer for the string: that is the buf_end argument
    592  * which is a pointer to the END of the buffer + 1 (i.e. if the buffer
    593  * is declared as buf[ 100 ], buf_end should be &buf[ 100 ])
    594  *
    595  * As with conv_10, we have a faster version which is used when
    596  * the number isn't quad size.
    597  */
    598 static char *conv_p2(register u_wide_int num, register int nbits,
    599 		     char format, char *buf_end, register int *len)
    600 {
    601     register int mask = (1 << nbits) - 1;
    602     register char *p = buf_end;
    603     static const char low_digits[] = "0123456789abcdef";
    604     static const char upper_digits[] = "0123456789ABCDEF";
    605     register const char *digits = (format == 'X') ? upper_digits : low_digits;
    606 
    607     do {
    608 	*--p = digits[num & mask];
    609 	num >>= nbits;
    610     }
    611     while (num);
    612 
    613     *len = buf_end - p;
    614     return (p);
    615 }
    616 
    617 static char *conv_p2_quad(u_widest_int num, register int nbits,
    618 		     char format, char *buf_end, register int *len)
    619 {
    620     register int mask = (1 << nbits) - 1;
    621     register char *p = buf_end;
    622     static const char low_digits[] = "0123456789abcdef";
    623     static const char upper_digits[] = "0123456789ABCDEF";
    624     register const char *digits = (format == 'X') ? upper_digits : low_digits;
    625 
    626     if (num <= ULONG_MAX)
    627     	return(conv_p2( (u_wide_int)num, nbits, format, buf_end, len));
    628 
    629     do {
    630 	*--p = digits[num & mask];
    631 	num >>= nbits;
    632     }
    633     while (num);
    634 
    635     *len = buf_end - p;
    636     return (p);
    637 }
    638 
    639 
    640 /*
    641  * Do format conversion placing the output in buffer
    642  */
    643 API_EXPORT(int) ap_vformatter(int (*flush_func)(ap_vformatter_buff *),
    644     ap_vformatter_buff *vbuff, const char *fmt, va_list ap)
    645 {
    646     register char *sp;
    647     register char *bep;
    648     register int cc = 0;
    649     register int i;
    650 
    651     register char *s = NULL;
    652     char *q;
    653     int s_len;
    654 
    655     register int min_width = 0;
    656     int precision = 0;
    657     enum {
    658 	LEFT, RIGHT
    659     } adjust;
    660     char pad_char;
    661     char prefix_char;
    662 
    663     double fp_num;
    664     widest_int i_quad = (widest_int) 0;
    665     u_widest_int ui_quad;
    666     wide_int i_num = (wide_int) 0;
    667     u_wide_int ui_num;
    668 
    669     char num_buf[NUM_BUF_SIZE];
    670     char char_buf[2];		/* for printing %% and %<unknown> */
    671 
    672     enum var_type_enum {
    673     	IS_QUAD, IS_LONG, IS_SHORT, IS_INT
    674     };
    675     enum var_type_enum var_type = IS_INT;
    676 
    677     /*
    678      * Flag variables
    679      */
    680     boolean_e alternate_form;
    681     boolean_e print_sign;
    682     boolean_e print_blank;
    683     boolean_e adjust_precision;
    684     boolean_e adjust_width;
    685     bool_int is_negative;
    686 
    687     sp = vbuff->curpos;
    688     bep = vbuff->endpos;
    689 
    690     while (*fmt) {
    691 	if (*fmt != '%') {
    692 	    INS_CHAR(*fmt, sp, bep, cc);
    693 	}
    694 	else {
    695 	    /*
    696 	     * Default variable settings
    697 	     */
    698 	    adjust = RIGHT;
    699 	    alternate_form = print_sign = print_blank = NO;
    700 	    pad_char = ' ';
    701 	    prefix_char = NUL;
    702 
    703 	    fmt++;
    704 
    705 	    /*
    706 	     * Try to avoid checking for flags, width or precision
    707 	     */
    708 	    if (!ap_islower(*fmt)) {
    709 		/*
    710 		 * Recognize flags: -, #, BLANK, +
    711 		 */
    712 		for (;; fmt++) {
    713 		    if (*fmt == '-')
    714 			adjust = LEFT;
    715 		    else if (*fmt == '+')
    716 			print_sign = YES;
    717 		    else if (*fmt == '#')
    718 			alternate_form = YES;
    719 		    else if (*fmt == ' ')
    720 			print_blank = YES;
    721 		    else if (*fmt == '0')
    722 			pad_char = '0';
    723 		    else
    724 			break;
    725 		}
    726 
    727 		/*
    728 		 * Check if a width was specified
    729 		 */
    730 		if (ap_isdigit(*fmt)) {
    731 		    STR_TO_DEC(fmt, min_width);
    732 		    adjust_width = YES;
    733 		}
    734 		else if (*fmt == '*') {
    735 		    min_width = va_arg(ap, int);
    736 		    fmt++;
    737 		    adjust_width = YES;
    738 		    if (min_width < 0) {
    739 			adjust = LEFT;
    740 			min_width = -min_width;
    741 		    }
    742 		}
    743 		else
    744 		    adjust_width = NO;
    745 
    746 		/*
    747 		 * Check if a precision was specified
    748 		 */
    749 		if (*fmt == '.') {
    750 		    adjust_precision = YES;
    751 		    fmt++;
    752 		    if (ap_isdigit(*fmt)) {
    753 			STR_TO_DEC(fmt, precision);
    754 		    }
    755 		    else if (*fmt == '*') {
    756 			precision = va_arg(ap, int);
    757 			fmt++;
    758 			if (precision < 0)
    759 			    precision = 0;
    760 		    }
    761 		    else
    762 			precision = 0;
    763 		}
    764 		else
    765 		    adjust_precision = NO;
    766 	    }
    767 	    else
    768 		adjust_precision = adjust_width = NO;
    769 
    770 	    /*
    771 	     * Modifier check
    772 	     */
    773 	    if (*fmt == 'q') {
    774 		var_type = IS_QUAD;
    775 		fmt++;
    776 	    }
    777 	    else if (*fmt == 'l') {
    778 		var_type = IS_LONG;
    779 		fmt++;
    780 	    }
    781 	    else if (*fmt == 'h') {
    782 		var_type = IS_SHORT;
    783 		fmt++;
    784 	    }
    785 	    else {
    786 		var_type = IS_INT;
    787 	    }
    788 
    789 	    /*
    790 	     * Argument extraction and printing.
    791 	     * First we determine the argument type.
    792 	     * Then, we convert the argument to a string.
    793 	     * On exit from the switch, s points to the string that
    794 	     * must be printed, s_len has the length of the string
    795 	     * The precision requirements, if any, are reflected in s_len.
    796 	     *
    797 	     * NOTE: pad_char may be set to '0' because of the 0 flag.
    798 	     *   It is reset to ' ' by non-numeric formats
    799 	     */
    800 	    switch (*fmt) {
    801 	    case 'u':
    802 	    	if (var_type == IS_QUAD) {
    803 		    i_quad = va_arg(ap, u_widest_int);
    804 		    s = conv_10_quad(i_quad, 1, &is_negative,
    805 			    &num_buf[NUM_BUF_SIZE], &s_len);
    806 		}
    807 		else {
    808 		    if (var_type == IS_LONG)
    809 			i_num = (wide_int) va_arg(ap, u_wide_int);
    810 		    else if (var_type == IS_SHORT)
    811 			i_num = (wide_int) (unsigned short) va_arg(ap, unsigned int);
    812 		    else
    813 			i_num = (wide_int) va_arg(ap, unsigned int);
    814 		    s = conv_10(i_num, 1, &is_negative,
    815 			    &num_buf[NUM_BUF_SIZE], &s_len);
    816 		}
    817 		FIX_PRECISION(adjust_precision, precision, s, s_len);
    818 		break;
    819 
    820 	    case 'd':
    821 	    case 'i':
    822 	    	if (var_type == IS_QUAD) {
    823 		    i_quad = va_arg(ap, widest_int);
    824 		    s = conv_10_quad(i_quad, 0, &is_negative,
    825 			    &num_buf[NUM_BUF_SIZE], &s_len);
    826 		}
    827 		else {
    828 		    if (var_type == IS_LONG)
    829 			i_num = (wide_int) va_arg(ap, wide_int);
    830 		    else if (var_type == IS_SHORT)
    831 			i_num = (wide_int) (short) va_arg(ap, int);
    832 		    else
    833 			i_num = (wide_int) va_arg(ap, int);
    834 		    s = conv_10(i_num, 0, &is_negative,
    835 			    &num_buf[NUM_BUF_SIZE], &s_len);
    836 		}
    837 		FIX_PRECISION(adjust_precision, precision, s, s_len);
    838 
    839 		if (is_negative)
    840 		    prefix_char = '-';
    841 		else if (print_sign)
    842 		    prefix_char = '+';
    843 		else if (print_blank)
    844 		    prefix_char = ' ';
    845 		break;
    846 
    847 
    848 	    case 'o':
    849 		if (var_type == IS_QUAD) {
    850 		    ui_quad = va_arg(ap, u_widest_int);
    851 		    s = conv_p2_quad(ui_quad, 3, *fmt,
    852 			    &num_buf[NUM_BUF_SIZE], &s_len);
    853 		}
    854 		else {
    855 		    if (var_type == IS_LONG)
    856 			ui_num = (u_wide_int) va_arg(ap, u_wide_int);
    857 		    else if (var_type == IS_SHORT)
    858 			ui_num = (u_wide_int) (unsigned short) va_arg(ap, unsigned int);
    859 		    else
    860 			ui_num = (u_wide_int) va_arg(ap, unsigned int);
    861 		    s = conv_p2(ui_num, 3, *fmt,
    862 			    &num_buf[NUM_BUF_SIZE], &s_len);
    863 		}
    864 		FIX_PRECISION(adjust_precision, precision, s, s_len);
    865 		if (alternate_form && *s != '0') {
    866 		    *--s = '0';
    867 		    s_len++;
    868 		}
    869 		break;
    870 
    871 
    872 	    case 'x':
    873 	    case 'X':
    874 		if (var_type == IS_QUAD) {
    875 		    ui_quad = va_arg(ap, u_widest_int);
    876 		    s = conv_p2_quad(ui_quad, 4, *fmt,
    877 			    &num_buf[NUM_BUF_SIZE], &s_len);
    878 		}
    879 		else {
    880 		    if (var_type == IS_LONG)
    881 			ui_num = (u_wide_int) va_arg(ap, u_wide_int);
    882 		    else if (var_type == IS_SHORT)
    883 			ui_num = (u_wide_int) (unsigned short) va_arg(ap, unsigned int);
    884 		    else
    885 			ui_num = (u_wide_int) va_arg(ap, unsigned int);
    886 		    s = conv_p2(ui_num, 4, *fmt,
    887 			    &num_buf[NUM_BUF_SIZE], &s_len);
    888 		}
    889 		FIX_PRECISION(adjust_precision, precision, s, s_len);
    890 		if (alternate_form && i_num != 0) {
    891 		    *--s = *fmt;	/* 'x' or 'X' */
    892 		    *--s = '0';
    893 		    s_len += 2;
    894 		}
    895 		break;
    896 
    897 
    898 	    case 's':
    899 		s = va_arg(ap, char *);
    900 		if (s != NULL) {
    901 		    s_len = strlen(s);
    902 		    if (adjust_precision && precision < s_len)
    903 			s_len = precision;
    904 		}
    905 		else {
    906 		    s = S_NULL;
    907 		    s_len = S_NULL_LEN;
    908 		}
    909 		pad_char = ' ';
    910 		break;
    911 
    912 
    913 	    case 'f':
    914 	    case 'e':
    915 	    case 'E':
    916 		fp_num = va_arg(ap, double);
    917 		/*
    918 		 * * We use &num_buf[ 1 ], so that we have room for the sign
    919 		 */
    920 #ifdef HAVE_ISNAN
    921 		if (isnan(fp_num)) {
    922 		    s = "nan";
    923 		    s_len = 3;
    924 		}
    925 		else
    926 #endif
    927 #ifdef HAVE_ISINF
    928 		if (isinf(fp_num)) {
    929 		    s = "inf";
    930 		    s_len = 3;
    931 		}
    932 		else
    933 #endif
    934 		{
    935 		    s = conv_fp(*fmt, fp_num, alternate_form,
    936 			    (adjust_precision == NO) ? FLOAT_DIGITS : precision,
    937 				&is_negative, &num_buf[1], &s_len);
    938 		    if (is_negative)
    939 			prefix_char = '-';
    940 		    else if (print_sign)
    941 			prefix_char = '+';
    942 		    else if (print_blank)
    943 			prefix_char = ' ';
    944 		}
    945 	        break;
    946 
    947 
    948 	    case 'g':
    949 	    case 'G':
    950 		if (adjust_precision == NO)
    951 		    precision = FLOAT_DIGITS;
    952 		else if (precision == 0)
    953 		    precision = 1;
    954 		/*
    955 		 * * We use &num_buf[ 1 ], so that we have room for the sign
    956 		 */
    957 		s = ap_gcvt(va_arg(ap, double), precision, &num_buf[1],
    958 		            alternate_form);
    959 		if (*s == '-')
    960 		    prefix_char = *s++;
    961 		else if (print_sign)
    962 		    prefix_char = '+';
    963 		else if (print_blank)
    964 		    prefix_char = ' ';
    965 
    966 		s_len = strlen(s);
    967 
    968 		if (alternate_form && (q = strchr(s, '.')) == NULL) {
    969 		    s[s_len++] = '.';
    970 		    s[s_len] = '\0'; /* delimit for following strchr() */
    971 		}
    972 		if (*fmt == 'G' && (q = strchr(s, 'e')) != NULL)
    973 		    *q = 'E';
    974 		break;
    975 
    976 
    977 	    case 'c':
    978 		char_buf[0] = (char) (va_arg(ap, int));
    979 		s = &char_buf[0];
    980 		s_len = 1;
    981 		pad_char = ' ';
    982 		break;
    983 
    984 
    985 	    case '%':
    986 		char_buf[0] = '%';
    987 		s = &char_buf[0];
    988 		s_len = 1;
    989 		pad_char = ' ';
    990 		break;
    991 
    992 
    993 	    case 'n':
    994 	    	if (var_type == IS_QUAD)
    995 		    *(va_arg(ap, widest_int *)) = cc;
    996 		else if (var_type == IS_LONG)
    997 		    *(va_arg(ap, long *)) = cc;
    998 		else if (var_type == IS_SHORT)
    999 		    *(va_arg(ap, short *)) = cc;
   1000 		else
   1001 		    *(va_arg(ap, int *)) = cc;
   1002 		break;
   1003 
   1004 		/*
   1005 		 * This is where we extend the printf format, with a second
   1006 		 * type specifier
   1007 		 */
   1008 	    case 'p':
   1009 		switch(*++fmt) {
   1010 		    /*
   1011 		     * If the pointer size is equal to or smaller than the size
   1012 		     * of the largest unsigned int, we convert the pointer to a
   1013 		     * hex number, otherwise we print "%p" to indicate that we
   1014 		     * don't handle "%p".
   1015 		     */
   1016 		case 'p':
   1017 #ifdef AP_VOID_P_IS_QUAD
   1018 		    if (sizeof(void *) <= sizeof(u_widest_int)) {
   1019 		    	ui_quad = (u_widest_int) va_arg(ap, void *);
   1020 			s = conv_p2_quad(ui_quad, 4, 'x',
   1021 				&num_buf[NUM_BUF_SIZE], &s_len);
   1022 		    }
   1023 #else
   1024 		    if (sizeof(void *) <= sizeof(u_wide_int)) {
   1025 		    	ui_num = (u_wide_int) va_arg(ap, void *);
   1026 			s = conv_p2(ui_num, 4, 'x',
   1027 				&num_buf[NUM_BUF_SIZE], &s_len);
   1028 		    }
   1029 #endif
   1030 		    else {
   1031 			s = "%p";
   1032 			s_len = 2;
   1033 			prefix_char = NUL;
   1034 		    }
   1035 		    pad_char = ' ';
   1036 		    break;
   1037 
   1038 		    /* print a struct sockaddr_in as a.b.c.d:port */
   1039 		case 'I':
   1040 		    {
   1041 			struct sockaddr_in *si;
   1042 
   1043 			si = va_arg(ap, struct sockaddr_in *);
   1044 			if (si != NULL) {
   1045 			    s = conv_sockaddr_in(si, &num_buf[NUM_BUF_SIZE], &s_len);
   1046 			    if (adjust_precision && precision < s_len)
   1047 				s_len = precision;
   1048 			}
   1049 			else {
   1050 			    s = S_NULL;
   1051 			    s_len = S_NULL_LEN;
   1052 			}
   1053 			pad_char = ' ';
   1054 		    }
   1055 		    break;
   1056 
   1057 		    /* print a struct in_addr as a.b.c.d */
   1058 		case 'A':
   1059 		    {
   1060 			struct in_addr *ia;
   1061 
   1062 			ia = va_arg(ap, struct in_addr *);
   1063 			if (ia != NULL) {
   1064 			    s = conv_in_addr(ia, &num_buf[NUM_BUF_SIZE], &s_len);
   1065 			    if (adjust_precision && precision < s_len)
   1066 				s_len = precision;
   1067 			}
   1068 			else {
   1069 			    s = S_NULL;
   1070 			    s_len = S_NULL_LEN;
   1071 			}
   1072 			pad_char = ' ';
   1073 		    }
   1074 		    break;
   1075 
   1076 		case NUL:
   1077 		    /* if %p ends the string, oh well ignore it */
   1078 		    continue;
   1079 
   1080 		default:
   1081 		    s = "bogus %p";
   1082 		    s_len = 8;
   1083 		    prefix_char = NUL;
   1084 		    break;
   1085 		}
   1086 		break;
   1087 
   1088 	    case NUL:
   1089 		/*
   1090 		 * The last character of the format string was %.
   1091 		 * We ignore it.
   1092 		 */
   1093 		continue;
   1094 
   1095 
   1096 		/*
   1097 		 * The default case is for unrecognized %'s.
   1098 		 * We print %<char> to help the user identify what
   1099 		 * option is not understood.
   1100 		 * This is also useful in case the user wants to pass
   1101 		 * the output of format_converter to another function
   1102 		 * that understands some other %<char> (like syslog).
   1103 		 * Note that we can't point s inside fmt because the
   1104 		 * unknown <char> could be preceded by width etc.
   1105 		 */
   1106 	    default:
   1107 		char_buf[0] = '%';
   1108 		char_buf[1] = *fmt;
   1109 		s = char_buf;
   1110 		s_len = 2;
   1111 		pad_char = ' ';
   1112 		break;
   1113 	    }
   1114 
   1115 	    if (prefix_char != NUL && s != S_NULL && s != char_buf) {
   1116 		*--s = prefix_char;
   1117 		s_len++;
   1118 	    }
   1119 
   1120 	    if (adjust_width && adjust == RIGHT && min_width > s_len) {
   1121 		if (pad_char == '0' && prefix_char != NUL) {
   1122 		    INS_CHAR(*s, sp, bep, cc);
   1123 		    s++;
   1124 		    s_len--;
   1125 		    min_width--;
   1126 		}
   1127 		PAD(min_width, s_len, pad_char);
   1128 	    }
   1129 
   1130 	    /*
   1131 	     * Print the string s.
   1132 	     */
   1133 	    for (i = s_len; i != 0; i--) {
   1134 		INS_CHAR(*s, sp, bep, cc);
   1135 		s++;
   1136 	    }
   1137 
   1138 	    if (adjust_width && adjust == LEFT && min_width > s_len)
   1139 		PAD(min_width, s_len, pad_char);
   1140 	}
   1141 	fmt++;
   1142     }
   1143     vbuff->curpos = sp;
   1144 
   1145     return cc;
   1146 }
   1147 
   1148 
   1149 static int snprintf_flush(ap_vformatter_buff *vbuff)
   1150 {
   1151     /* if the buffer fills we have to abort immediately, there is no way
   1152      * to "flush" an ap_snprintf... there's nowhere to flush it to.
   1153      */
   1154     return -1;
   1155 }
   1156 
   1157 
   1158 API_EXPORT_NONSTD(int) ap_snprintf(char *buf, size_t len, const char *format,...)
   1159 {
   1160     int cc;
   1161     va_list ap;
   1162     ap_vformatter_buff vbuff;
   1163 
   1164     if (len == 0)
   1165 	return 0;
   1166 
   1167     /* save one byte for nul terminator */
   1168     vbuff.curpos = buf;
   1169     vbuff.endpos = buf + len - 1;
   1170     va_start(ap, format);
   1171     cc = ap_vformatter(snprintf_flush, &vbuff, format, ap);
   1172     va_end(ap);
   1173     *vbuff.curpos = '\0';
   1174     return (cc == -1) ? len : cc;
   1175 }
   1176 
   1177 
   1178 API_EXPORT(int) ap_vsnprintf(char *buf, size_t len, const char *format,
   1179 			     va_list ap)
   1180 {
   1181     int cc;
   1182     ap_vformatter_buff vbuff;
   1183 
   1184     if (len == 0)
   1185 	return 0;
   1186 
   1187     /* save one byte for nul terminator */
   1188     vbuff.curpos = buf;
   1189     vbuff.endpos = buf + len - 1;
   1190     cc = ap_vformatter(snprintf_flush, &vbuff, format, ap);
   1191     *vbuff.curpos = '\0';
   1192     return (cc == -1) ? len : cc;
   1193 }
   1194