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

Reply via email to