2 * snprintf.c -- formatted output to a string
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.
9 /* ====================================================================
10 * Copyright (c) 1995-1999 The Apache Group. All rights reserved.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
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
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/)."
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
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.
38 * 6. Redistributions of any form whatsoever must retain the following
40 * "This product includes software developed by the Apache Group
41 * for use in the Apache HTTP server project (http://www.apache.org/)."
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 * ====================================================================
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/>.
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.
71 #include <sys/types.h>
76 #include <netinet/in.h>
89 #define INT_NULL ((int *)0)
97 typedef WIDE_INT wide_int
;
98 typedef unsigned WIDE_INT u_wide_int
;
101 #define S_NULL "(null)"
104 #define FLOAT_DIGITS 6
105 #define EXPONENT_LENGTH 10
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.
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))))
117 * NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions
119 * XXX: this is a magic number; do not decrease it
121 #define NUM_BUF_SIZE 512
124 * cvt.c - IEEE floating point formatting routines for FreeBSD
125 * from GNU libc-4.6.27. Modified to be thread safe.
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
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
)
142 register char *p
, *p1
;
144 if (ndigits
>= NDIG
- 1)
153 arg
= modf(arg
, &fi
);
161 fj
= modf(fi
/ 10, &fi
);
162 *--p1
= (int) ((fj
+ .03) * 10) + '0';
165 while (p1
< &buf
[NDIG
])
169 while ((fj
= arg
* 10) < 1) {
182 while (p
<= p1
&& p
< &buf
[NDIG
]) {
184 arg
= modf(arg
, &fj
);
185 *p
++ = (int) fj
+ '0';
187 if (p1
>= &buf
[NDIG
]) {
188 buf
[NDIG
- 1] = '\0';
211 static char *ap_ecvt(double arg
, int ndigits
, int *decpt
, int *sign
, char *buf
)
213 return (ap_cvt(arg
, ndigits
, decpt
, sign
, 1, buf
));
216 static char *ap_fcvt(double arg
, int ndigits
, int *decpt
, int *sign
, char *buf
)
218 return (ap_cvt(arg
, ndigits
, decpt
, sign
, 0, buf
));
222 * ap_gcvt - Floating output conversion to
223 * minimal length string
226 static char *ap_gcvt(double number
, int ndigit
, char *buf
, boolean_e altform
)
229 register char *p1
, *p2
;
233 p1
= ap_ecvt(number
, ndigit
, &decpt
, &sign
, buf1
);
237 for (i
= ndigit
- 1; i
> 0 && p1
[i
] == '0'; i
--)
239 if ((decpt
>= 0 && decpt
- ndigit
> 4)
240 || (decpt
< 0 && decpt
< -3)) { /* use E-style */
244 for (i
= 1; i
< ndigit
; i
++)
254 *p2
++ = decpt
/ 100 + '0';
256 *p2
++ = (decpt
% 100) / 10 + '0';
257 *p2
++ = decpt
% 10 + '0';
268 for (i
= 1; i
<= ndigit
; i
++) {
273 if (ndigit
< decpt
) {
274 while (ndigit
++ < decpt
)
279 if (p2
[-1] == '.' && !altform
)
286 * The INS_CHAR macro inserts a character in the buffer and writes
287 * the buffer back to disk if necessary
288 * It uses the char pointers sp and bep:
289 * sp points to the next available character in the buffer
290 * bep points to the end-of-buffer+1
291 * While using this macro, note that the nextb pointer is NOT updated.
293 * NOTE: Evaluation of the c argument should not have any side-effects
295 #define INS_CHAR(c, sp, bep, cc) \
298 vbuff->curpos = sp; \
299 if (flush_func(vbuff)) \
301 sp = vbuff->curpos; \
302 bep = vbuff->endpos; \
308 #define NUM( c ) ( c - '0' )
310 #define STR_TO_DEC( str, num ) \
311 num = NUM( *str++ ) ; \
312 while ( ap_isdigit( *str ) ) \
315 num += NUM( *str++ ) ; \
319 * This macro does zero padding so that the precision
320 * requirement is satisfied. The padding is done by
321 * adding '0's to the left of the string that is going
324 #define FIX_PRECISION( adjust, precision, s, s_len ) \
326 while ( s_len < precision ) \
333 * Macro that does padding. The padding is done by printing
336 #define PAD( width, len, ch ) do \
338 INS_CHAR( ch, sp, bep, cc ) ; \
341 while ( width > len )
344 * Prefix the character ch to the string str
346 * Set the has_prefix flag
348 #define PREFIX( str, length, ch ) *--str = ch ; length++ ; has_prefix = YES
352 * Convert num to its decimal format.
354 * - a pointer to a string containing the number (no sign)
355 * - len contains the length of the string
356 * - is_negative is set to TRUE or FALSE depending on the sign
357 * of the number (always set to FALSE if is_unsigned is TRUE)
359 * The caller provides a buffer for the string: that is the buf_end argument
360 * which is a pointer to the END of the buffer + 1 (i.e. if the buffer
361 * is declared as buf[ 100 ], buf_end should be &buf[ 100 ])
363 static char *conv_10(register wide_int num
, register bool_int is_unsigned
,
364 register bool_int
*is_negative
, char *buf_end
,
367 register char *p
= buf_end
;
368 register u_wide_int magnitude
;
371 magnitude
= (u_wide_int
) num
;
372 *is_negative
= FALSE
;
375 *is_negative
= (num
< 0);
378 * On a 2's complement machine, negating the most negative integer
379 * results in a number that cannot be represented as a signed integer.
380 * Here is what we do to obtain the number's magnitude:
381 * a. add 1 to the number
382 * b. negate it (becomes positive)
383 * c. convert it to unsigned
387 wide_int t
= num
+ 1;
389 magnitude
= ((u_wide_int
) -t
) + 1;
392 magnitude
= (u_wide_int
) num
;
396 * We use a do-while loop so that we write at least 1 digit
399 register u_wide_int new_magnitude
= magnitude
/ 10;
401 *--p
= (char) (magnitude
- new_magnitude
* 10 + '0');
402 magnitude
= new_magnitude
;
412 static char *conv_in_addr(struct in_addr
*ia
, char *buf_end
, int *len
)
414 unsigned addr
= ntohl(ia
->s_addr
);
416 bool_int is_negative
;
419 p
= conv_10((addr
& 0x000000FF) , TRUE
, &is_negative
, p
, &sub_len
);
421 p
= conv_10((addr
& 0x0000FF00) >> 8, TRUE
, &is_negative
, p
, &sub_len
);
423 p
= conv_10((addr
& 0x00FF0000) >> 16, TRUE
, &is_negative
, p
, &sub_len
);
425 p
= conv_10((addr
& 0xFF000000) >> 24, TRUE
, &is_negative
, p
, &sub_len
);
433 static char *conv_sockaddr_in(struct sockaddr_in
*si
, char *buf_end
, int *len
)
436 bool_int is_negative
;
439 p
= conv_10(ntohs(si
->sin_port
), TRUE
, &is_negative
, p
, &sub_len
);
441 p
= conv_in_addr(&si
->sin_addr
, p
, &sub_len
);
450 * Convert a floating point number to a string formats 'f', 'e' or 'E'.
451 * The result is placed in buf, and len denotes the length of the string
452 * The sign is returned in the is_negative argument (and is not placed
455 static char *conv_fp(register char format
, register double num
,
456 boolean_e add_dp
, int precision
, bool_int
*is_negative
,
459 register char *s
= buf
;
465 p
= ap_fcvt(num
, precision
, &decimal_point
, is_negative
, buf1
);
466 else /* either e or E format */
467 p
= ap_ecvt(num
, precision
+ 1, &decimal_point
, is_negative
, buf1
);
470 * Check for Infinity and NaN
472 if (ap_isalpha(*p
)) {
473 *len
= strlen(strcpy(buf
, p
));
474 *is_negative
= FALSE
;
479 if (decimal_point
<= 0) {
483 while (decimal_point
++ < 0)
490 while (decimal_point
-- > 0)
492 if (precision
> 0 || add_dp
)
498 if (precision
> 0 || add_dp
)
503 * copy the rest of p, the NUL is NOT copied
509 char temp
[EXPONENT_LENGTH
]; /* for exponent conversion */
511 bool_int exponent_is_negative
;
513 *s
++ = format
; /* either e or E */
515 if (decimal_point
!= 0) {
516 p
= conv_10((wide_int
) decimal_point
, FALSE
, &exponent_is_negative
,
517 &temp
[EXPONENT_LENGTH
], &t_len
);
518 *s
++ = exponent_is_negative
? '-' : '+';
521 * Make sure the exponent has at least 2 digits
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
544 * a pointer to a string containing the number
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 ])
550 static char *conv_p2(register u_wide_int num
, register int nbits
,
551 char format
, char *buf_end
, register int *len
)
553 register int mask
= (1 << nbits
) - 1;
554 register char *p
= buf_end
;
555 static const char low_digits
[] = "0123456789abcdef";
556 static const char upper_digits
[] = "0123456789ABCDEF";
557 register const char *digits
= (format
== 'X') ? upper_digits
: low_digits
;
560 *--p
= digits
[num
& mask
];
571 * Do format conversion placing the output in buffer
573 int ap_vformatter(int (*flush_func
)(ap_vformatter_buff
*),
574 ap_vformatter_buff
*vbuff
, const char *fmt
, va_list ap
)
581 register char *s
= NULL
;
585 register int min_width
= 0;
594 wide_int i_num
= (wide_int
) 0;
597 char num_buf
[NUM_BUF_SIZE
];
598 char char_buf
[2]; /* for printing %% and %<unknown> */
604 boolean_e alternate_form
;
605 boolean_e print_sign
;
606 boolean_e print_blank
;
607 boolean_e adjust_precision
;
608 boolean_e adjust_width
;
609 bool_int is_negative
;
616 INS_CHAR(*fmt
, sp
, bep
, cc
);
620 * Default variable settings
623 alternate_form
= print_sign
= print_blank
= NO
;
630 * Try to avoid checking for flags, width or precision
632 if (!ap_islower(*fmt
)) {
634 * Recognize flags: -, #, BLANK, +
639 else if (*fmt
== '+')
641 else if (*fmt
== '#')
642 alternate_form
= YES
;
643 else if (*fmt
== ' ')
645 else if (*fmt
== '0')
652 * Check if a width was specified
654 if (ap_isdigit(*fmt
)) {
655 STR_TO_DEC(fmt
, min_width
);
658 else if (*fmt
== '*') {
659 min_width
= va_arg(ap
, int);
664 min_width
= -min_width
;
671 * Check if a precision was specified
673 * XXX: an unreasonable amount of precision may be specified
674 * resulting in overflow of num_buf. Currently we
675 * ignore this possibility.
678 adjust_precision
= YES
;
680 if (ap_isdigit(*fmt
)) {
681 STR_TO_DEC(fmt
, precision
);
683 else if (*fmt
== '*') {
684 precision
= va_arg(ap
, int);
693 adjust_precision
= NO
;
696 adjust_precision
= adjust_width
= NO
;
706 if (*fmt
== 'h') /* "short" backward compatibility */
712 * Argument extraction and printing.
713 * First we determine the argument type.
714 * Then, we convert the argument to a string.
715 * On exit from the switch, s points to the string that
716 * must be printed, s_len has the length of the string
717 * The precision requirements, if any, are reflected in s_len.
719 * NOTE: pad_char may be set to '0' because of the 0 flag.
720 * It is reset to ' ' by non-numeric formats
725 i_num
= va_arg(ap
, u_wide_int
);
727 i_num
= (wide_int
) va_arg(ap
, unsigned int);
728 s
= conv_10(i_num
, 1, &is_negative
,
729 &num_buf
[NUM_BUF_SIZE
], &s_len
);
730 FIX_PRECISION(adjust_precision
, precision
, s
, s_len
);
736 i_num
= va_arg(ap
, wide_int
);
738 i_num
= (wide_int
) va_arg(ap
, int);
739 s
= conv_10(i_num
, 0, &is_negative
,
740 &num_buf
[NUM_BUF_SIZE
], &s_len
);
741 FIX_PRECISION(adjust_precision
, precision
, s
, s_len
);
747 else if (print_blank
)
754 ui_num
= va_arg(ap
, u_wide_int
);
756 ui_num
= (u_wide_int
) va_arg(ap
, unsigned int);
757 s
= conv_p2(ui_num
, 3, *fmt
,
758 &num_buf
[NUM_BUF_SIZE
], &s_len
);
759 FIX_PRECISION(adjust_precision
, precision
, s
, s_len
);
760 if (alternate_form
&& *s
!= '0') {
770 ui_num
= (u_wide_int
) va_arg(ap
, u_wide_int
);
772 ui_num
= (u_wide_int
) va_arg(ap
, unsigned int);
773 s
= conv_p2(ui_num
, 4, *fmt
,
774 &num_buf
[NUM_BUF_SIZE
], &s_len
);
775 FIX_PRECISION(adjust_precision
, precision
, s
, s_len
);
776 if (alternate_form
&& i_num
!= 0) {
777 *--s
= *fmt
; /* 'x' or 'X' */
785 s
= va_arg(ap
, char *);
788 if (adjust_precision
&& precision
< s_len
)
802 fp_num
= va_arg(ap
, double);
804 * * We use &num_buf[ 1 ], so that we have room for the sign
806 s
= conv_fp(*fmt
, fp_num
, alternate_form
,
807 (adjust_precision
== NO
) ? FLOAT_DIGITS
: precision
,
808 &is_negative
, &num_buf
[1], &s_len
);
813 else if (print_blank
)
820 if (adjust_precision
== NO
)
821 precision
= FLOAT_DIGITS
;
822 else if (precision
== 0)
825 * * We use &num_buf[ 1 ], so that we have room for the sign
827 s
= ap_gcvt(va_arg(ap
, double), precision
, &num_buf
[1],
833 else if (print_blank
)
838 if (alternate_form
&& (q
= strchr(s
, '.')) == NULL
) {
840 s
[s_len
] = '\0'; /* delimit for following strchr() */
842 if (*fmt
== 'G' && (q
= strchr(s
, 'e')) != NULL
)
848 char_buf
[0] = (char) (va_arg(ap
, int));
864 *(va_arg(ap
, int *)) = cc
;
868 * This is where we extend the printf format, with a second
874 * If the pointer size is equal to the size of an unsigned
875 * integer we convert the pointer to a hex number, otherwise
876 * we print "%p" to indicate that we don't handle "%p".
879 ui_num
= (u_wide_int
) va_arg(ap
, void *);
881 if (sizeof(char *) <= sizeof(u_wide_int
))
882 s
= conv_p2(ui_num
, 4, 'x',
883 &num_buf
[NUM_BUF_SIZE
], &s_len
);
892 /* print a struct sockaddr_in as a.b.c.d:port */
895 struct sockaddr_in
*si
;
897 si
= va_arg(ap
, struct sockaddr_in
*);
899 s
= conv_sockaddr_in(si
, &num_buf
[NUM_BUF_SIZE
], &s_len
);
900 if (adjust_precision
&& precision
< s_len
)
911 /* print a struct in_addr as a.b.c.d */
916 ia
= va_arg(ap
, struct in_addr
*);
918 s
= conv_in_addr(ia
, &num_buf
[NUM_BUF_SIZE
], &s_len
);
919 if (adjust_precision
&& precision
< s_len
)
931 /* if %p ends the string, oh well ignore it */
944 * The last character of the format string was %.
951 * The default case is for unrecognized %'s.
952 * We print %<char> to help the user identify what
953 * option is not understood.
954 * This is also useful in case the user wants to pass
955 * the output of format_converter to another function
956 * that understands some other %<char> (like syslog).
957 * Note that we can't point s inside fmt because the
958 * unknown <char> could be preceded by width etc.
969 if (prefix_char
!= NUL
&& s
!= S_NULL
&& s
!= char_buf
) {
974 if (adjust_width
&& adjust
== RIGHT
&& min_width
> s_len
) {
975 if (pad_char
== '0' && prefix_char
!= NUL
) {
976 INS_CHAR(*s
, sp
, bep
, cc
);
981 PAD(min_width
, s_len
, pad_char
);
985 * Print the string s.
987 for (i
= s_len
; i
!= 0; i
--) {
988 INS_CHAR(*s
, sp
, bep
, cc
);
992 if (adjust_width
&& adjust
== LEFT
&& min_width
> s_len
)
993 PAD(min_width
, s_len
, pad_char
);
1002 static int snprintf_flush(ap_vformatter_buff
*vbuff
)
1004 /* if the buffer fills we have to abort immediately, there is no way
1005 * to "flush" a snprintf... there's nowhere to flush it to.
1011 int snprintf(char *buf
, size_t len
, const char *format
,...)
1015 ap_vformatter_buff vbuff
;
1020 /* save one byte for nul terminator */
1022 vbuff
.endpos
= buf
+ len
- 1;
1023 va_start(ap
, format
);
1024 cc
= ap_vformatter(snprintf_flush
, &vbuff
, format
, ap
);
1026 *vbuff
.curpos
= '\0';
1027 return (cc
== -1) ? len
: cc
;
1031 int vsnprintf(char *buf
, size_t len
, const char *format
, va_list ap
)
1034 ap_vformatter_buff vbuff
;
1039 /* save one byte for nul terminator */
1041 vbuff
.endpos
= buf
+ len
- 1;
1042 cc
= ap_vformatter(snprintf_flush
, &vbuff
, format
, ap
);
1043 *vbuff
.curpos
= '\0';
1044 return (cc
== -1) ? len
: cc
;