1 /* ====================================================================
2 * Copyright (c) 1995-1997 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.
56 /* #include "conf.h" -- original line from the Apache distribution */
58 * These are what we need in Amanda.
64 #if !(defined(HAVE_SNPRINTF) && defined(HAVE_VSNPRINTF))
69 #include <sys/types.h>
85 * cvt.c - IEEE floating point formatting routines for FreeBSD
86 * from GNU libc-4.6.27
90 * ap_ecvt converts to decimal
91 * the number of digits is specified by ndigit
92 * decpt is set to the position of the decimal point
93 * sign is set to 0 for positive, 1 for negative
100 ap_cvt(double arg, int ndigits, int *decpt, int *sign, int eflag)
102 static char *ap_cvt(arg, ndigits, decpt, sign, eflag)
111 register char *p, *p1;
112 static char buf[NDIG];
114 if (ndigits >= NDIG - 1)
123 arg = modf(arg, &fi);
131 fj = modf(fi / 10, &fi);
132 *--p1 = (int) ((fj + .03) * 10) + '0';
135 while (p1 < &buf[NDIG])
139 while ((fj = arg * 10) < 1) {
152 while (p <= p1 && p < &buf[NDIG]) {
154 arg = modf(arg, &fj);
155 *p++ = (int) fj + '0';
157 if (p1 >= &buf[NDIG]) {
158 buf[NDIG - 1] = '\0';
183 ap_ecvt(double arg, int ndigits, int *decpt, int *sign)
185 static char *ap_ecvt(arg, ndigits, decpt, sign)
191 return (ap_cvt(arg, ndigits, decpt, sign, 1));
196 ap_fcvt(double arg, int ndigits, int *decpt, int *sign)
198 static char *ap_fcvt(arg, ndigits, decpt, sign)
204 return (ap_cvt(arg, ndigits, decpt, sign, 0));
208 * ap_gcvt - Floating output conversion to
209 * minimal length string
213 ap_gcvt(double number, int ndigit, char *buf)
215 static char *ap_gcvt(number, ndigit, buf)
221 register char *p1, *p2;
224 p1 = ap_ecvt(number, ndigit, &decpt, &sign);
228 for (i = ndigit - 1; i > 0 && p1[i] == '0'; i--)
230 if ((decpt >= 0 && decpt - ndigit > 4)
231 || (decpt < 0 && decpt < -3)) { /* use E-style */
235 for (i = 1; i < ndigit; i++)
245 *p2++ = decpt / 100 + '0';
247 *p2++ = (decpt % 100) / 10 + '0';
248 *p2++ = decpt % 10 + '0';
259 for (i = 1; i <= ndigit; i++) {
264 if (ndigit < decpt) {
265 while (ndigit++ < decpt)
276 #endif /* HAVE_CVT */
285 #define INT_NULL ((int *)0)
286 #define WIDE_INT long
288 typedef WIDE_INT wide_int;
289 typedef unsigned WIDE_INT u_wide_int;
290 typedef int bool_int;
292 #define S_NULL "(null)"
295 #define FLOAT_DIGITS 6
296 #define EXPONENT_LENGTH 10
299 * NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions
301 * XXX: this is a magic number; do not decrease it
303 #define NUM_BUF_SIZE 512
307 * Descriptor for buffer area
311 char *nextb; /* pointer to next byte to read/write */
314 typedef struct buf_area buffy;
317 * The INS_CHAR macro inserts a character in the buffer and writes
318 * the buffer back to disk if necessary
319 * It uses the char pointers sp and bep:
320 * sp points to the next available character in the buffer
321 * bep points to the end-of-buffer+1
322 * While using this macro, note that the nextb pointer is NOT updated.
324 * NOTE: Evaluation of the c argument should not have any side-effects
326 #define INS_CHAR( c, sp, bep, cc ) \
335 #define NUM( c ) ( c - '0' )
337 #define STR_TO_DEC( str, num ) \
338 num = NUM( *str++ ) ; \
339 while ( isdigit( *str ) ) \
342 num += NUM( *str++ ) ; \
346 * This macro does zero padding so that the precision
347 * requirement is satisfied. The padding is done by
348 * adding '0's to the left of the string that is going
351 #define FIX_PRECISION( adjust, precision, s, s_len ) \
353 while ( s_len < precision ) \
360 * Macro that does padding. The padding is done by printing
363 #define PAD( width, len, ch ) do \
365 INS_CHAR( ch, sp, bep, cc ) ; \
368 while ( width > len )
371 * Prefix the character ch to the string str
373 * Set the has_prefix flag
375 #define PREFIX( str, length, ch ) *--str = ch ; length++ ; has_prefix = YES
379 * Convert num to its decimal format.
381 * - a pointer to a string containing the number (no sign)
382 * - len contains the length of the string
383 * - is_negative is set to TRUE or FALSE depending on the sign
384 * of the number (always set to FALSE if is_unsigned is TRUE)
386 * The caller provides a buffer for the string: that is the buf_end argument
387 * which is a pointer to the END of the buffer + 1 (i.e. if the buffer
388 * is declared as buf[ 100 ], buf_end should be &buf[ 100 ])
392 conv_10(register wide_int num, register bool_int is_unsigned,
393 register bool_int * is_negative, char *buf_end, register int *len)
395 static char *conv_10(num, is_unsigned, is_negative, buf_end, len)
396 register wide_int num;
397 register bool_int is_unsigned;
398 register bool_int *is_negative;
402 register char *p = buf_end;
403 register u_wide_int magnitude;
406 magnitude = (u_wide_int) num;
407 *is_negative = FALSE;
410 *is_negative = (num < 0);
413 * On a 2's complement machine, negating the most negative integer
414 * results in a number that cannot be represented as a signed integer.
415 * Here is what we do to obtain the number's magnitude:
416 * a. add 1 to the number
417 * b. negate it (becomes positive)
418 * c. convert it to unsigned
422 wide_int t = num + 1;
424 magnitude = ((u_wide_int) - t) + 1;
427 magnitude = (u_wide_int) num;
431 * We use a do-while loop so that we write at least 1 digit
434 register u_wide_int new_magnitude = magnitude / 10;
436 *--p = magnitude - new_magnitude * 10 + '0';
437 magnitude = new_magnitude;
448 * Convert a floating point number to a string formats 'f', 'e' or 'E'.
449 * The result is placed in buf, and len denotes the length of the string
450 * The sign is returned in the is_negative argument (and is not placed
455 conv_fp(register char format, register double num,
456 boolean_e add_dp, int precision, bool_int * is_negative, char *buf, int *len)
458 static char *conv_fp(format, num, add_dp, precision, is_negative, buf, len)
459 register char format;
463 bool_int *is_negative;
467 register char *s = buf;
472 p = ap_fcvt(num, precision, &decimal_point, is_negative);
473 else /* either e or E format */
474 p = ap_ecvt(num, precision + 1, &decimal_point, is_negative);
477 * Check for Infinity and NaN
480 *len = strlen(strcpy(buf, p));
481 *is_negative = FALSE;
486 if (decimal_point <= 0) {
490 while (decimal_point++ < 0)
497 while (decimal_point-- > 0)
499 if (precision > 0 || add_dp)
504 if (precision > 0 || add_dp)
509 * copy the rest of p, the NUL is NOT copied
515 char temp[EXPONENT_LENGTH]; /* for exponent conversion */
517 bool_int exponent_is_negative;
519 *s++ = format; /* either e or E */
521 if (decimal_point != 0) {
522 p = conv_10((wide_int) decimal_point, FALSE, &exponent_is_negative,
523 &temp[EXPONENT_LENGTH], &t_len);
524 *s++ = exponent_is_negative ? '-' : '+';
527 * Make sure the exponent has at least 2 digits
547 * Convert num to a base X number where X is a power of 2. nbits determines X.
548 * For example, if nbits is 3, we do base 8 conversion
550 * a pointer to a string containing the number
552 * The caller provides a buffer for the string: that is the buf_end argument
553 * which is a pointer to the END of the buffer + 1 (i.e. if the buffer
554 * is declared as buf[ 100 ], buf_end should be &buf[ 100 ])
558 conv_p2(register u_wide_int num, register int nbits,
559 char format, char *buf_end, register int *len)
561 static char *conv_p2(num, nbits, format, buf_end, len)
562 register u_wide_int num;
568 register int mask = (1 << nbits) - 1;
569 register char *p = buf_end;
570 static char low_digits[] = "0123456789abcdef";
571 static char upper_digits[] = "0123456789ABCDEF";
572 register char *digits = (format == 'X') ? upper_digits : low_digits;
575 *--p = digits[num & mask];
586 * Do format conversion placing the output in buffer
589 static int format_converter(register buffy * odp, const char *fmt,
592 static int format_converter(odp, fmt, ap)
602 register char *s = NULL;
606 register int min_width = 0;
615 wide_int i_num = (wide_int) 0;
618 char num_buf[NUM_BUF_SIZE];
619 char char_buf[2]; /* for printing %% and %<unknown> */
625 boolean_e alternate_form;
626 boolean_e print_sign;
627 boolean_e print_blank;
628 boolean_e adjust_precision;
629 boolean_e adjust_width;
630 bool_int is_negative;
637 INS_CHAR(*fmt, sp, bep, cc);
641 * Default variable settings
644 alternate_form = print_sign = print_blank = NO;
651 * Try to avoid checking for flags, width or precision
653 if (isascii(*fmt) && !islower(*fmt)) {
655 * Recognize flags: -, #, BLANK, +
660 else if (*fmt == '+')
662 else if (*fmt == '#')
663 alternate_form = YES;
664 else if (*fmt == ' ')
666 else if (*fmt == '0')
673 * Check if a width was specified
676 STR_TO_DEC(fmt, min_width);
679 else if (*fmt == '*') {
680 min_width = arglist_val(ap, int);
685 min_width = -min_width;
692 * Check if a precision was specified
694 * XXX: an unreasonable amount of precision may be specified
695 * resulting in overflow of num_buf. Currently we
696 * ignore this possibility.
699 adjust_precision = YES;
702 STR_TO_DEC(fmt, precision);
704 else if (*fmt == '*') {
705 precision = arglist_val(ap, int);
714 adjust_precision = NO;
717 adjust_precision = adjust_width = NO;
730 * Argument extraction and printing.
731 * First we determine the argument type.
732 * Then, we convert the argument to a string.
733 * On exit from the switch, s points to the string that
734 * must be printed, s_len has the length of the string
735 * The precision requirements, if any, are reflected in s_len.
737 * NOTE: pad_char may be set to '0' because of the 0 flag.
738 * It is reset to ' ' by non-numeric formats
743 i_num = arglist_val(ap, u_wide_int);
745 i_num = (wide_int) arglist_val(ap, unsigned int);
747 * The rest also applies to other integer formats, so fall
753 * Get the arg if we haven't already.
757 i_num = arglist_val(ap, wide_int);
759 i_num = (wide_int) arglist_val(ap, int);
761 s = conv_10(i_num, (*fmt) == 'u', &is_negative,
762 &num_buf[NUM_BUF_SIZE], &s_len);
763 FIX_PRECISION(adjust_precision, precision, s, s_len);
770 else if (print_blank)
778 ui_num = arglist_val(ap, u_wide_int);
780 ui_num = (u_wide_int) arglist_val(ap, unsigned int);
781 s = conv_p2(ui_num, 3, *fmt,
782 &num_buf[NUM_BUF_SIZE], &s_len);
783 FIX_PRECISION(adjust_precision, precision, s, s_len);
784 if (alternate_form && *s != '0') {
794 ui_num = (u_wide_int) arglist_val(ap, u_wide_int);
796 ui_num = (u_wide_int) arglist_val(ap, unsigned int);
797 s = conv_p2(ui_num, 4, *fmt,
798 &num_buf[NUM_BUF_SIZE], &s_len);
799 FIX_PRECISION(adjust_precision, precision, s, s_len);
800 if (alternate_form && i_num != 0) {
801 *--s = *fmt; /* 'x' or 'X' */
809 s = arglist_val(ap, char *);
812 if (adjust_precision && precision < s_len)
826 fp_num = arglist_val(ap, double);
828 s = conv_fp(*fmt, fp_num, alternate_form,
829 (adjust_precision == NO) ? FLOAT_DIGITS : precision,
830 &is_negative, &num_buf[1], &s_len);
835 else if (print_blank)
842 if (adjust_precision == NO)
843 precision = FLOAT_DIGITS;
844 else if (precision == 0)
847 * * We use &num_buf[ 1 ], so that we have room for the sign
849 s = ap_gcvt(arglist_val(ap, double), precision, &num_buf[1]);
854 else if (print_blank)
859 if (alternate_form && (q = strchr(s, '.')) == NULL)
861 if (*fmt == 'G' && (q = strchr(s, 'e')) != NULL)
867 char_buf[0] = (char) (arglist_val(ap, int));
883 *(arglist_val(ap, int *)) = cc;
887 * Always extract the argument as a "char *" pointer. We
888 * should be using "void *" but there are still machines
889 * that don't understand it.
890 * If the pointer size is equal to the size of an unsigned
891 * integer we convert the pointer to a hex number, otherwise
892 * we print "%p" to indicate that we don't handle "%p".
895 ui_num = (u_wide_int) arglist_val(ap, char *);
897 if (sizeof(char *) <= sizeof(u_wide_int))
898 s = conv_p2(ui_num, 4, 'x',
899 &num_buf[NUM_BUF_SIZE], &s_len);
910 * The last character of the format string was %.
917 * The default case is for unrecognized %'s.
918 * We print %<char> to help the user identify what
919 * option is not understood.
920 * This is also useful in case the user wants to pass
921 * the output of format_converter to another function
922 * that understands some other %<char> (like syslog).
923 * Note that we can't point s inside fmt because the
924 * unknown <char> could be preceded by width etc.
935 if (prefix_char != NUL) {
940 if (adjust_width && adjust == RIGHT && min_width > s_len) {
941 if (pad_char == '0' && prefix_char != NUL) {
942 INS_CHAR(*s, sp, bep, cc)
947 PAD(min_width, s_len, pad_char);
951 * Print the string s.
953 for (i = s_len; i != 0; i--) {
954 INS_CHAR(*s, sp, bep, cc);
958 if (adjust_width && adjust == LEFT && min_width > s_len)
959 PAD(min_width, s_len, pad_char);
969 * This is the general purpose conversion function.
972 static void strx_printv(int *ccp, char *buf, size_t len, const char *format,
975 static void strx_printv(ccp, buf, len, format, ap)
986 * First initialize the descriptor
987 * Notice that if no length is given, we initialize buf_end to the
988 * highest possible address.
990 od.buf_end = len ? &buf[len] : (char *) ~0;
996 cc = format_converter(&od, format, ap);
997 if (len == 0 || od.nextb <= od.buf_end)
1005 int snprintf(char *buf, size_t len, const char *format,...)
1007 printf_arglist_function2(int snprintf,
1010 const char *, format)
1015 arglist_start(ap, format);
1016 strx_printv(&cc, buf, (len - 1), format, ap);
1023 int vsnprintf(char *buf, size_t len, const char *format, va_list ap)
1025 int vsnprintf(buf, len, format, ap)
1033 strx_printv(&cc, buf, (len - 1), format, ap);
1037 #endif /* HAVE_SNPRINTF */