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 /* 104251875Speter * Do integer part 105251875Speter */ 106251875Speter if (fi != 0) { 107251875Speter p1 = &buf[NDIG]; 108251875Speter while (p1 > &buf[0] && fi != 0) { 109251875Speter fj = modf(fi / 10, &fi); 110251875Speter *--p1 = (int) ((fj + .03) * 10) + '0'; 111251875Speter r2++; 112251875Speter } 113251875Speter while (p1 < &buf[NDIG]) 114251875Speter *p++ = *p1++; 115251875Speter } 116251875Speter else if (arg > 0) { 117251875Speter while ((fj = arg * 10) < 1) { 118251875Speter arg = fj; 119251875Speter r2--; 120251875Speter } 121251875Speter } 122251875Speter p1 = &buf[ndigits]; 123251875Speter if (eflag == 0) 124251875Speter p1 += r2; 125251875Speter if (p1 < &buf[0]) { 126251875Speter *decpt = -ndigits; 127251875Speter buf[0] = '\0'; 128251875Speter return (buf); 129251875Speter } 130251875Speter *decpt = r2; 131251875Speter while (p <= p1 && p < &buf[NDIG]) { 132251875Speter arg *= 10; 133251875Speter arg = modf(arg, &fj); 134251875Speter *p++ = (int) fj + '0'; 135251875Speter } 136251875Speter if (p1 >= &buf[NDIG]) { 137251875Speter buf[NDIG - 1] = '\0'; 138251875Speter return (buf); 139251875Speter } 140251875Speter p = p1; 141251875Speter *p1 += 5; 142251875Speter while (*p1 > '9') { 143251875Speter *p1 = '0'; 144251875Speter if (p1 > buf) 145251875Speter ++ * --p1; 146251875Speter else { 147251875Speter *p1 = '1'; 148251875Speter (*decpt)++; 149251875Speter if (eflag == 0) { 150251875Speter if (p > buf) 151251875Speter *p = '0'; 152251875Speter p++; 153251875Speter } 154251875Speter } 155251875Speter } 156251875Speter *p = '\0'; 157251875Speter return (buf); 158251875Speter} 159251875Speter 160251875Speterstatic char *apr_ecvt(double arg, int ndigits, int *decpt, int *sign, char *buf) 161251875Speter{ 162251875Speter return (apr_cvt(arg, ndigits, decpt, sign, 1, buf)); 163251875Speter} 164251875Speter 165251875Speterstatic char *apr_fcvt(double arg, int ndigits, int *decpt, int *sign, char *buf) 166251875Speter{ 167251875Speter return (apr_cvt(arg, ndigits, decpt, sign, 0, buf)); 168251875Speter} 169251875Speter 170251875Speter/* 171251875Speter * apr_gcvt - Floating output conversion to 172251875Speter * minimal length string 173251875Speter */ 174251875Speter 175251875Speterstatic char *apr_gcvt(double number, int ndigit, char *buf, boolean_e altform) 176251875Speter{ 177251875Speter int sign, decpt; 178251875Speter register char *p1, *p2; 179251875Speter register int i; 180251875Speter char buf1[NDIG]; 181251875Speter 182251875Speter p1 = apr_ecvt(number, ndigit, &decpt, &sign, buf1); 183251875Speter p2 = buf; 184251875Speter if (sign) 185251875Speter *p2++ = '-'; 186251875Speter for (i = ndigit - 1; i > 0 && p1[i] == '0'; i--) 187251875Speter ndigit--; 188251875Speter if ((decpt >= 0 && decpt - ndigit > 4) 189251875Speter || (decpt < 0 && decpt < -3)) { /* use E-style */ 190251875Speter decpt--; 191251875Speter *p2++ = *p1++; 192251875Speter *p2++ = '.'; 193251875Speter for (i = 1; i < ndigit; i++) 194251875Speter *p2++ = *p1++; 195251875Speter *p2++ = 'e'; 196251875Speter if (decpt < 0) { 197251875Speter decpt = -decpt; 198251875Speter *p2++ = '-'; 199251875Speter } 200251875Speter else 201251875Speter *p2++ = '+'; 202251875Speter if (decpt / 100 > 0) 203251875Speter *p2++ = decpt / 100 + '0'; 204251875Speter if (decpt / 10 > 0) 205251875Speter *p2++ = (decpt % 100) / 10 + '0'; 206251875Speter *p2++ = decpt % 10 + '0'; 207251875Speter } 208251875Speter else { 209251875Speter if (decpt <= 0) { 210251875Speter if (*p1 != '0') 211251875Speter *p2++ = '.'; 212251875Speter while (decpt < 0) { 213251875Speter decpt++; 214251875Speter *p2++ = '0'; 215251875Speter } 216251875Speter } 217251875Speter for (i = 1; i <= ndigit; i++) { 218251875Speter *p2++ = *p1++; 219251875Speter if (i == decpt) 220251875Speter *p2++ = '.'; 221251875Speter } 222251875Speter if (ndigit < decpt) { 223251875Speter while (ndigit++ < decpt) 224251875Speter *p2++ = '0'; 225251875Speter *p2++ = '.'; 226251875Speter } 227251875Speter } 228251875Speter if (p2[-1] == '.' && !altform) 229251875Speter p2--; 230251875Speter *p2 = '\0'; 231251875Speter return (buf); 232251875Speter} 233251875Speter 234251875Speter/* 235251875Speter * The INS_CHAR macro inserts a character in the buffer and writes 236251875Speter * the buffer back to disk if necessary 237251875Speter * It uses the char pointers sp and bep: 238251875Speter * sp points to the next available character in the buffer 239251875Speter * bep points to the end-of-buffer+1 240251875Speter * While using this macro, note that the nextb pointer is NOT updated. 241251875Speter * 242251875Speter * NOTE: Evaluation of the c argument should not have any side-effects 243251875Speter */ 244251875Speter#define INS_CHAR(c, sp, bep, cc) \ 245251875Speter{ \ 246251875Speter if (sp) { \ 247251875Speter if (sp >= bep) { \ 248251875Speter vbuff->curpos = sp; \ 249251875Speter if (flush_func(vbuff)) \ 250251875Speter return -1; \ 251251875Speter sp = vbuff->curpos; \ 252251875Speter bep = vbuff->endpos; \ 253251875Speter } \ 254251875Speter *sp++ = (c); \ 255251875Speter } \ 256251875Speter cc++; \ 257251875Speter} 258251875Speter 259251875Speter#define NUM(c) (c - '0') 260251875Speter 261251875Speter#define STR_TO_DEC(str, num) \ 262251875Speter num = NUM(*str++); \ 263251875Speter while (apr_isdigit(*str)) \ 264251875Speter { \ 265251875Speter num *= 10 ; \ 266251875Speter num += NUM(*str++); \ 267251875Speter } 268251875Speter 269251875Speter/* 270251875Speter * This macro does zero padding so that the precision 271251875Speter * requirement is satisfied. The padding is done by 272251875Speter * adding '0's to the left of the string that is going 273251875Speter * to be printed. We don't allow precision to be large 274251875Speter * enough that we continue past the start of s. 275251875Speter * 276251875Speter * NOTE: this makes use of the magic info that s is 277251875Speter * always based on num_buf with a size of NUM_BUF_SIZE. 278251875Speter */ 279251875Speter#define FIX_PRECISION(adjust, precision, s, s_len) \ 280251875Speter if (adjust) { \ 281251875Speter apr_size_t p = (precision + 1 < NUM_BUF_SIZE) \ 282251875Speter ? precision : NUM_BUF_SIZE - 1; \ 283251875Speter while (s_len < p) \ 284251875Speter { \ 285251875Speter *--s = '0'; \ 286251875Speter s_len++; \ 287251875Speter } \ 288251875Speter } 289251875Speter 290251875Speter/* 291251875Speter * Macro that does padding. The padding is done by printing 292251875Speter * the character ch. 293251875Speter */ 294251875Speter#define PAD(width, len, ch) \ 295251875Speterdo \ 296251875Speter{ \ 297251875Speter INS_CHAR(ch, sp, bep, cc); \ 298251875Speter width--; \ 299251875Speter} \ 300251875Speterwhile (width > len) 301251875Speter 302251875Speter/* 303251875Speter * Prefix the character ch to the string str 304251875Speter * Increase length 305251875Speter * Set the has_prefix flag 306251875Speter */ 307251875Speter#define PREFIX(str, length, ch) \ 308251875Speter *--str = ch; \ 309251875Speter length++; \ 310251875Speter has_prefix=YES; 311251875Speter 312251875Speter 313251875Speter/* 314251875Speter * Convert num to its decimal format. 315251875Speter * Return value: 316251875Speter * - a pointer to a string containing the number (no sign) 317251875Speter * - len contains the length of the string 318251875Speter * - is_negative is set to TRUE or FALSE depending on the sign 319251875Speter * of the number (always set to FALSE if is_unsigned is TRUE) 320251875Speter * 321251875Speter * The caller provides a buffer for the string: that is the buf_end argument 322251875Speter * which is a pointer to the END of the buffer + 1 (i.e. if the buffer 323251875Speter * is declared as buf[ 100 ], buf_end should be &buf[ 100 ]) 324251875Speter * 325251875Speter * Note: we have 2 versions. One is used when we need to use quads 326251875Speter * (conv_10_quad), the other when we don't (conv_10). We're assuming the 327251875Speter * latter is faster. 328251875Speter */ 329251875Speterstatic char *conv_10(register apr_int32_t num, register int is_unsigned, 330251875Speter register int *is_negative, char *buf_end, 331251875Speter register apr_size_t *len) 332251875Speter{ 333251875Speter register char *p = buf_end; 334251875Speter register apr_uint32_t magnitude = num; 335251875Speter 336251875Speter if (is_unsigned) { 337251875Speter *is_negative = FALSE; 338251875Speter } 339251875Speter else { 340251875Speter *is_negative = (num < 0); 341251875Speter 342251875Speter /* 343251875Speter * On a 2's complement machine, negating the most negative integer 344251875Speter * results in a number that cannot be represented as a signed integer. 345251875Speter * Here is what we do to obtain the number's magnitude: 346251875Speter * a. add 1 to the number 347251875Speter * b. negate it (becomes positive) 348251875Speter * c. convert it to unsigned 349251875Speter * d. add 1 350251875Speter */ 351251875Speter if (*is_negative) { 352251875Speter apr_int32_t t = num + 1; 353251875Speter magnitude = ((apr_uint32_t) -t) + 1; 354251875Speter } 355251875Speter } 356251875Speter 357251875Speter /* 358251875Speter * We use a do-while loop so that we write at least 1 digit 359251875Speter */ 360251875Speter do { 361251875Speter register apr_uint32_t new_magnitude = magnitude / 10; 362251875Speter 363251875Speter *--p = (char) (magnitude - new_magnitude * 10 + '0'); 364251875Speter magnitude = new_magnitude; 365251875Speter } 366251875Speter while (magnitude); 367251875Speter 368251875Speter *len = buf_end - p; 369251875Speter return (p); 370251875Speter} 371251875Speter 372251875Speterstatic char *conv_10_quad(apr_int64_t num, register int is_unsigned, 373251875Speter register int *is_negative, char *buf_end, 374251875Speter register apr_size_t *len) 375251875Speter{ 376251875Speter register char *p = buf_end; 377251875Speter apr_uint64_t magnitude = num; 378251875Speter 379251875Speter /* 380251875Speter * We see if we can use the faster non-quad version by checking the 381251875Speter * number against the largest long value it can be. If <=, we 382251875Speter * punt to the quicker version. 383251875Speter */ 384251875Speter if ((magnitude <= APR_UINT32_MAX && is_unsigned) 385251875Speter || (num <= APR_INT32_MAX && num >= APR_INT32_MIN && !is_unsigned)) 386251875Speter return(conv_10((apr_int32_t)num, is_unsigned, is_negative, buf_end, len)); 387251875Speter 388251875Speter if (is_unsigned) { 389251875Speter *is_negative = FALSE; 390251875Speter } 391251875Speter else { 392251875Speter *is_negative = (num < 0); 393251875Speter 394251875Speter /* 395251875Speter * On a 2's complement machine, negating the most negative integer 396251875Speter * results in a number that cannot be represented as a signed integer. 397251875Speter * Here is what we do to obtain the number's magnitude: 398251875Speter * a. add 1 to the number 399251875Speter * b. negate it (becomes positive) 400251875Speter * c. convert it to unsigned 401251875Speter * d. add 1 402251875Speter */ 403251875Speter if (*is_negative) { 404251875Speter apr_int64_t t = num + 1; 405251875Speter magnitude = ((apr_uint64_t) -t) + 1; 406251875Speter } 407251875Speter } 408251875Speter 409251875Speter /* 410251875Speter * We use a do-while loop so that we write at least 1 digit 411251875Speter */ 412251875Speter do { 413251875Speter apr_uint64_t new_magnitude = magnitude / 10; 414251875Speter 415251875Speter *--p = (char) (magnitude - new_magnitude * 10 + '0'); 416251875Speter magnitude = new_magnitude; 417251875Speter } 418251875Speter while (magnitude); 419251875Speter 420251875Speter *len = buf_end - p; 421251875Speter return (p); 422251875Speter} 423251875Speter 424251875Speterstatic char *conv_in_addr(struct in_addr *ia, char *buf_end, apr_size_t *len) 425251875Speter{ 426251875Speter unsigned addr = ntohl(ia->s_addr); 427251875Speter char *p = buf_end; 428251875Speter int is_negative; 429251875Speter apr_size_t sub_len; 430251875Speter 431251875Speter p = conv_10((addr & 0x000000FF) , TRUE, &is_negative, p, &sub_len); 432251875Speter *--p = '.'; 433251875Speter p = conv_10((addr & 0x0000FF00) >> 8, TRUE, &is_negative, p, &sub_len); 434251875Speter *--p = '.'; 435251875Speter p = conv_10((addr & 0x00FF0000) >> 16, TRUE, &is_negative, p, &sub_len); 436251875Speter *--p = '.'; 437251875Speter p = conv_10((addr & 0xFF000000) >> 24, TRUE, &is_negative, p, &sub_len); 438251875Speter 439251875Speter *len = buf_end - p; 440251875Speter return (p); 441251875Speter} 442251875Speter 443251875Speter 444251875Speter/* Must be passed a buffer of size NUM_BUF_SIZE where buf_end points 445251875Speter * to 1 byte past the end of the buffer. */ 446251875Speterstatic char *conv_apr_sockaddr(apr_sockaddr_t *sa, char *buf_end, apr_size_t *len) 447251875Speter{ 448251875Speter char *p = buf_end; 449251875Speter int is_negative; 450251875Speter apr_size_t sub_len; 451251875Speter char *ipaddr_str; 452251875Speter 453251875Speter p = conv_10(sa->port, TRUE, &is_negative, p, &sub_len); 454251875Speter *--p = ':'; 455251875Speter ipaddr_str = buf_end - NUM_BUF_SIZE; 456251875Speter if (apr_sockaddr_ip_getbuf(ipaddr_str, sa->addr_str_len, sa)) { 457251875Speter /* Should only fail if the buffer is too small, which it 458251875Speter * should not be; but fail safe anyway: */ 459251875Speter *--p = '?'; 460251875Speter *len = buf_end - p; 461251875Speter return p; 462251875Speter } 463251875Speter sub_len = strlen(ipaddr_str); 464251875Speter#if APR_HAVE_IPV6 465251875Speter if (sa->family == APR_INET6 && 466251875Speter !IN6_IS_ADDR_V4MAPPED(&sa->sa.sin6.sin6_addr)) { 467251875Speter *(p - 1) = ']'; 468251875Speter p -= sub_len + 2; 469251875Speter *p = '['; 470251875Speter memcpy(p + 1, ipaddr_str, sub_len); 471251875Speter } 472251875Speter else 473251875Speter#endif 474251875Speter { 475251875Speter p -= sub_len; 476251875Speter memcpy(p, ipaddr_str, sub_len); 477251875Speter } 478251875Speter 479251875Speter *len = buf_end - p; 480251875Speter return (p); 481251875Speter} 482251875Speter 483251875Speter 484251875Speter 485251875Speter#if APR_HAS_THREADS 486251875Speterstatic char *conv_os_thread_t(apr_os_thread_t *tid, char *buf_end, apr_size_t *len) 487251875Speter{ 488251875Speter union { 489251875Speter apr_os_thread_t tid; 490251875Speter apr_uint64_t u64; 491251875Speter apr_uint32_t u32; 492251875Speter } u; 493251875Speter int is_negative; 494251875Speter 495251875Speter u.tid = *tid; 496251875Speter switch(sizeof(u.tid)) { 497251875Speter case sizeof(apr_int32_t): 498251875Speter return conv_10(u.u32, TRUE, &is_negative, buf_end, len); 499251875Speter case sizeof(apr_int64_t): 500251875Speter return conv_10_quad(u.u64, TRUE, &is_negative, buf_end, len); 501251875Speter default: 502251875Speter /* not implemented; stick 0 in the buffer */ 503251875Speter return conv_10(0, TRUE, &is_negative, buf_end, len); 504251875Speter } 505251875Speter} 506251875Speter#endif 507251875Speter 508251875Speter 509251875Speter 510251875Speter/* 511251875Speter * Convert a floating point number to a string formats 'f', 'e' or 'E'. 512251875Speter * The result is placed in buf, and len denotes the length of the string 513251875Speter * The sign is returned in the is_negative argument (and is not placed 514251875Speter * in buf). 515251875Speter */ 516251875Speterstatic char *conv_fp(register char format, register double num, 517251875Speter boolean_e add_dp, int precision, int *is_negative, 518251875Speter char *buf, apr_size_t *len) 519251875Speter{ 520251875Speter register char *s = buf; 521251875Speter register char *p; 522251875Speter int decimal_point; 523251875Speter char buf1[NDIG]; 524251875Speter 525251875Speter if (format == 'f') 526251875Speter p = apr_fcvt(num, precision, &decimal_point, is_negative, buf1); 527251875Speter else /* either e or E format */ 528251875Speter p = apr_ecvt(num, precision + 1, &decimal_point, is_negative, buf1); 529251875Speter 530251875Speter /* 531251875Speter * Check for Infinity and NaN 532251875Speter */ 533251875Speter if (apr_isalpha(*p)) { 534251875Speter *len = strlen(p); 535251875Speter memcpy(buf, p, *len + 1); 536251875Speter *is_negative = FALSE; 537251875Speter return (buf); 538251875Speter } 539251875Speter 540251875Speter if (format == 'f') { 541251875Speter if (decimal_point <= 0) { 542251875Speter *s++ = '0'; 543251875Speter if (precision > 0) { 544251875Speter *s++ = '.'; 545251875Speter while (decimal_point++ < 0) 546251875Speter *s++ = '0'; 547251875Speter } 548251875Speter else if (add_dp) 549251875Speter *s++ = '.'; 550251875Speter } 551251875Speter else { 552251875Speter while (decimal_point-- > 0) 553251875Speter *s++ = *p++; 554251875Speter if (precision > 0 || add_dp) 555251875Speter *s++ = '.'; 556251875Speter } 557251875Speter } 558251875Speter else { 559251875Speter *s++ = *p++; 560251875Speter if (precision > 0 || add_dp) 561251875Speter *s++ = '.'; 562251875Speter } 563251875Speter 564251875Speter /* 565251875Speter * copy the rest of p, the NUL is NOT copied 566251875Speter */ 567251875Speter while (*p) 568251875Speter *s++ = *p++; 569251875Speter 570251875Speter if (format != 'f') { 571251875Speter char temp[EXPONENT_LENGTH]; /* for exponent conversion */ 572251875Speter apr_size_t t_len; 573251875Speter int exponent_is_negative; 574251875Speter 575251875Speter *s++ = format; /* either e or E */ 576251875Speter decimal_point--; 577251875Speter if (decimal_point != 0) { 578251875Speter p = conv_10((apr_int32_t) decimal_point, FALSE, &exponent_is_negative, 579251875Speter &temp[EXPONENT_LENGTH], &t_len); 580251875Speter *s++ = exponent_is_negative ? '-' : '+'; 581251875Speter 582251875Speter /* 583251875Speter * Make sure the exponent has at least 2 digits 584251875Speter */ 585251875Speter if (t_len == 1) 586251875Speter *s++ = '0'; 587251875Speter while (t_len--) 588251875Speter *s++ = *p++; 589251875Speter } 590251875Speter else { 591251875Speter *s++ = '+'; 592251875Speter *s++ = '0'; 593251875Speter *s++ = '0'; 594251875Speter } 595251875Speter } 596251875Speter 597251875Speter *len = s - buf; 598251875Speter return (buf); 599251875Speter} 600251875Speter 601251875Speter 602251875Speter/* 603251875Speter * Convert num to a base X number where X is a power of 2. nbits determines X. 604251875Speter * For example, if nbits is 3, we do base 8 conversion 605251875Speter * Return value: 606251875Speter * a pointer to a string containing the number 607251875Speter * 608251875Speter * The caller provides a buffer for the string: that is the buf_end argument 609251875Speter * which is a pointer to the END of the buffer + 1 (i.e. if the buffer 610251875Speter * is declared as buf[ 100 ], buf_end should be &buf[ 100 ]) 611251875Speter * 612251875Speter * As with conv_10, we have a faster version which is used when 613251875Speter * the number isn't quad size. 614251875Speter */ 615251875Speterstatic char *conv_p2(register apr_uint32_t num, register int nbits, 616251875Speter char format, char *buf_end, register apr_size_t *len) 617251875Speter{ 618251875Speter register int mask = (1 << nbits) - 1; 619251875Speter register char *p = buf_end; 620251875Speter static const char low_digits[] = "0123456789abcdef"; 621251875Speter static const char upper_digits[] = "0123456789ABCDEF"; 622251875Speter register const char *digits = (format == 'X') ? upper_digits : low_digits; 623251875Speter 624251875Speter do { 625251875Speter *--p = digits[num & mask]; 626251875Speter num >>= nbits; 627251875Speter } 628251875Speter while (num); 629251875Speter 630251875Speter *len = buf_end - p; 631251875Speter return (p); 632251875Speter} 633251875Speter 634251875Speterstatic char *conv_p2_quad(apr_uint64_t num, register int nbits, 635251875Speter char format, char *buf_end, register apr_size_t *len) 636251875Speter{ 637251875Speter register int mask = (1 << nbits) - 1; 638251875Speter register char *p = buf_end; 639251875Speter static const char low_digits[] = "0123456789abcdef"; 640251875Speter static const char upper_digits[] = "0123456789ABCDEF"; 641251875Speter register const char *digits = (format == 'X') ? upper_digits : low_digits; 642251875Speter 643251875Speter if (num <= APR_UINT32_MAX) 644251875Speter return(conv_p2((apr_uint32_t)num, nbits, format, buf_end, len)); 645251875Speter 646251875Speter do { 647251875Speter *--p = digits[num & mask]; 648251875Speter num >>= nbits; 649251875Speter } 650251875Speter while (num); 651251875Speter 652251875Speter *len = buf_end - p; 653251875Speter return (p); 654251875Speter} 655251875Speter 656251875Speter#if APR_HAS_THREADS 657251875Speterstatic char *conv_os_thread_t_hex(apr_os_thread_t *tid, char *buf_end, apr_size_t *len) 658251875Speter{ 659251875Speter union { 660251875Speter apr_os_thread_t tid; 661251875Speter apr_uint64_t u64; 662251875Speter apr_uint32_t u32; 663251875Speter } u; 664251875Speter int is_negative; 665251875Speter 666251875Speter u.tid = *tid; 667251875Speter switch(sizeof(u.tid)) { 668251875Speter case sizeof(apr_int32_t): 669251875Speter return conv_p2(u.u32, 4, 'x', buf_end, len); 670251875Speter case sizeof(apr_int64_t): 671251875Speter return conv_p2_quad(u.u64, 4, 'x', buf_end, len); 672251875Speter default: 673251875Speter /* not implemented; stick 0 in the buffer */ 674251875Speter return conv_10(0, TRUE, &is_negative, buf_end, len); 675251875Speter } 676251875Speter} 677251875Speter#endif 678251875Speter 679251875Speter/* 680251875Speter * Do format conversion placing the output in buffer 681251875Speter */ 682251875SpeterAPR_DECLARE(int) apr_vformatter(int (*flush_func)(apr_vformatter_buff_t *), 683251875Speter apr_vformatter_buff_t *vbuff, const char *fmt, va_list ap) 684251875Speter{ 685251875Speter register char *sp; 686251875Speter register char *bep; 687251875Speter register int cc = 0; 688251875Speter register apr_size_t i; 689251875Speter 690251875Speter register char *s = NULL; 691251875Speter char *q; 692251875Speter apr_size_t s_len = 0; 693251875Speter 694251875Speter register apr_size_t min_width = 0; 695251875Speter apr_size_t precision = 0; 696251875Speter enum { 697251875Speter LEFT, RIGHT 698251875Speter } adjust; 699251875Speter char pad_char; 700251875Speter char prefix_char; 701251875Speter 702251875Speter double fp_num; 703251875Speter apr_int64_t i_quad = 0; 704251875Speter apr_uint64_t ui_quad; 705251875Speter apr_int32_t i_num = 0; 706251875Speter apr_uint32_t ui_num = 0; 707251875Speter 708251875Speter char num_buf[NUM_BUF_SIZE]; 709251875Speter char char_buf[2]; /* for printing %% and %<unknown> */ 710362181Sdim char buf[5]; /* for printing %B, %F, and %S */ 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 apr_off_t size = 0; 1250251875Speter 1251251875Speter if (*fmt == 'B') { 1252251875Speter apr_uint32_t *arg = va_arg(ap, apr_uint32_t *); 1253251875Speter size = (arg) ? *arg : 0; 1254251875Speter } 1255251875Speter else if (*fmt == 'F') { 1256251875Speter apr_off_t *arg = va_arg(ap, apr_off_t *); 1257251875Speter size = (arg) ? *arg : 0; 1258251875Speter } 1259251875Speter else { 1260251875Speter apr_size_t *arg = va_arg(ap, apr_size_t *); 1261251875Speter size = (arg) ? *arg : 0; 1262251875Speter } 1263251875Speter 1264251875Speter s = apr_strfsize(size, buf); 1265251875Speter s_len = strlen(s); 1266251875Speter pad_char = ' '; 1267251875Speter } 1268251875Speter break; 1269251875Speter 1270251875Speter case NUL: 1271251875Speter /* if %p ends the string, oh well ignore it */ 1272251875Speter continue; 1273251875Speter 1274251875Speter default: 1275251875Speter s = "bogus %p"; 1276251875Speter s_len = 8; 1277251875Speter prefix_char = NUL; 1278251875Speter (void)va_arg(ap, void *); /* skip the bogus argument on the stack */ 1279251875Speter break; 1280251875Speter } 1281251875Speter break; 1282251875Speter 1283251875Speter case NUL: 1284251875Speter /* 1285251875Speter * The last character of the format string was %. 1286251875Speter * We ignore it. 1287251875Speter */ 1288251875Speter continue; 1289251875Speter 1290251875Speter 1291251875Speter /* 1292251875Speter * The default case is for unrecognized %'s. 1293251875Speter * We print %<char> to help the user identify what 1294251875Speter * option is not understood. 1295251875Speter * This is also useful in case the user wants to pass 1296251875Speter * the output of format_converter to another function 1297251875Speter * that understands some other %<char> (like syslog). 1298251875Speter * Note that we can't point s inside fmt because the 1299251875Speter * unknown <char> could be preceded by width etc. 1300251875Speter */ 1301251875Speter default: 1302251875Speter char_buf[0] = '%'; 1303251875Speter char_buf[1] = *fmt; 1304251875Speter s = char_buf; 1305251875Speter s_len = 2; 1306251875Speter pad_char = ' '; 1307251875Speter break; 1308251875Speter } 1309251875Speter 1310251875Speter if (prefix_char != NUL && s != S_NULL && s != char_buf) { 1311251875Speter *--s = prefix_char; 1312251875Speter s_len++; 1313251875Speter } 1314251875Speter 1315251875Speter if (adjust_width && adjust == RIGHT && min_width > s_len) { 1316251875Speter if (pad_char == '0' && prefix_char != NUL) { 1317251875Speter INS_CHAR(*s, sp, bep, cc); 1318251875Speter s++; 1319251875Speter s_len--; 1320251875Speter min_width--; 1321251875Speter } 1322251875Speter PAD(min_width, s_len, pad_char); 1323251875Speter } 1324251875Speter 1325251875Speter /* 1326251875Speter * Print the string s. 1327251875Speter */ 1328251875Speter if (print_something == YES) { 1329251875Speter for (i = s_len; i != 0; i--) { 1330362181Sdim INS_CHAR(*s, sp, bep, cc); 1331251875Speter s++; 1332251875Speter } 1333251875Speter } 1334251875Speter 1335251875Speter if (adjust_width && adjust == LEFT && min_width > s_len) 1336251875Speter PAD(min_width, s_len, pad_char); 1337251875Speter } 1338251875Speter fmt++; 1339251875Speter } 1340251875Speter vbuff->curpos = sp; 1341251875Speter 1342251875Speter return cc; 1343251875Speter} 1344251875Speter 1345251875Speter 1346251875Speterstatic int snprintf_flush(apr_vformatter_buff_t *vbuff) 1347251875Speter{ 1348251875Speter /* if the buffer fills we have to abort immediately, there is no way 1349251875Speter * to "flush" an apr_snprintf... there's nowhere to flush it to. 1350251875Speter */ 1351251875Speter return -1; 1352251875Speter} 1353251875Speter 1354251875Speter 1355251875SpeterAPR_DECLARE_NONSTD(int) apr_snprintf(char *buf, apr_size_t len, 1356251875Speter const char *format, ...) 1357251875Speter{ 1358251875Speter int cc; 1359251875Speter va_list ap; 1360251875Speter apr_vformatter_buff_t vbuff; 1361251875Speter 1362251875Speter if (len == 0) { 1363251875Speter /* NOTE: This is a special case; we just want to return the number 1364251875Speter * of chars that would be written (minus \0) if the buffer 1365251875Speter * size was infinite. We leverage the fact that INS_CHAR 1366251875Speter * just does actual inserts iff the buffer pointer is non-NULL. 1367251875Speter * In this case, we don't care what buf is; it can be NULL, since 1368251875Speter * we don't touch it at all. 1369251875Speter */ 1370251875Speter vbuff.curpos = NULL; 1371251875Speter vbuff.endpos = NULL; 1372251875Speter } else { 1373251875Speter /* save one byte for nul terminator */ 1374251875Speter vbuff.curpos = buf; 1375251875Speter vbuff.endpos = buf + len - 1; 1376251875Speter } 1377251875Speter va_start(ap, format); 1378251875Speter cc = apr_vformatter(snprintf_flush, &vbuff, format, ap); 1379251875Speter va_end(ap); 1380251875Speter if (len != 0) { 1381251875Speter *vbuff.curpos = '\0'; 1382251875Speter } 1383251875Speter return (cc == -1) ? (int)len - 1 : cc; 1384251875Speter} 1385251875Speter 1386251875Speter 1387251875SpeterAPR_DECLARE(int) apr_vsnprintf(char *buf, apr_size_t len, const char *format, 1388251875Speter va_list ap) 1389251875Speter{ 1390251875Speter int cc; 1391251875Speter apr_vformatter_buff_t vbuff; 1392251875Speter 1393251875Speter if (len == 0) { 1394251875Speter /* See above note */ 1395251875Speter vbuff.curpos = NULL; 1396251875Speter vbuff.endpos = NULL; 1397251875Speter } else { 1398251875Speter /* save one byte for nul terminator */ 1399251875Speter vbuff.curpos = buf; 1400251875Speter vbuff.endpos = buf + len - 1; 1401251875Speter } 1402251875Speter cc = apr_vformatter(snprintf_flush, &vbuff, format, ap); 1403251875Speter if (len != 0) { 1404251875Speter *vbuff.curpos = '\0'; 1405251875Speter } 1406251875Speter return (cc == -1) ? (int)len - 1 : cc; 1407251875Speter} 1408