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