1251875Speter/* Licensed to the Apache Software Foundation (ASF) under one or more 2251875Speter * contributor license agreements. See the NOTICE file distributed with 3251875Speter * this work for additional information regarding copyright ownership. 4251875Speter * The ASF licenses this file to You under the Apache License, Version 2.0 5251875Speter * (the "License"); you may not use this file except in compliance with 6251875Speter * the License. You may obtain a copy of the License at 7251875Speter * 8251875Speter * http://www.apache.org/licenses/LICENSE-2.0 9251875Speter * 10251875Speter * Unless required by applicable law or agreed to in writing, software 11251875Speter * distributed under the License is distributed on an "AS IS" BASIS, 12251875Speter * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13251875Speter * See the License for the specific language governing permissions and 14251875Speter * limitations under the License. 15251875Speter */ 16251875Speter 17251875Speter#include "apr.h" 18251875Speter#include "apr_private.h" 19251875Speter 20251875Speter#include "apr_lib.h" 21251875Speter#include "apr_strings.h" 22251875Speter#include "apr_network_io.h" 23251875Speter#include "apr_portable.h" 24251875Speter#include "apr_errno.h" 25251875Speter#include <math.h> 26251875Speter#if APR_HAVE_CTYPE_H 27251875Speter#include <ctype.h> 28251875Speter#endif 29251875Speter#if APR_HAVE_NETINET_IN_H 30251875Speter#include <netinet/in.h> 31251875Speter#endif 32251875Speter#if APR_HAVE_SYS_SOCKET_H 33251875Speter#include <sys/socket.h> 34251875Speter#endif 35251875Speter#if APR_HAVE_ARPA_INET_H 36251875Speter#include <arpa/inet.h> 37251875Speter#endif 38251875Speter#if APR_HAVE_LIMITS_H 39251875Speter#include <limits.h> 40251875Speter#endif 41251875Speter#if APR_HAVE_STRING_H 42251875Speter#include <string.h> 43251875Speter#endif 44251875Speter 45251875Spetertypedef enum { 46251875Speter NO = 0, YES = 1 47251875Speter} boolean_e; 48251875Speter 49251875Speter#ifndef FALSE 50251875Speter#define FALSE 0 51251875Speter#endif 52251875Speter#ifndef TRUE 53251875Speter#define TRUE 1 54251875Speter#endif 55251875Speter#define NUL '\0' 56251875Speter 57251875Speterstatic const char null_string[] = "(null)"; 58251875Speter#define S_NULL ((char *)null_string) 59251875Speter#define S_NULL_LEN 6 60251875Speter 61251875Speter#define FLOAT_DIGITS 6 62251875Speter#define EXPONENT_LENGTH 10 63251875Speter 64251875Speter/* 65251875Speter * NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions 66251875Speter * 67251875Speter * NOTICE: this is a magic number; do not decrease it 68251875Speter */ 69251875Speter#define NUM_BUF_SIZE 512 70251875Speter 71251875Speter/* 72251875Speter * cvt - IEEE floating point formatting routines. 73251875Speter * Derived from UNIX V7, Copyright(C) Caldera International Inc. 74251875Speter */ 75251875Speter 76251875Speter/* 77251875Speter * apr_ecvt converts to decimal 78251875Speter * the number of digits is specified by ndigit 79251875Speter * decpt is set to the position of the decimal point 80251875Speter * sign is set to 0 for positive, 1 for negative 81251875Speter */ 82251875Speter 83251875Speter#define NDIG 80 84251875Speter 85251875Speter/* buf must have at least NDIG bytes */ 86251875Speterstatic char *apr_cvt(double arg, int ndigits, int *decpt, int *sign, 87251875Speter int eflag, char *buf) 88251875Speter{ 89251875Speter register int r2; 90251875Speter double fi, fj; 91251875Speter register char *p, *p1; 92251875Speter 93251875Speter if (ndigits >= NDIG - 1) 94251875Speter ndigits = NDIG - 2; 95251875Speter r2 = 0; 96251875Speter *sign = 0; 97251875Speter p = &buf[0]; 98251875Speter if (arg < 0) { 99251875Speter *sign = 1; 100251875Speter arg = -arg; 101251875Speter } 102251875Speter arg = modf(arg, &fi); 103251875Speter p1 = &buf[NDIG]; 104251875Speter /* 105251875Speter * Do integer part 106251875Speter */ 107251875Speter if (fi != 0) { 108251875Speter p1 = &buf[NDIG]; 109251875Speter while (p1 > &buf[0] && fi != 0) { 110251875Speter fj = modf(fi / 10, &fi); 111251875Speter *--p1 = (int) ((fj + .03) * 10) + '0'; 112251875Speter r2++; 113251875Speter } 114251875Speter while (p1 < &buf[NDIG]) 115251875Speter *p++ = *p1++; 116251875Speter } 117251875Speter else if (arg > 0) { 118251875Speter while ((fj = arg * 10) < 1) { 119251875Speter arg = fj; 120251875Speter r2--; 121251875Speter } 122251875Speter } 123251875Speter p1 = &buf[ndigits]; 124251875Speter if (eflag == 0) 125251875Speter p1 += r2; 126251875Speter if (p1 < &buf[0]) { 127251875Speter *decpt = -ndigits; 128251875Speter buf[0] = '\0'; 129251875Speter return (buf); 130251875Speter } 131251875Speter *decpt = r2; 132251875Speter while (p <= p1 && p < &buf[NDIG]) { 133251875Speter arg *= 10; 134251875Speter arg = modf(arg, &fj); 135251875Speter *p++ = (int) fj + '0'; 136251875Speter } 137251875Speter if (p1 >= &buf[NDIG]) { 138251875Speter buf[NDIG - 1] = '\0'; 139251875Speter return (buf); 140251875Speter } 141251875Speter p = p1; 142251875Speter *p1 += 5; 143251875Speter while (*p1 > '9') { 144251875Speter *p1 = '0'; 145251875Speter if (p1 > buf) 146251875Speter ++ * --p1; 147251875Speter else { 148251875Speter *p1 = '1'; 149251875Speter (*decpt)++; 150251875Speter if (eflag == 0) { 151251875Speter if (p > buf) 152251875Speter *p = '0'; 153251875Speter p++; 154251875Speter } 155251875Speter } 156251875Speter } 157251875Speter *p = '\0'; 158251875Speter return (buf); 159251875Speter} 160251875Speter 161251875Speterstatic char *apr_ecvt(double arg, int ndigits, int *decpt, int *sign, char *buf) 162251875Speter{ 163251875Speter return (apr_cvt(arg, ndigits, decpt, sign, 1, buf)); 164251875Speter} 165251875Speter 166251875Speterstatic char *apr_fcvt(double arg, int ndigits, int *decpt, int *sign, char *buf) 167251875Speter{ 168251875Speter return (apr_cvt(arg, ndigits, decpt, sign, 0, buf)); 169251875Speter} 170251875Speter 171251875Speter/* 172251875Speter * apr_gcvt - Floating output conversion to 173251875Speter * minimal length string 174251875Speter */ 175251875Speter 176251875Speterstatic char *apr_gcvt(double number, int ndigit, char *buf, boolean_e altform) 177251875Speter{ 178251875Speter int sign, decpt; 179251875Speter register char *p1, *p2; 180251875Speter register int i; 181251875Speter char buf1[NDIG]; 182251875Speter 183251875Speter p1 = apr_ecvt(number, ndigit, &decpt, &sign, buf1); 184251875Speter p2 = buf; 185251875Speter if (sign) 186251875Speter *p2++ = '-'; 187251875Speter for (i = ndigit - 1; i > 0 && p1[i] == '0'; i--) 188251875Speter ndigit--; 189251875Speter if ((decpt >= 0 && decpt - ndigit > 4) 190251875Speter || (decpt < 0 && decpt < -3)) { /* use E-style */ 191251875Speter decpt--; 192251875Speter *p2++ = *p1++; 193251875Speter *p2++ = '.'; 194251875Speter for (i = 1; i < ndigit; i++) 195251875Speter *p2++ = *p1++; 196251875Speter *p2++ = 'e'; 197251875Speter if (decpt < 0) { 198251875Speter decpt = -decpt; 199251875Speter *p2++ = '-'; 200251875Speter } 201251875Speter else 202251875Speter *p2++ = '+'; 203251875Speter if (decpt / 100 > 0) 204251875Speter *p2++ = decpt / 100 + '0'; 205251875Speter if (decpt / 10 > 0) 206251875Speter *p2++ = (decpt % 100) / 10 + '0'; 207251875Speter *p2++ = decpt % 10 + '0'; 208251875Speter } 209251875Speter else { 210251875Speter if (decpt <= 0) { 211251875Speter if (*p1 != '0') 212251875Speter *p2++ = '.'; 213251875Speter while (decpt < 0) { 214251875Speter decpt++; 215251875Speter *p2++ = '0'; 216251875Speter } 217251875Speter } 218251875Speter for (i = 1; i <= ndigit; i++) { 219251875Speter *p2++ = *p1++; 220251875Speter if (i == decpt) 221251875Speter *p2++ = '.'; 222251875Speter } 223251875Speter if (ndigit < decpt) { 224251875Speter while (ndigit++ < decpt) 225251875Speter *p2++ = '0'; 226251875Speter *p2++ = '.'; 227251875Speter } 228251875Speter } 229251875Speter if (p2[-1] == '.' && !altform) 230251875Speter p2--; 231251875Speter *p2 = '\0'; 232251875Speter return (buf); 233251875Speter} 234251875Speter 235251875Speter/* 236251875Speter * The INS_CHAR macro inserts a character in the buffer and writes 237251875Speter * the buffer back to disk if necessary 238251875Speter * It uses the char pointers sp and bep: 239251875Speter * sp points to the next available character in the buffer 240251875Speter * bep points to the end-of-buffer+1 241251875Speter * While using this macro, note that the nextb pointer is NOT updated. 242251875Speter * 243251875Speter * NOTE: Evaluation of the c argument should not have any side-effects 244251875Speter */ 245251875Speter#define INS_CHAR(c, sp, bep, cc) \ 246251875Speter{ \ 247251875Speter if (sp) { \ 248251875Speter if (sp >= bep) { \ 249251875Speter vbuff->curpos = sp; \ 250251875Speter if (flush_func(vbuff)) \ 251251875Speter return -1; \ 252251875Speter sp = vbuff->curpos; \ 253251875Speter bep = vbuff->endpos; \ 254251875Speter } \ 255251875Speter *sp++ = (c); \ 256251875Speter } \ 257251875Speter cc++; \ 258251875Speter} 259251875Speter 260251875Speter#define NUM(c) (c - '0') 261251875Speter 262251875Speter#define STR_TO_DEC(str, num) \ 263251875Speter num = NUM(*str++); \ 264251875Speter while (apr_isdigit(*str)) \ 265251875Speter { \ 266251875Speter num *= 10 ; \ 267251875Speter num += NUM(*str++); \ 268251875Speter } 269251875Speter 270251875Speter/* 271251875Speter * This macro does zero padding so that the precision 272251875Speter * requirement is satisfied. The padding is done by 273251875Speter * adding '0's to the left of the string that is going 274251875Speter * to be printed. We don't allow precision to be large 275251875Speter * enough that we continue past the start of s. 276251875Speter * 277251875Speter * NOTE: this makes use of the magic info that s is 278251875Speter * always based on num_buf with a size of NUM_BUF_SIZE. 279251875Speter */ 280251875Speter#define FIX_PRECISION(adjust, precision, s, s_len) \ 281251875Speter if (adjust) { \ 282251875Speter apr_size_t p = (precision + 1 < NUM_BUF_SIZE) \ 283251875Speter ? precision : NUM_BUF_SIZE - 1; \ 284251875Speter while (s_len < p) \ 285251875Speter { \ 286251875Speter *--s = '0'; \ 287251875Speter s_len++; \ 288251875Speter } \ 289251875Speter } 290251875Speter 291251875Speter/* 292251875Speter * Macro that does padding. The padding is done by printing 293251875Speter * the character ch. 294251875Speter */ 295251875Speter#define PAD(width, len, ch) \ 296251875Speterdo \ 297251875Speter{ \ 298251875Speter INS_CHAR(ch, sp, bep, cc); \ 299251875Speter width--; \ 300251875Speter} \ 301251875Speterwhile (width > len) 302251875Speter 303251875Speter/* 304251875Speter * Prefix the character ch to the string str 305251875Speter * Increase length 306251875Speter * Set the has_prefix flag 307251875Speter */ 308251875Speter#define PREFIX(str, length, ch) \ 309251875Speter *--str = ch; \ 310251875Speter length++; \ 311251875Speter has_prefix=YES; 312251875Speter 313251875Speter 314251875Speter/* 315251875Speter * Convert num to its decimal format. 316251875Speter * Return value: 317251875Speter * - a pointer to a string containing the number (no sign) 318251875Speter * - len contains the length of the string 319251875Speter * - is_negative is set to TRUE or FALSE depending on the sign 320251875Speter * of the number (always set to FALSE if is_unsigned is TRUE) 321251875Speter * 322251875Speter * The caller provides a buffer for the string: that is the buf_end argument 323251875Speter * which is a pointer to the END of the buffer + 1 (i.e. if the buffer 324251875Speter * is declared as buf[ 100 ], buf_end should be &buf[ 100 ]) 325251875Speter * 326251875Speter * Note: we have 2 versions. One is used when we need to use quads 327251875Speter * (conv_10_quad), the other when we don't (conv_10). We're assuming the 328251875Speter * latter is faster. 329251875Speter */ 330251875Speterstatic char *conv_10(register apr_int32_t num, register int is_unsigned, 331251875Speter register int *is_negative, char *buf_end, 332251875Speter register apr_size_t *len) 333251875Speter{ 334251875Speter register char *p = buf_end; 335251875Speter register apr_uint32_t magnitude = num; 336251875Speter 337251875Speter if (is_unsigned) { 338251875Speter *is_negative = FALSE; 339251875Speter } 340251875Speter else { 341251875Speter *is_negative = (num < 0); 342251875Speter 343251875Speter /* 344251875Speter * On a 2's complement machine, negating the most negative integer 345251875Speter * results in a number that cannot be represented as a signed integer. 346251875Speter * Here is what we do to obtain the number's magnitude: 347251875Speter * a. add 1 to the number 348251875Speter * b. negate it (becomes positive) 349251875Speter * c. convert it to unsigned 350251875Speter * d. add 1 351251875Speter */ 352251875Speter if (*is_negative) { 353251875Speter apr_int32_t t = num + 1; 354251875Speter magnitude = ((apr_uint32_t) -t) + 1; 355251875Speter } 356251875Speter } 357251875Speter 358251875Speter /* 359251875Speter * We use a do-while loop so that we write at least 1 digit 360251875Speter */ 361251875Speter do { 362251875Speter register apr_uint32_t new_magnitude = magnitude / 10; 363251875Speter 364251875Speter *--p = (char) (magnitude - new_magnitude * 10 + '0'); 365251875Speter magnitude = new_magnitude; 366251875Speter } 367251875Speter while (magnitude); 368251875Speter 369251875Speter *len = buf_end - p; 370251875Speter return (p); 371251875Speter} 372251875Speter 373251875Speterstatic char *conv_10_quad(apr_int64_t num, register int is_unsigned, 374251875Speter register int *is_negative, char *buf_end, 375251875Speter register apr_size_t *len) 376251875Speter{ 377251875Speter register char *p = buf_end; 378251875Speter apr_uint64_t magnitude = num; 379251875Speter 380251875Speter /* 381251875Speter * We see if we can use the faster non-quad version by checking the 382251875Speter * number against the largest long value it can be. If <=, we 383251875Speter * punt to the quicker version. 384251875Speter */ 385251875Speter if ((magnitude <= APR_UINT32_MAX && is_unsigned) 386251875Speter || (num <= APR_INT32_MAX && num >= APR_INT32_MIN && !is_unsigned)) 387251875Speter return(conv_10((apr_int32_t)num, is_unsigned, is_negative, buf_end, len)); 388251875Speter 389251875Speter if (is_unsigned) { 390251875Speter *is_negative = FALSE; 391251875Speter } 392251875Speter else { 393251875Speter *is_negative = (num < 0); 394251875Speter 395251875Speter /* 396251875Speter * On a 2's complement machine, negating the most negative integer 397251875Speter * results in a number that cannot be represented as a signed integer. 398251875Speter * Here is what we do to obtain the number's magnitude: 399251875Speter * a. add 1 to the number 400251875Speter * b. negate it (becomes positive) 401251875Speter * c. convert it to unsigned 402251875Speter * d. add 1 403251875Speter */ 404251875Speter if (*is_negative) { 405251875Speter apr_int64_t t = num + 1; 406251875Speter magnitude = ((apr_uint64_t) -t) + 1; 407251875Speter } 408251875Speter } 409251875Speter 410251875Speter /* 411251875Speter * We use a do-while loop so that we write at least 1 digit 412251875Speter */ 413251875Speter do { 414251875Speter apr_uint64_t new_magnitude = magnitude / 10; 415251875Speter 416251875Speter *--p = (char) (magnitude - new_magnitude * 10 + '0'); 417251875Speter magnitude = new_magnitude; 418251875Speter } 419251875Speter while (magnitude); 420251875Speter 421251875Speter *len = buf_end - p; 422251875Speter return (p); 423251875Speter} 424251875Speter 425251875Speterstatic char *conv_in_addr(struct in_addr *ia, char *buf_end, apr_size_t *len) 426251875Speter{ 427251875Speter unsigned addr = ntohl(ia->s_addr); 428251875Speter char *p = buf_end; 429251875Speter int is_negative; 430251875Speter apr_size_t sub_len; 431251875Speter 432251875Speter p = conv_10((addr & 0x000000FF) , TRUE, &is_negative, p, &sub_len); 433251875Speter *--p = '.'; 434251875Speter p = conv_10((addr & 0x0000FF00) >> 8, TRUE, &is_negative, p, &sub_len); 435251875Speter *--p = '.'; 436251875Speter p = conv_10((addr & 0x00FF0000) >> 16, TRUE, &is_negative, p, &sub_len); 437251875Speter *--p = '.'; 438251875Speter p = conv_10((addr & 0xFF000000) >> 24, TRUE, &is_negative, p, &sub_len); 439251875Speter 440251875Speter *len = buf_end - p; 441251875Speter return (p); 442251875Speter} 443251875Speter 444251875Speter 445251875Speter/* Must be passed a buffer of size NUM_BUF_SIZE where buf_end points 446251875Speter * to 1 byte past the end of the buffer. */ 447251875Speterstatic char *conv_apr_sockaddr(apr_sockaddr_t *sa, char *buf_end, apr_size_t *len) 448251875Speter{ 449251875Speter char *p = buf_end; 450251875Speter int is_negative; 451251875Speter apr_size_t sub_len; 452251875Speter char *ipaddr_str; 453251875Speter 454251875Speter p = conv_10(sa->port, TRUE, &is_negative, p, &sub_len); 455251875Speter *--p = ':'; 456251875Speter ipaddr_str = buf_end - NUM_BUF_SIZE; 457251875Speter if (apr_sockaddr_ip_getbuf(ipaddr_str, sa->addr_str_len, sa)) { 458251875Speter /* Should only fail if the buffer is too small, which it 459251875Speter * should not be; but fail safe anyway: */ 460251875Speter *--p = '?'; 461251875Speter *len = buf_end - p; 462251875Speter return p; 463251875Speter } 464251875Speter sub_len = strlen(ipaddr_str); 465251875Speter#if APR_HAVE_IPV6 466251875Speter if (sa->family == APR_INET6 && 467251875Speter !IN6_IS_ADDR_V4MAPPED(&sa->sa.sin6.sin6_addr)) { 468251875Speter *(p - 1) = ']'; 469251875Speter p -= sub_len + 2; 470251875Speter *p = '['; 471251875Speter memcpy(p + 1, ipaddr_str, sub_len); 472251875Speter } 473251875Speter else 474251875Speter#endif 475251875Speter { 476251875Speter p -= sub_len; 477251875Speter memcpy(p, ipaddr_str, sub_len); 478251875Speter } 479251875Speter 480251875Speter *len = buf_end - p; 481251875Speter return (p); 482251875Speter} 483251875Speter 484251875Speter 485251875Speter 486251875Speter#if APR_HAS_THREADS 487251875Speterstatic char *conv_os_thread_t(apr_os_thread_t *tid, char *buf_end, apr_size_t *len) 488251875Speter{ 489251875Speter union { 490251875Speter apr_os_thread_t tid; 491251875Speter apr_uint64_t u64; 492251875Speter apr_uint32_t u32; 493251875Speter } u; 494251875Speter int is_negative; 495251875Speter 496251875Speter u.tid = *tid; 497251875Speter switch(sizeof(u.tid)) { 498251875Speter case sizeof(apr_int32_t): 499251875Speter return conv_10(u.u32, TRUE, &is_negative, buf_end, len); 500251875Speter case sizeof(apr_int64_t): 501251875Speter return conv_10_quad(u.u64, TRUE, &is_negative, buf_end, len); 502251875Speter default: 503251875Speter /* not implemented; stick 0 in the buffer */ 504251875Speter return conv_10(0, TRUE, &is_negative, buf_end, len); 505251875Speter } 506251875Speter} 507251875Speter#endif 508251875Speter 509251875Speter 510251875Speter 511251875Speter/* 512251875Speter * Convert a floating point number to a string formats 'f', 'e' or 'E'. 513251875Speter * The result is placed in buf, and len denotes the length of the string 514251875Speter * The sign is returned in the is_negative argument (and is not placed 515251875Speter * in buf). 516251875Speter */ 517251875Speterstatic char *conv_fp(register char format, register double num, 518251875Speter boolean_e add_dp, int precision, int *is_negative, 519251875Speter char *buf, apr_size_t *len) 520251875Speter{ 521251875Speter register char *s = buf; 522251875Speter register char *p; 523251875Speter int decimal_point; 524251875Speter char buf1[NDIG]; 525251875Speter 526251875Speter if (format == 'f') 527251875Speter p = apr_fcvt(num, precision, &decimal_point, is_negative, buf1); 528251875Speter else /* either e or E format */ 529251875Speter p = apr_ecvt(num, precision + 1, &decimal_point, is_negative, buf1); 530251875Speter 531251875Speter /* 532251875Speter * Check for Infinity and NaN 533251875Speter */ 534251875Speter if (apr_isalpha(*p)) { 535251875Speter *len = strlen(p); 536251875Speter memcpy(buf, p, *len + 1); 537251875Speter *is_negative = FALSE; 538251875Speter return (buf); 539251875Speter } 540251875Speter 541251875Speter if (format == 'f') { 542251875Speter if (decimal_point <= 0) { 543251875Speter *s++ = '0'; 544251875Speter if (precision > 0) { 545251875Speter *s++ = '.'; 546251875Speter while (decimal_point++ < 0) 547251875Speter *s++ = '0'; 548251875Speter } 549251875Speter else if (add_dp) 550251875Speter *s++ = '.'; 551251875Speter } 552251875Speter else { 553251875Speter while (decimal_point-- > 0) 554251875Speter *s++ = *p++; 555251875Speter if (precision > 0 || add_dp) 556251875Speter *s++ = '.'; 557251875Speter } 558251875Speter } 559251875Speter else { 560251875Speter *s++ = *p++; 561251875Speter if (precision > 0 || add_dp) 562251875Speter *s++ = '.'; 563251875Speter } 564251875Speter 565251875Speter /* 566251875Speter * copy the rest of p, the NUL is NOT copied 567251875Speter */ 568251875Speter while (*p) 569251875Speter *s++ = *p++; 570251875Speter 571251875Speter if (format != 'f') { 572251875Speter char temp[EXPONENT_LENGTH]; /* for exponent conversion */ 573251875Speter apr_size_t t_len; 574251875Speter int exponent_is_negative; 575251875Speter 576251875Speter *s++ = format; /* either e or E */ 577251875Speter decimal_point--; 578251875Speter if (decimal_point != 0) { 579251875Speter p = conv_10((apr_int32_t) decimal_point, FALSE, &exponent_is_negative, 580251875Speter &temp[EXPONENT_LENGTH], &t_len); 581251875Speter *s++ = exponent_is_negative ? '-' : '+'; 582251875Speter 583251875Speter /* 584251875Speter * Make sure the exponent has at least 2 digits 585251875Speter */ 586251875Speter if (t_len == 1) 587251875Speter *s++ = '0'; 588251875Speter while (t_len--) 589251875Speter *s++ = *p++; 590251875Speter } 591251875Speter else { 592251875Speter *s++ = '+'; 593251875Speter *s++ = '0'; 594251875Speter *s++ = '0'; 595251875Speter } 596251875Speter } 597251875Speter 598251875Speter *len = s - buf; 599251875Speter return (buf); 600251875Speter} 601251875Speter 602251875Speter 603251875Speter/* 604251875Speter * Convert num to a base X number where X is a power of 2. nbits determines X. 605251875Speter * For example, if nbits is 3, we do base 8 conversion 606251875Speter * Return value: 607251875Speter * a pointer to a string containing the number 608251875Speter * 609251875Speter * The caller provides a buffer for the string: that is the buf_end argument 610251875Speter * which is a pointer to the END of the buffer + 1 (i.e. if the buffer 611251875Speter * is declared as buf[ 100 ], buf_end should be &buf[ 100 ]) 612251875Speter * 613251875Speter * As with conv_10, we have a faster version which is used when 614251875Speter * the number isn't quad size. 615251875Speter */ 616251875Speterstatic char *conv_p2(register apr_uint32_t num, register int nbits, 617251875Speter char format, char *buf_end, register apr_size_t *len) 618251875Speter{ 619251875Speter register int mask = (1 << nbits) - 1; 620251875Speter register char *p = buf_end; 621251875Speter static const char low_digits[] = "0123456789abcdef"; 622251875Speter static const char upper_digits[] = "0123456789ABCDEF"; 623251875Speter register const char *digits = (format == 'X') ? upper_digits : low_digits; 624251875Speter 625251875Speter do { 626251875Speter *--p = digits[num & mask]; 627251875Speter num >>= nbits; 628251875Speter } 629251875Speter while (num); 630251875Speter 631251875Speter *len = buf_end - p; 632251875Speter return (p); 633251875Speter} 634251875Speter 635251875Speterstatic char *conv_p2_quad(apr_uint64_t num, register int nbits, 636251875Speter char format, char *buf_end, register apr_size_t *len) 637251875Speter{ 638251875Speter register int mask = (1 << nbits) - 1; 639251875Speter register char *p = buf_end; 640251875Speter static const char low_digits[] = "0123456789abcdef"; 641251875Speter static const char upper_digits[] = "0123456789ABCDEF"; 642251875Speter register const char *digits = (format == 'X') ? upper_digits : low_digits; 643251875Speter 644251875Speter if (num <= APR_UINT32_MAX) 645251875Speter return(conv_p2((apr_uint32_t)num, nbits, format, buf_end, len)); 646251875Speter 647251875Speter do { 648251875Speter *--p = digits[num & mask]; 649251875Speter num >>= nbits; 650251875Speter } 651251875Speter while (num); 652251875Speter 653251875Speter *len = buf_end - p; 654251875Speter return (p); 655251875Speter} 656251875Speter 657251875Speter#if APR_HAS_THREADS 658251875Speterstatic char *conv_os_thread_t_hex(apr_os_thread_t *tid, char *buf_end, apr_size_t *len) 659251875Speter{ 660251875Speter union { 661251875Speter apr_os_thread_t tid; 662251875Speter apr_uint64_t u64; 663251875Speter apr_uint32_t u32; 664251875Speter } u; 665251875Speter int is_negative; 666251875Speter 667251875Speter u.tid = *tid; 668251875Speter switch(sizeof(u.tid)) { 669251875Speter case sizeof(apr_int32_t): 670251875Speter return conv_p2(u.u32, 4, 'x', buf_end, len); 671251875Speter case sizeof(apr_int64_t): 672251875Speter return conv_p2_quad(u.u64, 4, 'x', buf_end, len); 673251875Speter default: 674251875Speter /* not implemented; stick 0 in the buffer */ 675251875Speter return conv_10(0, TRUE, &is_negative, buf_end, len); 676251875Speter } 677251875Speter} 678251875Speter#endif 679251875Speter 680251875Speter/* 681251875Speter * Do format conversion placing the output in buffer 682251875Speter */ 683251875SpeterAPR_DECLARE(int) apr_vformatter(int (*flush_func)(apr_vformatter_buff_t *), 684251875Speter apr_vformatter_buff_t *vbuff, const char *fmt, va_list ap) 685251875Speter{ 686251875Speter register char *sp; 687251875Speter register char *bep; 688251875Speter register int cc = 0; 689251875Speter register apr_size_t i; 690251875Speter 691251875Speter register char *s = NULL; 692251875Speter char *q; 693251875Speter apr_size_t s_len = 0; 694251875Speter 695251875Speter register apr_size_t min_width = 0; 696251875Speter apr_size_t precision = 0; 697251875Speter enum { 698251875Speter LEFT, RIGHT 699251875Speter } adjust; 700251875Speter char pad_char; 701251875Speter char prefix_char; 702251875Speter 703251875Speter double fp_num; 704251875Speter apr_int64_t i_quad = 0; 705251875Speter apr_uint64_t ui_quad; 706251875Speter apr_int32_t i_num = 0; 707251875Speter apr_uint32_t ui_num = 0; 708251875Speter 709251875Speter char num_buf[NUM_BUF_SIZE]; 710251875Speter char char_buf[2]; /* for printing %% and %<unknown> */ 711251875Speter 712251875Speter enum var_type_enum { 713251875Speter IS_QUAD, IS_LONG, IS_SHORT, IS_INT 714251875Speter }; 715251875Speter enum var_type_enum var_type = IS_INT; 716251875Speter 717251875Speter /* 718251875Speter * Flag variables 719251875Speter */ 720251875Speter boolean_e alternate_form; 721251875Speter boolean_e print_sign; 722251875Speter boolean_e print_blank; 723251875Speter boolean_e adjust_precision; 724251875Speter boolean_e adjust_width; 725251875Speter int is_negative; 726251875Speter 727251875Speter sp = vbuff->curpos; 728251875Speter bep = vbuff->endpos; 729251875Speter 730251875Speter while (*fmt) { 731251875Speter if (*fmt != '%') { 732251875Speter INS_CHAR(*fmt, sp, bep, cc); 733251875Speter } 734251875Speter else { 735251875Speter /* 736251875Speter * Default variable settings 737251875Speter */ 738251875Speter boolean_e print_something = YES; 739251875Speter adjust = RIGHT; 740251875Speter alternate_form = print_sign = print_blank = NO; 741251875Speter pad_char = ' '; 742251875Speter prefix_char = NUL; 743251875Speter 744251875Speter fmt++; 745251875Speter 746251875Speter /* 747251875Speter * Try to avoid checking for flags, width or precision 748251875Speter */ 749251875Speter if (!apr_islower(*fmt)) { 750251875Speter /* 751251875Speter * Recognize flags: -, #, BLANK, + 752251875Speter */ 753251875Speter for (;; fmt++) { 754251875Speter if (*fmt == '-') 755251875Speter adjust = LEFT; 756251875Speter else if (*fmt == '+') 757251875Speter print_sign = YES; 758251875Speter else if (*fmt == '#') 759251875Speter alternate_form = YES; 760251875Speter else if (*fmt == ' ') 761251875Speter print_blank = YES; 762251875Speter else if (*fmt == '0') 763251875Speter pad_char = '0'; 764251875Speter else 765251875Speter break; 766251875Speter } 767251875Speter 768251875Speter /* 769251875Speter * Check if a width was specified 770251875Speter */ 771251875Speter if (apr_isdigit(*fmt)) { 772251875Speter STR_TO_DEC(fmt, min_width); 773251875Speter adjust_width = YES; 774251875Speter } 775251875Speter else if (*fmt == '*') { 776251875Speter int v = va_arg(ap, int); 777251875Speter fmt++; 778251875Speter adjust_width = YES; 779251875Speter if (v < 0) { 780251875Speter adjust = LEFT; 781251875Speter min_width = (apr_size_t)(-v); 782251875Speter } 783251875Speter else 784251875Speter min_width = (apr_size_t)v; 785251875Speter } 786251875Speter else 787251875Speter adjust_width = NO; 788251875Speter 789251875Speter /* 790251875Speter * Check if a precision was specified 791251875Speter */ 792251875Speter if (*fmt == '.') { 793251875Speter adjust_precision = YES; 794251875Speter fmt++; 795251875Speter if (apr_isdigit(*fmt)) { 796251875Speter STR_TO_DEC(fmt, precision); 797251875Speter } 798251875Speter else if (*fmt == '*') { 799251875Speter int v = va_arg(ap, int); 800251875Speter fmt++; 801251875Speter precision = (v < 0) ? 0 : (apr_size_t)v; 802251875Speter } 803251875Speter else 804251875Speter precision = 0; 805251875Speter } 806251875Speter else 807251875Speter adjust_precision = NO; 808251875Speter } 809251875Speter else 810251875Speter adjust_precision = adjust_width = NO; 811251875Speter 812251875Speter /* 813251875Speter * Modifier check. In same cases, APR_OFF_T_FMT can be 814251875Speter * "lld" and APR_INT64_T_FMT can be "ld" (that is, off_t is 815251875Speter * "larger" than int64). Check that case 1st. 816251875Speter * Note that if APR_OFF_T_FMT is "d", 817251875Speter * the first if condition is never true. If APR_INT64_T_FMT 818251875Speter * is "d' then the second if condition is never true. 819251875Speter */ 820251875Speter if ((sizeof(APR_OFF_T_FMT) > sizeof(APR_INT64_T_FMT)) && 821251875Speter ((sizeof(APR_OFF_T_FMT) == 4 && 822251875Speter fmt[0] == APR_OFF_T_FMT[0] && 823251875Speter fmt[1] == APR_OFF_T_FMT[1]) || 824251875Speter (sizeof(APR_OFF_T_FMT) == 3 && 825251875Speter fmt[0] == APR_OFF_T_FMT[0]) || 826251875Speter (sizeof(APR_OFF_T_FMT) > 4 && 827251875Speter strncmp(fmt, APR_OFF_T_FMT, 828251875Speter sizeof(APR_OFF_T_FMT) - 2) == 0))) { 829251875Speter /* Need to account for trailing 'd' and null in sizeof() */ 830251875Speter var_type = IS_QUAD; 831251875Speter fmt += (sizeof(APR_OFF_T_FMT) - 2); 832251875Speter } 833251875Speter else if ((sizeof(APR_INT64_T_FMT) == 4 && 834251875Speter fmt[0] == APR_INT64_T_FMT[0] && 835251875Speter fmt[1] == APR_INT64_T_FMT[1]) || 836251875Speter (sizeof(APR_INT64_T_FMT) == 3 && 837251875Speter fmt[0] == APR_INT64_T_FMT[0]) || 838251875Speter (sizeof(APR_INT64_T_FMT) > 4 && 839251875Speter strncmp(fmt, APR_INT64_T_FMT, 840251875Speter sizeof(APR_INT64_T_FMT) - 2) == 0)) { 841251875Speter /* Need to account for trailing 'd' and null in sizeof() */ 842251875Speter var_type = IS_QUAD; 843251875Speter fmt += (sizeof(APR_INT64_T_FMT) - 2); 844251875Speter } 845251875Speter else if (*fmt == 'q') { 846251875Speter var_type = IS_QUAD; 847251875Speter fmt++; 848251875Speter } 849251875Speter else if (*fmt == 'l') { 850251875Speter var_type = IS_LONG; 851251875Speter fmt++; 852251875Speter } 853251875Speter else if (*fmt == 'h') { 854251875Speter var_type = IS_SHORT; 855251875Speter fmt++; 856251875Speter } 857251875Speter else { 858251875Speter var_type = IS_INT; 859251875Speter } 860251875Speter 861251875Speter /* 862251875Speter * Argument extraction and printing. 863251875Speter * First we determine the argument type. 864251875Speter * Then, we convert the argument to a string. 865251875Speter * On exit from the switch, s points to the string that 866251875Speter * must be printed, s_len has the length of the string 867251875Speter * The precision requirements, if any, are reflected in s_len. 868251875Speter * 869251875Speter * NOTE: pad_char may be set to '0' because of the 0 flag. 870251875Speter * It is reset to ' ' by non-numeric formats 871251875Speter */ 872251875Speter switch (*fmt) { 873251875Speter case 'u': 874251875Speter if (var_type == IS_QUAD) { 875251875Speter i_quad = va_arg(ap, apr_uint64_t); 876251875Speter s = conv_10_quad(i_quad, 1, &is_negative, 877251875Speter &num_buf[NUM_BUF_SIZE], &s_len); 878251875Speter } 879251875Speter else { 880251875Speter if (var_type == IS_LONG) 881251875Speter i_num = (apr_int32_t) va_arg(ap, apr_uint32_t); 882251875Speter else if (var_type == IS_SHORT) 883251875Speter i_num = (apr_int32_t) (unsigned short) va_arg(ap, unsigned int); 884251875Speter else 885251875Speter i_num = (apr_int32_t) va_arg(ap, unsigned int); 886251875Speter s = conv_10(i_num, 1, &is_negative, 887251875Speter &num_buf[NUM_BUF_SIZE], &s_len); 888251875Speter } 889251875Speter FIX_PRECISION(adjust_precision, precision, s, s_len); 890251875Speter break; 891251875Speter 892251875Speter case 'd': 893251875Speter case 'i': 894251875Speter if (var_type == IS_QUAD) { 895251875Speter i_quad = va_arg(ap, apr_int64_t); 896251875Speter s = conv_10_quad(i_quad, 0, &is_negative, 897251875Speter &num_buf[NUM_BUF_SIZE], &s_len); 898251875Speter } 899251875Speter else { 900251875Speter if (var_type == IS_LONG) 901251875Speter i_num = va_arg(ap, apr_int32_t); 902251875Speter else if (var_type == IS_SHORT) 903251875Speter i_num = (short) va_arg(ap, int); 904251875Speter else 905251875Speter i_num = va_arg(ap, int); 906251875Speter s = conv_10(i_num, 0, &is_negative, 907251875Speter &num_buf[NUM_BUF_SIZE], &s_len); 908251875Speter } 909251875Speter FIX_PRECISION(adjust_precision, precision, s, s_len); 910251875Speter 911251875Speter if (is_negative) 912251875Speter prefix_char = '-'; 913251875Speter else if (print_sign) 914251875Speter prefix_char = '+'; 915251875Speter else if (print_blank) 916251875Speter prefix_char = ' '; 917251875Speter break; 918251875Speter 919251875Speter 920251875Speter case 'o': 921251875Speter if (var_type == IS_QUAD) { 922251875Speter ui_quad = va_arg(ap, apr_uint64_t); 923251875Speter s = conv_p2_quad(ui_quad, 3, *fmt, 924251875Speter &num_buf[NUM_BUF_SIZE], &s_len); 925251875Speter } 926251875Speter else { 927251875Speter if (var_type == IS_LONG) 928251875Speter ui_num = va_arg(ap, apr_uint32_t); 929251875Speter else if (var_type == IS_SHORT) 930251875Speter ui_num = (unsigned short) va_arg(ap, unsigned int); 931251875Speter else 932251875Speter ui_num = va_arg(ap, unsigned int); 933251875Speter s = conv_p2(ui_num, 3, *fmt, 934251875Speter &num_buf[NUM_BUF_SIZE], &s_len); 935251875Speter } 936251875Speter FIX_PRECISION(adjust_precision, precision, s, s_len); 937251875Speter if (alternate_form && *s != '0') { 938251875Speter *--s = '0'; 939251875Speter s_len++; 940251875Speter } 941251875Speter break; 942251875Speter 943251875Speter 944251875Speter case 'x': 945251875Speter case 'X': 946251875Speter if (var_type == IS_QUAD) { 947251875Speter ui_quad = va_arg(ap, apr_uint64_t); 948251875Speter s = conv_p2_quad(ui_quad, 4, *fmt, 949251875Speter &num_buf[NUM_BUF_SIZE], &s_len); 950251875Speter } 951251875Speter else { 952251875Speter if (var_type == IS_LONG) 953251875Speter ui_num = va_arg(ap, apr_uint32_t); 954251875Speter else if (var_type == IS_SHORT) 955251875Speter ui_num = (unsigned short) va_arg(ap, unsigned int); 956251875Speter else 957251875Speter ui_num = va_arg(ap, unsigned int); 958251875Speter s = conv_p2(ui_num, 4, *fmt, 959251875Speter &num_buf[NUM_BUF_SIZE], &s_len); 960251875Speter } 961251875Speter FIX_PRECISION(adjust_precision, precision, s, s_len); 962251875Speter if (alternate_form && ui_num != 0) { 963251875Speter *--s = *fmt; /* 'x' or 'X' */ 964251875Speter *--s = '0'; 965251875Speter s_len += 2; 966251875Speter } 967251875Speter break; 968251875Speter 969251875Speter 970251875Speter case 's': 971251875Speter s = va_arg(ap, char *); 972251875Speter if (s != NULL) { 973251875Speter if (!adjust_precision) { 974251875Speter s_len = strlen(s); 975251875Speter } 976251875Speter else { 977251875Speter /* From the C library standard in section 7.9.6.1: 978251875Speter * ...if the precision is specified, no more then 979251875Speter * that many characters are written. If the 980251875Speter * precision is not specified or is greater 981251875Speter * than the size of the array, the array shall 982251875Speter * contain a null character. 983251875Speter * 984251875Speter * My reading is is precision is specified and 985251875Speter * is less then or equal to the size of the 986251875Speter * array, no null character is required. So 987251875Speter * we can't do a strlen. 988251875Speter * 989251875Speter * This figures out the length of the string 990251875Speter * up to the precision. Once it's long enough 991251875Speter * for the specified precision, we don't care 992251875Speter * anymore. 993251875Speter * 994251875Speter * NOTE: you must do the length comparison 995251875Speter * before the check for the null character. 996251875Speter * Otherwise, you'll check one beyond the 997251875Speter * last valid character. 998251875Speter */ 999251875Speter const char *walk; 1000251875Speter 1001251875Speter for (walk = s, s_len = 0; 1002251875Speter (s_len < precision) && (*walk != '\0'); 1003251875Speter ++walk, ++s_len); 1004251875Speter } 1005251875Speter } 1006251875Speter else { 1007251875Speter s = S_NULL; 1008251875Speter s_len = S_NULL_LEN; 1009251875Speter } 1010251875Speter pad_char = ' '; 1011251875Speter break; 1012251875Speter 1013251875Speter 1014251875Speter case 'f': 1015251875Speter case 'e': 1016251875Speter case 'E': 1017251875Speter fp_num = va_arg(ap, double); 1018251875Speter /* 1019251875Speter * We use &num_buf[ 1 ], so that we have room for the sign 1020251875Speter */ 1021251875Speter s = NULL; 1022251875Speter#ifdef HAVE_ISNAN 1023251875Speter if (isnan(fp_num)) { 1024251875Speter s = "nan"; 1025251875Speter s_len = 3; 1026251875Speter } 1027251875Speter#endif 1028251875Speter#ifdef HAVE_ISINF 1029251875Speter if (!s && isinf(fp_num)) { 1030251875Speter s = "inf"; 1031251875Speter s_len = 3; 1032251875Speter } 1033251875Speter#endif 1034251875Speter if (!s) { 1035251875Speter s = conv_fp(*fmt, fp_num, alternate_form, 1036251875Speter (int)((adjust_precision == NO) ? FLOAT_DIGITS : precision), 1037251875Speter &is_negative, &num_buf[1], &s_len); 1038251875Speter if (is_negative) 1039251875Speter prefix_char = '-'; 1040251875Speter else if (print_sign) 1041251875Speter prefix_char = '+'; 1042251875Speter else if (print_blank) 1043251875Speter prefix_char = ' '; 1044251875Speter } 1045251875Speter break; 1046251875Speter 1047251875Speter 1048251875Speter case 'g': 1049251875Speter case 'G': 1050251875Speter if (adjust_precision == NO) 1051251875Speter precision = FLOAT_DIGITS; 1052251875Speter else if (precision == 0) 1053251875Speter precision = 1; 1054251875Speter /* 1055251875Speter * * We use &num_buf[ 1 ], so that we have room for the sign 1056251875Speter */ 1057251875Speter s = apr_gcvt(va_arg(ap, double), (int) precision, &num_buf[1], 1058251875Speter alternate_form); 1059251875Speter if (*s == '-') 1060251875Speter prefix_char = *s++; 1061251875Speter else if (print_sign) 1062251875Speter prefix_char = '+'; 1063251875Speter else if (print_blank) 1064251875Speter prefix_char = ' '; 1065251875Speter 1066251875Speter s_len = strlen(s); 1067251875Speter 1068251875Speter if (alternate_form && (q = strchr(s, '.')) == NULL) { 1069251875Speter s[s_len++] = '.'; 1070251875Speter s[s_len] = '\0'; /* delimit for following strchr() */ 1071251875Speter } 1072251875Speter if (*fmt == 'G' && (q = strchr(s, 'e')) != NULL) 1073251875Speter *q = 'E'; 1074251875Speter break; 1075251875Speter 1076251875Speter 1077251875Speter case 'c': 1078251875Speter char_buf[0] = (char) (va_arg(ap, int)); 1079251875Speter s = &char_buf[0]; 1080251875Speter s_len = 1; 1081251875Speter pad_char = ' '; 1082251875Speter break; 1083251875Speter 1084251875Speter 1085251875Speter case '%': 1086251875Speter char_buf[0] = '%'; 1087251875Speter s = &char_buf[0]; 1088251875Speter s_len = 1; 1089251875Speter pad_char = ' '; 1090251875Speter break; 1091251875Speter 1092251875Speter 1093251875Speter case 'n': 1094251875Speter if (var_type == IS_QUAD) 1095251875Speter *(va_arg(ap, apr_int64_t *)) = cc; 1096251875Speter else if (var_type == IS_LONG) 1097251875Speter *(va_arg(ap, long *)) = cc; 1098251875Speter else if (var_type == IS_SHORT) 1099251875Speter *(va_arg(ap, short *)) = cc; 1100251875Speter else 1101251875Speter *(va_arg(ap, int *)) = cc; 1102251875Speter print_something = NO; 1103251875Speter break; 1104251875Speter 1105251875Speter /* 1106251875Speter * This is where we extend the printf format, with a second 1107251875Speter * type specifier 1108251875Speter */ 1109251875Speter case 'p': 1110251875Speter switch(*++fmt) { 1111251875Speter /* 1112251875Speter * If the pointer size is equal to or smaller than the size 1113251875Speter * of the largest unsigned int, we convert the pointer to a 1114251875Speter * hex number, otherwise we print "%p" to indicate that we 1115251875Speter * don't handle "%p". 1116251875Speter */ 1117251875Speter case 'p': 1118251875Speter#if APR_SIZEOF_VOIDP == 8 1119251875Speter if (sizeof(void *) <= sizeof(apr_uint64_t)) { 1120251875Speter ui_quad = (apr_uint64_t) va_arg(ap, void *); 1121251875Speter s = conv_p2_quad(ui_quad, 4, 'x', 1122251875Speter &num_buf[NUM_BUF_SIZE], &s_len); 1123251875Speter } 1124251875Speter#else 1125251875Speter if (sizeof(void *) <= sizeof(apr_uint32_t)) { 1126251875Speter ui_num = (apr_uint32_t) va_arg(ap, void *); 1127251875Speter s = conv_p2(ui_num, 4, 'x', 1128251875Speter &num_buf[NUM_BUF_SIZE], &s_len); 1129251875Speter } 1130251875Speter#endif 1131251875Speter else { 1132251875Speter s = "%p"; 1133251875Speter s_len = 2; 1134251875Speter prefix_char = NUL; 1135251875Speter } 1136251875Speter pad_char = ' '; 1137251875Speter break; 1138251875Speter 1139251875Speter /* print an apr_sockaddr_t as a.b.c.d:port */ 1140251875Speter case 'I': 1141251875Speter { 1142251875Speter apr_sockaddr_t *sa; 1143251875Speter 1144251875Speter sa = va_arg(ap, apr_sockaddr_t *); 1145251875Speter if (sa != NULL) { 1146251875Speter s = conv_apr_sockaddr(sa, &num_buf[NUM_BUF_SIZE], &s_len); 1147251875Speter if (adjust_precision && precision < s_len) 1148251875Speter s_len = precision; 1149251875Speter } 1150251875Speter else { 1151251875Speter s = S_NULL; 1152251875Speter s_len = S_NULL_LEN; 1153251875Speter } 1154251875Speter pad_char = ' '; 1155251875Speter } 1156251875Speter break; 1157251875Speter 1158251875Speter /* print a struct in_addr as a.b.c.d */ 1159251875Speter case 'A': 1160251875Speter { 1161251875Speter struct in_addr *ia; 1162251875Speter 1163251875Speter ia = va_arg(ap, struct in_addr *); 1164251875Speter if (ia != NULL) { 1165251875Speter s = conv_in_addr(ia, &num_buf[NUM_BUF_SIZE], &s_len); 1166251875Speter if (adjust_precision && precision < s_len) 1167251875Speter s_len = precision; 1168251875Speter } 1169251875Speter else { 1170251875Speter s = S_NULL; 1171251875Speter s_len = S_NULL_LEN; 1172251875Speter } 1173251875Speter pad_char = ' '; 1174251875Speter } 1175251875Speter break; 1176251875Speter 1177251875Speter /* print the error for an apr_status_t */ 1178251875Speter case 'm': 1179251875Speter { 1180251875Speter apr_status_t *mrv; 1181251875Speter 1182251875Speter mrv = va_arg(ap, apr_status_t *); 1183251875Speter if (mrv != NULL) { 1184251875Speter s = apr_strerror(*mrv, num_buf, NUM_BUF_SIZE-1); 1185251875Speter s_len = strlen(s); 1186251875Speter } 1187251875Speter else { 1188251875Speter s = S_NULL; 1189251875Speter s_len = S_NULL_LEN; 1190251875Speter } 1191251875Speter pad_char = ' '; 1192251875Speter } 1193251875Speter break; 1194251875Speter 1195251875Speter case 'T': 1196251875Speter#if APR_HAS_THREADS 1197251875Speter { 1198251875Speter apr_os_thread_t *tid; 1199251875Speter 1200251875Speter tid = va_arg(ap, apr_os_thread_t *); 1201251875Speter if (tid != NULL) { 1202251875Speter s = conv_os_thread_t(tid, &num_buf[NUM_BUF_SIZE], &s_len); 1203251875Speter if (adjust_precision && precision < s_len) 1204251875Speter s_len = precision; 1205251875Speter } 1206251875Speter else { 1207251875Speter s = S_NULL; 1208251875Speter s_len = S_NULL_LEN; 1209251875Speter } 1210251875Speter pad_char = ' '; 1211251875Speter } 1212251875Speter#else 1213251875Speter char_buf[0] = '0'; 1214251875Speter s = &char_buf[0]; 1215251875Speter s_len = 1; 1216251875Speter pad_char = ' '; 1217251875Speter#endif 1218251875Speter break; 1219251875Speter 1220251875Speter case 't': 1221251875Speter#if APR_HAS_THREADS 1222251875Speter { 1223251875Speter apr_os_thread_t *tid; 1224251875Speter 1225251875Speter tid = va_arg(ap, apr_os_thread_t *); 1226251875Speter if (tid != NULL) { 1227251875Speter s = conv_os_thread_t_hex(tid, &num_buf[NUM_BUF_SIZE], &s_len); 1228251875Speter if (adjust_precision && precision < s_len) 1229251875Speter s_len = precision; 1230251875Speter } 1231251875Speter else { 1232251875Speter s = S_NULL; 1233251875Speter s_len = S_NULL_LEN; 1234251875Speter } 1235251875Speter pad_char = ' '; 1236251875Speter } 1237251875Speter#else 1238251875Speter char_buf[0] = '0'; 1239251875Speter s = &char_buf[0]; 1240251875Speter s_len = 1; 1241251875Speter pad_char = ' '; 1242251875Speter#endif 1243251875Speter break; 1244251875Speter 1245251875Speter case 'B': 1246251875Speter case 'F': 1247251875Speter case 'S': 1248251875Speter { 1249251875Speter char buf[5]; 1250251875Speter apr_off_t size = 0; 1251251875Speter 1252251875Speter if (*fmt == 'B') { 1253251875Speter apr_uint32_t *arg = va_arg(ap, apr_uint32_t *); 1254251875Speter size = (arg) ? *arg : 0; 1255251875Speter } 1256251875Speter else if (*fmt == 'F') { 1257251875Speter apr_off_t *arg = va_arg(ap, apr_off_t *); 1258251875Speter size = (arg) ? *arg : 0; 1259251875Speter } 1260251875Speter else { 1261251875Speter apr_size_t *arg = va_arg(ap, apr_size_t *); 1262251875Speter size = (arg) ? *arg : 0; 1263251875Speter } 1264251875Speter 1265251875Speter s = apr_strfsize(size, buf); 1266251875Speter s_len = strlen(s); 1267251875Speter pad_char = ' '; 1268251875Speter } 1269251875Speter break; 1270251875Speter 1271251875Speter case NUL: 1272251875Speter /* if %p ends the string, oh well ignore it */ 1273251875Speter continue; 1274251875Speter 1275251875Speter default: 1276251875Speter s = "bogus %p"; 1277251875Speter s_len = 8; 1278251875Speter prefix_char = NUL; 1279251875Speter (void)va_arg(ap, void *); /* skip the bogus argument on the stack */ 1280251875Speter break; 1281251875Speter } 1282251875Speter break; 1283251875Speter 1284251875Speter case NUL: 1285251875Speter /* 1286251875Speter * The last character of the format string was %. 1287251875Speter * We ignore it. 1288251875Speter */ 1289251875Speter continue; 1290251875Speter 1291251875Speter 1292251875Speter /* 1293251875Speter * The default case is for unrecognized %'s. 1294251875Speter * We print %<char> to help the user identify what 1295251875Speter * option is not understood. 1296251875Speter * This is also useful in case the user wants to pass 1297251875Speter * the output of format_converter to another function 1298251875Speter * that understands some other %<char> (like syslog). 1299251875Speter * Note that we can't point s inside fmt because the 1300251875Speter * unknown <char> could be preceded by width etc. 1301251875Speter */ 1302251875Speter default: 1303251875Speter char_buf[0] = '%'; 1304251875Speter char_buf[1] = *fmt; 1305251875Speter s = char_buf; 1306251875Speter s_len = 2; 1307251875Speter pad_char = ' '; 1308251875Speter break; 1309251875Speter } 1310251875Speter 1311251875Speter if (prefix_char != NUL && s != S_NULL && s != char_buf) { 1312251875Speter *--s = prefix_char; 1313251875Speter s_len++; 1314251875Speter } 1315251875Speter 1316251875Speter if (adjust_width && adjust == RIGHT && min_width > s_len) { 1317251875Speter if (pad_char == '0' && prefix_char != NUL) { 1318251875Speter INS_CHAR(*s, sp, bep, cc); 1319251875Speter s++; 1320251875Speter s_len--; 1321251875Speter min_width--; 1322251875Speter } 1323251875Speter PAD(min_width, s_len, pad_char); 1324251875Speter } 1325251875Speter 1326251875Speter /* 1327251875Speter * Print the string s. 1328251875Speter */ 1329251875Speter if (print_something == YES) { 1330251875Speter for (i = s_len; i != 0; i--) { 1331251875Speter INS_CHAR(*s, sp, bep, cc); 1332251875Speter s++; 1333251875Speter } 1334251875Speter } 1335251875Speter 1336251875Speter if (adjust_width && adjust == LEFT && min_width > s_len) 1337251875Speter PAD(min_width, s_len, pad_char); 1338251875Speter } 1339251875Speter fmt++; 1340251875Speter } 1341251875Speter vbuff->curpos = sp; 1342251875Speter 1343251875Speter return cc; 1344251875Speter} 1345251875Speter 1346251875Speter 1347251875Speterstatic int snprintf_flush(apr_vformatter_buff_t *vbuff) 1348251875Speter{ 1349251875Speter /* if the buffer fills we have to abort immediately, there is no way 1350251875Speter * to "flush" an apr_snprintf... there's nowhere to flush it to. 1351251875Speter */ 1352251875Speter return -1; 1353251875Speter} 1354251875Speter 1355251875Speter 1356251875SpeterAPR_DECLARE_NONSTD(int) apr_snprintf(char *buf, apr_size_t len, 1357251875Speter const char *format, ...) 1358251875Speter{ 1359251875Speter int cc; 1360251875Speter va_list ap; 1361251875Speter apr_vformatter_buff_t vbuff; 1362251875Speter 1363251875Speter if (len == 0) { 1364251875Speter /* NOTE: This is a special case; we just want to return the number 1365251875Speter * of chars that would be written (minus \0) if the buffer 1366251875Speter * size was infinite. We leverage the fact that INS_CHAR 1367251875Speter * just does actual inserts iff the buffer pointer is non-NULL. 1368251875Speter * In this case, we don't care what buf is; it can be NULL, since 1369251875Speter * we don't touch it at all. 1370251875Speter */ 1371251875Speter vbuff.curpos = NULL; 1372251875Speter vbuff.endpos = NULL; 1373251875Speter } else { 1374251875Speter /* save one byte for nul terminator */ 1375251875Speter vbuff.curpos = buf; 1376251875Speter vbuff.endpos = buf + len - 1; 1377251875Speter } 1378251875Speter va_start(ap, format); 1379251875Speter cc = apr_vformatter(snprintf_flush, &vbuff, format, ap); 1380251875Speter va_end(ap); 1381251875Speter if (len != 0) { 1382251875Speter *vbuff.curpos = '\0'; 1383251875Speter } 1384251875Speter return (cc == -1) ? (int)len - 1 : cc; 1385251875Speter} 1386251875Speter 1387251875Speter 1388251875SpeterAPR_DECLARE(int) apr_vsnprintf(char *buf, apr_size_t len, const char *format, 1389251875Speter va_list ap) 1390251875Speter{ 1391251875Speter int cc; 1392251875Speter apr_vformatter_buff_t vbuff; 1393251875Speter 1394251875Speter if (len == 0) { 1395251875Speter /* See above note */ 1396251875Speter vbuff.curpos = NULL; 1397251875Speter vbuff.endpos = NULL; 1398251875Speter } else { 1399251875Speter /* save one byte for nul terminator */ 1400251875Speter vbuff.curpos = buf; 1401251875Speter vbuff.endpos = buf + len - 1; 1402251875Speter } 1403251875Speter cc = apr_vformatter(snprintf_flush, &vbuff, format, ap); 1404251875Speter if (len != 0) { 1405251875Speter *vbuff.curpos = '\0'; 1406251875Speter } 1407251875Speter return (cc == -1) ? (int)len - 1 : cc; 1408251875Speter} 1409