fix typo and clarify two sentences in mhpath man page
[mmh] / sbr / snprintf.c
1 /*
2  * snprintf.c -- formatted output to a string
3  *
4  * This is an implementation of snprintf() and vsnprintf()
5  * taken from the Apache web server.  This is only used on
6  * systems which do not have a native version.
7  */
8
9 /* ====================================================================
10  * Copyright (c) 1995-1999 The Apache Group.  All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  *
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer. 
18  *
19  * 2. Redistributions in binary form must reproduce the above copyright
20  *    notice, this list of conditions and the following disclaimer in
21  *    the documentation and/or other materials provided with the
22  *    distribution.
23  *
24  * 3. All advertising materials mentioning features or use of this
25  *    software must display the following acknowledgment:
26  *    "This product includes software developed by the Apache Group
27  *    for use in the Apache HTTP server project (http://www.apache.org/)."
28  *
29  * 4. The names "Apache Server" and "Apache Group" must not be used to
30  *    endorse or promote products derived from this software without
31  *    prior written permission. For written permission, please contact
32  *    apache@apache.org.
33  *
34  * 5. Products derived from this software may not be called "Apache"
35  *    nor may "Apache" appear in their names without prior written
36  *    permission of the Apache Group.
37  *
38  * 6. Redistributions of any form whatsoever must retain the following
39  *    acknowledgment:
40  *    "This product includes software developed by the Apache Group
41  *    for use in the Apache HTTP server project (http://www.apache.org/)."
42  *
43  * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
44  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
45  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
46  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR
47  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
48  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
49  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
50  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
52  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
53  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
54  * OF THE POSSIBILITY OF SUCH DAMAGE.
55  * ====================================================================
56  *
57  * This software consists of voluntary contributions made by many
58  * individuals on behalf of the Apache Group and was originally based
59  * on public domain software written at the National Center for
60  * Supercomputing Applications, University of Illinois, Urbana-Champaign.
61  * For more information on the Apache Group and the Apache HTTP server
62  * project, please see <http://www.apache.org/>.
63  *
64  * This code is based on, and used with the permission of, the
65  * SIO stdio-replacement strx_* functions by Panos Tsirigotis
66  * <panos@alumni.cs.colorado.edu> for xinetd.
67  */
68
69 #include <stdio.h>
70 #include <ctype.h>
71 #include <sys/types.h>
72 #include <stdarg.h>
73 #include <string.h>
74 #include <stdlib.h>
75 #include <math.h>
76 #include <netinet/in.h>
77
78 typedef enum {
79     NO = 0, YES = 1
80 } boolean_e;
81
82 #ifndef FALSE
83 #define FALSE                   0
84 #endif
85 #ifndef TRUE
86 #define TRUE                    1
87 #endif
88 #define NUL                     '\0'
89 #define INT_NULL                ((int *)0)
90 #define WIDE_INT                long
91
92 typedef struct {
93     char *curpos;
94     char *endpos;
95 } ap_vformatter_buff;
96
97 typedef WIDE_INT wide_int;
98 typedef unsigned WIDE_INT u_wide_int;
99 typedef int bool_int;
100
101 #define S_NULL                  "(null)"
102 #define S_NULL_LEN              6
103
104 #define FLOAT_DIGITS            6
105 #define EXPONENT_LENGTH         10
106
107 /* These macros allow correct support of 8-bit characters on systems which
108  * support 8-bit characters.  Pretty dumb how the cast is required, but
109  * that's legacy libc for ya.  These new macros do not support EOF like
110  * the standard macros do.  Tough.
111  */
112 #define ap_isalpha(c) (isalpha(((unsigned char)(c))))
113 #define ap_isdigit(c) (isdigit(((unsigned char)(c))))
114 #define ap_islower(c) (islower(((unsigned char)(c))))
115
116 /*
117  * NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions
118  *
119  * XXX: this is a magic number; do not decrease it
120  */
121 #define NUM_BUF_SIZE            512
122
123 /*
124  * cvt.c - IEEE floating point formatting routines for FreeBSD
125  * from GNU libc-4.6.27.  Modified to be thread safe.
126  */
127
128 /*
129  *    ap_ecvt converts to decimal
130  *      the number of digits is specified by ndigit
131  *      decpt is set to the position of the decimal point
132  *      sign is set to 0 for positive, 1 for negative
133  */
134
135 #define NDIG    80
136
137 /* buf must have at least NDIG bytes */
138 static char *ap_cvt(double arg, int ndigits, int *decpt, int *sign, int eflag, char *buf)
139 {
140     register int r2;
141     double fi, fj;
142     register char *p, *p1;
143
144     if (ndigits >= NDIG - 1)
145         ndigits = NDIG - 2;
146     r2 = 0;
147     *sign = 0;
148     p = &buf[0];
149     if (arg < 0) {
150         *sign = 1;
151         arg = -arg;
152     }
153     arg = modf(arg, &fi);
154     p1 = &buf[NDIG];
155     /*
156      * Do integer part
157      */
158     if (fi != 0) {
159         p1 = &buf[NDIG];
160         while (fi != 0) {
161             fj = modf(fi / 10, &fi);
162             *--p1 = (int) ((fj + .03) * 10) + '0';
163             r2++;
164         }
165         while (p1 < &buf[NDIG])
166             *p++ = *p1++;
167     }
168     else if (arg > 0) {
169         while ((fj = arg * 10) < 1) {
170             arg = fj;
171             r2--;
172         }
173     }
174     p1 = &buf[ndigits];
175     if (eflag == 0)
176         p1 += r2;
177     *decpt = r2;
178     if (p1 < &buf[0]) {
179         buf[0] = '\0';
180         return (buf);
181     }
182     while (p <= p1 && p < &buf[NDIG]) {
183         arg *= 10;
184         arg = modf(arg, &fj);
185         *p++ = (int) fj + '0';
186     }
187     if (p1 >= &buf[NDIG]) {
188         buf[NDIG - 1] = '\0';
189         return (buf);
190     }
191     p = p1;
192     *p1 += 5;
193     while (*p1 > '9') {
194         *p1 = '0';
195         if (p1 > buf)
196             ++ * --p1;
197         else {
198             *p1 = '1';
199             (*decpt)++;
200             if (eflag == 0) {
201                 if (p > buf)
202                     *p = '0';
203                 p++;
204             }
205         }
206     }
207     *p = '\0';
208     return (buf);
209 }
210
211 static char *ap_ecvt(double arg, int ndigits, int *decpt, int *sign, char *buf)
212 {
213     return (ap_cvt(arg, ndigits, decpt, sign, 1, buf));
214 }
215
216 static char *ap_fcvt(double arg, int ndigits, int *decpt, int *sign, char *buf)
217 {
218     return (ap_cvt(arg, ndigits, decpt, sign, 0, buf));
219 }
220
221 /*
222  * ap_gcvt  - Floating output conversion to
223  * minimal length string
224  */
225
226 static char *ap_gcvt(double number, int ndigit, char *buf, boolean_e altform)
227 {
228     int sign, decpt;
229     register char *p1, *p2;
230     register int i;
231     char buf1[NDIG];
232
233     p1 = ap_ecvt(number, ndigit, &decpt, &sign, buf1);
234     p2 = buf;
235     if (sign)
236         *p2++ = '-';
237     for (i = ndigit - 1; i > 0 && p1[i] == '0'; i--)
238         ndigit--;
239     if ((decpt >= 0 && decpt - ndigit > 4)
240         || (decpt < 0 && decpt < -3)) {         /* use E-style */
241         decpt--;
242         *p2++ = *p1++;
243         *p2++ = '.';
244         for (i = 1; i < ndigit; i++)
245             *p2++ = *p1++;
246         *p2++ = 'e';
247         if (decpt < 0) {
248             decpt = -decpt;
249             *p2++ = '-';
250         }
251         else
252             *p2++ = '+';
253         if (decpt / 100 > 0)
254             *p2++ = decpt / 100 + '0';
255         if (decpt / 10 > 0)
256             *p2++ = (decpt % 100) / 10 + '0';
257         *p2++ = decpt % 10 + '0';
258     }
259     else {
260         if (decpt <= 0) {
261             if (*p1 != '0')
262                 *p2++ = '.';
263             while (decpt < 0) {
264                 decpt++;
265                 *p2++ = '0';
266             }
267         }
268         for (i = 1; i <= ndigit; i++) {
269             *p2++ = *p1++;
270             if (i == decpt)
271                 *p2++ = '.';
272         }
273         if (ndigit < decpt) {
274             while (ndigit++ < decpt)
275                 *p2++ = '0';
276             *p2++ = '.';
277         }
278     }
279     if (p2[-1] == '.' && !altform)
280         p2--;
281     *p2 = '\0';
282     return (buf);
283 }
284
285 /*
286  * The INS_CHAR macro inserts a character in the buffer and writes
287  * the buffer back to disk if necessary
288  * It uses the char pointers sp and bep:
289  *      sp points to the next available character in the buffer
290  *      bep points to the end-of-buffer+1
291  * While using this macro, note that the nextb pointer is NOT updated.
292  *
293  * NOTE: Evaluation of the c argument should not have any side-effects
294  */
295 #define INS_CHAR(c, sp, bep, cc)                                \
296             {                                                   \
297                 if (sp >= bep) {                                \
298                     vbuff->curpos = sp;                         \
299                     if (flush_func(vbuff))                      \
300                         return -1;                              \
301                     sp = vbuff->curpos;                         \
302                     bep = vbuff->endpos;                        \
303                 }                                               \
304                 *sp++ = (c);                                    \
305                 cc++;                                           \
306             }
307
308 #define NUM( c )                        ( c - '0' )
309
310 #define STR_TO_DEC( str, num )          \
311     num = NUM( *str++ ) ;               \
312     while ( ap_isdigit( *str ) )                \
313     {                                   \
314         num *= 10 ;                     \
315         num += NUM( *str++ ) ;          \
316     }
317
318 /*
319  * This macro does zero padding so that the precision
320  * requirement is satisfied. The padding is done by
321  * adding '0's to the left of the string that is going
322  * to be printed.
323  */
324 #define FIX_PRECISION( adjust, precision, s, s_len )    \
325     if ( adjust )                                       \
326         while ( s_len < precision )                     \
327         {                                               \
328             *--s = '0' ;                                \
329             s_len++ ;                                   \
330         }
331
332 /*
333  * Macro that does padding. The padding is done by printing
334  * the character ch.
335  */
336 #define PAD( width, len, ch )   do              \
337         {                                       \
338             INS_CHAR( ch, sp, bep, cc ) ;       \
339             width-- ;                           \
340         }                                       \
341         while ( width > len )
342
343 /*
344  * Prefix the character ch to the string str
345  * Increase length
346  * Set the has_prefix flag
347  */
348 #define PREFIX( str, length, ch )        *--str = ch ; length++ ; has_prefix = YES
349
350
351 /*
352  * Convert num to its decimal format.
353  * Return value:
354  *   - a pointer to a string containing the number (no sign)
355  *   - len contains the length of the string
356  *   - is_negative is set to TRUE or FALSE depending on the sign
357  *     of the number (always set to FALSE if is_unsigned is TRUE)
358  *
359  * The caller provides a buffer for the string: that is the buf_end argument
360  * which is a pointer to the END of the buffer + 1 (i.e. if the buffer
361  * is declared as buf[ 100 ], buf_end should be &buf[ 100 ])
362  */
363 static char *conv_10(register wide_int num, register bool_int is_unsigned,
364                      register bool_int *is_negative, char *buf_end,
365                      register int *len)
366 {
367     register char *p = buf_end;
368     register u_wide_int magnitude;
369
370     if (is_unsigned) {
371         magnitude = (u_wide_int) num;
372         *is_negative = FALSE;
373     }
374     else {
375         *is_negative = (num < 0);
376
377         /*
378          * On a 2's complement machine, negating the most negative integer 
379          * results in a number that cannot be represented as a signed integer.
380          * Here is what we do to obtain the number's magnitude:
381          *      a. add 1 to the number
382          *      b. negate it (becomes positive)
383          *      c. convert it to unsigned
384          *      d. add 1
385          */
386         if (*is_negative) {
387             wide_int t = num + 1;
388
389             magnitude = ((u_wide_int) -t) + 1;
390         }
391         else
392             magnitude = (u_wide_int) num;
393     }
394
395     /*
396      * We use a do-while loop so that we write at least 1 digit 
397      */
398     do {
399         register u_wide_int new_magnitude = magnitude / 10;
400
401         *--p = (char) (magnitude - new_magnitude * 10 + '0');
402         magnitude = new_magnitude;
403     }
404     while (magnitude);
405
406     *len = buf_end - p;
407     return (p);
408 }
409
410
411
412 static char *conv_in_addr(struct in_addr *ia, char *buf_end, int *len)
413 {
414     unsigned addr = ntohl(ia->s_addr);
415     char *p = buf_end;
416     bool_int is_negative;
417     int sub_len;
418
419     p = conv_10((addr & 0x000000FF)      , TRUE, &is_negative, p, &sub_len);
420     *--p = '.';
421     p = conv_10((addr & 0x0000FF00) >>  8, TRUE, &is_negative, p, &sub_len);
422     *--p = '.';
423     p = conv_10((addr & 0x00FF0000) >> 16, TRUE, &is_negative, p, &sub_len);
424     *--p = '.';
425     p = conv_10((addr & 0xFF000000) >> 24, TRUE, &is_negative, p, &sub_len);
426
427     *len = buf_end - p;
428     return (p);
429 }
430
431
432
433 static char *conv_sockaddr_in(struct sockaddr_in *si, char *buf_end, int *len)
434 {
435     char *p = buf_end;
436     bool_int is_negative;
437     int sub_len;
438
439     p = conv_10(ntohs(si->sin_port), TRUE, &is_negative, p, &sub_len);
440     *--p = ':';
441     p = conv_in_addr(&si->sin_addr, p, &sub_len);
442
443     *len = buf_end - p;
444     return (p);
445 }
446
447
448
449 /*
450  * Convert a floating point number to a string formats 'f', 'e' or 'E'.
451  * The result is placed in buf, and len denotes the length of the string
452  * The sign is returned in the is_negative argument (and is not placed
453  * in buf).
454  */
455 static char *conv_fp(register char format, register double num,
456     boolean_e add_dp, int precision, bool_int *is_negative,
457     char *buf, int *len)
458 {
459     register char *s = buf;
460     register char *p;
461     int decimal_point;
462     char buf1[NDIG];
463
464     if (format == 'f')
465         p = ap_fcvt(num, precision, &decimal_point, is_negative, buf1);
466     else                        /* either e or E format */
467         p = ap_ecvt(num, precision + 1, &decimal_point, is_negative, buf1);
468
469     /*
470      * Check for Infinity and NaN
471      */
472     if (ap_isalpha(*p)) {
473         *len = strlen(strcpy(buf, p));
474         *is_negative = FALSE;
475         return (buf);
476     }
477
478     if (format == 'f') {
479         if (decimal_point <= 0) {
480             *s++ = '0';
481             if (precision > 0) {
482                 *s++ = '.';
483                 while (decimal_point++ < 0)
484                     *s++ = '0';
485             }
486             else if (add_dp)
487                 *s++ = '.';
488         }
489         else {
490             while (decimal_point-- > 0)
491                 *s++ = *p++;
492             if (precision > 0 || add_dp)
493                 *s++ = '.';
494         }
495     }
496     else {
497         *s++ = *p++;
498         if (precision > 0 || add_dp)
499             *s++ = '.';
500     }
501
502     /*
503      * copy the rest of p, the NUL is NOT copied
504      */
505     while (*p)
506         *s++ = *p++;
507
508     if (format != 'f') {
509         char temp[EXPONENT_LENGTH];     /* for exponent conversion */
510         int t_len;
511         bool_int exponent_is_negative;
512
513         *s++ = format;          /* either e or E */
514         decimal_point--;
515         if (decimal_point != 0) {
516             p = conv_10((wide_int) decimal_point, FALSE, &exponent_is_negative,
517                         &temp[EXPONENT_LENGTH], &t_len);
518             *s++ = exponent_is_negative ? '-' : '+';
519
520             /*
521              * Make sure the exponent has at least 2 digits
522              */
523             if (t_len == 1)
524                 *s++ = '0';
525             while (t_len--)
526                 *s++ = *p++;
527         }
528         else {
529             *s++ = '+';
530             *s++ = '0';
531             *s++ = '0';
532         }
533     }
534
535     *len = s - buf;
536     return (buf);
537 }
538
539
540 /*
541  * Convert num to a base X number where X is a power of 2. nbits determines X.
542  * For example, if nbits is 3, we do base 8 conversion
543  * Return value:
544  *      a pointer to a string containing the number
545  *
546  * The caller provides a buffer for the string: that is the buf_end argument
547  * which is a pointer to the END of the buffer + 1 (i.e. if the buffer
548  * is declared as buf[ 100 ], buf_end should be &buf[ 100 ])
549  */
550 static char *conv_p2(register u_wide_int num, register int nbits,
551                      char format, char *buf_end, register int *len)
552 {
553     register int mask = (1 << nbits) - 1;
554     register char *p = buf_end;
555     static const char low_digits[] = "0123456789abcdef";
556     static const char upper_digits[] = "0123456789ABCDEF";
557     register const char *digits = (format == 'X') ? upper_digits : low_digits;
558
559     do {
560         *--p = digits[num & mask];
561         num >>= nbits;
562     }
563     while (num);
564
565     *len = buf_end - p;
566     return (p);
567 }
568
569
570 /*
571  * Do format conversion placing the output in buffer
572  */
573 int ap_vformatter(int (*flush_func)(ap_vformatter_buff *),
574     ap_vformatter_buff *vbuff, const char *fmt, va_list ap)
575 {
576     register char *sp;
577     register char *bep;
578     register int cc = 0;
579     register int i;
580
581     register char *s = NULL;
582     char *q;
583     int s_len;
584
585     register int min_width = 0;
586     int precision = 0;
587     enum {
588         LEFT, RIGHT
589     } adjust;
590     char pad_char;
591     char prefix_char;
592
593     double fp_num;
594     wide_int i_num = (wide_int) 0;
595     u_wide_int ui_num;
596
597     char num_buf[NUM_BUF_SIZE];
598     char char_buf[2];           /* for printing %% and %<unknown> */
599
600     /*
601      * Flag variables
602      */
603     boolean_e is_long;
604     boolean_e alternate_form;
605     boolean_e print_sign;
606     boolean_e print_blank;
607     boolean_e adjust_precision;
608     boolean_e adjust_width;
609     bool_int is_negative;
610
611     sp = vbuff->curpos;
612     bep = vbuff->endpos;
613
614     while (*fmt) {
615         if (*fmt != '%') {
616             INS_CHAR(*fmt, sp, bep, cc);
617         }
618         else {
619             /*
620              * Default variable settings
621              */
622             adjust = RIGHT;
623             alternate_form = print_sign = print_blank = NO;
624             pad_char = ' ';
625             prefix_char = NUL;
626
627             fmt++;
628
629             /*
630              * Try to avoid checking for flags, width or precision
631              */
632             if (!ap_islower(*fmt)) {
633                 /*
634                  * Recognize flags: -, #, BLANK, +
635                  */
636                 for (;; fmt++) {
637                     if (*fmt == '-')
638                         adjust = LEFT;
639                     else if (*fmt == '+')
640                         print_sign = YES;
641                     else if (*fmt == '#')
642                         alternate_form = YES;
643                     else if (*fmt == ' ')
644                         print_blank = YES;
645                     else if (*fmt == '0')
646                         pad_char = '0';
647                     else
648                         break;
649                 }
650
651                 /*
652                  * Check if a width was specified
653                  */
654                 if (ap_isdigit(*fmt)) {
655                     STR_TO_DEC(fmt, min_width);
656                     adjust_width = YES;
657                 }
658                 else if (*fmt == '*') {
659                     min_width = va_arg(ap, int);
660                     fmt++;
661                     adjust_width = YES;
662                     if (min_width < 0) {
663                         adjust = LEFT;
664                         min_width = -min_width;
665                     }
666                 }
667                 else
668                     adjust_width = NO;
669
670                 /*
671                  * Check if a precision was specified
672                  *
673                  * XXX: an unreasonable amount of precision may be specified
674                  * resulting in overflow of num_buf. Currently we
675                  * ignore this possibility.
676                  */
677                 if (*fmt == '.') {
678                     adjust_precision = YES;
679                     fmt++;
680                     if (ap_isdigit(*fmt)) {
681                         STR_TO_DEC(fmt, precision);
682                     }
683                     else if (*fmt == '*') {
684                         precision = va_arg(ap, int);
685                         fmt++;
686                         if (precision < 0)
687                             precision = 0;
688                     }
689                     else
690                         precision = 0;
691                 }
692                 else
693                     adjust_precision = NO;
694             }
695             else
696                 adjust_precision = adjust_width = NO;
697
698             /*
699              * Modifier check
700              */
701             if (*fmt == 'l') {
702                 is_long = YES;
703                 fmt++;
704             }
705             else {
706                 if (*fmt == 'h')  /* "short" backward compatibility */
707                     ++fmt;
708                 is_long = NO;
709             }
710
711             /*
712              * Argument extraction and printing.
713              * First we determine the argument type.
714              * Then, we convert the argument to a string.
715              * On exit from the switch, s points to the string that
716              * must be printed, s_len has the length of the string
717              * The precision requirements, if any, are reflected in s_len.
718              *
719              * NOTE: pad_char may be set to '0' because of the 0 flag.
720              *   It is reset to ' ' by non-numeric formats
721              */
722             switch (*fmt) {
723             case 'u':
724                 if (is_long)
725                     i_num = va_arg(ap, u_wide_int);
726                 else
727                     i_num = (wide_int) va_arg(ap, unsigned int);
728                 s = conv_10(i_num, 1, &is_negative,
729                             &num_buf[NUM_BUF_SIZE], &s_len);
730                 FIX_PRECISION(adjust_precision, precision, s, s_len);
731                 break;
732
733             case 'd':
734             case 'i':
735                 if (is_long)
736                     i_num = va_arg(ap, wide_int);
737                 else
738                     i_num = (wide_int) va_arg(ap, int);
739                 s = conv_10(i_num, 0, &is_negative,
740                             &num_buf[NUM_BUF_SIZE], &s_len);
741                 FIX_PRECISION(adjust_precision, precision, s, s_len);
742
743                 if (is_negative)
744                     prefix_char = '-';
745                 else if (print_sign)
746                     prefix_char = '+';
747                 else if (print_blank)
748                     prefix_char = ' ';
749                 break;
750
751
752             case 'o':
753                 if (is_long)
754                     ui_num = va_arg(ap, u_wide_int);
755                 else
756                     ui_num = (u_wide_int) va_arg(ap, unsigned int);
757                 s = conv_p2(ui_num, 3, *fmt,
758                             &num_buf[NUM_BUF_SIZE], &s_len);
759                 FIX_PRECISION(adjust_precision, precision, s, s_len);
760                 if (alternate_form && *s != '0') {
761                     *--s = '0';
762                     s_len++;
763                 }
764                 break;
765
766
767             case 'x':
768             case 'X':
769                 if (is_long)
770                     ui_num = (u_wide_int) va_arg(ap, u_wide_int);
771                 else
772                     ui_num = (u_wide_int) va_arg(ap, unsigned int);
773                 s = conv_p2(ui_num, 4, *fmt,
774                             &num_buf[NUM_BUF_SIZE], &s_len);
775                 FIX_PRECISION(adjust_precision, precision, s, s_len);
776                 if (alternate_form && i_num != 0) {
777                     *--s = *fmt;        /* 'x' or 'X' */
778                     *--s = '0';
779                     s_len += 2;
780                 }
781                 break;
782
783
784             case 's':
785                 s = va_arg(ap, char *);
786                 if (s != NULL) {
787                     s_len = strlen(s);
788                     if (adjust_precision && precision < s_len)
789                         s_len = precision;
790                 }
791                 else {
792                     s = S_NULL;
793                     s_len = S_NULL_LEN;
794                 }
795                 pad_char = ' ';
796                 break;
797
798
799             case 'f':
800             case 'e':
801             case 'E':
802                 fp_num = va_arg(ap, double);
803                 /*
804                  * * We use &num_buf[ 1 ], so that we have room for the sign
805                  */
806                 s = conv_fp(*fmt, fp_num, alternate_form,
807                         (adjust_precision == NO) ? FLOAT_DIGITS : precision,
808                             &is_negative, &num_buf[1], &s_len);
809                 if (is_negative)
810                     prefix_char = '-';
811                 else if (print_sign)
812                     prefix_char = '+';
813                 else if (print_blank)
814                     prefix_char = ' ';
815                 break;
816
817
818             case 'g':
819             case 'G':
820                 if (adjust_precision == NO)
821                     precision = FLOAT_DIGITS;
822                 else if (precision == 0)
823                     precision = 1;
824                 /*
825                  * * We use &num_buf[ 1 ], so that we have room for the sign
826                  */
827                 s = ap_gcvt(va_arg(ap, double), precision, &num_buf[1],
828                             alternate_form);
829                 if (*s == '-')
830                     prefix_char = *s++;
831                 else if (print_sign)
832                     prefix_char = '+';
833                 else if (print_blank)
834                     prefix_char = ' ';
835
836                 s_len = strlen(s);
837
838                 if (alternate_form && (q = strchr(s, '.')) == NULL) {
839                     s[s_len++] = '.';
840                     s[s_len] = '\0'; /* delimit for following strchr() */
841                 }
842                 if (*fmt == 'G' && (q = strchr(s, 'e')) != NULL)
843                     *q = 'E';
844                 break;
845
846
847             case 'c':
848                 char_buf[0] = (char) (va_arg(ap, int));
849                 s = &char_buf[0];
850                 s_len = 1;
851                 pad_char = ' ';
852                 break;
853
854
855             case '%':
856                 char_buf[0] = '%';
857                 s = &char_buf[0];
858                 s_len = 1;
859                 pad_char = ' ';
860                 break;
861
862
863             case 'n':
864                 *(va_arg(ap, int *)) = cc;
865                 break;
866
867                 /*
868                  * This is where we extend the printf format, with a second
869                  * type specifier
870                  */
871             case 'p':
872                 switch(*++fmt) {
873                     /*
874                      * If the pointer size is equal to the size of an unsigned
875                      * integer we convert the pointer to a hex number, otherwise 
876                      * we print "%p" to indicate that we don't handle "%p".
877                      */
878                 case 'p':
879                     ui_num = (u_wide_int) va_arg(ap, void *);
880
881                     if (sizeof(char *) <= sizeof(u_wide_int))
882                                 s = conv_p2(ui_num, 4, 'x',
883                                             &num_buf[NUM_BUF_SIZE], &s_len);
884                     else {
885                         s = "%p";
886                         s_len = 2;
887                         prefix_char = NUL;
888                     }
889                     pad_char = ' ';
890                     break;
891
892                     /* print a struct sockaddr_in as a.b.c.d:port */
893                 case 'I':
894                     {
895                         struct sockaddr_in *si;
896
897                         si = va_arg(ap, struct sockaddr_in *);
898                         if (si != NULL) {
899                             s = conv_sockaddr_in(si, &num_buf[NUM_BUF_SIZE], &s_len);
900                             if (adjust_precision && precision < s_len)
901                                 s_len = precision;
902                         }
903                         else {
904                             s = S_NULL;
905                             s_len = S_NULL_LEN;
906                         }
907                         pad_char = ' ';
908                     }
909                     break;
910
911                     /* print a struct in_addr as a.b.c.d */
912                 case 'A':
913                     {
914                         struct in_addr *ia;
915
916                         ia = va_arg(ap, struct in_addr *);
917                         if (ia != NULL) {
918                             s = conv_in_addr(ia, &num_buf[NUM_BUF_SIZE], &s_len);
919                             if (adjust_precision && precision < s_len)
920                                 s_len = precision;
921                         }
922                         else {
923                             s = S_NULL;
924                             s_len = S_NULL_LEN;
925                         }
926                         pad_char = ' ';
927                     }
928                     break;
929
930                 case NUL:
931                     /* if %p ends the string, oh well ignore it */
932                     continue;
933
934                 default:
935                     s = "bogus %p";
936                     s_len = 8;
937                     prefix_char = NUL;
938                     break;
939                 }
940                 break;
941
942             case NUL:
943                 /*
944                  * The last character of the format string was %.
945                  * We ignore it.
946                  */
947                 continue;
948
949
950                 /*
951                  * The default case is for unrecognized %'s.
952                  * We print %<char> to help the user identify what
953                  * option is not understood.
954                  * This is also useful in case the user wants to pass
955                  * the output of format_converter to another function
956                  * that understands some other %<char> (like syslog).
957                  * Note that we can't point s inside fmt because the
958                  * unknown <char> could be preceded by width etc.
959                  */
960             default:
961                 char_buf[0] = '%';
962                 char_buf[1] = *fmt;
963                 s = char_buf;
964                 s_len = 2;
965                 pad_char = ' ';
966                 break;
967             }
968
969             if (prefix_char != NUL && s != S_NULL && s != char_buf) {
970                 *--s = prefix_char;
971                 s_len++;
972             }
973
974             if (adjust_width && adjust == RIGHT && min_width > s_len) {
975                 if (pad_char == '0' && prefix_char != NUL) {
976                     INS_CHAR(*s, sp, bep, cc);
977                     s++;
978                     s_len--;
979                     min_width--;
980                 }
981                 PAD(min_width, s_len, pad_char);
982             }
983
984             /*
985              * Print the string s. 
986              */
987             for (i = s_len; i != 0; i--) {
988                 INS_CHAR(*s, sp, bep, cc);
989                 s++;
990             }
991
992             if (adjust_width && adjust == LEFT && min_width > s_len)
993                 PAD(min_width, s_len, pad_char);
994         }
995         fmt++;
996     }
997     vbuff->curpos = sp;
998     return cc;
999 }
1000
1001
1002 static int snprintf_flush(ap_vformatter_buff *vbuff)
1003 {
1004     /* if the buffer fills we have to abort immediately, there is no way
1005      * to "flush" a snprintf... there's nowhere to flush it to.
1006      */
1007     return -1;
1008 }
1009
1010
1011 int snprintf(char *buf, size_t len, const char *format,...)
1012 {
1013     int cc;
1014     va_list ap;
1015     ap_vformatter_buff vbuff;
1016
1017     if (len == 0)
1018         return 0;
1019
1020     /* save one byte for nul terminator */
1021     vbuff.curpos = buf;
1022     vbuff.endpos = buf + len - 1;
1023     va_start(ap, format);
1024     cc = ap_vformatter(snprintf_flush, &vbuff, format, ap);
1025     va_end(ap);
1026     *vbuff.curpos = '\0';
1027     return (cc == -1) ? len : cc;
1028 }
1029
1030
1031 int vsnprintf(char *buf, size_t len, const char *format, va_list ap)
1032 {
1033     int cc;
1034     ap_vformatter_buff vbuff;
1035
1036     if (len == 0)
1037         return 0;
1038
1039     /* save one byte for nul terminator */
1040     vbuff.curpos = buf;
1041     vbuff.endpos = buf + len - 1;
1042     cc = ap_vformatter(snprintf_flush, &vbuff, format, ap);
1043     *vbuff.curpos = '\0';
1044     return (cc == -1) ? len : cc;
1045 }