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