/* Copyright 2000-2004 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "apr.h" #include "apr_private.h" #include "apr_lib.h" #include "apr_strings.h" #include "apr_network_io.h" #include "apr_portable.h" #include #if APR_HAVE_CTYPE_H #include #endif #if APR_HAVE_NETINET_IN_H #include #endif #if APR_HAVE_SYS_SOCKET_H #include #endif #if APR_HAVE_ARPA_INET_H #include #endif #if APR_HAVE_LIMITS_H #include #endif #if APR_HAVE_STRING_H #include #endif typedef enum { NO = 0, YES = 1 } boolean_e; #ifndef FALSE #define FALSE 0 #endif #ifndef TRUE #define TRUE 1 #endif #define NUL '\0' #define WIDE_INT long typedef WIDE_INT wide_int; typedef unsigned WIDE_INT u_wide_int; typedef apr_int64_t widest_int; #ifdef __TANDEM /* Although Tandem supports "long long" there is no unsigned variant. */ typedef unsigned long u_widest_int; #else typedef apr_uint64_t u_widest_int; #endif typedef int bool_int; #define S_NULL "(null)" #define S_NULL_LEN 6 #define FLOAT_DIGITS 6 #define EXPONENT_LENGTH 10 /* * NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions * * NOTICE: this is a magic number; do not decrease it */ #define NUM_BUF_SIZE 512 /* * cvt.c - IEEE floating point formatting routines for FreeBSD * from GNU libc-4.6.27. Modified to be thread safe. */ /* * apr_ecvt converts to decimal * the number of digits is specified by ndigit * decpt is set to the position of the decimal point * sign is set to 0 for positive, 1 for negative */ #define NDIG 80 /* buf must have at least NDIG bytes */ static char *apr_cvt(double arg, int ndigits, int *decpt, int *sign, int eflag, char *buf) ###### { ###### register int r2; ###### double fi, fj; ###### register char *p, *p1; ###### if (ndigits >= NDIG - 1) ###### ndigits = NDIG - 2; ###### r2 = 0; ###### *sign = 0; ###### p = &buf[0]; ###### if (arg < 0) { ###### *sign = 1; ###### arg = -arg; } ###### arg = modf(arg, &fi); ###### p1 = &buf[NDIG]; /* * Do integer part */ ###### if (fi != 0) { ###### p1 = &buf[NDIG]; ###### while (p1 > &buf[0] && fi != 0) { ###### fj = modf(fi / 10, &fi); ###### *--p1 = (int) ((fj + .03) * 10) + '0'; ###### r2++; } ###### while (p1 < &buf[NDIG]) ###### *p++ = *p1++; } ###### else if (arg > 0) { ###### while ((fj = arg * 10) < 1) { ###### arg = fj; ###### r2--; } } ###### p1 = &buf[ndigits]; ###### if (eflag == 0) ###### p1 += r2; ###### *decpt = r2; ###### if (p1 < &buf[0]) { ###### buf[0] = '\0'; ###### return (buf); } ###### while (p <= p1 && p < &buf[NDIG]) { ###### arg *= 10; ###### arg = modf(arg, &fj); ###### *p++ = (int) fj + '0'; } ###### if (p1 >= &buf[NDIG]) { ###### buf[NDIG - 1] = '\0'; ###### return (buf); } ###### p = p1; ###### *p1 += 5; ###### while (*p1 > '9') { ###### *p1 = '0'; ###### if (p1 > buf) ###### ++ * --p1; else { ###### *p1 = '1'; ###### (*decpt)++; ###### if (eflag == 0) { ###### if (p > buf) ###### *p = '0'; ###### p++; } } } ###### *p = '\0'; ###### return (buf); } static char *apr_ecvt(double arg, int ndigits, int *decpt, int *sign, char *buf) ###### { ###### return (apr_cvt(arg, ndigits, decpt, sign, 1, buf)); } static char *apr_fcvt(double arg, int ndigits, int *decpt, int *sign, char *buf) ###### { ###### return (apr_cvt(arg, ndigits, decpt, sign, 0, buf)); } /* * apr_gcvt - Floating output conversion to * minimal length string */ static char *apr_gcvt(double number, int ndigit, char *buf, boolean_e altform) ###### { ###### int sign, decpt; ###### register char *p1, *p2; ###### register int i; ###### char buf1[NDIG]; ###### p1 = apr_ecvt(number, ndigit, &decpt, &sign, buf1); ###### p2 = buf; ###### if (sign) ###### *p2++ = '-'; ###### for (i = ndigit - 1; i > 0 && p1[i] == '0'; i--) ###### ndigit--; ###### if ((decpt >= 0 && decpt - ndigit > 4) || (decpt < 0 && decpt < -3)) { /* use E-style */ ###### decpt--; ###### *p2++ = *p1++; ###### *p2++ = '.'; ###### for (i = 1; i < ndigit; i++) ###### *p2++ = *p1++; ###### *p2++ = 'e'; ###### if (decpt < 0) { ###### decpt = -decpt; ###### *p2++ = '-'; } else ###### *p2++ = '+'; ###### if (decpt / 100 > 0) ###### *p2++ = decpt / 100 + '0'; ###### if (decpt / 10 > 0) ###### *p2++ = (decpt % 100) / 10 + '0'; ###### *p2++ = decpt % 10 + '0'; } else { ###### if (decpt <= 0) { ###### if (*p1 != '0') ###### *p2++ = '.'; ###### while (decpt < 0) { ###### decpt++; ###### *p2++ = '0'; } } ###### for (i = 1; i <= ndigit; i++) { ###### *p2++ = *p1++; ###### if (i == decpt) ###### *p2++ = '.'; } ###### if (ndigit < decpt) { ###### while (ndigit++ < decpt) ###### *p2++ = '0'; ###### *p2++ = '.'; } } ###### if (p2[-1] == '.' && !altform) ###### p2--; ###### *p2 = '\0'; ###### return (buf); } /* * The INS_CHAR macro inserts a character in the buffer and writes * the buffer back to disk if necessary * It uses the char pointers sp and bep: * sp points to the next available character in the buffer * bep points to the end-of-buffer+1 * While using this macro, note that the nextb pointer is NOT updated. * * NOTE: Evaluation of the c argument should not have any side-effects */ #define INS_CHAR(c, sp, bep, cc) \ { \ if (sp) { \ if (sp >= bep) { \ vbuff->curpos = sp; \ if (flush_func(vbuff)) \ return -1; \ sp = vbuff->curpos; \ bep = vbuff->endpos; \ } \ *sp++ = (c); \ } \ cc++; \ } #define NUM(c) (c - '0') #define STR_TO_DEC(str, num) \ num = NUM(*str++); \ while (apr_isdigit(*str)) \ { \ num *= 10 ; \ num += NUM(*str++); \ } /* * This macro does zero padding so that the precision * requirement is satisfied. The padding is done by * adding '0's to the left of the string that is going * to be printed. We don't allow precision to be large * enough that we continue past the start of s. * * NOTE: this makes use of the magic info that s is * always based on num_buf with a size of NUM_BUF_SIZE. */ #define FIX_PRECISION(adjust, precision, s, s_len) \ if (adjust) { \ int p = precision < NUM_BUF_SIZE - 1 ? precision : NUM_BUF_SIZE - 1; \ while (s_len < p) \ { \ *--s = '0'; \ s_len++; \ } \ } /* * Macro that does padding. The padding is done by printing * the character ch. */ #define PAD(width, len, ch) \ do \ { \ INS_CHAR(ch, sp, bep, cc); \ width--; \ } \ while (width > len) /* * Prefix the character ch to the string str * Increase length * Set the has_prefix flag */ #define PREFIX(str, length, ch) \ *--str = ch; \ length++; \ has_prefix=YES; /* * Convert num to its decimal format. * Return value: * - a pointer to a string containing the number (no sign) * - len contains the length of the string * - is_negative is set to TRUE or FALSE depending on the sign * of the number (always set to FALSE if is_unsigned is TRUE) * * 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, register int *len) 51 { 51 register char *p = buf_end; 51 register u_wide_int magnitude; 51 if (is_unsigned) { 2 magnitude = (u_wide_int) num; 2 *is_negative = FALSE; } else { 49 *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 */ 49 if (*is_negative) { 2 wide_int t = num + 1; 2 magnitude = ((u_wide_int) -t) + 1; } else 47 magnitude = (u_wide_int) num; } /* * We use a do-while loop so that we write at least 1 digit */ 80 do { 80 register u_wide_int new_magnitude = magnitude / 10; 80 *--p = (char) (magnitude - new_magnitude * 10 + '0'); 80 magnitude = new_magnitude; 80 } while (magnitude); 51 *len = buf_end - p; 51 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) 5 { 5 register char *p = buf_end; 5 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. */ 5 if ((num <= ULONG_MAX && is_unsigned) || (num <= LONG_MAX && !is_unsigned)) 4 return(conv_10( (wide_int)num, is_unsigned, is_negative, buf_end, len)); 1 if (is_unsigned) { 1 magnitude = (u_widest_int) num; 1 *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 */ 19 do { 19 u_widest_int new_magnitude = magnitude / 10; 19 *--p = (char) (magnitude - new_magnitude * 10 + '0'); 19 magnitude = new_magnitude; 19 } while (magnitude); 1 *len = buf_end - p; 1 return (p); } static char *conv_in_addr(struct in_addr *ia, char *buf_end, int *len) ###### { ###### unsigned addr = ntohl(ia->s_addr); ###### char *p = buf_end; ###### bool_int is_negative; ###### int sub_len; ###### p = conv_10((addr & 0x000000FF) , TRUE, &is_negative, p, &sub_len); ###### *--p = '.'; ###### p = conv_10((addr & 0x0000FF00) >> 8, TRUE, &is_negative, p, &sub_len); ###### *--p = '.'; ###### p = conv_10((addr & 0x00FF0000) >> 16, TRUE, &is_negative, p, &sub_len); ###### *--p = '.'; ###### p = conv_10((addr & 0xFF000000) >> 24, TRUE, &is_negative, p, &sub_len); ###### *len = buf_end - p; ###### return (p); } static char *conv_apr_sockaddr(apr_sockaddr_t *sa, char *buf_end, int *len) ###### { ###### char *p = buf_end; ###### bool_int is_negative; ###### int sub_len; ###### char *ipaddr_str; ###### p = conv_10(sa->port, TRUE, &is_negative, p, &sub_len); ###### *--p = ':'; ###### apr_sockaddr_ip_get(&ipaddr_str, sa); ###### sub_len = strlen(ipaddr_str); #if APR_HAVE_IPV6 ###### if (sa->family == APR_INET6 && !IN6_IS_ADDR_V4MAPPED(&sa->sa.sin6.sin6_addr)) { ###### *(p - 1) = ']'; ###### p -= sub_len + 2; ###### *p = '['; ###### memcpy(p + 1, ipaddr_str, sub_len); } else #endif { ###### p -= sub_len; ###### memcpy(p, ipaddr_str, sub_len); } ###### *len = buf_end - p; ###### return (p); } #if APR_HAS_THREADS static char *conv_os_thread_t(apr_os_thread_t *tid, char *buf_end, int *len) ###### { union { apr_os_thread_t tid; apr_uint64_t alignme; ###### } u; ###### int is_negative; ###### u.tid = *tid; ###### switch(sizeof(u.tid)) { case sizeof(apr_int32_t): ###### return conv_10(*(apr_uint32_t *)&u.tid, TRUE, &is_negative, buf_end, len); case sizeof(apr_int64_t): ###### return conv_10_quad(*(apr_uint64_t *)&u.tid, TRUE, &is_negative, buf_end, len); default: /* not implemented; stick 0 in the buffer */ ###### return conv_10(0, TRUE, &is_negative, buf_end, len); } } #endif /* * Convert a floating point number to a string formats 'f', 'e' or 'E'. * The result is placed in buf, and len denotes the length of the string * The sign is returned in the is_negative argument (and is not placed * in buf). */ static char *conv_fp(register char format, register double num, boolean_e add_dp, int precision, bool_int *is_negative, char *buf, int *len) ###### { ###### register char *s = buf; ###### register char *p; ###### int decimal_point; ###### char buf1[NDIG]; ###### if (format == 'f') ###### p = apr_fcvt(num, precision, &decimal_point, is_negative, buf1); else /* either e or E format */ ###### p = apr_ecvt(num, precision + 1, &decimal_point, is_negative, buf1); /* * Check for Infinity and NaN */ ###### if (apr_isalpha(*p)) { ###### *len = strlen(p); ###### memcpy(buf, p, *len + 1); ###### *is_negative = FALSE; ###### return (buf); } ###### if (format == 'f') { ###### if (decimal_point <= 0) { ###### *s++ = '0'; ###### if (precision > 0) { ###### *s++ = '.'; ###### while (decimal_point++ < 0) ###### *s++ = '0'; } ###### else if (add_dp) ###### *s++ = '.'; } else { ###### while (decimal_point-- > 0) ###### *s++ = *p++; ###### if (precision > 0 || add_dp) ###### *s++ = '.'; } } else { ###### *s++ = *p++; ###### if (precision > 0 || add_dp) ###### *s++ = '.'; } /* * copy the rest of p, the NUL is NOT copied */ ###### while (*p) ###### *s++ = *p++; ###### if (format != 'f') { ###### char temp[EXPONENT_LENGTH]; /* for exponent conversion */ ###### int t_len; ###### bool_int exponent_is_negative; ###### *s++ = format; /* either e or E */ ###### decimal_point--; ###### if (decimal_point != 0) { ###### p = conv_10((wide_int) decimal_point, FALSE, &exponent_is_negative, &temp[EXPONENT_LENGTH], &t_len); ###### *s++ = exponent_is_negative ? '-' : '+'; /* * Make sure the exponent has at least 2 digits */ ###### if (t_len == 1) ###### *s++ = '0'; ###### while (t_len--) ###### *s++ = *p++; } else { ###### *s++ = '+'; ###### *s++ = '0'; ###### *s++ = '0'; } } ###### *len = s - buf; ###### return (buf); } /* * Convert num to a base X number where X is a power of 2. nbits determines X. * For example, if nbits is 3, we do base 8 conversion * Return value: * a pointer to a string containing the number * * 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) 1 { 1 register int mask = (1 << nbits) - 1; 1 register char *p = buf_end; 1 static const char low_digits[] = "0123456789abcdef"; 1 static const char upper_digits[] = "0123456789ABCDEF"; 1 register const char *digits = (format == 'X') ? upper_digits : low_digits; 6 do { 6 *--p = digits[num & mask]; 6 num >>= nbits; 6 } while (num); 1 *len = buf_end - p; 1 return (p); } static char *conv_p2_quad(u_widest_int num, register int nbits, char format, char *buf_end, register int *len) 1 { 1 register int mask = (1 << nbits) - 1; 1 register char *p = buf_end; 1 static const char low_digits[] = "0123456789abcdef"; 1 static const char upper_digits[] = "0123456789ABCDEF"; 1 register const char *digits = (format == 'X') ? upper_digits : low_digits; 1 if (num <= ULONG_MAX) 1 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 */ APR_DECLARE(int) apr_vformatter(int (*flush_func)(apr_vformatter_buff_t *), apr_vformatter_buff_t *vbuff, const char *fmt, va_list ap) 58 { 58 register char *sp; 58 register char *bep; 58 register int cc = 0; 58 register int i; 58 register char *s = NULL; 58 char *q; 58 int s_len; 58 register int min_width = 0; 58 int precision = 0; enum { LEFT, RIGHT 58 } adjust; 58 char pad_char; 58 char prefix_char; 58 double fp_num; 58 widest_int i_quad = (widest_int) 0; 58 u_widest_int ui_quad; 58 wide_int i_num = (wide_int) 0; 58 u_wide_int ui_num; 58 char num_buf[NUM_BUF_SIZE]; 58 char char_buf[2]; /* for printing %% and % */ enum var_type_enum { IS_QUAD, IS_LONG, IS_SHORT, IS_INT }; 58 enum var_type_enum var_type = IS_INT; /* * Flag variables */ 58 boolean_e alternate_form; 58 boolean_e print_sign; 58 boolean_e print_blank; 58 boolean_e adjust_precision; 58 boolean_e adjust_width; 58 bool_int is_negative; 58 sp = vbuff->curpos; 58 bep = vbuff->endpos; 909 while (*fmt) { 851 if (*fmt != '%') { 687 INS_CHAR(*fmt, sp, bep, cc); } else { /* * Default variable settings */ 164 boolean_e print_something = YES; 164 adjust = RIGHT; 164 alternate_form = print_sign = print_blank = NO; 164 pad_char = ' '; 164 prefix_char = NUL; 164 fmt++; /* * Try to avoid checking for flags, width or precision */ 164 if (!apr_islower(*fmt)) { /* * Recognize flags: -, #, BLANK, + */ 27 for (;; fmt++) { 18 if (*fmt == '-') ###### adjust = LEFT; 18 else if (*fmt == '+') 1 print_sign = YES; 17 else if (*fmt == '#') ###### alternate_form = YES; 17 else if (*fmt == ' ') ###### print_blank = YES; 17 else if (*fmt == '0') 8 pad_char = '0'; else 9 break; } /* * Check if a width was specified */ 9 if (apr_isdigit(*fmt)) { 8 STR_TO_DEC(fmt, min_width); 8 adjust_width = YES; } 1 else if (*fmt == '*') { ###### min_width = va_arg(ap, int); ###### fmt++; ###### adjust_width = YES; ###### if (min_width < 0) { ###### adjust = LEFT; ###### min_width = -min_width; } } else 1 adjust_width = NO; /* * Check if a precision was specified */ 9 if (*fmt == '.') { 1 adjust_precision = YES; 1 fmt++; 1 if (apr_isdigit(*fmt)) { ###### STR_TO_DEC(fmt, precision); } 1 else if (*fmt == '*') { 1 precision = va_arg(ap, int); 1 fmt++; 1 if (precision < 0) ###### precision = 0; } else ###### precision = 0; } else 8 adjust_precision = NO; } else 155 adjust_precision = adjust_width = NO; /* * Modifier check. Note that if APR_INT64_T_FMT is "d", * the first if condition is never true. */ 164 if ((sizeof(APR_INT64_T_FMT) == 4 && fmt[0] == APR_INT64_T_FMT[0] && fmt[1] == APR_INT64_T_FMT[1]) || (sizeof(APR_INT64_T_FMT) == 3 && fmt[0] == APR_INT64_T_FMT[0]) || (sizeof(APR_INT64_T_FMT) > 4 && strncmp(fmt, APR_INT64_T_FMT, sizeof(APR_INT64_T_FMT) - 2) == 0)) { /* Need to account for trailing 'd' and null in sizeof() */ 6 var_type = IS_QUAD; 6 fmt += (sizeof(APR_INT64_T_FMT) - 2); } 158 else if (*fmt == 'q') { ###### var_type = IS_QUAD; ###### fmt++; } 158 else if (*fmt == 'l') { 1 var_type = IS_LONG; 1 fmt++; } 157 else if (*fmt == 'h') { ###### var_type = IS_SHORT; ###### fmt++; } else { 157 var_type = IS_INT; } /* * Argument extraction and printing. * First we determine the argument type. * Then, we convert the argument to a string. * On exit from the switch, s points to the string that * must be printed, s_len has the length of the string * The precision requirements, if any, are reflected in s_len. * * NOTE: pad_char may be set to '0' because of the 0 flag. * It is reset to ' ' by non-numeric formats */ 164 switch (*fmt) { case 'u': 3 if (var_type == IS_QUAD) { 3 i_quad = va_arg(ap, u_widest_int); 3 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); } 3 FIX_PRECISION(adjust_precision, precision, s, s_len); 49 break; case 'd': case 'i': 49 if (var_type == IS_QUAD) { 2 i_quad = va_arg(ap, widest_int); 2 s = conv_10_quad(i_quad, 0, &is_negative, &num_buf[NUM_BUF_SIZE], &s_len); } else { 47 if (var_type == IS_LONG) 1 i_num = (wide_int) va_arg(ap, wide_int); 46 else if (var_type == IS_SHORT) ###### i_num = (wide_int) (short) va_arg(ap, int); else 46 i_num = (wide_int) va_arg(ap, int); 47 s = conv_10(i_num, 0, &is_negative, &num_buf[NUM_BUF_SIZE], &s_len); } 49 FIX_PRECISION(adjust_precision, precision, s, s_len); 49 if (is_negative) 2 prefix_char = '-'; 47 else if (print_sign) 1 prefix_char = '+'; 46 else if (print_blank) ###### prefix_char = ' '; ###### break; case 'o': ###### 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'; ###### s_len++; } ###### break; case 'x': case 'X': 1 if (var_type == IS_QUAD) { 1 ui_quad = va_arg(ap, u_widest_int); 1 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); } 1 FIX_PRECISION(adjust_precision, precision, s, s_len); 1 if (alternate_form && i_num != 0) { ###### *--s = *fmt; /* 'x' or 'X' */ ###### *--s = '0'; ###### s_len += 2; } ###### break; case 's': 102 s = va_arg(ap, char *); 102 if (s != NULL) { 102 if (!adjust_precision) { 101 s_len = strlen(s); } else { /* From the C library standard in section 7.9.6.1: * ...if the precision is specified, no more then * that many characters are written. If the * precision is not specified or is greater * than the size of the array, the array shall * contain a null character. * * My reading is is precision is specified and * is less then or equal to the size of the * array, no null character is required. So * we can't do a strlen. * * This figures out the length of the string * up to the precision. Once it's long enough * for the specified precision, we don't care * anymore. * * NOTE: you must do the length comparison * before the check for the null character. * Otherwise, you'll check one beyond the * last valid character. */ 1 const char *walk; 1 for (walk = s, s_len = 0; (s_len < precision) && (*walk != '\0'); ++walk, ++s_len); } } else { ###### s = S_NULL; ###### s_len = S_NULL_LEN; } 102 pad_char = ' '; 102 break; case 'f': case 'e': case 'E': ###### fp_num = va_arg(ap, double); /* * We use &num_buf[ 1 ], so that we have room for the sign */ ###### s = NULL; #ifdef HAVE_ISNAN ###### if (isnan(fp_num)) { ###### s = "nan"; ###### s_len = 3; } #endif #ifdef HAVE_ISINF ###### if (!s && isinf(fp_num)) { ###### s = "inf"; ###### s_len = 3; } #endif ###### if (!s) { ###### s = conv_fp(*fmt, fp_num, alternate_form, (adjust_precision == NO) ? FLOAT_DIGITS : precision, &is_negative, &num_buf[1], &s_len); ###### if (is_negative) ###### prefix_char = '-'; ###### else if (print_sign) ###### prefix_char = '+'; ###### else if (print_blank) ###### prefix_char = ' '; } ###### break; case 'g': case 'G': ###### if (adjust_precision == NO) ###### precision = FLOAT_DIGITS; ###### else if (precision == 0) ###### precision = 1; /* * * We use &num_buf[ 1 ], so that we have room for the sign */ ###### s = apr_gcvt(va_arg(ap, double), precision, &num_buf[1], alternate_form); ###### if (*s == '-') ###### prefix_char = *s++; ###### else if (print_sign) ###### prefix_char = '+'; ###### else if (print_blank) ###### prefix_char = ' '; ###### s_len = strlen(s); ###### if (alternate_form && (q = strchr(s, '.')) == NULL) { ###### s[s_len++] = '.'; ###### s[s_len] = '\0'; /* delimit for following strchr() */ } ###### if (*fmt == 'G' && (q = strchr(s, 'e')) != NULL) ###### *q = 'E'; ###### break; case 'c': 9 char_buf[0] = (char) (va_arg(ap, int)); 9 s = &char_buf[0]; 9 s_len = 1; 9 pad_char = ' '; 9 break; case '%': ###### char_buf[0] = '%'; ###### s = &char_buf[0]; ###### s_len = 1; ###### pad_char = ' '; ###### break; case 'n': ###### 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; ###### print_something = NO; ###### break; /* * This is where we extend the printf format, with a second * type specifier */ case 'p': ###### switch(*++fmt) { /* * 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': #ifdef APR_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; ###### prefix_char = NUL; } ###### pad_char = ' '; ###### break; /* print an apr_sockaddr_t as a.b.c.d:port */ case 'I': { ###### apr_sockaddr_t *sa; ###### sa = va_arg(ap, apr_sockaddr_t *); ###### if (sa != NULL) { ###### s = conv_apr_sockaddr(sa, &num_buf[NUM_BUF_SIZE], &s_len); ###### if (adjust_precision && precision < s_len) ###### s_len = precision; } else { ###### s = S_NULL; ###### s_len = S_NULL_LEN; } ###### pad_char = ' '; } ###### break; /* print a struct in_addr as a.b.c.d */ case 'A': { ###### struct in_addr *ia; ###### ia = va_arg(ap, struct in_addr *); ###### if (ia != NULL) { ###### s = conv_in_addr(ia, &num_buf[NUM_BUF_SIZE], &s_len); ###### if (adjust_precision && precision < s_len) ###### s_len = precision; } else { ###### s = S_NULL; ###### s_len = S_NULL_LEN; } ###### pad_char = ' '; } ###### break; case 'T': #if APR_HAS_THREADS { ###### apr_os_thread_t *tid; ###### tid = va_arg(ap, apr_os_thread_t *); ###### if (tid != NULL) { ###### s = conv_os_thread_t(tid, &num_buf[NUM_BUF_SIZE], &s_len); ###### if (adjust_precision && precision < s_len) ###### s_len = precision; } else { ###### s = S_NULL; ###### s_len = S_NULL_LEN; } ###### pad_char = ' '; } #else char_buf[0] = '0'; s = &char_buf[0]; s_len = 1; pad_char = ' '; #endif ###### break; case NUL: /* if %p ends the string, oh well ignore it */ ###### continue; default: ###### s = "bogus %p"; ###### s_len = 8; ###### prefix_char = NUL; ###### (void)va_arg(ap, void *); /* skip the bogus argument on the stack */ ###### break; } ###### break; case NUL: /* * The last character of the format string was %. * We ignore it. */ ###### continue; /* * The default case is for unrecognized %'s. * We print % to help the user identify what * option is not understood. * This is also useful in case the user wants to pass * the output of format_converter to another function * that understands some other % (like syslog). * Note that we can't point s inside fmt because the * unknown could be preceded by width etc. */ default: ###### char_buf[0] = '%'; ###### char_buf[1] = *fmt; ###### s = char_buf; ###### s_len = 2; ###### pad_char = ' '; 164 break; } 164 if (prefix_char != NUL && s != S_NULL && s != char_buf) { 3 *--s = prefix_char; 3 s_len++; } 164 if (adjust_width && adjust == RIGHT && min_width > s_len) { 3 if (pad_char == '0' && prefix_char != NUL) { 1 INS_CHAR(*s, sp, bep, cc); 1 s++; 1 s_len--; 1 min_width--; } 5 PAD(min_width, s_len, pad_char); } /* * Print the string s. */ 164 if (print_something == YES) { 183819 for (i = s_len; i != 0; i--) { 183655 INS_CHAR(*s, sp, bep, cc); 183655 s++; } } 164 if (adjust_width && adjust == LEFT && min_width > s_len) ###### PAD(min_width, s_len, pad_char); } 851 fmt++; } 58 vbuff->curpos = sp; 58 return cc; } static int snprintf_flush(apr_vformatter_buff_t *vbuff) ###### { /* if the buffer fills we have to abort immediately, there is no way * to "flush" an apr_snprintf... there's nowhere to flush it to. */ ###### return -1; } APR_DECLARE_NONSTD(int) apr_snprintf(char *buf, apr_size_t len, const char *format, ...) 50 { 50 int cc; 50 va_list ap; 50 apr_vformatter_buff_t vbuff; 50 if (len == 0) { /* NOTE: This is a special case; we just want to return the number * of chars that would be written (minus \0) if the buffer * size was infinite. We leverage the fact that INS_CHAR * just does actual inserts iff the buffer pointer is non-NULL. * In this case, we don't care what buf is; it can be NULL, since * we don't touch it at all. */ 2 vbuff.curpos = NULL; 2 vbuff.endpos = NULL; } else { /* save one byte for nul terminator */ 48 vbuff.curpos = buf; 48 vbuff.endpos = buf + len - 1; } 50 va_start(ap, format); 50 cc = apr_vformatter(snprintf_flush, &vbuff, format, ap); 50 va_end(ap); 50 if (len != 0) { 48 *vbuff.curpos = '\0'; } 50 return (cc == -1) ? (int)len : cc; } APR_DECLARE(int) apr_vsnprintf(char *buf, apr_size_t len, const char *format, va_list ap) 4 { 4 int cc; 4 apr_vformatter_buff_t vbuff; 4 if (len == 0) { /* See above note */ ###### vbuff.curpos = NULL; ###### vbuff.endpos = NULL; } else { /* save one byte for nul terminator */ 4 vbuff.curpos = buf; 4 vbuff.endpos = buf + len - 1; } 4 cc = apr_vformatter(snprintf_flush, &vbuff, format, ap); 4 if (len != 0) { 4 *vbuff.curpos = '\0'; } 4 return (cc == -1) ? (int)len : cc; }