jim 99/12/13 05:36:17
Modified: src/lib/apr/lib apr_snprintf.c Log: Fold in the snprintf() changes Revision Changes Path 1.5 +202 -44 apache-2.0/src/lib/apr/lib/apr_snprintf.c Index: apr_snprintf.c =================================================================== RCS file: /export/home/cvs/apache-2.0/src/lib/apr/lib/apr_snprintf.c,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- apr_snprintf.c 1999/12/09 21:00:44 1.4 +++ apr_snprintf.c 1999/12/13 13:36:16 1.5 @@ -54,7 +54,7 @@ * project, please see <http://www.apache.org/>. * * This code is based on, and used with the permission of, the - * SIO stdiocntxteplacement strx_* functions by Panos Tsirigotis + * SIO stdio-replacement strx_* functions by Panos Tsirigotis * <[EMAIL PROTECTED]> for xinetd. */ @@ -90,12 +90,22 @@ #ifndef TRUE #define TRUE 1 #endif +#ifndef AP_LONGEST_LONG +#define AP_LONGEST_LONG long +#endif #define NUL '\0' -#define INT_NULL ((int *)0) #define WIDE_INT long +#define WIDEST_INT AP_LONGEST_LONG typedef WIDE_INT wide_int; typedef unsigned WIDE_INT u_wide_int; +typedef WIDEST_INT widest_int; +#ifdef __TANDEM +/* Although Tandem supports "long long" there is no unsigned variant. */ +typedef unsigned long u_widest_int; +#else +typedef unsigned WIDEST_INT u_widest_int; +#endif typedef int bool_int; #define S_NULL "(null)" @@ -131,7 +141,7 @@ register int r2; double fi, fj; register char *p, *p1; - + if (ndigits >= NDIG - 1) ndigits = NDIG - 2; r2 = 0; @@ -350,6 +360,10 @@ * The caller provides a buffer for the string: that is the buf_end argument * which is a pointer to the END of the buffer + 1 (i.e. if the buffer * is declared as buf[ 100 ], buf_end should be &buf[ 100 ]) + * + * Note: we have 2 versions. One is used when we need to use quads + * (conv_10_quad), the other when we don't (conv_10). We're assuming the + * latter is faster. */ static char *conv_10(register wide_int num, register bool_int is_unsigned, register bool_int *is_negative, char *buf_end, @@ -398,6 +412,62 @@ return (p); } +static char *conv_10_quad(widest_int num, register bool_int is_unsigned, + register bool_int *is_negative, char *buf_end, + register int *len) +{ + register char *p = buf_end; + u_widest_int magnitude; + + /* + * We see if we can use the faster non-quad version by checking the + * number against the largest long value it can be. If <=, we + * punt to the quicker version. + */ + if ((num <= ULONG_MAX && is_unsigned) || (num <= LONG_MAX && !is_unsigned)) + return(conv_10( (wide_int)num, is_unsigned, is_negative, + buf_end, len)); + + if (is_unsigned) { + magnitude = (u_widest_int) num; + *is_negative = FALSE; + } + else { + *is_negative = (num < 0); + + /* + * On a 2's complement machine, negating the most negative integer + * results in a number that cannot be represented as a signed integer. + * Here is what we do to obtain the number's magnitude: + * a. add 1 to the number + * b. negate it (becomes positive) + * c. convert it to unsigned + * d. add 1 + */ + if (*is_negative) { + widest_int t = num + 1; + + magnitude = ((u_widest_int) -t) + 1; + } + else + magnitude = (u_widest_int) num; + } + + /* + * We use a do-while loop so that we write at least 1 digit + */ + do { + u_widest_int new_magnitude = magnitude / 10; + + *--p = (char) (magnitude - new_magnitude * 10 + '0'); + magnitude = new_magnitude; + } + while (magnitude); + + *len = buf_end - p; + return (p); +} + static char *conv_in_addr(struct in_addr *ia, char *buf_end, int *len) @@ -537,6 +607,9 @@ * The caller provides a buffer for the string: that is the buf_end argument * which is a pointer to the END of the buffer + 1 (i.e. if the buffer * is declared as buf[ 100 ], buf_end should be &buf[ 100 ]) + * + * As with conv_10, we have a faster version which is used when + * the number isn't quad size. */ static char *conv_p2(register u_wide_int num, register int nbits, char format, char *buf_end, register int *len) @@ -557,12 +630,34 @@ return (p); } +static char *conv_p2_quad(u_widest_int num, register int nbits, + char format, char *buf_end, register int *len) +{ + register int mask = (1 << nbits) - 1; + register char *p = buf_end; + static const char low_digits[] = "0123456789abcdef"; + static const char upper_digits[] = "0123456789ABCDEF"; + register const char *digits = (format == 'X') ? upper_digits : low_digits; + + if (num <= ULONG_MAX) + return(conv_p2( (u_wide_int)num, nbits, format, buf_end, len)); + + do { + *--p = digits[num & mask]; + num >>= nbits; + } + while (num); + + *len = buf_end - p; + return (p); +} + /* * Do format conversion placing the output in buffer */ -API_EXPORT(int) ap_vformatter(int (*flush_func)(ap_vformatter_buff_t *), - ap_vformatter_buff_t *vbuff, const char *fmt, va_list ap) +API_EXPORT(int) ap_vformatter(int (*flush_func)(ap_vformatter_buff *), + ap_vformatter_buff *vbuff, const char *fmt, va_list ap) { register char *sp; register char *bep; @@ -582,16 +677,22 @@ char prefix_char; double fp_num; + widest_int i_quad = (widest_int) 0; + u_widest_int ui_quad; wide_int i_num = (wide_int) 0; u_wide_int ui_num; char num_buf[NUM_BUF_SIZE]; char char_buf[2]; /* for printing %% and %<unknown> */ + enum var_type_enum { + IS_QUAD, IS_LONG, IS_SHORT, IS_INT + }; + enum var_type_enum var_type = IS_INT; + /* * Flag variables */ - boolean_e is_long; boolean_e alternate_form; boolean_e print_sign; boolean_e print_blank; @@ -689,14 +790,20 @@ /* * Modifier check */ - if (*fmt == 'l') { - is_long = YES; + if (*fmt == 'q') { + var_type = IS_QUAD; fmt++; } + else if (*fmt == 'l') { + var_type = IS_LONG; + fmt++; + } + else if (*fmt == 'h') { + var_type = IS_SHORT; + fmt++; + } else { - if (*fmt == 'h') /* "short" backward compatibility */ - ++fmt; - is_long = NO; + var_type = IS_INT; } /* @@ -712,23 +819,41 @@ */ switch (*fmt) { case 'u': - if (is_long) - i_num = va_arg(ap, u_wide_int); - else - i_num = (wide_int) va_arg(ap, unsigned int); - s = conv_10(i_num, 1, &is_negative, + if (var_type == IS_QUAD) { + i_quad = va_arg(ap, u_widest_int); + s = conv_10_quad(i_quad, 1, &is_negative, + &num_buf[NUM_BUF_SIZE], &s_len); + } + else { + if (var_type == IS_LONG) + i_num = (wide_int) va_arg(ap, u_wide_int); + else if (var_type == IS_SHORT) + i_num = (wide_int) (unsigned short) va_arg(ap, unsigned int); + else + i_num = (wide_int) va_arg(ap, unsigned int); + s = conv_10(i_num, 1, &is_negative, &num_buf[NUM_BUF_SIZE], &s_len); + } FIX_PRECISION(adjust_precision, precision, s, s_len); break; case 'd': case 'i': - if (is_long) - i_num = va_arg(ap, wide_int); - else - i_num = (wide_int) va_arg(ap, int); - s = conv_10(i_num, 0, &is_negative, + if (var_type == IS_QUAD) { + i_quad = va_arg(ap, widest_int); + s = conv_10_quad(i_quad, 0, &is_negative, &num_buf[NUM_BUF_SIZE], &s_len); + } + else { + if (var_type == IS_LONG) + i_num = (wide_int) va_arg(ap, wide_int); + else if (var_type == IS_SHORT) + i_num = (wide_int) (short) va_arg(ap, int); + else + i_num = (wide_int) va_arg(ap, int); + s = conv_10(i_num, 0, &is_negative, + &num_buf[NUM_BUF_SIZE], &s_len); + } FIX_PRECISION(adjust_precision, precision, s, s_len); if (is_negative) @@ -741,12 +866,21 @@ case 'o': - if (is_long) - ui_num = va_arg(ap, u_wide_int); - else - ui_num = (u_wide_int) va_arg(ap, unsigned int); - s = conv_p2(ui_num, 3, *fmt, + if (var_type == IS_QUAD) { + ui_quad = va_arg(ap, u_widest_int); + s = conv_p2_quad(ui_quad, 3, *fmt, + &num_buf[NUM_BUF_SIZE], &s_len); + } + else { + if (var_type == IS_LONG) + ui_num = (u_wide_int) va_arg(ap, u_wide_int); + else if (var_type == IS_SHORT) + ui_num = (u_wide_int) (unsigned short) va_arg(ap, unsigned int); + else + ui_num = (u_wide_int) va_arg(ap, unsigned int); + s = conv_p2(ui_num, 3, *fmt, &num_buf[NUM_BUF_SIZE], &s_len); + } FIX_PRECISION(adjust_precision, precision, s, s_len); if (alternate_form && *s != '0') { *--s = '0'; @@ -757,12 +891,21 @@ case 'x': case 'X': - if (is_long) - ui_num = (u_wide_int) va_arg(ap, u_wide_int); - else - ui_num = (u_wide_int) va_arg(ap, unsigned int); - s = conv_p2(ui_num, 4, *fmt, + if (var_type == IS_QUAD) { + ui_quad = va_arg(ap, u_widest_int); + s = conv_p2_quad(ui_quad, 4, *fmt, &num_buf[NUM_BUF_SIZE], &s_len); + } + else { + if (var_type == IS_LONG) + ui_num = (u_wide_int) va_arg(ap, u_wide_int); + else if (var_type == IS_SHORT) + ui_num = (u_wide_int) (unsigned short) va_arg(ap, unsigned int); + else + ui_num = (u_wide_int) va_arg(ap, unsigned int); + s = conv_p2(ui_num, 4, *fmt, + &num_buf[NUM_BUF_SIZE], &s_len); + } FIX_PRECISION(adjust_precision, precision, s, s_len); if (alternate_form && i_num != 0) { *--s = *fmt; /* 'x' or 'X' */ @@ -852,7 +995,14 @@ case 'n': - *(va_arg(ap, int *)) = cc; + if (var_type == IS_QUAD) + *(va_arg(ap, widest_int *)) = cc; + else if (var_type == IS_LONG) + *(va_arg(ap, long *)) = cc; + else if (var_type == IS_SHORT) + *(va_arg(ap, short *)) = cc; + else + *(va_arg(ap, int *)) = cc; break; /* @@ -862,16 +1012,25 @@ case 'p': switch(*++fmt) { /* - * If the pointer size is equal to the size of an unsigned - * integer we convert the pointer to a hex number, otherwise - * we print "%p" to indicate that we don't handle "%p". + * If the pointer size is equal to or smaller than the size + * of the largest unsigned int, we convert the pointer to a + * hex number, otherwise we print "%p" to indicate that we + * don't handle "%p". */ case 'p': - ui_num = (u_wide_int) va_arg(ap, void *); - - if (sizeof(char *) <= sizeof(u_wide_int)) - s = conv_p2(ui_num, 4, 'x', - &num_buf[NUM_BUF_SIZE], &s_len); +#ifdef AP_VOID_P_IS_QUAD + if (sizeof(void *) <= sizeof(u_widest_int)) { + ui_quad = (u_widest_int) va_arg(ap, void *); + s = conv_p2_quad(ui_quad, 4, 'x', + &num_buf[NUM_BUF_SIZE], &s_len); + } +#else + if (sizeof(void *) <= sizeof(u_wide_int)) { + ui_num = (u_wide_int) va_arg(ap, void *); + s = conv_p2(ui_num, 4, 'x', + &num_buf[NUM_BUF_SIZE], &s_len); + } +#endif else { s = "%p"; s_len = 2; @@ -990,7 +1149,7 @@ } -static int snprintf_flush(ap_vformatter_buff_t *vbuff) +static int snprintf_flush(ap_vformatter_buff *vbuff) { /* if the buffer fills we have to abort immediately, there is no way * to "flush" an ap_snprintf... there's nowhere to flush it to. @@ -1003,7 +1162,7 @@ { int cc; va_list ap; - ap_vformatter_buff_t vbuff; + ap_vformatter_buff vbuff; if (len == 0) return 0; @@ -1023,7 +1182,7 @@ va_list ap) { int cc; - ap_vformatter_buff_t vbuff; + ap_vformatter_buff vbuff; if (len == 0) return 0; @@ -1035,4 +1194,3 @@ *vbuff.curpos = '\0'; return (cc == -1) ? len : cc; } -