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