2b198811aa740030699e1150c78c6cf0767e8fa9
[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 *
139 ap_cvt(double arg, int ndigits, int *decpt, int *sign, int eflag, char *buf)
140 {
141         register int r2;
142         double fi, fj;
143         register char *p, *p1;
144
145         if (ndigits >= NDIG - 1)
146                 ndigits = NDIG - 2;
147         r2 = 0;
148         *sign = 0;
149         p = &buf[0];
150         if (arg < 0) {
151                 *sign = 1;
152                 arg = -arg;
153         }
154         arg = modf(arg, &fi);
155         p1 = &buf[NDIG];
156         /*
157          * Do integer part
158          */
159         if (fi != 0) {
160                 p1 = &buf[NDIG];
161                 while (fi != 0) {
162                         fj = modf(fi / 10, &fi);
163                         *--p1 = (int) ((fj + .03) * 10) + '0';
164                         r2++;
165                 }
166                 while (p1 < &buf[NDIG])
167                         *p++ = *p1++;
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 *
212 ap_ecvt(double arg, int ndigits, int *decpt, int *sign, char *buf)
213 {
214         return (ap_cvt(arg, ndigits, decpt, sign, 1, buf));
215 }
216
217 static char *
218 ap_fcvt(double arg, int ndigits, int *decpt, int *sign, char *buf)
219 {
220         return (ap_cvt(arg, ndigits, decpt, sign, 0, buf));
221 }
222
223 /*
224  * ap_gcvt  - Floating output conversion to
225  * minimal length string
226  */
227
228 static char *
229 ap_gcvt(double number, int ndigit, char *buf, boolean_e altform)
230 {
231         int sign, decpt;
232         register char *p1, *p2;
233         register int i;
234         char buf1[NDIG];
235
236         p1 = ap_ecvt(number, ndigit, &decpt, &sign, buf1);
237         p2 = buf;
238         if (sign)
239                 *p2++ = '-';
240         for (i = ndigit - 1; i > 0 && p1[i] == '0'; i--)
241                 ndigit--;
242         if ((decpt >= 0 && decpt - ndigit > 4)
243                 || (decpt < 0 && decpt < -3)) {  /* use E-style */
244                 decpt--;
245                 *p2++ = *p1++;
246                 *p2++ = '.';
247                 for (i = 1; i < ndigit; i++)
248                         *p2++ = *p1++;
249                 *p2++ = 'e';
250                 if (decpt < 0) {
251                         decpt = -decpt;
252                         *p2++ = '-';
253                 } else
254                         *p2++ = '+';
255                 if (decpt / 100 > 0)
256                         *p2++ = decpt / 100 + '0';
257                 if (decpt / 10 > 0)
258                         *p2++ = (decpt % 100) / 10 + '0';
259                 *p2++ = decpt % 10 + '0';
260         } else {
261                 if (decpt <= 0) {
262                         if (*p1 != '0')
263                                 *p2++ = '.';
264                         while (decpt < 0) {
265                                 decpt++;
266                                 *p2++ = '0';
267                         }
268                 }
269                 for (i = 1; i <= ndigit; i++) {
270                         *p2++ = *p1++;
271                         if (i == decpt)
272                                 *p2++ = '.';
273                 }
274                 if (ndigit < decpt) {
275                         while (ndigit++ < decpt)
276                                 *p2++ = '0';
277                         *p2++ = '.';
278                 }
279         }
280         if (p2[-1] == '.' && !altform)
281                 p2--;
282         *p2 = '\0';
283         return (buf);
284 }
285
286 /*
287  * The INS_CHAR macro inserts a character in the buffer and writes
288  * the buffer back to disk if necessary
289  * It uses the char pointers sp and bep:
290  *      sp points to the next available character in the buffer
291  *      bep points to the end-of-buffer+1
292  * While using this macro, note that the nextb pointer is NOT updated.
293  *
294  * NOTE: Evaluation of the c argument should not have any side-effects
295  */
296 #define INS_CHAR(c, sp, bep, cc) \
297         { \
298                 if (sp >= bep) { \
299                         vbuff->curpos = sp; \
300                         if (flush_func(vbuff)) \
301                                 return -1; \
302                         sp = vbuff->curpos; \
303                         bep = vbuff->endpos; \
304                 } \
305                 *sp++ = (c); \
306                 cc++; \
307         }
308
309 #define NUM( c ) ( c - '0' )
310
311 #define STR_TO_DEC( str, num ) \
312         num = NUM( *str++ ) ; \
313         while ( ap_isdigit( *str ) ) \
314         { \
315                 num *= 10 ; \
316                 num += NUM( *str++ ) ; \
317         }
318
319 /*
320  * This macro does zero padding so that the precision
321  * requirement is satisfied. The padding is done by
322  * adding '0's to the left of the string that is going
323  * to be printed.
324  */
325 #define FIX_PRECISION( adjust, precision, s, s_len ) \
326         if ( adjust ) \
327                 while ( s_len < precision ) \
328                 { \
329                         *--s = '0' ; \
330                         s_len++ ; \
331                 }
332
333 /*
334  * Macro that does padding. The padding is done by printing
335  * the character ch.
336  */
337 #define PAD( width, len, ch ) do \
338         { \
339                 INS_CHAR( ch, sp, bep, cc ) ; \
340                 width-- ; \
341         } \
342         while ( width > len )
343
344 /*
345  * Prefix the character ch to the string str
346  * Increase length
347  * Set the has_prefix flag
348  */
349 #define PREFIX( str, length, ch ) *--str = ch ; length++ ; has_prefix = YES
350
351
352 /*
353  * Convert num to its decimal format.
354  * Return value:
355  *   - a pointer to a string containing the number (no sign)
356  *   - len contains the length of the string
357  *   - is_negative is set to TRUE or FALSE depending on the sign
358  *     of the number (always set to FALSE if is_unsigned is TRUE)
359  *
360  * The caller provides a buffer for the string: that is the buf_end argument
361  * which is a pointer to the END of the buffer + 1 (i.e. if the buffer
362  * is declared as buf[ 100 ], buf_end should be &buf[ 100 ])
363  */
364 static char *
365 conv_10(register wide_int num, register bool_int is_unsigned,
366          register bool_int *is_negative, char *buf_end,
367          register int *len)
368 {
369         register char *p = buf_end;
370         register u_wide_int magnitude;
371
372         if (is_unsigned) {
373                 magnitude = (u_wide_int) num;
374                 *is_negative = FALSE;
375         } else {
376                 *is_negative = (num < 0);
377
378                 /*
379                  * On a 2's complement machine, negating the most negative integer
380                  * results in a number that cannot be represented as a signed integer.
381                  * Here is what we do to obtain the number's magnitude:
382                  *   a. add 1 to the number
383                  *   b. negate it (becomes positive)
384                  *   c. convert it to unsigned
385                  *   d. add 1
386                  */
387                 if (*is_negative) {
388                         wide_int t = num + 1;
389
390                         magnitude = ((u_wide_int) -t) + 1;
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 *
413 conv_in_addr(struct in_addr *ia, char *buf_end, int *len)
414 {
415         unsigned addr = ntohl(ia->s_addr);
416         char *p = buf_end;
417         bool_int is_negative;
418         int sub_len;
419
420         p = conv_10((addr & 0x000000FF)  , TRUE, &is_negative, p, &sub_len);
421         *--p = '.';
422         p = conv_10((addr & 0x0000FF00) >>  8, TRUE, &is_negative, p, &sub_len);
423         *--p = '.';
424         p = conv_10((addr & 0x00FF0000) >> 16, TRUE, &is_negative, p, &sub_len);
425         *--p = '.';
426         p = conv_10((addr & 0xFF000000) >> 24, TRUE, &is_negative, p, &sub_len);
427
428         *len = buf_end - p;
429         return (p);
430 }
431
432
433
434 static char *
435 conv_sockaddr_in(struct sockaddr_in *si, char *buf_end, int *len)
436 {
437         char *p = buf_end;
438         bool_int is_negative;
439         int sub_len;
440
441         p = conv_10(ntohs(si->sin_port), TRUE, &is_negative, p, &sub_len);
442         *--p = ':';
443         p = conv_in_addr(&si->sin_addr, p, &sub_len);
444
445         *len = buf_end - p;
446         return (p);
447 }
448
449
450
451 /*
452  * Convert a floating point number to a string formats 'f', 'e' or 'E'.
453  * The result is placed in buf, and len denotes the length of the string
454  * The sign is returned in the is_negative argument (and is not placed
455  * in buf).
456  */
457 static char *
458 conv_fp(register char format, register double num,
459         boolean_e add_dp, int precision, bool_int *is_negative,
460         char *buf, int *len)
461 {
462         register char *s = buf;
463         register char *p;
464         int decimal_point;
465         char buf1[NDIG];
466
467         if (format == 'f')
468                 p = ap_fcvt(num, precision, &decimal_point, is_negative, buf1);
469         else  /* either e or E format */
470                 p = ap_ecvt(num, precision + 1, &decimal_point, is_negative, buf1);
471
472         /*
473          * Check for Infinity and NaN
474          */
475         if (ap_isalpha(*p)) {
476                 *len = strlen(strcpy(buf, p));
477                 *is_negative = FALSE;
478                 return (buf);
479         }
480
481         if (format == 'f') {
482                 if (decimal_point <= 0) {
483                         *s++ = '0';
484                         if (precision > 0) {
485                                 *s++ = '.';
486                                 while (decimal_point++ < 0)
487                                         *s++ = '0';
488                         } else if (add_dp)
489                                 *s++ = '.';
490                 } else {
491                         while (decimal_point-- > 0)
492                                 *s++ = *p++;
493                         if (precision > 0 || add_dp)
494                                 *s++ = '.';
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,
517                                 &exponent_is_negative, &temp[EXPONENT_LENGTH],
518                                 &t_len);
519                         *s++ = exponent_is_negative ? '-' : '+';
520
521                         /*
522                          * Make sure the exponent has at least 2 digits
523                          */
524                         if (t_len == 1)
525                                 *s++ = '0';
526                         while (t_len--)
527                                 *s++ = *p++;
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 *
551 conv_p2(register u_wide_int num, register int nbits,
552         char format, char *buf_end, register int *len)
553 {
554         register int mask = (1 << nbits) - 1;
555         register char *p = buf_end;
556         static const char low_digits[] = "0123456789abcdef";
557         static const char upper_digits[] = "0123456789ABCDEF";
558         register const char *digits = (format == 'X') ? upper_digits : low_digits;
559
560         do {
561                 *--p = digits[num & mask];
562                 num >>= nbits;
563         }
564         while (num);
565
566         *len = buf_end - p;
567         return (p);
568 }
569
570
571 /*
572  * Do format conversion placing the output in buffer
573  */
574 static int
575 ap_vformatter(int (*flush_func)(ap_vformatter_buff *),
576         ap_vformatter_buff *vbuff, const char *fmt, va_list ap)
577 {
578         register char *sp;
579         register char *bep;
580         register int cc = 0;
581         register int i;
582
583         register char *s = NULL;
584         char *q;
585         int s_len;
586
587         register int min_width = 0;
588         int precision = 0;
589         enum {
590                 LEFT, RIGHT
591         } adjust;
592         char pad_char;
593         char prefix_char;
594
595         double fp_num;
596         wide_int i_num = (wide_int) 0;
597         u_wide_int ui_num;
598
599         char num_buf[NUM_BUF_SIZE];
600         char char_buf[2];  /* for printing %% and %<unknown> */
601
602         /*
603          * Flag variables
604          */
605         boolean_e is_long;
606         boolean_e alternate_form;
607         boolean_e print_sign;
608         boolean_e print_blank;
609         boolean_e adjust_precision;
610         boolean_e adjust_width;
611         bool_int is_negative;
612
613         sp = vbuff->curpos;
614         bep = vbuff->endpos;
615
616         while (*fmt) {
617                 if (*fmt != '%') {
618                         INS_CHAR(*fmt, sp, bep, cc);
619                 } else {
620                         /*
621                          * Default variable settings
622                          */
623                         adjust = RIGHT;
624                         alternate_form = print_sign = print_blank = NO;
625                         pad_char = ' ';
626                         prefix_char = NUL;
627
628                         fmt++;
629
630                         /*
631                          * Try to avoid checking for flags, width or precision
632                          */
633                         if (!ap_islower(*fmt)) {
634                                 /*
635                                  * Recognize flags: -, #, BLANK, +
636                                  */
637                                 for (;; fmt++) {
638                                         if (*fmt == '-')
639                                                 adjust = LEFT;
640                                         else if (*fmt == '+')
641                                                 print_sign = YES;
642                                         else if (*fmt == '#')
643                                                 alternate_form = YES;
644                                         else if (*fmt == ' ')
645                                                 print_blank = YES;
646                                         else if (*fmt == '0')
647                                                 pad_char = '0';
648                                         else
649                                                 break;
650                                 }
651
652                                 /*
653                                  * Check if a width was specified
654                                  */
655                                 if (ap_isdigit(*fmt)) {
656                                         STR_TO_DEC(fmt, min_width);
657                                         adjust_width = YES;
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                                 } else
667                                         adjust_width = NO;
668
669                                 /*
670                                  * Check if a precision was specified
671                                  *
672                                  * XXX: an unreasonable amount of precision may be specified
673                                  * resulting in overflow of num_buf. Currently we
674                                  * ignore this possibility.
675                                  */
676                                 if (*fmt == '.') {
677                                         adjust_precision = YES;
678                                         fmt++;
679                                         if (ap_isdigit(*fmt)) {
680                                                 STR_TO_DEC(fmt, precision);
681                                         } else if (*fmt == '*') {
682                                                 precision = va_arg(ap, int);
683                                                 fmt++;
684                                                 if (precision < 0)
685                                                         precision = 0;
686                                         } else
687                                                 precision = 0;
688                                 } else
689                                         adjust_precision = NO;
690                         } else
691                                 adjust_precision = adjust_width = NO;
692
693                         /*
694                          * Modifier check
695                          */
696                         if (*fmt == 'l') {
697                                 is_long = YES;
698                                 fmt++;
699                         } else {
700                                 if (*fmt == 'h')  /* "short" backward compatibility */
701                                         ++fmt;
702                                 is_long = NO;
703                         }
704
705                         /*
706                          * Argument extraction and printing.
707                          * First we determine the argument type.
708                          * Then, we convert the argument to a string.
709                          * On exit from the switch, s points to the string that
710                          * must be printed, s_len has the length of the string
711                          * The precision requirements, if any, are reflected in s_len.
712                          *
713                          * NOTE: pad_char may be set to '0' because of the 0 flag.
714                          *   It is reset to ' ' by non-numeric formats
715                          */
716                         switch (*fmt) {
717                         case 'u':
718                                 if (is_long)
719                                         i_num = va_arg(ap, u_wide_int);
720                                 else
721                                         i_num = (wide_int) va_arg(ap, unsigned int);
722                                 s = conv_10(i_num, 1, &is_negative,
723                                                         &num_buf[NUM_BUF_SIZE], &s_len);
724                                 FIX_PRECISION(adjust_precision, precision, s, s_len);
725                                 break;
726
727                         case 'd':
728                         case 'i':
729                                 if (is_long)
730                                         i_num = va_arg(ap, wide_int);
731                                 else
732                                         i_num = (wide_int) va_arg(ap, int);
733                                 s = conv_10(i_num, 0, &is_negative,
734                                                         &num_buf[NUM_BUF_SIZE], &s_len);
735                                 FIX_PRECISION(adjust_precision, precision, s, s_len);
736
737                                 if (is_negative)
738                                         prefix_char = '-';
739                                 else if (print_sign)
740                                         prefix_char = '+';
741                                 else if (print_blank)
742                                         prefix_char = ' ';
743                                 break;
744
745
746                         case 'o':
747                                 if (is_long)
748                                         ui_num = va_arg(ap, u_wide_int);
749                                 else
750                                         ui_num = (u_wide_int) va_arg(ap, unsigned int);
751                                 s = conv_p2(ui_num, 3, *fmt,
752                                                         &num_buf[NUM_BUF_SIZE], &s_len);
753                                 FIX_PRECISION(adjust_precision, precision, s, s_len);
754                                 if (alternate_form && *s != '0') {
755                                         *--s = '0';
756                                         s_len++;
757                                 }
758                                 break;
759
760
761                         case 'x':
762                         case 'X':
763                                 if (is_long)
764                                         ui_num = (u_wide_int) va_arg(ap, u_wide_int);
765                                 else
766                                         ui_num = (u_wide_int) va_arg(ap, unsigned int);
767                                 s = conv_p2(ui_num, 4, *fmt,
768                                                         &num_buf[NUM_BUF_SIZE], &s_len);
769                                 FIX_PRECISION(adjust_precision, precision, s, s_len);
770                                 if (alternate_form && i_num != 0) {
771                                         *--s = *fmt;  /* 'x' or 'X' */
772                                         *--s = '0';
773                                         s_len += 2;
774                                 }
775                                 break;
776
777
778                         case 's':
779                                 s = va_arg(ap, char *);
780                                 if (s != NULL) {
781                                         s_len = strlen(s);
782                                         if (adjust_precision && precision < s_len)
783                                                 s_len = precision;
784                                 }
785                                 else {
786                                         s = S_NULL;
787                                         s_len = S_NULL_LEN;
788                                 }
789                                 pad_char = ' ';
790                                 break;
791
792
793                         case 'f':
794                         case 'e':
795                         case 'E':
796                                 fp_num = va_arg(ap, double);
797                                 /*
798                                  * * We use &num_buf[ 1 ], so that we have room for the sign
799                                  */
800                                 s = conv_fp(*fmt, fp_num, alternate_form,
801                                                 (adjust_precision == NO) ? FLOAT_DIGITS : precision,
802                                                         &is_negative, &num_buf[1], &s_len);
803                                 if (is_negative)
804                                         prefix_char = '-';
805                                 else if (print_sign)
806                                         prefix_char = '+';
807                                 else if (print_blank)
808                                         prefix_char = ' ';
809                                 break;
810
811
812                         case 'g':
813                         case 'G':
814                                 if (adjust_precision == NO)
815                                         precision = FLOAT_DIGITS;
816                                 else if (precision == 0)
817                                         precision = 1;
818                                 /*
819                                  * * We use &num_buf[ 1 ], so that we have room for the sign
820                                  */
821                                 s = ap_gcvt(va_arg(ap, double), precision, &num_buf[1],
822                                                         alternate_form);
823                                 if (*s == '-')
824                                         prefix_char = *s++;
825                                 else if (print_sign)
826                                         prefix_char = '+';
827                                 else if (print_blank)
828                                         prefix_char = ' ';
829
830                                 s_len = strlen(s);
831
832                                 if (alternate_form && (q = strchr(s, '.')) == NULL) {
833                                         s[s_len++] = '.';
834                                         s[s_len] = '\0'; /* delimit for following strchr() */
835                                 }
836                                 if (*fmt == 'G' && (q = strchr(s, 'e')) != NULL)
837                                         *q = 'E';
838                                 break;
839
840
841                         case 'c':
842                                 char_buf[0] = (char) (va_arg(ap, int));
843                                 s = &char_buf[0];
844                                 s_len = 1;
845                                 pad_char = ' ';
846                                 break;
847
848
849                         case '%':
850                                 char_buf[0] = '%';
851                                 s = &char_buf[0];
852                                 s_len = 1;
853                                 pad_char = ' ';
854                                 break;
855
856
857                         case 'n':
858                                 *(va_arg(ap, int *)) = cc;
859                                 break;
860
861                                 /*
862                                  * This is where we extend the printf format, with a second
863                                  * type specifier
864                                  */
865                         case 'p':
866                                 switch(*++fmt) {
867                                         /*
868                                          * If the pointer size is equal to the size of an unsigned
869                                          * integer we convert the pointer to a hex number, otherwise
870                                          * we print "%p" to indicate that we don't handle "%p".
871                                          */
872                                 case 'p':
873                                         ui_num = (u_wide_int) va_arg(ap, void *);
874
875                                         if (sizeof(char *) <= sizeof(u_wide_int))
876                                                                 s = conv_p2(ui_num, 4, 'x',
877                                                                                         &num_buf[NUM_BUF_SIZE], &s_len);
878                                         else {
879                                                 s = "%p";
880                                                 s_len = 2;
881                                                 prefix_char = NUL;
882                                         }
883                                         pad_char = ' ';
884                                         break;
885
886                                         /* print a struct sockaddr_in as a.b.c.d:port */
887                                 case 'I':
888                                         {
889                                                 struct sockaddr_in *si;
890
891                                                 si = va_arg(ap, struct sockaddr_in *);
892                                                 if (si != NULL) {
893                                                         s = conv_sockaddr_in(si, &num_buf[NUM_BUF_SIZE], &s_len);
894                                                         if (adjust_precision && precision < s_len)
895                                                                 s_len = precision;
896                                                 }
897                                                 else {
898                                                         s = S_NULL;
899                                                         s_len = S_NULL_LEN;
900                                                 }
901                                                 pad_char = ' ';
902                                         }
903                                         break;
904
905                                         /* print a struct in_addr as a.b.c.d */
906                                 case 'A':
907                                         {
908                                                 struct in_addr *ia;
909
910                                                 ia = va_arg(ap, struct in_addr *);
911                                                 if (ia != NULL) {
912                                                         s = conv_in_addr(ia, &num_buf[NUM_BUF_SIZE], &s_len);
913                                                         if (adjust_precision && precision < s_len)
914                                                                 s_len = precision;
915                                                 }
916                                                 else {
917                                                         s = S_NULL;
918                                                         s_len = S_NULL_LEN;
919                                                 }
920                                                 pad_char = ' ';
921                                         }
922                                         break;
923
924                                 case NUL:
925                                         /* if %p ends the string, oh well ignore it */
926                                         continue;
927
928                                 default:
929                                         s = "bogus %p";
930                                         s_len = 8;
931                                         prefix_char = NUL;
932                                         break;
933                                 }
934                                 break;
935
936                         case NUL:
937                                 /*
938                                  * The last character of the format string was %.
939                                  * We ignore it.
940                                  */
941                                 continue;
942
943
944                                 /*
945                                  * The default case is for unrecognized %'s.
946                                  * We print %<char> to help the user identify what
947                                  * option is not understood.
948                                  * This is also useful in case the user wants to pass
949                                  * the output of format_converter to another function
950                                  * that understands some other %<char> (like syslog).
951                                  * Note that we can't point s inside fmt because the
952                                  * unknown <char> could be preceded by width etc.
953                                  */
954                         default:
955                                 char_buf[0] = '%';
956                                 char_buf[1] = *fmt;
957                                 s = char_buf;
958                                 s_len = 2;
959                                 pad_char = ' ';
960                                 break;
961                         }
962
963                         if (prefix_char != NUL && s != S_NULL && s != char_buf) {
964                                 *--s = prefix_char;
965                                 s_len++;
966                         }
967
968                         if (adjust_width && adjust == RIGHT && min_width > s_len) {
969                                 if (pad_char == '0' && prefix_char != NUL) {
970                                         INS_CHAR(*s, sp, bep, cc);
971                                         s++;
972                                         s_len--;
973                                         min_width--;
974                                 }
975                                 PAD(min_width, s_len, pad_char);
976                         }
977
978                         /*
979                          * Print the string s.
980                          */
981                         for (i = s_len; i != 0; i--) {
982                                 INS_CHAR(*s, sp, bep, cc);
983                                 s++;
984                         }
985
986                         if (adjust_width && adjust == LEFT && min_width > s_len)
987                                 PAD(min_width, s_len, pad_char);
988                 }
989                 fmt++;
990         }
991         vbuff->curpos = sp;
992         return cc;
993 }
994
995
996 static int
997 snprintf_flush(ap_vformatter_buff *vbuff)
998 {
999         /* if the buffer fills we have to abort immediately, there is no way
1000          * to "flush" a snprintf... there's nowhere to flush it to.
1001          */
1002         return -1;
1003 }
1004
1005
1006 int
1007 snprintf(char *buf, size_t len, const char *format,...)
1008 {
1009         int cc;
1010         va_list ap;
1011         ap_vformatter_buff vbuff;
1012
1013         if (len == 0)
1014                 return 0;
1015
1016         /* save one byte for nul terminator */
1017         vbuff.curpos = buf;
1018         vbuff.endpos = buf + len - 1;
1019         va_start(ap, format);
1020         cc = ap_vformatter(snprintf_flush, &vbuff, format, ap);
1021         va_end(ap);
1022         *vbuff.curpos = '\0';
1023         return (cc == -1) ? len : cc;
1024 }
1025
1026
1027 int
1028 vsnprintf(char *buf, size_t len, const char *format, va_list ap)
1029 {
1030         int cc;
1031         ap_vformatter_buff vbuff;
1032
1033         if (len == 0)
1034                 return 0;
1035
1036         /* save one byte for nul terminator */
1037         vbuff.curpos = buf;
1038         vbuff.endpos = buf + len - 1;
1039         cc = ap_vformatter(snprintf_flush, &vbuff, format, ap);
1040         *vbuff.curpos = '\0';
1041         return (cc == -1) ? len : cc;
1042 }