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