1 /* ====================================================================
2 * Copyright (c) 1995-1998 The Apache Group. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
16 * 3. All advertising materials mentioning features or use of this
17 * software must display the following acknowledgment:
18 * "This product includes software developed by the Apache Group
19 * for use in the Apache HTTP server project (http://www.apache.org/)."
21 * 4. The names "Apache Server" and "Apache Group" must not be used to
22 * endorse or promote products derived from this software without
23 * prior written permission.
25 * 5. Redistributions of any form whatsoever must retain the following
27 * "This product includes software developed by the Apache Group
28 * for use in the Apache HTTP server project (http://www.apache.org/)."
30 * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
31 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
33 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR
34 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
35 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
36 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
41 * OF THE POSSIBILITY OF SUCH DAMAGE.
42 * ====================================================================
44 * This software consists of voluntary contributions made by many
45 * individuals on behalf of the Apache Group and was originally based
46 * on public domain software written at the National Center for
47 * Supercomputing Applications, University of Illinois, Urbana-Champaign.
48 * For more information on the Apache Group and the Apache HTTP server
49 * project, please see <http://www.apache.org/>.
51 * This code is based on, and used with the permission of, the
52 * SIO stdio-replacement strx_* functions by Panos Tsirigotis
53 * <panos@alumni.cs.colorado.edu> for xinetd.
58 #if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF)
62 #include <sys/types.h>
78 * cvt.c - IEEE floating point formatting routines for FreeBSD
79 * from GNU libc-4.6.27
83 * ap_ecvt converts to decimal
84 * the number of digits is specified by ndigit
85 * decpt is set to the position of the decimal point
86 * sign is set to 0 for positive, 1 for negative
92 ap_cvt(double arg
, int ndigits
, int *decpt
, int *sign
, int eflag
)
96 register char *p
, *p1
;
97 static char buf
[NDIG
];
99 if (ndigits
>= NDIG
- 1)
108 arg
= modf(arg
, &fi
);
116 fj
= modf(fi
/ 10, &fi
);
117 *--p1
= (int) ((fj
+ .03) * 10) + '0';
120 while (p1
< &buf
[NDIG
])
122 } else if (arg
> 0) {
123 while ((fj
= arg
* 10) < 1) {
136 while (p
<= p1
&& p
< &buf
[NDIG
]) {
138 arg
= modf(arg
, &fj
);
139 *p
++ = (int) fj
+ '0';
141 if (p1
>= &buf
[NDIG
]) {
142 buf
[NDIG
- 1] = '\0';
166 ap_ecvt(double arg
, int ndigits
, int *decpt
, int *sign
)
168 return (ap_cvt(arg
, ndigits
, decpt
, sign
, 1));
172 ap_fcvt(double arg
, int ndigits
, int *decpt
, int *sign
)
174 return (ap_cvt(arg
, ndigits
, decpt
, sign
, 0));
178 * ap_gcvt - Floating output conversion to
179 * minimal length string
183 ap_gcvt(double number
, int ndigit
, char *buf
)
186 register char *p1
, *p2
;
189 p1
= ap_ecvt(number
, ndigit
, &decpt
, &sign
);
193 for (i
= ndigit
- 1; i
> 0 && p1
[i
] == '0'; i
--)
195 if ((decpt
>= 0 && decpt
- ndigit
> 4)
196 || (decpt
< 0 && decpt
< -3)) { /* use E-style */
200 for (i
= 1; i
< ndigit
; i
++)
209 *p2
++ = decpt
/ 100 + '0';
211 *p2
++ = (decpt
% 100) / 10 + '0';
212 *p2
++ = decpt
% 10 + '0';
222 for (i
= 1; i
<= ndigit
; i
++) {
227 if (ndigit
< decpt
) {
228 while (ndigit
++ < decpt
)
239 #endif /* HAVE_CVT */
248 #define INT_NULL ((int *)0)
249 #define WIDE_INT long
251 typedef WIDE_INT wide_int
;
252 typedef unsigned WIDE_INT u_wide_int
;
253 typedef int bool_int
;
255 #define S_NULL "(null)"
258 #define FLOAT_DIGITS 6
259 #define EXPONENT_LENGTH 10
262 * NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions
264 * XXX: this is a magic number; do not decrease it
266 #define NUM_BUF_SIZE 512
270 * Descriptor for buffer area
274 char *nextb
; /* pointer to next byte to read/write */
277 typedef struct buf_area buffy
;
280 * The INS_CHAR macro inserts a character in the buffer and writes
281 * the buffer back to disk if necessary
282 * It uses the char pointers sp and bep:
283 * sp points to the next available character in the buffer
284 * bep points to the end-of-buffer+1
285 * While using this macro, note that the nextb pointer is NOT updated.
287 * NOTE: Evaluation of the c argument should not have any side-effects
289 #define INS_CHAR( c, sp, bep, cc ) \
298 #define NUM( c ) ( c - '0' )
300 #define STR_TO_DEC( str, num ) \
301 num = NUM( *str++ ) ; \
302 while ( isdigit((int)*str ) ) \
305 num += NUM( *str++ ) ; \
309 * This macro does zero padding so that the precision
310 * requirement is satisfied. The padding is done by
311 * adding '0's to the left of the string that is going
314 #define FIX_PRECISION( adjust, precision, s, s_len ) \
316 while ( s_len < precision ) \
323 * Macro that does padding. The padding is done by printing
326 #define PAD( width, len, ch ) do \
328 INS_CHAR( ch, sp, bep, cc ) ; \
331 while ( width > len )
334 * Prefix the character ch to the string str
336 * Set the has_prefix flag
338 #define PREFIX( str, length, ch ) *--str = ch ; length++ ; has_prefix = YES
342 * Convert num to its decimal format.
344 * - a pointer to a string containing the number (no sign)
345 * - len contains the length of the string
346 * - is_negative is set to TRUE or FALSE depending on the sign
347 * of the number (always set to FALSE if is_unsigned is TRUE)
349 * The caller provides a buffer for the string: that is the buf_end argument
350 * which is a pointer to the END of the buffer + 1 (i.e. if the buffer
351 * is declared as buf[ 100 ], buf_end should be &buf[ 100 ])
354 conv_10(register wide_int num
, register bool_int is_unsigned
,
355 register bool_int
* is_negative
, char *buf_end
, register int *len
)
357 register char *p
= buf_end
;
358 register u_wide_int magnitude
;
361 magnitude
= (u_wide_int
) num
;
362 *is_negative
= FALSE
;
364 *is_negative
= (num
< 0);
367 * On a 2's complement machine, negating the most negative integer
368 * results in a number that cannot be represented as a signed integer.
369 * Here is what we do to obtain the number's magnitude:
370 * a. add 1 to the number
371 * b. negate it (becomes positive)
372 * c. convert it to unsigned
376 wide_int t
= num
+ 1;
378 magnitude
= ((u_wide_int
) - t
) + 1;
380 magnitude
= (u_wide_int
) num
;
384 * We use a do-while loop so that we write at least 1 digit
387 register u_wide_int new_magnitude
= magnitude
/ 10;
389 *--p
= magnitude
- new_magnitude
* 10 + '0';
390 magnitude
= new_magnitude
;
401 * Convert a floating point number to a string formats 'f', 'e' or 'E'.
402 * The result is placed in buf, and len denotes the length of the string
403 * The sign is returned in the is_negative argument (and is not placed
407 conv_fp(register char format
, register double num
,
408 boolean_e add_dp
, int precision
, bool_int
* is_negative
, char *buf
, int *len
)
410 register char *s
= buf
;
415 p
= ap_fcvt(num
, precision
, &decimal_point
, is_negative
);
416 else /* either e or E format */
417 p
= ap_ecvt(num
, precision
+ 1, &decimal_point
, is_negative
);
420 * Check for Infinity and NaN
422 if (isalpha((int)*p
)) {
423 *len
= strlen(strcpy(buf
, p
));
424 *is_negative
= FALSE
;
428 if (decimal_point
<= 0) {
432 while (decimal_point
++ < 0)
438 while (decimal_point
-- > 0) {
441 if (precision
> 0 || add_dp
) {
447 if (precision
> 0 || add_dp
)
452 * copy the rest of p, the NUL is NOT copied
458 char temp
[EXPONENT_LENGTH
]; /* for exponent conversion */
460 bool_int exponent_is_negative
;
462 *s
++ = format
; /* either e or E */
464 if (decimal_point
!= 0) {
465 p
= conv_10((wide_int
) decimal_point
, FALSE
, &exponent_is_negative
,
466 &temp
[EXPONENT_LENGTH
], &t_len
);
467 *s
++ = exponent_is_negative
? '-' : '+';
470 * Make sure the exponent has at least 2 digits
488 * Convert num to a base X number where X is a power of 2. nbits determines X.
489 * For example, if nbits is 3, we do base 8 conversion
491 * a pointer to a string containing the number
493 * The caller provides a buffer for the string: that is the buf_end argument
494 * which is a pointer to the END of the buffer + 1 (i.e. if the buffer
495 * is declared as buf[ 100 ], buf_end should be &buf[ 100 ])
498 conv_p2(register u_wide_int num
, register int nbits
,
499 char format
, char *buf_end
, register int *len
)
501 register int mask
= (1 << nbits
) - 1;
502 register char *p
= buf_end
;
503 static char low_digits
[] = "0123456789abcdef";
504 static char upper_digits
[] = "0123456789ABCDEF";
505 register char *digits
= (format
== 'X') ? upper_digits
: low_digits
;
508 *--p
= digits
[num
& mask
];
519 * Do format conversion placing the output in buffer
521 static int format_converter(register buffy
* odp
, const char *fmt
,
529 register char *s
= NULL
;
533 register int min_width
= 0;
542 wide_int i_num
= (wide_int
) 0;
545 char num_buf
[NUM_BUF_SIZE
];
546 char char_buf
[2]; /* for printing %% and %<unknown> */
552 boolean_e alternate_form
;
553 boolean_e print_sign
;
554 boolean_e print_blank
;
555 boolean_e adjust_precision
;
556 boolean_e adjust_width
;
557 bool_int is_negative
;
564 INS_CHAR(*fmt
, sp
, bep
, cc
);
567 * Default variable settings
570 alternate_form
= print_sign
= print_blank
= NO
;
577 * Try to avoid checking for flags, width or precision
579 if (isascii((int)*fmt
) && !islower((int)*fmt
)) {
581 * Recognize flags: -, #, BLANK, +
586 else if (*fmt
== '+')
588 else if (*fmt
== '#')
589 alternate_form
= YES
;
590 else if (*fmt
== ' ')
592 else if (*fmt
== '0')
599 * Check if a width was specified
601 if (isdigit((int)*fmt
)) {
602 STR_TO_DEC(fmt
, min_width
);
604 } else if (*fmt
== '*') {
605 min_width
= va_arg(ap
, int);
610 min_width
= -min_width
;
616 * Check if a precision was specified
618 * XXX: an unreasonable amount of precision may be specified
619 * resulting in overflow of num_buf. Currently we
620 * ignore this possibility.
623 adjust_precision
= YES
;
625 if (isdigit((int)*fmt
)) {
626 STR_TO_DEC(fmt
, precision
);
627 } else if (*fmt
== '*') {
628 precision
= va_arg(ap
, int);
635 adjust_precision
= NO
;
637 adjust_precision
= adjust_width
= NO
;
649 * Argument extraction and printing.
650 * First we determine the argument type.
651 * Then, we convert the argument to a string.
652 * On exit from the switch, s points to the string that
653 * must be printed, s_len has the length of the string
654 * The precision requirements, if any, are reflected in s_len.
656 * NOTE: pad_char may be set to '0' because of the 0 flag.
657 * It is reset to ' ' by non-numeric formats
662 i_num
= va_arg(ap
, u_wide_int
);
664 i_num
= (wide_int
) va_arg(ap
, unsigned int);
666 * The rest also applies to other integer formats, so fall
672 * Get the arg if we haven't already.
676 i_num
= va_arg(ap
, wide_int
);
678 i_num
= (wide_int
) va_arg(ap
, int);
680 s
= conv_10(i_num
, (*fmt
) == 'u', &is_negative
,
681 &num_buf
[NUM_BUF_SIZE
], &s_len
);
682 FIX_PRECISION(adjust_precision
, precision
, s
, s_len
);
689 else if (print_blank
)
697 ui_num
= va_arg(ap
, u_wide_int
);
699 ui_num
= (u_wide_int
) va_arg(ap
, unsigned int);
700 s
= conv_p2(ui_num
, 3, *fmt
,
701 &num_buf
[NUM_BUF_SIZE
], &s_len
);
702 FIX_PRECISION(adjust_precision
, precision
, s
, s_len
);
703 if (alternate_form
&& *s
!= '0') {
713 ui_num
= (u_wide_int
) va_arg(ap
, u_wide_int
);
715 ui_num
= (u_wide_int
) va_arg(ap
, unsigned int);
716 s
= conv_p2(ui_num
, 4, *fmt
,
717 &num_buf
[NUM_BUF_SIZE
], &s_len
);
718 FIX_PRECISION(adjust_precision
, precision
, s
, s_len
);
719 if (alternate_form
&& i_num
!= 0) {
720 *--s
= *fmt
; /* 'x' or 'X' */
728 s
= va_arg(ap
, char *);
731 if (adjust_precision
&& precision
< s_len
)
744 fp_num
= va_arg(ap
, double);
746 s
= conv_fp(*fmt
, fp_num
, alternate_form
,
747 (adjust_precision
== NO
) ? FLOAT_DIGITS
: precision
,
748 &is_negative
, &num_buf
[1], &s_len
);
753 else if (print_blank
)
760 if (adjust_precision
== NO
)
761 precision
= FLOAT_DIGITS
;
762 else if (precision
== 0)
765 * * We use &num_buf[ 1 ], so that we have room for the sign
767 s
= ap_gcvt(va_arg(ap
, double), precision
, &num_buf
[1]);
772 else if (print_blank
)
777 if (alternate_form
&& (q
= strchr(s
, '.')) == NULL
)
779 if (*fmt
== 'G' && (q
= strchr(s
, 'e')) != NULL
)
785 char_buf
[0] = (char) (va_arg(ap
, int));
801 *(va_arg(ap
, int *)) = cc
;
805 * Always extract the argument as a "char *" pointer. We
806 * should be using "void *" but there are still machines
807 * that don't understand it.
808 * If the pointer size is equal to the size of an unsigned
809 * integer we convert the pointer to a hex number, otherwise
810 * we print "%p" to indicate that we don't handle "%p".
813 ui_num
= (u_wide_int
) va_arg(ap
, char *);
815 if (sizeof(char *) <= sizeof(u_wide_int
))
816 s
= conv_p2(ui_num
, 4, 'x',
817 &num_buf
[NUM_BUF_SIZE
], &s_len
);
828 * The last character of the format string was %.
835 * The default case is for unrecognized %'s.
836 * We print %<char> to help the user identify what
837 * option is not understood.
838 * This is also useful in case the user wants to pass
839 * the output of format_converter to another function
840 * that understands some other %<char> (like syslog).
841 * Note that we can't point s inside fmt because the
842 * unknown <char> could be preceded by width etc.
853 if (prefix_char
!= NUL
) {
857 if (adjust_width
&& adjust
== RIGHT
&& min_width
> s_len
) {
858 if (pad_char
== '0' && prefix_char
!= NUL
) {
859 INS_CHAR(*s
, sp
, bep
, cc
)
864 PAD(min_width
, s_len
, pad_char
);
867 * Print the string s.
869 for (i
= s_len
; i
!= 0; i
--) {
870 INS_CHAR(*s
, sp
, bep
, cc
);
874 if (adjust_width
&& adjust
== LEFT
&& min_width
> s_len
)
875 PAD(min_width
, s_len
, pad_char
);
885 * This is the general purpose conversion function.
887 static void strx_printv(int *ccp
, char *buf
, size_t len
, const char *format
,
894 * First initialize the descriptor
895 * Notice that if no length is given, we initialize buf_end to the
896 * highest possible address.
898 od
.buf_end
= len
? &buf
[len
] : (char *) ~0;
904 cc
= format_converter(&od
, format
, ap
);
905 if (len
== 0 || od
.nextb
<= od
.buf_end
)
912 int ap_snprintf(char *buf
, size_t len
, const char *format
,...)
917 va_start(ap
, format
);
918 strx_printv(&cc
, buf
, (len
- 1), format
, ap
);
924 int ap_vsnprintf(char *buf
, size_t len
, const char *format
, va_list ap
)
928 strx_printv(&cc
, buf
, (len
- 1), format
, ap
);
932 #endif /* HAVE_SNPRINTF */