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