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