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