diff options
Diffstat (limited to 'main/spprintf.c')
-rw-r--r-- | main/spprintf.c | 654 |
1 files changed, 0 insertions, 654 deletions
diff --git a/main/spprintf.c b/main/spprintf.c deleted file mode 100644 index 1bda78d1c6..0000000000 --- a/main/spprintf.c +++ /dev/null @@ -1,654 +0,0 @@ -/* - +----------------------------------------------------------------------+ - | PHP Version 4 | - +----------------------------------------------------------------------+ - | Copyright (c) 1997-2002 The PHP Group | - +----------------------------------------------------------------------+ - | This source file is subject to version 2.02 of the PHP license, | - | that is bundled with this package in the file LICENSE, and is | - | available at through the world-wide-web at | - | http://www.php.net/license/2_02.txt. | - | If you did not receive a copy of the PHP license and are unable to | - | obtain it through the world-wide-web, please send a note to | - | license@php.net so we can mail you a copy immediately. | - +----------------------------------------------------------------------+ - | Author: Marcus Boerger <helly@php.net> | - +----------------------------------------------------------------------+ - */ - -/* This is the spprintf implementation. - * It has emerged from apache snprintf. See original header: - */ - -/* ==================================================================== - * Copyright (c) 1995-1998 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - * This code is based on, and used with the permission of, the - * SIO stdio-replacement strx_* functions by Panos Tsirigotis - * <panos@alumni.cs.colorado.edu> for xinetd. - */ - -#include "php.h" -#include "snprintf.h" - -#define FALSE 0 -#define TRUE 1 -#define NUL '\0' -#define INT_NULL ((int *)0) - -#define S_NULL "(null)" -#define S_NULL_LEN 6 - -#define FLOAT_DIGITS 6 -#define EXPONENT_LENGTH 10 - -/* - * NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions - * - * XXX: this is a magic number; do not decrease it - */ -#define NUM_BUF_SIZE 512 - - -/* - * Size for realloc operations - */ -#define SPPRINTF_BLOCK_SIZE 10 - -/* - * Descriptor for buffer area - */ -struct xbuf_area { - char *buf; /* pointer to buffer */ - size_t size; - size_t max_len; - char *buf_end; /* pointer to buffer end or ~0 */ - char *nextb; /* pointer to next byte to read/write */ -}; - -typedef struct xbuf_area xbuffy; - -/* Resize xbuf so that add bytes can be added. Reallocation is done - * in defined block size to minimize calls to realloc. - */ -static int xbuf_resize(xbuffy *xbuf, size_t add) -{ - char *buf; - int ret; - size_t size, offset; - - if (xbuf->buf) { - offset = xbuf->nextb - xbuf->buf; - if (offset+add < xbuf->size) { - return 0; /* do not change size if not necessary */ - } - } else { - offset = 0; - } - if (add<SPPRINTF_BLOCK_SIZE) { - size = xbuf->size + SPPRINTF_BLOCK_SIZE; - } else { - size = xbuf->size + add; - } - if (xbuf->max_len && size > xbuf->max_len) { - size = xbuf->max_len; - ret = 1; - } else { - ret = 0; - } - - buf = erealloc(xbuf->buf, size+1); /* alloc space for NUL */ - - if (!buf) { - return 1; - } else { - xbuf->buf = buf; - xbuf->buf_end = xbuf->max_len ? &buf[size] : (char *) ~0; - xbuf->nextb = buf+offset; - xbuf->size = size; - return ret; - } -} - -/* Initialise xbuffy with size spprintf_BLOCK_SIZE - */ -static int xbuf_init(xbuffy *xbuf, size_t max_len) -{ - xbuf->buf = NULL; - xbuf->size = 0; - xbuf->max_len = max_len; - return xbuf_resize(xbuf, 0); /* NOT max_len */ -} - -/* - * The INS_CHAR macro inserts a character in the buffer and writes - * the buffer back to disk if necessary - * It uses the char pointers sp and bep: - * sp points to the next available character in the buffer - * bep points to the end-of-buffer+1 - * While using this macro, note that the nextb pointer is NOT updated. - * - * NOTE: Evaluation of the c argument should not have any side-effects - */ -#define INS_CHAR_NR(xbuf, ch, cc) \ - if (xbuf->nextb < xbuf->buf_end) { \ - *(xbuf->nextb++) = ch; \ - cc++; \ - } - -#define INS_CHAR(xbuf, ch, cc) \ - xbuf_resize(xbuf, 1); \ - INS_CHAR_NR(xbuf, ch, cc) - -/* - * Macro that does padding. The padding is done by printing - * the character ch. - */ -#define PAD(xbuf, width, len, ch) \ - if (width > len) { \ - xbuf_resize(xbuf, width-len); \ - do { \ - INS_CHAR_NR(xbuf, ch, cc); \ - width--; \ - } \ - while (width > len);\ - } - -#define NUM(c) (c - '0') - -#define STR_TO_DEC(str, num) \ - num = NUM(*str++); \ - while (isdigit((int)*str)) { \ - num *= 10; \ - num += NUM(*str++); \ - } - -/* - * This macro does zero padding so that the precision - * requirement is satisfied. The padding is done by - * adding '0's to the left of the string that is going - * to be printed. - */ -#define FIX_PRECISION(adjust, precision, s, s_len) \ - if (adjust) \ - while (s_len < precision) { \ - *--s = '0'; \ - s_len++; \ - } - -/* - * Prefix the character ch to the string str - * Increase length - * Set the has_prefix flag - */ -#define PREFIX(str, length, ch) \ - *--str = ch; \ - length++; \ - has_prefix = YES - - - -/* - * Do format conversion placing the output in buffer - */ -static int xbuf_format_converter(register xbuffy * xbuf, const char *fmt, va_list ap) -{ - register int cc = 0; - register int i; - - register char *s = NULL; - char *q; - int s_len; - - register int min_width = 0; - int precision = 0; - enum { - LEFT, RIGHT - } adjust; - char pad_char; - char prefix_char; - - double fp_num; - wide_int i_num = (wide_int) 0; - u_wide_int ui_num; - - char num_buf[NUM_BUF_SIZE]; - char char_buf[2]; /* for printing %% and %<unknown> */ - - /* - * Flag variables - */ - boolean_e is_long; - boolean_e alternate_form; - boolean_e print_sign; - boolean_e print_blank; - boolean_e adjust_precision; - boolean_e adjust_width; - bool_int is_negative; - - while (*fmt) { - if (*fmt != '%') { - INS_CHAR(xbuf, *fmt, cc); - } else { - /* - * Default variable settings - */ - adjust = RIGHT; - alternate_form = print_sign = print_blank = NO; - pad_char = ' '; - prefix_char = NUL; - - fmt++; - - /* - * Try to avoid checking for flags, width or precision - */ - if (isascii((int)*fmt) && !islower((int)*fmt)) { - /* - * Recognize flags: -, #, BLANK, + - */ - for (;; fmt++) { - if (*fmt == '-') - adjust = LEFT; - else if (*fmt == '+') - print_sign = YES; - else if (*fmt == '#') - alternate_form = YES; - else if (*fmt == ' ') - print_blank = YES; - else if (*fmt == '0') - pad_char = '0'; - else - break; - } - - /* - * Check if a width was specified - */ - if (isdigit((int)*fmt)) { - STR_TO_DEC(fmt, min_width); - adjust_width = YES; - } else if (*fmt == '*') { - min_width = va_arg(ap, int); - fmt++; - adjust_width = YES; - if (min_width < 0) { - adjust = LEFT; - min_width = -min_width; - } - } else - adjust_width = NO; - - /* - * Check if a precision was specified - * - * XXX: an unreasonable amount of precision may be specified - * resulting in overflow of num_buf. Currently we - * ignore this possibility. - */ - if (*fmt == '.') { - adjust_precision = YES; - fmt++; - if (isdigit((int)*fmt)) { - STR_TO_DEC(fmt, precision); - } else if (*fmt == '*') { - precision = va_arg(ap, int); - fmt++; - if (precision < 0) - precision = 0; - } else - precision = 0; - } else - adjust_precision = NO; - } else - adjust_precision = adjust_width = NO; - - /* - * Modifier check - */ - if (*fmt == 'l') { - is_long = YES; - fmt++; - } else - is_long = NO; - - /* - * Argument extraction and printing. - * First we determine the argument type. - * Then, we convert the argument to a string. - * On exit from the switch, s points to the string that - * must be printed, s_len has the length of the string - * The precision requirements, if any, are reflected in s_len. - * - * NOTE: pad_char may be set to '0' because of the 0 flag. - * It is reset to ' ' by non-numeric formats - */ - switch (*fmt) { - case 'u': - if (is_long) - i_num = va_arg(ap, u_wide_int); - else - i_num = (wide_int) va_arg(ap, unsigned int); - /* - * The rest also applies to other integer formats, so fall - * into that case. - */ - case 'd': - case 'i': - /* - * Get the arg if we haven't already. - */ - if ((*fmt) != 'u') { - if (is_long) - i_num = va_arg(ap, wide_int); - else - i_num = (wide_int) va_arg(ap, int); - }; - s = ap_php_conv_10(i_num, (*fmt) == 'u', &is_negative, - &num_buf[NUM_BUF_SIZE], &s_len); - FIX_PRECISION(adjust_precision, precision, s, s_len); - - if (*fmt != 'u') { - if (is_negative) - prefix_char = '-'; - else if (print_sign) - prefix_char = '+'; - else if (print_blank) - prefix_char = ' '; - } - break; - - - case 'o': - if (is_long) - ui_num = va_arg(ap, u_wide_int); - else - ui_num = (u_wide_int) va_arg(ap, unsigned int); - s = ap_php_conv_p2(ui_num, 3, *fmt, - &num_buf[NUM_BUF_SIZE], &s_len); - FIX_PRECISION(adjust_precision, precision, s, s_len); - if (alternate_form && *s != '0') { - *--s = '0'; - s_len++; - } - break; - - - case 'x': - case 'X': - if (is_long) - ui_num = (u_wide_int) va_arg(ap, u_wide_int); - else - ui_num = (u_wide_int) va_arg(ap, unsigned int); - s = ap_php_conv_p2(ui_num, 4, *fmt, - &num_buf[NUM_BUF_SIZE], &s_len); - FIX_PRECISION(adjust_precision, precision, s, s_len); - if (alternate_form && i_num != 0) { - *--s = *fmt; /* 'x' or 'X' */ - *--s = '0'; - s_len += 2; - } - break; - - - case 's': - s = va_arg(ap, char *); - if (s != NULL) { - s_len = strlen(s); - if (adjust_precision && precision < s_len) - s_len = precision; - } else { - s = S_NULL; - s_len = S_NULL_LEN; - } - pad_char = ' '; - break; - - - case 'f': - case 'e': - case 'E': - fp_num = va_arg(ap, double); - - if (zend_isnan(fp_num)) { - s = "nan"; - s_len = 3; - } else if (zend_isinf(fp_num)) { - s = "inf"; - s_len = 3; - } else { - s = ap_php_conv_fp(*fmt, fp_num, alternate_form, - (adjust_precision == NO) ? FLOAT_DIGITS : precision, - &is_negative, &num_buf[1], &s_len); - if (is_negative) - prefix_char = '-'; - else if (print_sign) - prefix_char = '+'; - else if (print_blank) - prefix_char = ' '; - } - break; - - - case 'g': - case 'G': - if (adjust_precision == NO) - precision = FLOAT_DIGITS; - else if (precision == 0) - precision = 1; - /* - * * We use &num_buf[ 1 ], so that we have room for the sign - */ - s = ap_php_gcvt(va_arg(ap, double), precision, &num_buf[1], - alternate_form); - if (*s == '-') - prefix_char = *s++; - else if (print_sign) - prefix_char = '+'; - else if (print_blank) - prefix_char = ' '; - - s_len = strlen(s); - - if (alternate_form && (q = strchr(s, '.')) == NULL) - s[s_len++] = '.'; - if (*fmt == 'G' && (q = strchr(s, 'e')) != NULL) - *q = 'E'; - break; - - - case 'c': - char_buf[0] = (char) (va_arg(ap, int)); - s = &char_buf[0]; - s_len = 1; - pad_char = ' '; - break; - - - case '%': - char_buf[0] = '%'; - s = &char_buf[0]; - s_len = 1; - pad_char = ' '; - break; - - - case 'n': - *(va_arg(ap, int *)) = cc; - break; - - /* - * Always extract the argument as a "char *" pointer. We - * should be using "void *" but there are still machines - * that don't understand it. - * If the pointer size is equal to the size of an unsigned - * integer we convert the pointer to a hex number, otherwise - * we print "%p" to indicate that we don't handle "%p". - */ - case 'p': - ui_num = (u_wide_int) va_arg(ap, char *); - - if (sizeof(char *) <= sizeof(u_wide_int)) - s = ap_php_conv_p2(ui_num, 4, 'x', &num_buf[NUM_BUF_SIZE], &s_len); - else { - s = "%p"; - s_len = 2; - } - pad_char = ' '; - break; - - - case NUL: - /* - * The last character of the format string was %. - * We ignore it. - */ - continue; - - - /* - * The default case is for unrecognized %'s. - * We print %<char> to help the user identify what - * option is not understood. - * This is also useful in case the user wants to pass - * the output of format_converter to another function - * that understands some other %<char> (like syslog). - * Note that we can't point s inside fmt because the - * unknown <char> could be preceded by width etc. - */ - default: - char_buf[0] = '%'; - char_buf[1] = *fmt; - s = char_buf; - s_len = 2; - pad_char = ' '; - break; - } - - if (prefix_char != NUL) { - *--s = prefix_char; - s_len++; - } - if (adjust_width && adjust == RIGHT && min_width > s_len) { - if (pad_char == '0' && prefix_char != NUL) { - INS_CHAR(xbuf, *s, cc) - s++; - s_len--; - min_width--; - } - PAD(xbuf, min_width, s_len, pad_char); - } - /* - * Print the string s. - */ - xbuf_resize(xbuf, s_len); - for (i = s_len; i != 0; i--) { - INS_CHAR_NR(xbuf, *s, cc); - s++; - } - - if (adjust_width && adjust == LEFT && min_width > s_len) - PAD(xbuf, min_width, s_len, pad_char); - } - fmt++; - } - return (cc); -} - - -/* - * This is the general purpose conversion function. - */ -PHPAPI int vspprintf(char **pbuf, size_t max_len, const char *format, va_list ap) -{ - xbuffy xbuf; - int cc; - - assert(pbuf != NULL); - /* - * First initialize the descriptor - * Notice that if no length is given, we initialize buf_end to the - * highest possible address. - */ - if (xbuf_init(&xbuf, max_len)) { - *pbuf = NULL; - return 0; - } else { - /* - * Do the conversion - */ - cc = xbuf_format_converter(&xbuf, format, ap); - if (xbuf.nextb <= xbuf.buf_end) - *(xbuf.nextb) = '\0'; - *pbuf = xbuf.buf; - return cc; - } -} - - -int spprintf(char **pbuf, size_t max_len, const char *format, ...) -{ - int cc; - va_list ap; - - va_start(ap, format); - cc = vspprintf(pbuf, max_len, format, ap); - va_end(ap); - return (cc); -} - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: sw=4 ts=4 fdm=marker - * vim<600: sw=4 ts=4 - */ |