- 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.
This commit is contained in:
Sascha Schumann 2003-02-12 19:38:10 +00:00
parent 8fee867865
commit 0cb1ff3bda

View file

@ -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,47 @@
*/
#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_CHAR_NR(xbuf, ch) do { \
smart_str_appendc(xbuf, ch); \
} while (0)
#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_STRING(xbuf, s, slen) do { \
smart_str_appendl(xbuf, s, slen); \
} while (0)
#define INS_CHAR(xbuf, ch, cc) \
xbuf_resize(xbuf, 1); \
INS_CHAR_NR(xbuf, ch, cc)
#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++); \
}
#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 +146,21 @@ static char * xbuf_init(xbuffy *xbuf, size_t max_len)
* 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 +193,7 @@ static int xbuf_format_converter(register xbuffy * xbuf, const char *fmt, va_lis
while (*fmt) {
if (*fmt != '%') {
INS_CHAR(xbuf, *fmt, cc);
INS_CHAR(xbuf, *fmt);
} else {
/*
* Default variable settings
@ -536,7 +439,7 @@ static int xbuf_format_converter(register xbuffy * xbuf, const char *fmt, va_lis
case 'n':
*(va_arg(ap, int *)) = cc;
*(va_arg(ap, int *)) = xbuf->len;
break;
/*
@ -593,24 +496,24 @@ static int xbuf_format_converter(register xbuffy * xbuf, const char *fmt, va_lis
}
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 +522,18 @@ static int xbuf_format_converter(register xbuffy * xbuf, const char *fmt, va_lis
*/
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;
}