Markus, here is a patch against the current CVS which
- trims +100 lines of code from spprintf.c - introduces an overflow detection in STR_TO_DEC - eliminates dead code (e.g. assert(foo); if (foo) {..}) - removes unused macros from the original code - simplifies code (e.g. cc was completely dropped) - improves run-time performance The max_len feature is never used in our code base. Nevertheless, cpu cycles were spent on each string operation to check the current length against max_len which is quite inefficient. Thus, I've moved the check to vspprintf where it is applied only once per call. - Sascha
Index: spprintf.c =================================================================== RCS file: /repository/php4/main/spprintf.c,v retrieving revision 1.12 diff -u -r1.12 spprintf.c --- spprintf.c 11 Feb 2003 20:30:37 -0000 1.12 +++ spprintf.c 11 Feb 2003 22:43:10 -0000 @@ -89,6 +89,8 @@ #define FLOAT_DIGITS 6 #define EXPONENT_LENGTH 10 +#include "ext/standard/php_smart_str.h" + /* * NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions * @@ -96,134 +98,48 @@ */ #define NUM_BUF_SIZE 512 - -/* - * Size for realloc operations - */ -#define SPPRINTF_BLOCK_SIZE 128 - -/* - * 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 void xbuf_resize(xbuffy *xbuf, size_t add) -{ - char *buf; - size_t size, offset; - - if (xbuf->buf) { - offset = xbuf->nextb - xbuf->buf; - if (offset+add < xbuf->size) { - return; /* 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; - } - - buf = erealloc(xbuf->buf, size+1); /* alloc space for NUL */ - - if (buf) { - xbuf->buf = buf; - xbuf->buf_end = xbuf->max_len ? &buf[size] : (char *) ~0; - xbuf->nextb = buf+offset; - xbuf->size = size; - } -} - -/* Initialise xbuffy with size spprintf_BLOCK_SIZE - */ -static char * xbuf_init(xbuffy *xbuf, size_t max_len) -{ - xbuf->buf = NULL; - xbuf->size = 0; - xbuf->max_len = max_len; - xbuf_resize(xbuf, 0); /* NOT max_len */ - return xbuf->buf; -} - /* - * 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. + * The INS_CHAR macro inserts a character in the buffer. * - * NOTE: Evaluation of the c argument should not have any side-effects + * NOTE: Evaluation of the ch 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_STRING(xbuf, s, slen, cc) \ - xbuf_resize(xbuf, s_len); \ - if (xbuf->nextb+slen < xbuf->buf_end) { \ - memcpy(xbuf->nextb, s, slen); \ - xbuf->nextb += slen; \ - cc += slen; \ - s += slen; \ - } else { \ - for (i = s_len; i != 0; i--) { \ - INS_CHAR_NR(xbuf, *s, cc); \ - s++; \ - } \ - } - -#define INS_CHAR(xbuf, ch, cc) \ - xbuf_resize(xbuf, 1); \ - INS_CHAR_NR(xbuf, ch, cc) +#define INS_CHAR_NR(xbuf, ch) do { \ + smart_str_appendc(xbuf, ch); \ +} while (0) + +#define INS_STRING(xbuf, s, slen) do { \ + smart_str_appendl(xbuf, s, slen); \ +} while (0) + +#define INS_CHAR(xbuf, ch) \ + INS_CHAR_NR(xbuf, ch) /* * Macro that does padding. The padding is done by printing * the character ch. */ -#define PAD(xbuf, width, len, ch, cc) \ - if (width > len) { \ - int slen = width-len; \ - xbuf_resize(xbuf, slen); \ - if (xbuf->nextb+slen < xbuf->buf_end) { \ - memset(xbuf->nextb, ch, slen);\ - xbuf->nextb += slen; \ - cc += slen; \ - } else { \ - do { \ - INS_CHAR_NR(xbuf, ch, cc); \ - width--; \ - } \ - while (width > len); \ - } \ - } +#define PAD(xbuf, count, ch) do { \ + if ((count) > 0) { \ + size_t newlen; + \ + smart_str_alloc(xbuf, (count), 0); \ + memset(xbuf->c + xbuf->len, ch, (count)); \ + } + \ +} while (0) #define NUM(c) (c - '0') -#define STR_TO_DEC(str, num) \ - num = NUM(*str++); \ - while (isdigit((int)*str)) { \ - num *= 10; \ - num += NUM(*str++); \ - } +/* XXX: Does not handle overflow. */ +#define STR_TO_DEC(str, num) do { \ + num = NUM(*str++); \ + while (isdigit((int)*str)) { \ + num *= 10; \ + num += NUM(*str++); \ + if (num >= LONG_MAX / 10) { \ + while (isdigit((int)*str++)); \ + break; \ + } + \ + } \ +} while (0) /* * This macro does zero padding so that the precision @@ -231,33 +147,21 @@ * 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 +#define FIX_PRECISION(adjust, precision, s, s_len) do { \ + if (adjust) \ + while (s_len < precision) { \ + *--s = '0'; \ + s_len++; \ + } + \ +} while (0) /* * Do format conversion placing the output in buffer */ -static int xbuf_format_converter(register xbuffy * xbuf, const char *fmt, va_list ap) +static void xbuf_format_converter(smart_str *xbuf, const char *fmt, va_list ap) { - register int cc = 0; - register int i; - register char *s = NULL; char *q; int s_len; @@ -290,7 +194,7 @@ while (*fmt) { if (*fmt != '%') { - INS_CHAR(xbuf, *fmt, cc); + INS_CHAR(xbuf, *fmt); } else { /* * Default variable settings @@ -536,7 +440,7 @@ case 'n': - *(va_arg(ap, int *)) = cc; + *(va_arg(ap, int *)) = xbuf->len; break; /* @@ -593,24 +497,24 @@ } if (adjust_width && adjust == RIGHT && min_width > s_len) { if (pad_char == '0' && prefix_char != NUL) { - INS_CHAR(xbuf, *s, cc) - s++; + INS_CHAR(xbuf, *s); + s++; s_len--; min_width--; } - PAD(xbuf, min_width, s_len, pad_char, cc); + PAD(xbuf, min_width - s_len, pad_char); } /* * Print the string s. */ - INS_STRING(xbuf, s, s_len, cc); + INS_STRING(xbuf, s, s_len); if (adjust_width && adjust == LEFT && min_width > s_len) - PAD(xbuf, min_width, s_len, pad_char, cc); + PAD(xbuf, min_width - s_len, pad_char); } fmt++; } - return (cc); + return; } @@ -619,34 +523,18 @@ */ PHPAPI int vspprintf(char **pbuf, size_t max_len, const char *format, va_list ap) { - xbuffy xbuf; - int cc; + smart_str xbuf = {0}; - 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)) { - if (pbuf) - *pbuf = NULL; - return 0; - } else { - /* - * Do the conversion - */ - cc = xbuf_format_converter(&xbuf, format, ap); - if (xbuf.nextb <= xbuf.buf_end) - *(xbuf.nextb) = '\0'; - else if (xbuf.size) - xbuf.buf[xbuf.size-1] = '\0'; - if (pbuf) - *pbuf = xbuf.buf; - else - efree(pbuf); - return cc; + xbuf_format_converter(&xbuf, format, ap); + + if (max_len && xbuf.len > max_len) { + xbuf.len = max_len; } + smart_str_0(&xbuf); + + *pbuf = xbuf.c; + + return xbuf.len; }
-- PHP Development Mailing List <http://www.php.net/> To unsubscribe, visit: http://www.php.net/unsub.php