bottleneck testcase based on rubbos
[bottlenecks.git] / rubbos / app / tomcat-connectors-1.2.32-src / native / common / ap_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 /*
18  * This code is based on, and used with the permission of, the
19  * SIO stdio-replacement strx_* functions by Panos Tsirigotis
20  * <panos@alumni.cs.colorado.edu> for xinetd.
21  */
22 #define BUILD_STANDALONE
23
24 #ifndef BUILD_STANDALONE
25 #include "httpd.h"
26 #else
27 #include "ap_snprintf.h"
28 #endif
29
30 #include <stdio.h>
31 #include <ctype.h>
32 #ifndef NETWARE
33 #include <sys/types.h>
34 #endif
35 #include <stdarg.h>
36 #include <string.h>
37 #include <stdlib.h>
38 #include <math.h>
39 #ifdef WIN32
40 #include <float.h>
41 #endif
42
43 typedef enum {
44     NO = 0, YES = 1
45 } boolean_e;
46
47 #ifndef FALSE
48 #define FALSE                   0
49 #endif
50 #ifndef TRUE
51 #define TRUE                    1
52 #endif
53 #ifndef AP_LONGEST_LONG
54 #define AP_LONGEST_LONG         long
55 #endif
56 #define NUL                     '\0'
57 #define WIDE_INT                long
58 #define WIDEST_INT              AP_LONGEST_LONG
59
60 typedef WIDE_INT wide_int;
61 typedef unsigned WIDE_INT u_wide_int;
62 typedef WIDEST_INT widest_int;
63 #ifdef __TANDEM
64 /* Although Tandem supports "long long" there is no unsigned variant. */
65 typedef unsigned long       u_widest_int;
66 #else
67 typedef unsigned WIDEST_INT u_widest_int;
68 #endif
69 typedef int bool_int;
70
71 #define S_NULL                  "(null)"
72 #define S_NULL_LEN              6
73
74 #define FLOAT_DIGITS            6
75 #define EXPONENT_LENGTH         10
76
77 /*
78  * NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions
79  *
80  * XXX: this is a magic number; do not decrease it
81  */
82 #define NUM_BUF_SIZE            512
83
84 /*
85  * cvt - IEEE floating point formatting routines.
86  *       Derived from UNIX V7, Copyright(C) Caldera International Inc.
87  */
88
89 /*
90  *    ap_ecvt converts to decimal
91  *      the number of digits is specified by ndigit
92  *      decpt is set to the position of the decimal point
93  *      sign is set to 0 for positive, 1 for negative
94  */
95
96 #define NDIG    80
97
98 /* buf must have at least NDIG bytes */
99 static char *ap_cvt(double arg, int ndigits, int *decpt, int *sign, int eflag, char *buf)
100 {
101     register int r2;
102     double fi, fj;
103     register char *p, *p1;
104     
105     if (ndigits >= NDIG - 1)
106         ndigits = NDIG - 2;
107     r2 = 0;
108     *sign = 0;
109     p = &buf[0];
110     if (arg < 0) {
111         *sign = 1;
112         arg = -arg;
113     }
114     arg = modf(arg, &fi);
115     p1 = &buf[NDIG];
116     /*
117      * Do integer part
118      */
119     if (fi != 0) {
120         p1 = &buf[NDIG];
121         while (p1 > &buf[0] && fi != 0) {
122             fj = modf(fi / 10, &fi);
123             *--p1 = (int) ((fj + .03) * 10) + '0';
124             r2++;
125         }
126         while (p1 < &buf[NDIG])
127             *p++ = *p1++;
128     }
129     else if (arg > 0) {
130         while ((fj = arg * 10) < 1) {
131             arg = fj;
132             r2--;
133         }
134     }
135     p1 = &buf[ndigits];
136     if (eflag == 0)
137         p1 += r2;
138     *decpt = r2;
139     if (p1 < &buf[0]) {
140         buf[0] = '\0';
141         return (buf);
142     }
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 *ap_ecvt(double arg, int ndigits, int *decpt, int *sign, char *buf)
173 {
174     return (ap_cvt(arg, ndigits, decpt, sign, 1, buf));
175 }
176
177 static char *ap_fcvt(double arg, int ndigits, int *decpt, int *sign, char *buf)
178 {
179     return (ap_cvt(arg, ndigits, decpt, sign, 0, buf));
180 }
181
182 /*
183  * ap_gcvt  - Floating output conversion to
184  * minimal length string
185  */
186
187 static char *ap_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 = ap_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 >= bep) {                                \
259                     vbuff->curpos = sp;                         \
260                     if (flush_func(vbuff))                      \
261                         return -1;                              \
262                     sp = vbuff->curpos;                         \
263                     bep = vbuff->endpos;                        \
264                 }                                               \
265                 *sp++ = (c);                                    \
266                 cc++;                                           \
267             }
268
269 #define NUM( c )                        ( c - '0' )
270
271 #define STR_TO_DEC( str, num )          \
272     num = NUM( *str++ ) ;               \
273     while ( ap_isdigit( *str ) )                \
274     {                                   \
275         num *= 10 ;                     \
276         num += NUM( *str++ ) ;          \
277     }
278
279 /*
280  * This macro does zero padding so that the precision
281  * requirement is satisfied. The padding is done by
282  * adding '0's to the left of the string that is going
283  * to be printed. We don't allow precision to be large
284  * enough that we continue past the start of s.
285  *
286  * NOTE: this makes use of the magic info that s is
287  * always based on num_buf with a size of NUM_BUF_SIZE.
288  */
289 #define FIX_PRECISION( adjust, precision, s, s_len )    \
290     if ( adjust ) {                                     \
291         int p = precision < NUM_BUF_SIZE - 1 ? precision : NUM_BUF_SIZE - 1; \
292         while ( s_len < p )                             \
293         {                                               \
294             *--s = '0' ;                                \
295             s_len++ ;                                   \
296         }                                               \
297     }
298
299 /*
300  * Macro that does padding. The padding is done by printing
301  * the character ch.
302  */
303 #define PAD( width, len, ch )   do              \
304         {                                       \
305             INS_CHAR( ch, sp, bep, cc ) ;       \
306             width-- ;                           \
307         }                                       \
308         while ( width > len )
309
310 /*
311  * Prefix the character ch to the string str
312  * Increase length
313  * Set the has_prefix flag
314  */
315 #define PREFIX( str, length, ch )        *--str = ch ; length++ ; has_prefix = YES
316
317
318 /*
319  * Convert num to its decimal format.
320  * Return value:
321  *   - a pointer to a string containing the number (no sign)
322  *   - len contains the length of the string
323  *   - is_negative is set to TRUE or FALSE depending on the sign
324  *     of the number (always set to FALSE if is_unsigned is TRUE)
325  *
326  * The caller provides a buffer for the string: that is the buf_end argument
327  * which is a pointer to the END of the buffer + 1 (i.e. if the buffer
328  * is declared as buf[ 100 ], buf_end should be &buf[ 100 ])
329  *
330  * Note: we have 2 versions. One is used when we need to use quads
331  * (conv_10_quad), the other when we don't (conv_10). We're assuming the
332  * latter is faster.
333  */
334 static char *conv_10(register wide_int num, register bool_int is_unsigned,
335                      register bool_int *is_negative, char *buf_end,
336                      register int *len)
337 {
338     register char *p = buf_end;
339     register u_wide_int magnitude;
340
341     if (is_unsigned) {
342         magnitude = (u_wide_int) num;
343         *is_negative = FALSE;
344     }
345     else {
346         *is_negative = (num < 0);
347
348         /*
349          * On a 2's complement machine, negating the most negative integer 
350          * results in a number that cannot be represented as a signed integer.
351          * Here is what we do to obtain the number's magnitude:
352          *      a. add 1 to the number
353          *      b. negate it (becomes positive)
354          *      c. convert it to unsigned
355          *      d. add 1
356          */
357         if (*is_negative) {
358             wide_int t = num + 1;
359
360             magnitude = ((u_wide_int) -t) + 1;
361         }
362         else
363             magnitude = (u_wide_int) num;
364     }
365
366     /*
367      * We use a do-while loop so that we write at least 1 digit 
368      */
369     do {
370         register u_wide_int new_magnitude = magnitude / 10;
371
372         *--p = (char) (magnitude - new_magnitude * 10 + '0');
373         magnitude = new_magnitude;
374     }
375     while (magnitude);
376
377     *len = buf_end - p;
378     return (p);
379 }
380
381 static char *conv_10_quad(widest_int num, register bool_int is_unsigned,
382                      register bool_int *is_negative, char *buf_end,
383                      register int *len)
384 {
385     register char *p = buf_end;
386     u_widest_int magnitude;
387
388     /*
389      * We see if we can use the faster non-quad version by checking the
390      * number against the largest long value it can be. If <=, we
391      * punt to the quicker version.
392      */
393     if ((num <= ULONG_MAX && is_unsigned) || (num <= LONG_MAX && !is_unsigned))
394         return(conv_10( (wide_int)num, is_unsigned, is_negative,
395                buf_end, len));
396
397     if (is_unsigned) {
398         magnitude = (u_widest_int) num;
399         *is_negative = FALSE;
400     }
401     else {
402         *is_negative = (num < 0);
403
404         /*
405          * On a 2's complement machine, negating the most negative integer 
406          * results in a number that cannot be represented as a signed integer.
407          * Here is what we do to obtain the number's magnitude:
408          *      a. add 1 to the number
409          *      b. negate it (becomes positive)
410          *      c. convert it to unsigned
411          *      d. add 1
412          */
413         if (*is_negative) {
414             widest_int t = num + 1;
415
416             magnitude = ((u_widest_int) -t) + 1;
417         }
418         else
419             magnitude = (u_widest_int) num;
420     }
421
422     /*
423      * We use a do-while loop so that we write at least 1 digit 
424      */
425     do {
426         u_widest_int new_magnitude = magnitude / 10;
427
428         *--p = (char) (magnitude - new_magnitude * 10 + '0');
429         magnitude = new_magnitude;
430     }
431     while (magnitude);
432
433     *len = buf_end - p;
434     return (p);
435 }
436
437
438
439 #ifndef BUILD_STANDALONE
440 static char *conv_in_addr(struct in_addr *ia, char *buf_end, int *len)
441 {
442     unsigned addr = ntohl(ia->s_addr);
443     char *p = buf_end;
444     bool_int is_negative;
445     int sub_len;
446
447     p = conv_10((addr & 0x000000FF)      , TRUE, &is_negative, p, &sub_len);
448     *--p = '.';
449     p = conv_10((addr & 0x0000FF00) >>  8, TRUE, &is_negative, p, &sub_len);
450     *--p = '.';
451     p = conv_10((addr & 0x00FF0000) >> 16, TRUE, &is_negative, p, &sub_len);
452     *--p = '.';
453     p = conv_10((addr & 0xFF000000) >> 24, TRUE, &is_negative, p, &sub_len);
454
455     *len = buf_end - p;
456     return (p);
457 }
458
459
460
461 static char *conv_sockaddr_in(struct sockaddr_in *si, char *buf_end, int *len)
462 {
463     char *p = buf_end;
464     bool_int is_negative;
465     int sub_len;
466
467     p = conv_10(ntohs(si->sin_port), TRUE, &is_negative, p, &sub_len);
468     *--p = ':';
469     p = conv_in_addr(&si->sin_addr, p, &sub_len);
470
471     *len = buf_end - p;
472     return (p);
473 }
474 #endif
475
476
477 /*
478  * Convert a floating point number to a string formats 'f', 'e' or 'E'.
479  * The result is placed in buf, and len denotes the length of the string
480  * The sign is returned in the is_negative argument (and is not placed
481  * in buf).
482  */
483 static char *conv_fp(register char format, register double num,
484     boolean_e add_dp, int precision, bool_int *is_negative,
485     char *buf, int *len)
486 {
487     register char *s = buf;
488     register char *p;
489     int decimal_point;
490     char buf1[NDIG];
491
492     if (format == 'f')
493         p = ap_fcvt(num, precision, &decimal_point, is_negative, buf1);
494     else                        /* either e or E format */
495         p = ap_ecvt(num, precision + 1, &decimal_point, is_negative, buf1);
496
497     /*
498      * Check for Infinity and NaN
499      */
500     if (ap_isalpha(*p)) {
501         *len = strlen(strcpy(buf, p));
502         *is_negative = FALSE;
503         return (buf);
504     }
505
506     if (format == 'f') {
507         if (decimal_point <= 0) {
508             *s++ = '0';
509             if (precision > 0) {
510                 *s++ = '.';
511                 while (decimal_point++ < 0)
512                     *s++ = '0';
513             }
514             else if (add_dp)
515                 *s++ = '.';
516         }
517         else {
518             while (decimal_point-- > 0)
519                 *s++ = *p++;
520             if (precision > 0 || add_dp)
521                 *s++ = '.';
522         }
523     }
524     else {
525         *s++ = *p++;
526         if (precision > 0 || add_dp)
527             *s++ = '.';
528     }
529
530     /*
531      * copy the rest of p, the NUL is NOT copied
532      */
533     while (*p)
534         *s++ = *p++;
535
536     if (format != 'f') {
537         char temp[EXPONENT_LENGTH];     /* for exponent conversion */
538         int t_len;
539         bool_int exponent_is_negative;
540
541         *s++ = format;          /* either e or E */
542         decimal_point--;
543         if (decimal_point != 0) {
544             p = conv_10((wide_int) decimal_point, FALSE, &exponent_is_negative,
545                         &temp[EXPONENT_LENGTH], &t_len);
546             *s++ = exponent_is_negative ? '-' : '+';
547
548             /*
549              * Make sure the exponent has at least 2 digits
550              */
551             if (t_len == 1)
552                 *s++ = '0';
553             while (t_len--)
554                 *s++ = *p++;
555         }
556         else {
557             *s++ = '+';
558             *s++ = '0';
559             *s++ = '0';
560         }
561     }
562
563     *len = s - buf;
564     return (buf);
565 }
566
567
568 /*
569  * Convert num to a base X number where X is a power of 2. nbits determines X.
570  * For example, if nbits is 3, we do base 8 conversion
571  * Return value:
572  *      a pointer to a string containing the number
573  *
574  * The caller provides a buffer for the string: that is the buf_end argument
575  * which is a pointer to the END of the buffer + 1 (i.e. if the buffer
576  * is declared as buf[ 100 ], buf_end should be &buf[ 100 ])
577  *
578  * As with conv_10, we have a faster version which is used when
579  * the number isn't quad size.
580  */
581 static char *conv_p2(register u_wide_int num, register int nbits,
582                      char format, char *buf_end, register int *len)
583 {
584     register int mask = (1 << nbits) - 1;
585     register char *p = buf_end;
586     static const char low_digits[] = "0123456789abcdef";
587     static const char upper_digits[] = "0123456789ABCDEF";
588     register const char *digits = (format == 'X') ? upper_digits : low_digits;
589
590     do {
591         *--p = digits[num & mask];
592         num >>= nbits;
593     }
594     while (num);
595
596     *len = buf_end - p;
597     return (p);
598 }
599
600 static char *conv_p2_quad(u_widest_int num, register int nbits,
601                      char format, char *buf_end, register int *len)
602 {
603     register int mask = (1 << nbits) - 1;
604     register char *p = buf_end;
605     static const char low_digits[] = "0123456789abcdef";
606     static const char upper_digits[] = "0123456789ABCDEF";
607     register const char *digits = (format == 'X') ? upper_digits : low_digits;
608
609     if (num <= ULONG_MAX)
610         return(conv_p2( (u_wide_int)num, nbits, format, buf_end, len));
611
612     do {
613         *--p = digits[num & mask];
614         num >>= nbits;
615     }
616     while (num);
617
618     *len = buf_end - p;
619     return (p);
620 }
621
622
623 /*
624  * Do format conversion placing the output in buffer
625  */
626 API_EXPORT(int) ap_vformatter(int (*flush_func)(ap_vformatter_buff *),
627     ap_vformatter_buff *vbuff, const char *fmt, va_list ap)
628 {
629     register char *sp;
630     register char *bep;
631     register int cc = 0;
632     register int i;
633
634     register char *s = NULL;
635     char *q;
636     int s_len;
637
638     register int min_width = 0;
639     int precision = 0;
640     enum {
641         LEFT, RIGHT
642     } adjust;
643     char pad_char;
644     char prefix_char;
645
646     double fp_num;
647     widest_int i_quad = (widest_int) 0;
648     u_widest_int ui_quad;
649     wide_int i_num = (wide_int) 0;
650     u_wide_int ui_num;
651
652     char num_buf[NUM_BUF_SIZE];
653     char char_buf[2];           /* for printing %% and %<unknown> */
654
655     enum var_type_enum {
656         IS_QUAD, IS_LONG, IS_SHORT, IS_INT
657     };
658     enum var_type_enum var_type = IS_INT;
659
660     /*
661      * Flag variables
662      */
663     boolean_e alternate_form;
664     boolean_e print_sign;
665     boolean_e print_blank;
666     boolean_e adjust_precision;
667     boolean_e adjust_width;
668     bool_int is_negative;
669
670     sp = vbuff->curpos;
671     bep = vbuff->endpos;
672
673     while (*fmt) {
674         if (*fmt != '%') {
675             INS_CHAR(*fmt, sp, bep, cc);
676         }
677         else {
678             /*
679              * Default variable settings
680              */
681             adjust = RIGHT;
682             alternate_form = print_sign = print_blank = NO;
683             pad_char = ' ';
684             prefix_char = NUL;
685
686             fmt++;
687
688             /*
689              * Try to avoid checking for flags, width or precision
690              */
691             if (!ap_islower(*fmt)) {
692                 /*
693                  * Recognize flags: -, #, BLANK, +
694                  */
695                 for (;; fmt++) {
696                     if (*fmt == '-')
697                         adjust = LEFT;
698                     else if (*fmt == '+')
699                         print_sign = YES;
700                     else if (*fmt == '#')
701                         alternate_form = YES;
702                     else if (*fmt == ' ')
703                         print_blank = YES;
704                     else if (*fmt == '0')
705                         pad_char = '0';
706                     else
707                         break;
708                 }
709
710                 /*
711                  * Check if a width was specified
712                  */
713                 if (ap_isdigit(*fmt)) {
714                     STR_TO_DEC(fmt, min_width);
715                     adjust_width = YES;
716                 }
717                 else if (*fmt == '*') {
718                     min_width = va_arg(ap, int);
719                     fmt++;
720                     adjust_width = YES;
721                     if (min_width < 0) {
722                         adjust = LEFT;
723                         min_width = -min_width;
724                     }
725                 }
726                 else
727                     adjust_width = NO;
728
729                 /*
730                  * Check if a precision was specified
731                  */
732                 if (*fmt == '.') {
733                     adjust_precision = YES;
734                     fmt++;
735                     if (ap_isdigit(*fmt)) {
736                         STR_TO_DEC(fmt, precision);
737                     }
738                     else if (*fmt == '*') {
739                         precision = va_arg(ap, int);
740                         fmt++;
741                         if (precision < 0)
742                             precision = 0;
743                     }
744                     else
745                         precision = 0;
746                 }
747                 else
748                     adjust_precision = NO;
749             }
750             else
751                 adjust_precision = adjust_width = NO;
752
753             /*
754              * Modifier check
755              */
756             if (*fmt == 'q') {
757                 var_type = IS_QUAD;
758                 fmt++;
759             }
760             else if (*fmt == 'l') {
761                 var_type = IS_LONG;
762                 fmt++;
763             }
764             else if (*fmt == 'h') {
765                 var_type = IS_SHORT;
766                 fmt++;
767             }
768             else {
769                 var_type = IS_INT;
770             }
771
772             /*
773              * Argument extraction and printing.
774              * First we determine the argument type.
775              * Then, we convert the argument to a string.
776              * On exit from the switch, s points to the string that
777              * must be printed, s_len has the length of the string
778              * The precision requirements, if any, are reflected in s_len.
779              *
780              * NOTE: pad_char may be set to '0' because of the 0 flag.
781              *   It is reset to ' ' by non-numeric formats
782              */
783             switch (*fmt) {
784             case 'u':
785                 if (var_type == IS_QUAD) {
786                     i_quad = va_arg(ap, u_widest_int);
787                     s = conv_10_quad(i_quad, 1, &is_negative,
788                             &num_buf[NUM_BUF_SIZE], &s_len);
789                 }
790                 else {
791                     if (var_type == IS_LONG)
792                         i_num = (wide_int) va_arg(ap, u_wide_int);
793                     else if (var_type == IS_SHORT)
794                         i_num = (wide_int) (unsigned short) va_arg(ap, unsigned int);
795                     else
796                         i_num = (wide_int) va_arg(ap, unsigned int);
797                     s = conv_10(i_num, 1, &is_negative,
798                             &num_buf[NUM_BUF_SIZE], &s_len);
799                 }
800                 FIX_PRECISION(adjust_precision, precision, s, s_len);
801                 break;
802
803             case 'd':
804             case 'i':
805                 if (var_type == IS_QUAD) {
806                     i_quad = va_arg(ap, widest_int);
807                     s = conv_10_quad(i_quad, 0, &is_negative,
808                             &num_buf[NUM_BUF_SIZE], &s_len);
809                 }
810                 else {
811                     if (var_type == IS_LONG)
812                         i_num = (wide_int) va_arg(ap, wide_int);
813                     else if (var_type == IS_SHORT)
814                         i_num = (wide_int) (short) va_arg(ap, int);
815                     else
816                         i_num = (wide_int) va_arg(ap, int);
817                     s = conv_10(i_num, 0, &is_negative,
818                             &num_buf[NUM_BUF_SIZE], &s_len);
819                 }
820                 FIX_PRECISION(adjust_precision, precision, s, s_len);
821
822                 if (is_negative)
823                     prefix_char = '-';
824                 else if (print_sign)
825                     prefix_char = '+';
826                 else if (print_blank)
827                     prefix_char = ' ';
828                 break;
829
830
831             case 'o':
832                 if (var_type == IS_QUAD) {
833                     ui_quad = va_arg(ap, u_widest_int);
834                     s = conv_p2_quad(ui_quad, 3, *fmt,
835                             &num_buf[NUM_BUF_SIZE], &s_len);
836                 }
837                 else {
838                     if (var_type == IS_LONG)
839                         ui_num = (u_wide_int) va_arg(ap, u_wide_int);
840                     else if (var_type == IS_SHORT)
841                         ui_num = (u_wide_int) (unsigned short) va_arg(ap, unsigned int);
842                     else
843                         ui_num = (u_wide_int) va_arg(ap, unsigned int);
844                     s = conv_p2(ui_num, 3, *fmt,
845                             &num_buf[NUM_BUF_SIZE], &s_len);
846                 }
847                 FIX_PRECISION(adjust_precision, precision, s, s_len);
848                 if (alternate_form && *s != '0') {
849                     *--s = '0';
850                     s_len++;
851                 }
852                 break;
853
854
855             case 'x':
856             case 'X':
857                 if (var_type == IS_QUAD) {
858                     ui_quad = va_arg(ap, u_widest_int);
859                     s = conv_p2_quad(ui_quad, 4, *fmt,
860                             &num_buf[NUM_BUF_SIZE], &s_len);
861                 }
862                 else {
863                     if (var_type == IS_LONG)
864                         ui_num = (u_wide_int) va_arg(ap, u_wide_int);
865                     else if (var_type == IS_SHORT)
866                         ui_num = (u_wide_int) (unsigned short) va_arg(ap, unsigned int);
867                     else
868                         ui_num = (u_wide_int) va_arg(ap, unsigned int);
869                     s = conv_p2(ui_num, 4, *fmt,
870                             &num_buf[NUM_BUF_SIZE], &s_len);
871                 }
872                 FIX_PRECISION(adjust_precision, precision, s, s_len);
873                 if (alternate_form && i_num != 0) {
874                     *--s = *fmt;        /* 'x' or 'X' */
875                     *--s = '0';
876                     s_len += 2;
877                 }
878                 break;
879
880
881             case 's':
882                 s = va_arg(ap, char *);
883                 if (s != NULL) {
884                     s_len = strlen(s);
885                     if (adjust_precision && precision < s_len)
886                         s_len = precision;
887                 }
888                 else {
889                     s = S_NULL;
890                     s_len = S_NULL_LEN;
891                 }
892                 pad_char = ' ';
893                 break;
894
895
896             case 'f':
897             case 'e':
898             case 'E':
899                 fp_num = va_arg(ap, double);
900                 /*
901                  * * We use &num_buf[ 1 ], so that we have room for the sign
902                  */
903 #ifdef HAVE_ISNAN
904                 if (isnan(fp_num)) {
905                     s = "nan";
906                     s_len = 3;
907                 }
908                 else
909 #endif
910 #ifdef HAVE_ISINF
911                 if (isinf(fp_num)) {
912                     s = "inf";
913                     s_len = 3;
914                 }
915                 else
916 #endif
917                 {
918                     s = conv_fp(*fmt, fp_num, alternate_form,
919                             (adjust_precision == NO) ? FLOAT_DIGITS : precision,
920                                 &is_negative, &num_buf[1], &s_len);
921                     if (is_negative)
922                         prefix_char = '-';
923                     else if (print_sign)
924                         prefix_char = '+';
925                     else if (print_blank)
926                         prefix_char = ' ';
927                 }
928                 break;
929
930
931             case 'g':
932             case 'G':
933                 if (adjust_precision == NO)
934                     precision = FLOAT_DIGITS;
935                 else if (precision == 0)
936                     precision = 1;
937                 /*
938                  * * We use &num_buf[ 1 ], so that we have room for the sign
939                  */
940                 s = ap_gcvt(va_arg(ap, double), precision, &num_buf[1],
941                             alternate_form);
942                 if (*s == '-')
943                     prefix_char = *s++;
944                 else if (print_sign)
945                     prefix_char = '+';
946                 else if (print_blank)
947                     prefix_char = ' ';
948
949                 s_len = strlen(s);
950
951                 if (alternate_form && (q = strchr(s, '.')) == NULL) {
952                     s[s_len++] = '.';
953                     s[s_len] = '\0'; /* delimit for following strchr() */
954                 }
955                 if (*fmt == 'G' && (q = strchr(s, 'e')) != NULL)
956                     *q = 'E';
957                 break;
958
959
960             case 'c':
961                 char_buf[0] = (char) (va_arg(ap, int));
962                 s = &char_buf[0];
963                 s_len = 1;
964                 pad_char = ' ';
965                 break;
966
967
968             case '%':
969                 char_buf[0] = '%';
970                 s = &char_buf[0];
971                 s_len = 1;
972                 pad_char = ' ';
973                 break;
974
975
976             case 'n':
977                 if (var_type == IS_QUAD)
978                     *(va_arg(ap, widest_int *)) = cc;
979                 else if (var_type == IS_LONG)
980                     *(va_arg(ap, long *)) = cc;
981                 else if (var_type == IS_SHORT)
982                     *(va_arg(ap, short *)) = cc;
983                 else
984                     *(va_arg(ap, int *)) = cc;
985                 break;
986
987                 /*
988                  * This is where we extend the printf format, with a second
989                  * type specifier
990                  */
991             case 'p':
992                 switch(*++fmt) {
993                     /*
994                      * If the pointer size is equal to or smaller than the size
995                      * of the largest unsigned int, we convert the pointer to a
996                      * hex number, otherwise we print "%p" to indicate that we
997                      * don't handle "%p".
998                      */
999                 case 'p':
1000 #ifdef AP_VOID_P_IS_QUAD
1001                     if (sizeof(void *) <= sizeof(u_widest_int)) {
1002                         ui_quad = (u_widest_int) va_arg(ap, void *);
1003                         s = conv_p2_quad(ui_quad, 4, 'x',
1004                                 &num_buf[NUM_BUF_SIZE], &s_len);
1005                     }
1006 #else
1007                     if (sizeof(void *) <= sizeof(u_wide_int)) {
1008                         ui_num = (u_wide_int) va_arg(ap, void *);
1009                         s = conv_p2(ui_num, 4, 'x',
1010                                 &num_buf[NUM_BUF_SIZE], &s_len);
1011                     }
1012 #endif
1013                     else {
1014                         s = "%p";
1015                         s_len = 2;
1016                         prefix_char = NUL;
1017                     }
1018                     pad_char = ' ';
1019                     break;
1020
1021 #ifndef BUILD_STANDALONE
1022                     /* print a struct sockaddr_in as a.b.c.d:port */
1023                 case 'I':
1024                     {
1025                         struct sockaddr_in *si;
1026
1027                         si = va_arg(ap, struct sockaddr_in *);
1028                         if (si != NULL) {
1029                             s = conv_sockaddr_in(si, &num_buf[NUM_BUF_SIZE], &s_len);
1030                             if (adjust_precision && precision < s_len)
1031                                 s_len = precision;
1032                         }
1033                         else {
1034                             s = S_NULL;
1035                             s_len = S_NULL_LEN;
1036                         }
1037                         pad_char = ' ';
1038                     }
1039                     break;
1040
1041                     /* print a struct in_addr as a.b.c.d */
1042                 case 'A':
1043                     {
1044                         struct in_addr *ia;
1045
1046                         ia = va_arg(ap, struct in_addr *);
1047                         if (ia != NULL) {
1048                             s = conv_in_addr(ia, &num_buf[NUM_BUF_SIZE], &s_len);
1049                             if (adjust_precision && precision < s_len)
1050                                 s_len = precision;
1051                         }
1052                         else {
1053                             s = S_NULL;
1054                             s_len = S_NULL_LEN;
1055                         }
1056                         pad_char = ' ';
1057                     }
1058                     break;
1059 #endif
1060
1061                 case NUL:
1062                     /* if %p ends the string, oh well ignore it */
1063                     continue;
1064
1065                 default:
1066                     s = "bogus %p";
1067                     s_len = 8;
1068                     prefix_char = NUL;
1069                     break;
1070                 }
1071                 break;
1072
1073             case NUL:
1074                 /*
1075                  * The last character of the format string was %.
1076                  * We ignore it.
1077                  */
1078                 continue;
1079
1080
1081                 /*
1082                  * The default case is for unrecognized %'s.
1083                  * We print %<char> to help the user identify what
1084                  * option is not understood.
1085                  * This is also useful in case the user wants to pass
1086                  * the output of format_converter to another function
1087                  * that understands some other %<char> (like syslog).
1088                  * Note that we can't point s inside fmt because the
1089                  * unknown <char> could be preceded by width etc.
1090                  */
1091             default:
1092                 char_buf[0] = '%';
1093                 char_buf[1] = *fmt;
1094                 s = char_buf;
1095                 s_len = 2;
1096                 pad_char = ' ';
1097                 break;
1098             }
1099
1100             if (prefix_char != NUL && s != S_NULL && s != char_buf) {
1101                 *--s = prefix_char;
1102                 s_len++;
1103             }
1104
1105             if (adjust_width && adjust == RIGHT && min_width > s_len) {
1106                 if (pad_char == '0' && prefix_char != NUL) {
1107                     INS_CHAR(*s, sp, bep, cc);
1108                     s++;
1109                     s_len--;
1110                     min_width--;
1111                 }
1112                 PAD(min_width, s_len, pad_char);
1113             }
1114
1115             /*
1116              * Print the string s. 
1117              */
1118             for (i = s_len; i != 0; i--) {
1119                 INS_CHAR(*s, sp, bep, cc);
1120                 s++;
1121             }
1122
1123             if (adjust_width && adjust == LEFT && min_width > s_len)
1124                 PAD(min_width, s_len, pad_char);
1125         }
1126         fmt++;
1127     }
1128     vbuff->curpos = sp;
1129
1130     return cc;
1131 }
1132
1133
1134 static int snprintf_flush(ap_vformatter_buff *vbuff)
1135 {
1136     /* if the buffer fills we have to abort immediately, there is no way
1137      * to "flush" an ap_snprintf... there's nowhere to flush it to.
1138      */
1139     return -1;
1140 }
1141
1142
1143 API_EXPORT_NONSTD(int) ap_snprintf(char *buf, size_t len, const char *format,...)
1144 {
1145     int cc;
1146     va_list ap;
1147     ap_vformatter_buff vbuff;
1148
1149     if (len == 0)
1150         return 0;
1151
1152     /* save one byte for nul terminator */
1153     vbuff.curpos = buf;
1154     vbuff.endpos = buf + len - 1;
1155     va_start(ap, format);
1156     cc = ap_vformatter(snprintf_flush, &vbuff, format, ap);
1157     va_end(ap);
1158     *vbuff.curpos = '\0';
1159     return (cc == -1) ? len : cc;
1160 }
1161
1162
1163 API_EXPORT(int) ap_vsnprintf(char *buf, size_t len, const char *format,
1164                              va_list ap)
1165 {
1166     int cc;
1167     ap_vformatter_buff vbuff;
1168
1169     if (len == 0)
1170         return 0;
1171
1172     /* save one byte for nul terminator */
1173     vbuff.curpos = buf;
1174     vbuff.endpos = buf + len - 1;
1175     cc = ap_vformatter(snprintf_flush, &vbuff, format, ap);
1176     *vbuff.curpos = '\0';
1177     return (cc == -1) ? len : cc;
1178 }