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