~ubuntu-branches/ubuntu/feisty/apache2/feisty

« back to all changes in this revision

Viewing changes to srclib/apr/strings/apr_snprintf.c

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Barth
  • Date: 2006-12-09 21:05:45 UTC
  • mfrom: (0.6.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20061209210545-h70s0xaqc2v8vqr2
Tags: 2.2.3-3.2
* Non-maintainer upload.
* 043_ajp_connection_reuse: Patch from upstream Bugzilla, fixing a critical
  issue with regard to connection reuse in mod_proxy_ajp.
  Closes: #396265

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as
 
2
 * applicable.
 
3
 *
 
4
 * Licensed under the Apache License, Version 2.0 (the "License");
 
5
 * you may not use this file except in compliance with the License.
 
6
 * You may obtain a copy of the License at
 
7
 *
 
8
 *     http://www.apache.org/licenses/LICENSE-2.0
 
9
 *
 
10
 * Unless required by applicable law or agreed to in writing, software
 
11
 * distributed under the License is distributed on an "AS IS" BASIS,
 
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
13
 * See the License for the specific language governing permissions and
 
14
 * limitations under the License.
 
15
 */
 
16
 
 
17
#include "apr.h"
 
18
#include "apr_private.h"
 
19
 
 
20
#include "apr_lib.h"
 
21
#include "apr_strings.h"
 
22
#include "apr_network_io.h"
 
23
#include "apr_portable.h"
 
24
#include <math.h>
 
25
#if APR_HAVE_CTYPE_H
 
26
#include <ctype.h>
 
27
#endif
 
28
#if APR_HAVE_NETINET_IN_H
 
29
#include <netinet/in.h>
 
30
#endif
 
31
#if APR_HAVE_SYS_SOCKET_H
 
32
#include <sys/socket.h>
 
33
#endif
 
34
#if APR_HAVE_ARPA_INET_H
 
35
#include <arpa/inet.h>
 
36
#endif
 
37
#if APR_HAVE_LIMITS_H
 
38
#include <limits.h>
 
39
#endif
 
40
#if APR_HAVE_STRING_H
 
41
#include <string.h>
 
42
#endif
 
43
 
 
44
typedef enum {
 
45
    NO = 0, YES = 1
 
46
} boolean_e;
 
47
 
 
48
#ifndef FALSE
 
49
#define FALSE 0
 
50
#endif
 
51
#ifndef TRUE
 
52
#define TRUE 1
 
53
#endif
 
54
#define NUL '\0'
 
55
#define WIDE_INT long
 
56
 
 
57
typedef WIDE_INT wide_int;
 
58
typedef unsigned WIDE_INT u_wide_int;
 
59
typedef apr_int64_t widest_int;
 
60
#ifdef __TANDEM
 
61
/* Although Tandem supports "long long" there is no unsigned variant. */
 
62
typedef unsigned long       u_widest_int;
 
63
#else
 
64
typedef apr_uint64_t u_widest_int;
 
65
#endif
 
66
typedef int bool_int;
 
67
 
 
68
#define S_NULL "(null)"
 
69
#define S_NULL_LEN 6
 
70
 
 
71
#define FLOAT_DIGITS 6
 
72
#define EXPONENT_LENGTH 10
 
73
 
 
74
/*
 
75
 * NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions
 
76
 *
 
77
 * NOTICE: this is a magic number; do not decrease it
 
78
 */
 
79
#define NUM_BUF_SIZE 512
 
80
 
 
81
/*
 
82
 * cvt.c - IEEE floating point formatting routines for FreeBSD
 
83
 * from GNU libc-4.6.27.  Modified to be thread safe.
 
84
 */
 
85
 
 
86
/*
 
87
 *    apr_ecvt converts to decimal
 
88
 *      the number of digits is specified by ndigit
 
89
 *      decpt is set to the position of the decimal point
 
90
 *      sign is set to 0 for positive, 1 for negative
 
91
 */
 
92
 
 
93
#define NDIG 80
 
94
 
 
95
/* buf must have at least NDIG bytes */
 
96
static char *apr_cvt(double arg, int ndigits, int *decpt, int *sign, 
 
97
                     int eflag, char *buf)
 
98
{
 
99
    register int r2;
 
100
    double fi, fj;
 
101
    register char *p, *p1;
 
102
    
 
103
    if (ndigits >= NDIG - 1)
 
104
        ndigits = NDIG - 2;
 
105
    r2 = 0;
 
106
    *sign = 0;
 
107
    p = &buf[0];
 
108
    if (arg < 0) {
 
109
        *sign = 1;
 
110
        arg = -arg;
 
111
    }
 
112
    arg = modf(arg, &fi);
 
113
    p1 = &buf[NDIG];
 
114
    /*
 
115
     * Do integer part
 
116
     */
 
117
    if (fi != 0) {
 
118
        p1 = &buf[NDIG];
 
119
        while (p1 > &buf[0] && fi != 0) {
 
120
            fj = modf(fi / 10, &fi);
 
121
            *--p1 = (int) ((fj + .03) * 10) + '0';
 
122
            r2++;
 
123
        }
 
124
        while (p1 < &buf[NDIG])
 
125
            *p++ = *p1++;
 
126
    }
 
127
    else if (arg > 0) {
 
128
        while ((fj = arg * 10) < 1) {
 
129
            arg = fj;
 
130
            r2--;
 
131
        }
 
132
    }
 
133
    p1 = &buf[ndigits];
 
134
    if (eflag == 0)
 
135
        p1 += r2;
 
136
    if (p1 < &buf[0]) {
 
137
        *decpt = -ndigits;
 
138
        buf[0] = '\0';
 
139
        return (buf);
 
140
    }
 
141
    *decpt = r2;
 
142
    while (p <= p1 && p < &buf[NDIG]) {
 
143
        arg *= 10;
 
144
        arg = modf(arg, &fj);
 
145
        *p++ = (int) fj + '0';
 
146
    }
 
147
    if (p1 >= &buf[NDIG]) {
 
148
        buf[NDIG - 1] = '\0';
 
149
        return (buf);
 
150
    }
 
151
    p = p1;
 
152
    *p1 += 5;
 
153
    while (*p1 > '9') {
 
154
        *p1 = '0';
 
155
        if (p1 > buf)
 
156
            ++ * --p1;
 
157
        else {
 
158
            *p1 = '1';
 
159
            (*decpt)++;
 
160
            if (eflag == 0) {
 
161
                if (p > buf)
 
162
                    *p = '0';
 
163
                p++;
 
164
            }
 
165
        }
 
166
    }
 
167
    *p = '\0';
 
168
    return (buf);
 
169
}
 
170
 
 
171
static char *apr_ecvt(double arg, int ndigits, int *decpt, int *sign, char *buf)
 
172
{
 
173
    return (apr_cvt(arg, ndigits, decpt, sign, 1, buf));
 
174
}
 
175
 
 
176
static char *apr_fcvt(double arg, int ndigits, int *decpt, int *sign, char *buf)
 
177
{
 
178
    return (apr_cvt(arg, ndigits, decpt, sign, 0, buf));
 
179
}
 
180
 
 
181
/*
 
182
 * apr_gcvt  - Floating output conversion to
 
183
 * minimal length string
 
184
 */
 
185
 
 
186
static char *apr_gcvt(double number, int ndigit, char *buf, boolean_e altform)
 
187
{
 
188
    int sign, decpt;
 
189
    register char *p1, *p2;
 
190
    register int i;
 
191
    char buf1[NDIG];
 
192
 
 
193
    p1 = apr_ecvt(number, ndigit, &decpt, &sign, buf1);
 
194
    p2 = buf;
 
195
    if (sign)
 
196
        *p2++ = '-';
 
197
    for (i = ndigit - 1; i > 0 && p1[i] == '0'; i--)
 
198
        ndigit--;
 
199
    if ((decpt >= 0 && decpt - ndigit > 4)
 
200
        || (decpt < 0 && decpt < -3)) {                /* use E-style */
 
201
        decpt--;
 
202
        *p2++ = *p1++;
 
203
        *p2++ = '.';
 
204
        for (i = 1; i < ndigit; i++)
 
205
            *p2++ = *p1++;
 
206
        *p2++ = 'e';
 
207
        if (decpt < 0) {
 
208
            decpt = -decpt;
 
209
            *p2++ = '-';
 
210
        }
 
211
        else
 
212
            *p2++ = '+';
 
213
        if (decpt / 100 > 0)
 
214
            *p2++ = decpt / 100 + '0';
 
215
        if (decpt / 10 > 0)
 
216
            *p2++ = (decpt % 100) / 10 + '0';
 
217
        *p2++ = decpt % 10 + '0';
 
218
    }
 
219
    else {
 
220
        if (decpt <= 0) {
 
221
            if (*p1 != '0')
 
222
                *p2++ = '.';
 
223
            while (decpt < 0) {
 
224
                decpt++;
 
225
                *p2++ = '0';
 
226
            }
 
227
        }
 
228
        for (i = 1; i <= ndigit; i++) {
 
229
            *p2++ = *p1++;
 
230
            if (i == decpt)
 
231
                *p2++ = '.';
 
232
        }
 
233
        if (ndigit < decpt) {
 
234
            while (ndigit++ < decpt)
 
235
                *p2++ = '0';
 
236
            *p2++ = '.';
 
237
        }
 
238
    }
 
239
    if (p2[-1] == '.' && !altform)
 
240
        p2--;
 
241
    *p2 = '\0';
 
242
    return (buf);
 
243
}
 
244
 
 
245
/*
 
246
 * The INS_CHAR macro inserts a character in the buffer and writes
 
247
 * the buffer back to disk if necessary
 
248
 * It uses the char pointers sp and bep:
 
249
 *      sp points to the next available character in the buffer
 
250
 *      bep points to the end-of-buffer+1
 
251
 * While using this macro, note that the nextb pointer is NOT updated.
 
252
 *
 
253
 * NOTE: Evaluation of the c argument should not have any side-effects
 
254
 */
 
255
#define INS_CHAR(c, sp, bep, cc)                    \
 
256
{                                                   \
 
257
    if (sp) {                                       \
 
258
        if (sp >= bep) {                            \
 
259
            vbuff->curpos = sp;                     \
 
260
            if (flush_func(vbuff))                  \
 
261
                return -1;                          \
 
262
            sp = vbuff->curpos;                     \
 
263
            bep = vbuff->endpos;                    \
 
264
        }                                           \
 
265
        *sp++ = (c);                                \
 
266
    }                                               \
 
267
    cc++;                                           \
 
268
}
 
269
 
 
270
#define NUM(c) (c - '0')
 
271
 
 
272
#define STR_TO_DEC(str, num)                        \
 
273
    num = NUM(*str++);                              \
 
274
    while (apr_isdigit(*str))                       \
 
275
    {                                               \
 
276
        num *= 10 ;                                 \
 
277
        num += NUM(*str++);                         \
 
278
    }
 
279
 
 
280
/*
 
281
 * This macro does zero padding so that the precision
 
282
 * requirement is satisfied. The padding is done by
 
283
 * adding '0's to the left of the string that is going
 
284
 * to be printed. We don't allow precision to be large
 
285
 * enough that we continue past the start of s.
 
286
 *
 
287
 * NOTE: this makes use of the magic info that s is
 
288
 * always based on num_buf with a size of NUM_BUF_SIZE.
 
289
 */
 
290
#define FIX_PRECISION(adjust, precision, s, s_len)  \
 
291
    if (adjust) {                                   \
 
292
        apr_size_t p = (precision + 1 < NUM_BUF_SIZE) \
 
293
                     ? precision : NUM_BUF_SIZE - 1;  \
 
294
        while (s_len < p)                           \
 
295
        {                                           \
 
296
            *--s = '0';                             \
 
297
            s_len++;                                \
 
298
        }                                           \
 
299
    }
 
300
 
 
301
/*
 
302
 * Macro that does padding. The padding is done by printing
 
303
 * the character ch.
 
304
 */
 
305
#define PAD(width, len, ch)                         \
 
306
do                                                  \
 
307
{                                                   \
 
308
    INS_CHAR(ch, sp, bep, cc);                      \
 
309
    width--;                                        \
 
310
}                                                   \
 
311
while (width > len)
 
312
 
 
313
/*
 
314
 * Prefix the character ch to the string str
 
315
 * Increase length
 
316
 * Set the has_prefix flag
 
317
 */
 
318
#define PREFIX(str, length, ch)                     \
 
319
    *--str = ch;                                    \
 
320
    length++;                                       \
 
321
    has_prefix=YES;
 
322
 
 
323
 
 
324
/*
 
325
 * Convert num to its decimal format.
 
326
 * Return value:
 
327
 *   - a pointer to a string containing the number (no sign)
 
328
 *   - len contains the length of the string
 
329
 *   - is_negative is set to TRUE or FALSE depending on the sign
 
330
 *     of the number (always set to FALSE if is_unsigned is TRUE)
 
331
 *
 
332
 * The caller provides a buffer for the string: that is the buf_end argument
 
333
 * which is a pointer to the END of the buffer + 1 (i.e. if the buffer
 
334
 * is declared as buf[ 100 ], buf_end should be &buf[ 100 ])
 
335
 *
 
336
 * Note: we have 2 versions. One is used when we need to use quads
 
337
 * (conv_10_quad), the other when we don't (conv_10). We're assuming the
 
338
 * latter is faster.
 
339
 */
 
340
static char *conv_10(register wide_int num, register bool_int is_unsigned,
 
341
                     register bool_int *is_negative, char *buf_end,
 
342
                     register apr_size_t *len)
 
343
{
 
344
    register char *p = buf_end;
 
345
    register u_wide_int magnitude;
 
346
 
 
347
    if (is_unsigned) {
 
348
        magnitude = (u_wide_int) num;
 
349
        *is_negative = FALSE;
 
350
    }
 
351
    else {
 
352
        *is_negative = (num < 0);
 
353
 
 
354
        /*
 
355
         * On a 2's complement machine, negating the most negative integer 
 
356
         * results in a number that cannot be represented as a signed integer.
 
357
         * Here is what we do to obtain the number's magnitude:
 
358
         *      a. add 1 to the number
 
359
         *      b. negate it (becomes positive)
 
360
         *      c. convert it to unsigned
 
361
         *      d. add 1
 
362
         */
 
363
        if (*is_negative) {
 
364
            wide_int t = num + 1;
 
365
 
 
366
            magnitude = ((u_wide_int) -t) + 1;
 
367
        }
 
368
        else
 
369
            magnitude = (u_wide_int) num;
 
370
    }
 
371
 
 
372
    /*
 
373
     * We use a do-while loop so that we write at least 1 digit 
 
374
     */
 
375
    do {
 
376
        register u_wide_int new_magnitude = magnitude / 10;
 
377
 
 
378
        *--p = (char) (magnitude - new_magnitude * 10 + '0');
 
379
        magnitude = new_magnitude;
 
380
    }
 
381
    while (magnitude);
 
382
 
 
383
    *len = buf_end - p;
 
384
    return (p);
 
385
}
 
386
 
 
387
static char *conv_10_quad(widest_int num, register bool_int is_unsigned,
 
388
                     register bool_int *is_negative, char *buf_end,
 
389
                     register apr_size_t *len)
 
390
{
 
391
    register char *p = buf_end;
 
392
    u_widest_int magnitude;
 
393
 
 
394
    /*
 
395
     * We see if we can use the faster non-quad version by checking the
 
396
     * number against the largest long value it can be. If <=, we
 
397
     * punt to the quicker version.
 
398
     */
 
399
    if ((num <= ULONG_MAX && is_unsigned) 
 
400
        || (num <= LONG_MAX && num >= LONG_MIN && !is_unsigned))
 
401
            return(conv_10( (wide_int)num, is_unsigned, is_negative,
 
402
               buf_end, len));
 
403
 
 
404
    if (is_unsigned) {
 
405
        magnitude = (u_widest_int) num;
 
406
        *is_negative = FALSE;
 
407
    }
 
408
    else {
 
409
        *is_negative = (num < 0);
 
410
 
 
411
        /*
 
412
         * On a 2's complement machine, negating the most negative integer 
 
413
         * results in a number that cannot be represented as a signed integer.
 
414
         * Here is what we do to obtain the number's magnitude:
 
415
         *      a. add 1 to the number
 
416
         *      b. negate it (becomes positive)
 
417
         *      c. convert it to unsigned
 
418
         *      d. add 1
 
419
         */
 
420
        if (*is_negative) {
 
421
            widest_int t = num + 1;
 
422
 
 
423
            magnitude = ((u_widest_int) -t) + 1;
 
424
        }
 
425
        else
 
426
            magnitude = (u_widest_int) num;
 
427
    }
 
428
 
 
429
    /*
 
430
     * We use a do-while loop so that we write at least 1 digit 
 
431
     */
 
432
    do {
 
433
        u_widest_int new_magnitude = magnitude / 10;
 
434
 
 
435
        *--p = (char) (magnitude - new_magnitude * 10 + '0');
 
436
        magnitude = new_magnitude;
 
437
    }
 
438
    while (magnitude);
 
439
 
 
440
    *len = buf_end - p;
 
441
    return (p);
 
442
}
 
443
 
 
444
 
 
445
 
 
446
static char *conv_in_addr(struct in_addr *ia, char *buf_end, apr_size_t *len)
 
447
{
 
448
    unsigned addr = ntohl(ia->s_addr);
 
449
    char *p = buf_end;
 
450
    bool_int is_negative;
 
451
    apr_size_t sub_len;
 
452
 
 
453
    p = conv_10((addr & 0x000000FF)      , TRUE, &is_negative, p, &sub_len);
 
454
    *--p = '.';
 
455
    p = conv_10((addr & 0x0000FF00) >>  8, TRUE, &is_negative, p, &sub_len);
 
456
    *--p = '.';
 
457
    p = conv_10((addr & 0x00FF0000) >> 16, TRUE, &is_negative, p, &sub_len);
 
458
    *--p = '.';
 
459
    p = conv_10((addr & 0xFF000000) >> 24, TRUE, &is_negative, p, &sub_len);
 
460
 
 
461
    *len = buf_end - p;
 
462
    return (p);
 
463
}
 
464
 
 
465
 
 
466
 
 
467
static char *conv_apr_sockaddr(apr_sockaddr_t *sa, char *buf_end, apr_size_t *len)
 
468
{
 
469
    char *p = buf_end;
 
470
    bool_int is_negative;
 
471
    apr_size_t sub_len;
 
472
    char *ipaddr_str;
 
473
 
 
474
    p = conv_10(sa->port, TRUE, &is_negative, p, &sub_len);
 
475
    *--p = ':';
 
476
    apr_sockaddr_ip_get(&ipaddr_str, sa);
 
477
    sub_len = strlen(ipaddr_str);
 
478
#if APR_HAVE_IPV6
 
479
    if (sa->family == APR_INET6 &&
 
480
        !IN6_IS_ADDR_V4MAPPED(&sa->sa.sin6.sin6_addr)) {
 
481
        *(p - 1) = ']';
 
482
        p -= sub_len + 2;
 
483
        *p = '[';
 
484
        memcpy(p + 1, ipaddr_str, sub_len);
 
485
    }
 
486
    else
 
487
#endif
 
488
    {
 
489
        p -= sub_len;
 
490
        memcpy(p, ipaddr_str, sub_len);
 
491
    }
 
492
 
 
493
    *len = buf_end - p;
 
494
    return (p);
 
495
}
 
496
 
 
497
 
 
498
 
 
499
#if APR_HAS_THREADS
 
500
static char *conv_os_thread_t(apr_os_thread_t *tid, char *buf_end, apr_size_t *len)
 
501
{
 
502
    union {
 
503
        apr_os_thread_t tid;
 
504
        apr_uint64_t alignme;
 
505
    } u;
 
506
    int is_negative;
 
507
 
 
508
    u.tid = *tid;
 
509
    switch(sizeof(u.tid)) {
 
510
    case sizeof(apr_int32_t):
 
511
        return conv_10(*(apr_uint32_t *)&u.tid, TRUE, &is_negative, buf_end, len);
 
512
    case sizeof(apr_int64_t):
 
513
        return conv_10_quad(*(apr_uint64_t *)&u.tid, TRUE, &is_negative, buf_end, len);
 
514
    default:
 
515
        /* not implemented; stick 0 in the buffer */
 
516
        return conv_10(0, TRUE, &is_negative, buf_end, len);
 
517
    }
 
518
}
 
519
#endif
 
520
 
 
521
 
 
522
 
 
523
/*
 
524
 * Convert a floating point number to a string formats 'f', 'e' or 'E'.
 
525
 * The result is placed in buf, and len denotes the length of the string
 
526
 * The sign is returned in the is_negative argument (and is not placed
 
527
 * in buf).
 
528
 */
 
529
static char *conv_fp(register char format, register double num,
 
530
    boolean_e add_dp, int precision, bool_int *is_negative,
 
531
    char *buf, apr_size_t *len)
 
532
{
 
533
    register char *s = buf;
 
534
    register char *p;
 
535
    int decimal_point;
 
536
    char buf1[NDIG];
 
537
 
 
538
    if (format == 'f')
 
539
        p = apr_fcvt(num, precision, &decimal_point, is_negative, buf1);
 
540
    else /* either e or E format */
 
541
        p = apr_ecvt(num, precision + 1, &decimal_point, is_negative, buf1);
 
542
 
 
543
    /*
 
544
     * Check for Infinity and NaN
 
545
     */
 
546
    if (apr_isalpha(*p)) {
 
547
        *len = strlen(p);
 
548
        memcpy(buf, p, *len + 1);
 
549
        *is_negative = FALSE;
 
550
        return (buf);
 
551
    }
 
552
 
 
553
    if (format == 'f') {
 
554
        if (decimal_point <= 0) {
 
555
            *s++ = '0';
 
556
            if (precision > 0) {
 
557
                *s++ = '.';
 
558
                while (decimal_point++ < 0)
 
559
                    *s++ = '0';
 
560
            }
 
561
            else if (add_dp)
 
562
                *s++ = '.';
 
563
        }
 
564
        else {
 
565
            while (decimal_point-- > 0)
 
566
                *s++ = *p++;
 
567
            if (precision > 0 || add_dp)
 
568
                *s++ = '.';
 
569
        }
 
570
    }
 
571
    else {
 
572
        *s++ = *p++;
 
573
        if (precision > 0 || add_dp)
 
574
            *s++ = '.';
 
575
    }
 
576
 
 
577
    /*
 
578
     * copy the rest of p, the NUL is NOT copied
 
579
     */
 
580
    while (*p)
 
581
        *s++ = *p++;
 
582
 
 
583
    if (format != 'f') {
 
584
        char temp[EXPONENT_LENGTH];        /* for exponent conversion */
 
585
        apr_size_t t_len;
 
586
        bool_int exponent_is_negative;
 
587
 
 
588
        *s++ = format;                /* either e or E */
 
589
        decimal_point--;
 
590
        if (decimal_point != 0) {
 
591
            p = conv_10((wide_int) decimal_point, FALSE, &exponent_is_negative,
 
592
                        &temp[EXPONENT_LENGTH], &t_len);
 
593
            *s++ = exponent_is_negative ? '-' : '+';
 
594
 
 
595
            /*
 
596
             * Make sure the exponent has at least 2 digits
 
597
             */
 
598
            if (t_len == 1)
 
599
                *s++ = '0';
 
600
            while (t_len--)
 
601
                *s++ = *p++;
 
602
        }
 
603
        else {
 
604
            *s++ = '+';
 
605
            *s++ = '0';
 
606
            *s++ = '0';
 
607
        }
 
608
    }
 
609
 
 
610
    *len = s - buf;
 
611
    return (buf);
 
612
}
 
613
 
 
614
 
 
615
/*
 
616
 * Convert num to a base X number where X is a power of 2. nbits determines X.
 
617
 * For example, if nbits is 3, we do base 8 conversion
 
618
 * Return value:
 
619
 *      a pointer to a string containing the number
 
620
 *
 
621
 * The caller provides a buffer for the string: that is the buf_end argument
 
622
 * which is a pointer to the END of the buffer + 1 (i.e. if the buffer
 
623
 * is declared as buf[ 100 ], buf_end should be &buf[ 100 ])
 
624
 *
 
625
 * As with conv_10, we have a faster version which is used when
 
626
 * the number isn't quad size.
 
627
 */
 
628
static char *conv_p2(register u_wide_int num, register int nbits,
 
629
                     char format, char *buf_end, register apr_size_t *len)
 
630
{
 
631
    register int mask = (1 << nbits) - 1;
 
632
    register char *p = buf_end;
 
633
    static const char low_digits[] = "0123456789abcdef";
 
634
    static const char upper_digits[] = "0123456789ABCDEF";
 
635
    register const char *digits = (format == 'X') ? upper_digits : low_digits;
 
636
 
 
637
    do {
 
638
        *--p = digits[num & mask];
 
639
        num >>= nbits;
 
640
    }
 
641
    while (num);
 
642
 
 
643
    *len = buf_end - p;
 
644
    return (p);
 
645
}
 
646
 
 
647
static char *conv_p2_quad(u_widest_int num, register int nbits,
 
648
                     char format, char *buf_end, register apr_size_t *len)
 
649
{
 
650
    register int mask = (1 << nbits) - 1;
 
651
    register char *p = buf_end;
 
652
    static const char low_digits[] = "0123456789abcdef";
 
653
    static const char upper_digits[] = "0123456789ABCDEF";
 
654
    register const char *digits = (format == 'X') ? upper_digits : low_digits;
 
655
 
 
656
    if (num <= ULONG_MAX)
 
657
        return(conv_p2((u_wide_int)num, nbits, format, buf_end, len));
 
658
 
 
659
    do {
 
660
        *--p = digits[num & mask];
 
661
        num >>= nbits;
 
662
    }
 
663
    while (num);
 
664
 
 
665
    *len = buf_end - p;
 
666
    return (p);
 
667
}
 
668
 
 
669
#if APR_HAS_THREADS
 
670
static char *conv_os_thread_t_hex(apr_os_thread_t *tid, char *buf_end, apr_size_t *len)
 
671
{
 
672
    union {
 
673
        apr_os_thread_t tid;
 
674
        apr_uint64_t alignme;
 
675
    } u;
 
676
    int is_negative;
 
677
 
 
678
    u.tid = *tid;
 
679
    switch(sizeof(u.tid)) {
 
680
    case sizeof(apr_int32_t):
 
681
        return conv_p2(*(apr_uint32_t *)&u.tid, 4, 'x', buf_end, len);
 
682
    case sizeof(apr_int64_t):
 
683
        return conv_p2_quad(*(apr_uint64_t *)&u.tid, 4, 'x', buf_end, len);
 
684
    default:
 
685
        /* not implemented; stick 0 in the buffer */
 
686
        return conv_10(0, TRUE, &is_negative, buf_end, len);
 
687
    }
 
688
}
 
689
#endif
 
690
 
 
691
/*
 
692
 * Do format conversion placing the output in buffer
 
693
 */
 
694
APR_DECLARE(int) apr_vformatter(int (*flush_func)(apr_vformatter_buff_t *),
 
695
    apr_vformatter_buff_t *vbuff, const char *fmt, va_list ap)
 
696
{
 
697
    register char *sp;
 
698
    register char *bep;
 
699
    register int cc = 0;
 
700
    register apr_size_t i;
 
701
 
 
702
    register char *s = NULL;
 
703
    char *q;
 
704
    apr_size_t s_len;
 
705
 
 
706
    register apr_size_t min_width = 0;
 
707
    apr_size_t precision = 0;
 
708
    enum {
 
709
        LEFT, RIGHT
 
710
    } adjust;
 
711
    char pad_char;
 
712
    char prefix_char;
 
713
 
 
714
    double fp_num;
 
715
    widest_int i_quad = (widest_int) 0;
 
716
    u_widest_int ui_quad;
 
717
    wide_int i_num = (wide_int) 0;
 
718
    u_wide_int ui_num;
 
719
 
 
720
    char num_buf[NUM_BUF_SIZE];
 
721
    char char_buf[2];                /* for printing %% and %<unknown> */
 
722
 
 
723
    enum var_type_enum {
 
724
            IS_QUAD, IS_LONG, IS_SHORT, IS_INT
 
725
    };
 
726
    enum var_type_enum var_type = IS_INT;
 
727
 
 
728
    /*
 
729
     * Flag variables
 
730
     */
 
731
    boolean_e alternate_form;
 
732
    boolean_e print_sign;
 
733
    boolean_e print_blank;
 
734
    boolean_e adjust_precision;
 
735
    boolean_e adjust_width;
 
736
    bool_int is_negative;
 
737
 
 
738
    sp = vbuff->curpos;
 
739
    bep = vbuff->endpos;
 
740
 
 
741
    while (*fmt) {
 
742
        if (*fmt != '%') {
 
743
            INS_CHAR(*fmt, sp, bep, cc);
 
744
        }
 
745
        else {
 
746
            /*
 
747
             * Default variable settings
 
748
             */
 
749
            boolean_e print_something = YES;
 
750
            adjust = RIGHT;
 
751
            alternate_form = print_sign = print_blank = NO;
 
752
            pad_char = ' ';
 
753
            prefix_char = NUL;
 
754
 
 
755
            fmt++;
 
756
 
 
757
            /*
 
758
             * Try to avoid checking for flags, width or precision
 
759
             */
 
760
            if (!apr_islower(*fmt)) {
 
761
                /*
 
762
                 * Recognize flags: -, #, BLANK, +
 
763
                 */
 
764
                for (;; fmt++) {
 
765
                    if (*fmt == '-')
 
766
                        adjust = LEFT;
 
767
                    else if (*fmt == '+')
 
768
                        print_sign = YES;
 
769
                    else if (*fmt == '#')
 
770
                        alternate_form = YES;
 
771
                    else if (*fmt == ' ')
 
772
                        print_blank = YES;
 
773
                    else if (*fmt == '0')
 
774
                        pad_char = '0';
 
775
                    else
 
776
                        break;
 
777
                }
 
778
 
 
779
                /*
 
780
                 * Check if a width was specified
 
781
                 */
 
782
                if (apr_isdigit(*fmt)) {
 
783
                    STR_TO_DEC(fmt, min_width);
 
784
                    adjust_width = YES;
 
785
                }
 
786
                else if (*fmt == '*') {
 
787
                    int v = va_arg(ap, int);
 
788
                    fmt++;
 
789
                    adjust_width = YES;
 
790
                    if (v < 0) {
 
791
                        adjust = LEFT;
 
792
                        min_width = (apr_size_t)(-v);
 
793
                    }
 
794
                    else
 
795
                        min_width = (apr_size_t)v;
 
796
                }
 
797
                else
 
798
                    adjust_width = NO;
 
799
 
 
800
                /*
 
801
                 * Check if a precision was specified
 
802
                 */
 
803
                if (*fmt == '.') {
 
804
                    adjust_precision = YES;
 
805
                    fmt++;
 
806
                    if (apr_isdigit(*fmt)) {
 
807
                        STR_TO_DEC(fmt, precision);
 
808
                    }
 
809
                    else if (*fmt == '*') {
 
810
                        int v = va_arg(ap, int);
 
811
                        fmt++;
 
812
                        precision = (v < 0) ? 0 : (apr_size_t)v;
 
813
                    }
 
814
                    else
 
815
                        precision = 0;
 
816
                }
 
817
                else
 
818
                    adjust_precision = NO;
 
819
            }
 
820
            else
 
821
                adjust_precision = adjust_width = NO;
 
822
 
 
823
            /*
 
824
             * Modifier check.  Note that if APR_INT64_T_FMT is "d",
 
825
             * the first if condition is never true.
 
826
             */
 
827
            if ((sizeof(APR_INT64_T_FMT) == 4 &&
 
828
                 fmt[0] == APR_INT64_T_FMT[0] &&
 
829
                 fmt[1] == APR_INT64_T_FMT[1]) ||
 
830
                (sizeof(APR_INT64_T_FMT) == 3 &&
 
831
                 fmt[0] == APR_INT64_T_FMT[0]) ||
 
832
                (sizeof(APR_INT64_T_FMT) > 4 &&
 
833
                 strncmp(fmt, APR_INT64_T_FMT, 
 
834
                         sizeof(APR_INT64_T_FMT) - 2) == 0)) {
 
835
                /* Need to account for trailing 'd' and null in sizeof() */
 
836
                var_type = IS_QUAD;
 
837
                fmt += (sizeof(APR_INT64_T_FMT) - 2);
 
838
            }
 
839
            else if (*fmt == 'q') {
 
840
                var_type = IS_QUAD;
 
841
                fmt++;
 
842
            }
 
843
            else if (*fmt == 'l') {
 
844
                var_type = IS_LONG;
 
845
                fmt++;
 
846
            }
 
847
            else if (*fmt == 'h') {
 
848
                var_type = IS_SHORT;
 
849
                fmt++;
 
850
            }
 
851
            else {
 
852
                var_type = IS_INT;
 
853
            }
 
854
 
 
855
            /*
 
856
             * Argument extraction and printing.
 
857
             * First we determine the argument type.
 
858
             * Then, we convert the argument to a string.
 
859
             * On exit from the switch, s points to the string that
 
860
             * must be printed, s_len has the length of the string
 
861
             * The precision requirements, if any, are reflected in s_len.
 
862
             *
 
863
             * NOTE: pad_char may be set to '0' because of the 0 flag.
 
864
             *   It is reset to ' ' by non-numeric formats
 
865
             */
 
866
            switch (*fmt) {
 
867
            case 'u':
 
868
                if (var_type == IS_QUAD) {
 
869
                    i_quad = va_arg(ap, u_widest_int);
 
870
                    s = conv_10_quad(i_quad, 1, &is_negative,
 
871
                            &num_buf[NUM_BUF_SIZE], &s_len);
 
872
                }
 
873
                else {
 
874
                    if (var_type == IS_LONG)
 
875
                        i_num = (wide_int) va_arg(ap, u_wide_int);
 
876
                    else if (var_type == IS_SHORT)
 
877
                        i_num = (wide_int) (unsigned short) va_arg(ap, unsigned int);
 
878
                    else
 
879
                        i_num = (wide_int) va_arg(ap, unsigned int);
 
880
                    s = conv_10(i_num, 1, &is_negative,
 
881
                            &num_buf[NUM_BUF_SIZE], &s_len);
 
882
                }
 
883
                FIX_PRECISION(adjust_precision, precision, s, s_len);
 
884
                break;
 
885
 
 
886
            case 'd':
 
887
            case 'i':
 
888
                if (var_type == IS_QUAD) {
 
889
                    i_quad = va_arg(ap, widest_int);
 
890
                    s = conv_10_quad(i_quad, 0, &is_negative,
 
891
                            &num_buf[NUM_BUF_SIZE], &s_len);
 
892
                }
 
893
                else {
 
894
                    if (var_type == IS_LONG)
 
895
                        i_num = (wide_int) va_arg(ap, wide_int);
 
896
                    else if (var_type == IS_SHORT)
 
897
                        i_num = (wide_int) (short) va_arg(ap, int);
 
898
                    else
 
899
                        i_num = (wide_int) va_arg(ap, int);
 
900
                    s = conv_10(i_num, 0, &is_negative,
 
901
                            &num_buf[NUM_BUF_SIZE], &s_len);
 
902
                }
 
903
                FIX_PRECISION(adjust_precision, precision, s, s_len);
 
904
 
 
905
                if (is_negative)
 
906
                    prefix_char = '-';
 
907
                else if (print_sign)
 
908
                    prefix_char = '+';
 
909
                else if (print_blank)
 
910
                    prefix_char = ' ';
 
911
                break;
 
912
 
 
913
 
 
914
            case 'o':
 
915
                if (var_type == IS_QUAD) {
 
916
                    ui_quad = va_arg(ap, u_widest_int);
 
917
                    s = conv_p2_quad(ui_quad, 3, *fmt,
 
918
                            &num_buf[NUM_BUF_SIZE], &s_len);
 
919
                }
 
920
                else {
 
921
                    if (var_type == IS_LONG)
 
922
                        ui_num = (u_wide_int) va_arg(ap, u_wide_int);
 
923
                    else if (var_type == IS_SHORT)
 
924
                        ui_num = (u_wide_int) (unsigned short) va_arg(ap, unsigned int);
 
925
                    else
 
926
                        ui_num = (u_wide_int) va_arg(ap, unsigned int);
 
927
                    s = conv_p2(ui_num, 3, *fmt,
 
928
                            &num_buf[NUM_BUF_SIZE], &s_len);
 
929
                }
 
930
                FIX_PRECISION(adjust_precision, precision, s, s_len);
 
931
                if (alternate_form && *s != '0') {
 
932
                    *--s = '0';
 
933
                    s_len++;
 
934
                }
 
935
                break;
 
936
 
 
937
 
 
938
            case 'x':
 
939
            case 'X':
 
940
                if (var_type == IS_QUAD) {
 
941
                    ui_quad = va_arg(ap, u_widest_int);
 
942
                    s = conv_p2_quad(ui_quad, 4, *fmt,
 
943
                            &num_buf[NUM_BUF_SIZE], &s_len);
 
944
                }
 
945
                else {
 
946
                    if (var_type == IS_LONG)
 
947
                        ui_num = (u_wide_int) va_arg(ap, u_wide_int);
 
948
                    else if (var_type == IS_SHORT)
 
949
                        ui_num = (u_wide_int) (unsigned short) va_arg(ap, unsigned int);
 
950
                    else
 
951
                        ui_num = (u_wide_int) va_arg(ap, unsigned int);
 
952
                    s = conv_p2(ui_num, 4, *fmt,
 
953
                            &num_buf[NUM_BUF_SIZE], &s_len);
 
954
                }
 
955
                FIX_PRECISION(adjust_precision, precision, s, s_len);
 
956
                if (alternate_form && i_num != 0) {
 
957
                    *--s = *fmt;        /* 'x' or 'X' */
 
958
                    *--s = '0';
 
959
                    s_len += 2;
 
960
                }
 
961
                break;
 
962
 
 
963
 
 
964
            case 's':
 
965
                s = va_arg(ap, char *);
 
966
                if (s != NULL) {
 
967
                    if (!adjust_precision) {
 
968
                        s_len = strlen(s);
 
969
                    }
 
970
                    else {
 
971
                        /* From the C library standard in section 7.9.6.1:
 
972
                         * ...if the precision is specified, no more then
 
973
                         * that many characters are written.  If the
 
974
                         * precision is not specified or is greater
 
975
                         * than the size of the array, the array shall
 
976
                         * contain a null character.
 
977
                         *
 
978
                         * My reading is is precision is specified and
 
979
                         * is less then or equal to the size of the
 
980
                         * array, no null character is required.  So
 
981
                         * we can't do a strlen.
 
982
                         *
 
983
                         * This figures out the length of the string
 
984
                         * up to the precision.  Once it's long enough
 
985
                         * for the specified precision, we don't care
 
986
                         * anymore.
 
987
                         *
 
988
                         * NOTE: you must do the length comparison
 
989
                         * before the check for the null character.
 
990
                         * Otherwise, you'll check one beyond the
 
991
                         * last valid character.
 
992
                         */
 
993
                        const char *walk;
 
994
 
 
995
                        for (walk = s, s_len = 0;
 
996
                             (s_len < precision) && (*walk != '\0');
 
997
                             ++walk, ++s_len);
 
998
                    }
 
999
                }
 
1000
                else {
 
1001
                    s = S_NULL;
 
1002
                    s_len = S_NULL_LEN;
 
1003
                }
 
1004
                pad_char = ' ';
 
1005
                break;
 
1006
 
 
1007
 
 
1008
            case 'f':
 
1009
            case 'e':
 
1010
            case 'E':
 
1011
                fp_num = va_arg(ap, double);
 
1012
                /*
 
1013
                 * We use &num_buf[ 1 ], so that we have room for the sign
 
1014
                 */
 
1015
                s = NULL;
 
1016
#ifdef HAVE_ISNAN
 
1017
                if (isnan(fp_num)) {
 
1018
                    s = "nan";
 
1019
                    s_len = 3;
 
1020
                }
 
1021
#endif
 
1022
#ifdef HAVE_ISINF
 
1023
                if (!s && isinf(fp_num)) {
 
1024
                    s = "inf";
 
1025
                    s_len = 3;
 
1026
                }
 
1027
#endif
 
1028
                if (!s) {
 
1029
                    s = conv_fp(*fmt, fp_num, alternate_form,
 
1030
                            (adjust_precision == NO) ? FLOAT_DIGITS : precision,
 
1031
                                &is_negative, &num_buf[1], &s_len);
 
1032
                    if (is_negative)
 
1033
                        prefix_char = '-';
 
1034
                    else if (print_sign)
 
1035
                        prefix_char = '+';
 
1036
                    else if (print_blank)
 
1037
                        prefix_char = ' ';
 
1038
                }
 
1039
                break;
 
1040
 
 
1041
 
 
1042
            case 'g':
 
1043
            case 'G':
 
1044
                if (adjust_precision == NO)
 
1045
                    precision = FLOAT_DIGITS;
 
1046
                else if (precision == 0)
 
1047
                    precision = 1;
 
1048
                /*
 
1049
                 * * We use &num_buf[ 1 ], so that we have room for the sign
 
1050
                 */
 
1051
                s = apr_gcvt(va_arg(ap, double), precision, &num_buf[1],
 
1052
                            alternate_form);
 
1053
                if (*s == '-')
 
1054
                    prefix_char = *s++;
 
1055
                else if (print_sign)
 
1056
                    prefix_char = '+';
 
1057
                else if (print_blank)
 
1058
                    prefix_char = ' ';
 
1059
 
 
1060
                s_len = strlen(s);
 
1061
 
 
1062
                if (alternate_form && (q = strchr(s, '.')) == NULL) {
 
1063
                    s[s_len++] = '.';
 
1064
                    s[s_len] = '\0'; /* delimit for following strchr() */
 
1065
                }
 
1066
                if (*fmt == 'G' && (q = strchr(s, 'e')) != NULL)
 
1067
                    *q = 'E';
 
1068
                break;
 
1069
 
 
1070
 
 
1071
            case 'c':
 
1072
                char_buf[0] = (char) (va_arg(ap, int));
 
1073
                s = &char_buf[0];
 
1074
                s_len = 1;
 
1075
                pad_char = ' ';
 
1076
                break;
 
1077
 
 
1078
 
 
1079
            case '%':
 
1080
                char_buf[0] = '%';
 
1081
                s = &char_buf[0];
 
1082
                s_len = 1;
 
1083
                pad_char = ' ';
 
1084
                break;
 
1085
 
 
1086
 
 
1087
            case 'n':
 
1088
                if (var_type == IS_QUAD)
 
1089
                    *(va_arg(ap, widest_int *)) = cc;
 
1090
                else if (var_type == IS_LONG)
 
1091
                    *(va_arg(ap, long *)) = cc;
 
1092
                else if (var_type == IS_SHORT)
 
1093
                    *(va_arg(ap, short *)) = cc;
 
1094
                else
 
1095
                    *(va_arg(ap, int *)) = cc;
 
1096
                print_something = NO;
 
1097
                break;
 
1098
 
 
1099
                /*
 
1100
                 * This is where we extend the printf format, with a second
 
1101
                 * type specifier
 
1102
                 */
 
1103
            case 'p':
 
1104
                switch(*++fmt) {
 
1105
                /*
 
1106
                 * If the pointer size is equal to or smaller than the size
 
1107
                 * of the largest unsigned int, we convert the pointer to a
 
1108
                 * hex number, otherwise we print "%p" to indicate that we
 
1109
                 * don't handle "%p".
 
1110
                 */
 
1111
                case 'p':
 
1112
#ifdef APR_VOID_P_IS_QUAD
 
1113
                    if (sizeof(void *) <= sizeof(u_widest_int)) {
 
1114
                        ui_quad = (u_widest_int) va_arg(ap, void *);
 
1115
                        s = conv_p2_quad(ui_quad, 4, 'x',
 
1116
                                &num_buf[NUM_BUF_SIZE], &s_len);
 
1117
                    }
 
1118
#else
 
1119
                    if (sizeof(void *) <= sizeof(u_wide_int)) {
 
1120
                        ui_num = (u_wide_int) va_arg(ap, void *);
 
1121
                        s = conv_p2(ui_num, 4, 'x',
 
1122
                                &num_buf[NUM_BUF_SIZE], &s_len);
 
1123
                    }
 
1124
#endif
 
1125
                    else {
 
1126
                        s = "%p";
 
1127
                        s_len = 2;
 
1128
                        prefix_char = NUL;
 
1129
                    }
 
1130
                    pad_char = ' ';
 
1131
                    break;
 
1132
 
 
1133
                /* print an apr_sockaddr_t as a.b.c.d:port */
 
1134
                case 'I':
 
1135
                {
 
1136
                    apr_sockaddr_t *sa;
 
1137
 
 
1138
                    sa = va_arg(ap, apr_sockaddr_t *);
 
1139
                    if (sa != NULL) {
 
1140
                        s = conv_apr_sockaddr(sa, &num_buf[NUM_BUF_SIZE], &s_len);
 
1141
                        if (adjust_precision && precision < s_len)
 
1142
                            s_len = precision;
 
1143
                    }
 
1144
                    else {
 
1145
                        s = S_NULL;
 
1146
                        s_len = S_NULL_LEN;
 
1147
                    }
 
1148
                    pad_char = ' ';
 
1149
                }
 
1150
                break;
 
1151
 
 
1152
                /* print a struct in_addr as a.b.c.d */
 
1153
                case 'A':
 
1154
                {
 
1155
                    struct in_addr *ia;
 
1156
 
 
1157
                    ia = va_arg(ap, struct in_addr *);
 
1158
                    if (ia != NULL) {
 
1159
                        s = conv_in_addr(ia, &num_buf[NUM_BUF_SIZE], &s_len);
 
1160
                        if (adjust_precision && precision < s_len)
 
1161
                            s_len = precision;
 
1162
                    }
 
1163
                    else {
 
1164
                        s = S_NULL;
 
1165
                        s_len = S_NULL_LEN;
 
1166
                    }
 
1167
                    pad_char = ' ';
 
1168
                }
 
1169
                break;
 
1170
 
 
1171
                case 'T':
 
1172
#if APR_HAS_THREADS
 
1173
                {
 
1174
                    apr_os_thread_t *tid;
 
1175
 
 
1176
                    tid = va_arg(ap, apr_os_thread_t *);
 
1177
                    if (tid != NULL) {
 
1178
                        s = conv_os_thread_t(tid, &num_buf[NUM_BUF_SIZE], &s_len);
 
1179
                        if (adjust_precision && precision < s_len)
 
1180
                            s_len = precision;
 
1181
                    }
 
1182
                    else {
 
1183
                        s = S_NULL;
 
1184
                        s_len = S_NULL_LEN;
 
1185
                    }
 
1186
                    pad_char = ' ';
 
1187
                }
 
1188
#else
 
1189
                    char_buf[0] = '0';
 
1190
                    s = &char_buf[0];
 
1191
                    s_len = 1;
 
1192
                    pad_char = ' ';
 
1193
#endif
 
1194
                    break;
 
1195
 
 
1196
                case 't':
 
1197
#if APR_HAS_THREADS
 
1198
                {
 
1199
                    apr_os_thread_t *tid;
 
1200
 
 
1201
                    tid = va_arg(ap, apr_os_thread_t *);
 
1202
                    if (tid != NULL) {
 
1203
                        s = conv_os_thread_t_hex(tid, &num_buf[NUM_BUF_SIZE], &s_len);
 
1204
                        if (adjust_precision && precision < s_len)
 
1205
                            s_len = precision;
 
1206
                    }
 
1207
                    else {
 
1208
                        s = S_NULL;
 
1209
                        s_len = S_NULL_LEN;
 
1210
                    }
 
1211
                    pad_char = ' ';
 
1212
                }
 
1213
#else
 
1214
                    char_buf[0] = '0';
 
1215
                    s = &char_buf[0];
 
1216
                    s_len = 1;
 
1217
                    pad_char = ' ';
 
1218
#endif
 
1219
                    break;
 
1220
 
 
1221
                case NUL:
 
1222
                    /* if %p ends the string, oh well ignore it */
 
1223
                    continue;
 
1224
 
 
1225
                default:
 
1226
                    s = "bogus %p";
 
1227
                    s_len = 8;
 
1228
                    prefix_char = NUL;
 
1229
                    (void)va_arg(ap, void *); /* skip the bogus argument on the stack */
 
1230
                    break;
 
1231
                }
 
1232
                break;
 
1233
 
 
1234
            case NUL:
 
1235
                /*
 
1236
                 * The last character of the format string was %.
 
1237
                 * We ignore it.
 
1238
                 */
 
1239
                continue;
 
1240
 
 
1241
 
 
1242
                /*
 
1243
                 * The default case is for unrecognized %'s.
 
1244
                 * We print %<char> to help the user identify what
 
1245
                 * option is not understood.
 
1246
                 * This is also useful in case the user wants to pass
 
1247
                 * the output of format_converter to another function
 
1248
                 * that understands some other %<char> (like syslog).
 
1249
                 * Note that we can't point s inside fmt because the
 
1250
                 * unknown <char> could be preceded by width etc.
 
1251
                 */
 
1252
            default:
 
1253
                char_buf[0] = '%';
 
1254
                char_buf[1] = *fmt;
 
1255
                s = char_buf;
 
1256
                s_len = 2;
 
1257
                pad_char = ' ';
 
1258
                break;
 
1259
            }
 
1260
 
 
1261
            if (prefix_char != NUL && s != S_NULL && s != char_buf) {
 
1262
                *--s = prefix_char;
 
1263
                s_len++;
 
1264
            }
 
1265
 
 
1266
            if (adjust_width && adjust == RIGHT && min_width > s_len) {
 
1267
                if (pad_char == '0' && prefix_char != NUL) {
 
1268
                    INS_CHAR(*s, sp, bep, cc);
 
1269
                    s++;
 
1270
                    s_len--;
 
1271
                    min_width--;
 
1272
                }
 
1273
                PAD(min_width, s_len, pad_char);
 
1274
            }
 
1275
 
 
1276
            /*
 
1277
             * Print the string s. 
 
1278
             */
 
1279
            if (print_something == YES) {
 
1280
                for (i = s_len; i != 0; i--) {
 
1281
                      INS_CHAR(*s, sp, bep, cc);
 
1282
                    s++;
 
1283
                }
 
1284
            }
 
1285
 
 
1286
            if (adjust_width && adjust == LEFT && min_width > s_len)
 
1287
                PAD(min_width, s_len, pad_char);
 
1288
        }
 
1289
        fmt++;
 
1290
    }
 
1291
    vbuff->curpos = sp;
 
1292
 
 
1293
    return cc;
 
1294
}
 
1295
 
 
1296
 
 
1297
static int snprintf_flush(apr_vformatter_buff_t *vbuff)
 
1298
{
 
1299
    /* if the buffer fills we have to abort immediately, there is no way
 
1300
     * to "flush" an apr_snprintf... there's nowhere to flush it to.
 
1301
     */
 
1302
    return -1;
 
1303
}
 
1304
 
 
1305
 
 
1306
APR_DECLARE_NONSTD(int) apr_snprintf(char *buf, apr_size_t len, 
 
1307
                                     const char *format, ...)
 
1308
{
 
1309
    int cc;
 
1310
    va_list ap;
 
1311
    apr_vformatter_buff_t vbuff;
 
1312
 
 
1313
    if (len == 0) {
 
1314
        /* NOTE: This is a special case; we just want to return the number
 
1315
         * of chars that would be written (minus \0) if the buffer
 
1316
         * size was infinite. We leverage the fact that INS_CHAR
 
1317
         * just does actual inserts iff the buffer pointer is non-NULL.
 
1318
         * In this case, we don't care what buf is; it can be NULL, since
 
1319
         * we don't touch it at all.
 
1320
         */
 
1321
        vbuff.curpos = NULL;
 
1322
        vbuff.endpos = NULL;
 
1323
    } else {
 
1324
        /* save one byte for nul terminator */
 
1325
        vbuff.curpos = buf;
 
1326
        vbuff.endpos = buf + len - 1;
 
1327
    }
 
1328
    va_start(ap, format);
 
1329
    cc = apr_vformatter(snprintf_flush, &vbuff, format, ap);
 
1330
    va_end(ap);
 
1331
    if (len != 0) {
 
1332
        *vbuff.curpos = '\0';
 
1333
    }
 
1334
    return (cc == -1) ? (int)len : cc;
 
1335
}
 
1336
 
 
1337
 
 
1338
APR_DECLARE(int) apr_vsnprintf(char *buf, apr_size_t len, const char *format,
 
1339
                               va_list ap)
 
1340
{
 
1341
    int cc;
 
1342
    apr_vformatter_buff_t vbuff;
 
1343
 
 
1344
    if (len == 0) {
 
1345
        /* See above note */
 
1346
        vbuff.curpos = NULL;
 
1347
        vbuff.endpos = NULL;
 
1348
    } else {
 
1349
        /* save one byte for nul terminator */
 
1350
        vbuff.curpos = buf;
 
1351
        vbuff.endpos = buf + len - 1;
 
1352
    }
 
1353
    cc = apr_vformatter(snprintf_flush, &vbuff, format, ap);
 
1354
    if (len != 0) {
 
1355
        *vbuff.curpos = '\0';
 
1356
    }
 
1357
    return (cc == -1) ? (int)len : cc;
 
1358
}