#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
*
*/
#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_NR(xbuf, ch) do { \
+ smart_str_appendc(xbuf, ch); \
+} while (0)
-#define INS_CHAR(xbuf, ch, cc) \
- xbuf_resize(xbuf, 1); \
- INS_CHAR_NR(xbuf, ch, cc)
+#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++); \
- }
+#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
* 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;
while (*fmt) {
if (*fmt != '%') {
- INS_CHAR(xbuf, *fmt, cc);
+ INS_CHAR(xbuf, *fmt);
} else {
/*
* Default variable settings
case 'n':
- *(va_arg(ap, int *)) = cc;
+ *(va_arg(ap, int *)) = xbuf->len;
break;
/*
}
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;
}
*/
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;
}