--- /dev/null
+
+/* $Id$ */
+
+#include "php.h"
+#include "phpstr.h"
+
+#ifndef PHPSTR_DEFAULT_SIZE
+#define PHPSTR_DEFAULT_SIZE 4096
+#endif
+
+PHPSTR_API phpstr *phpstr_init_ex(phpstr *buf, size_t chunk_size, zend_bool pre_alloc)
+{
+ if (!buf) {
+ buf = ecalloc(1, sizeof(phpstr));
+ }
+
+ buf->used = 0;
+ buf->size = chunk_size > 0 ? chunk_size : PHPSTR_DEFAULT_SIZE;
+ buf->free = pre_alloc ? buf->size : 0;
+ buf->data = pre_alloc ? emalloc(buf->size) : NULL;
+
+ return buf;
+}
+
+PHPSTR_API phpstr *phpstr_from_string_ex(phpstr *buf, char *string, size_t length)
+{
+ buf = phpstr_init(buf);
+ phpstr_append(buf, string, length);
+ return buf;
+}
+
+PHPSTR_API void phpstr_resize_ex(phpstr *buf, size_t len, size_t override_size)
+{
+ if (buf->free < len) {
+ size_t size = override_size ? override_size : buf->size;
+ while ((size + buf->free) < len) {
+ size *= 2;
+ }
+ if (buf->data) {
+ buf->data = erealloc(buf->data, buf->used + buf->free + size);
+ } else {
+ buf->data = emalloc(size);
+ }
+ buf->free += size;
+ }
+}
+
+PHPSTR_API void phpstr_append(phpstr *buf, const char *append, size_t append_len)
+{
+ phpstr_resize(buf, append_len);
+ memcpy(buf->data + buf->used, append, append_len);
+ buf->used += append_len;
+ buf->free -= append_len;
+}
+
+PHPSTR_API size_t phpstr_appendf(phpstr *buf, const char *format, ...)
+{
+ va_list argv;
+ char *append;
+ size_t append_len;
+
+ va_start(argv, format);
+ append_len = vspprintf(&append, 0, format, argv);
+ va_end(argv);
+
+ phpstr_append(buf, append, append_len);
+ efree(append);
+
+ return append_len;
+}
+
+PHPSTR_API void phpstr_insert(phpstr *buf, const char *insert, size_t insert_len, size_t offset)
+{
+ phpstr_resize(buf, insert_len);
+ memmove(buf->data + offset + insert_len, buf->data + offset, insert_len);
+ memcpy(buf->data + offset, insert, insert_len);
+ buf->used += insert_len;
+ buf->free -= insert_len;
+}
+
+PHPSTR_API size_t phpstr_insertf(phpstr *buf, size_t offset, const char *format, ...)
+{
+ va_list argv;
+ char *insert;
+ size_t insert_len;
+
+ va_start(argv, format);
+ insert_len = vspprintf(&insert, 0, format, argv);
+ va_end(argv);
+
+ phpstr_insert(buf, insert, insert_len, offset);
+ efree(insert);
+
+ return insert_len;
+}
+
+PHPSTR_API void phpstr_prepend(phpstr *buf, const char *prepend, size_t prepend_len)
+{
+ phpstr_resize(buf, prepend_len);
+ memmove(buf->data + prepend_len, buf->data, buf->used);
+ memcpy(buf->data, prepend, prepend_len);
+ buf->used += prepend_len;
+ buf->free -= prepend_len;
+}
+
+PHPSTR_API size_t phpstr_prependf(phpstr *buf, const char *format, ...)
+{
+ va_list argv;
+ char *prepend;
+ size_t prepend_len;
+
+ va_start(argv, format);
+ prepend_len = vspprintf(&prepend, 0, format, argv);
+ va_end(argv);
+
+ phpstr_prepend(buf, prepend, prepend_len);
+ efree(prepend);
+
+ return prepend_len;
+}
+
+PHPSTR_API char *phpstr_data(const phpstr *buf, char **into, size_t *len)
+{
+ char *copy = ecalloc(1, buf->used + 1);
+ memcpy(copy, buf->data, buf->used);
+ if (into) {
+ *into = copy;
+ }
+ if (len) {
+ *len = buf->used;
+ }
+ return copy;
+}
+
+PHPSTR_API phpstr *phpstr_dup(const phpstr *buf)
+{
+ phpstr *dup = phpstr_clone(buf);
+ phpstr_append(dup, buf->data, buf->used);
+ return dup;
+}
+
+PHPSTR_API ssize_t phpstr_cut(phpstr *buf, size_t offset, size_t length)
+{
+ if (offset >= buf->used) {
+ return -1;
+ }
+ if (offset + length > buf->used) {
+ length = buf->used - offset;
+ }
+ memmove(buf->data + offset, buf->data + offset + length, buf->used - length);
+ buf->used -= length;
+ buf->free += length;
+ return length;
+}
+
+PHPSTR_API phpstr *phpstr_sub(const phpstr *buf, size_t offset, size_t length)
+{
+ if (offset >= buf->used) {
+ return NULL;
+ } else {
+ size_t need = (length + offset) > buf->used ? (buf->used - offset) : (length - offset);
+ phpstr *sub = phpstr_init_ex(NULL, need, 1);
+ phpstr_append(sub, buf->data + offset, need);
+ sub->size = buf->size;
+ return sub;
+ }
+}
+
+PHPSTR_API phpstr *phpstr_right(const phpstr *buf, size_t length)
+{
+ if (length < buf->used) {
+ return phpstr_sub(buf, buf->used - length, length);
+ } else {
+ return phpstr_sub(buf, 0, buf->used);
+ }
+}
+
+
+PHPSTR_API phpstr *phpstr_merge_va(phpstr *buf, unsigned argc, va_list argv)
+{
+ unsigned i = 0;
+ buf = phpstr_init(buf);
+
+ while (argc > i++) {
+ phpstr_free_t f = va_arg(argv, phpstr_free_t);
+ phpstr *current = va_arg(argv, phpstr *);
+ phpstr_append(buf, current->data, current->used);
+ FREE_PHPSTR(f, current);
+ }
+
+ return buf;
+}
+
+PHPSTR_API phpstr *phpstr_merge_ex(phpstr *buf, unsigned argc, ...)
+{
+ va_list argv;
+ phpstr *ret;
+
+ va_start(argv, argc);
+ ret = phpstr_merge_va(buf, argc, argv);
+ va_end(argv);
+ return ret;
+}
+
+PHPSTR_API phpstr *phpstr_merge(unsigned argc, ...)
+{
+ va_list argv;
+ phpstr *ret;
+
+ va_start(argv, argc);
+ ret = phpstr_merge_va(NULL, argc, argv);
+ va_end(argv);
+ return ret;
+}
+
+PHPSTR_API void phpstr_fix(phpstr *buf)
+{
+ phpstr_resize_ex(buf, 1, 1);
+ buf->data[buf->used] = '\0';
+}
+
+PHPSTR_API int phpstr_cmp(phpstr *left, phpstr *right)
+{
+ if (left->used > right->used) {
+ return -1;
+ } else if (right->used > left->used) {
+ return 1;
+ } else {
+ return memcmp(left->data, right->data, left->used);
+ }
+}
+
+PHPSTR_API void phpstr_free(phpstr *buf)
+{
+ if (buf->data) {
+ efree(buf->data);
+ buf->data = NULL;
+ }
+ buf->used = 0;
+ buf->free = 0;
+}
+
+PHPSTR_API void phpstr_dtor(phpstr *buf)
+{
+ if (buf) {
+ phpstr_free(buf);
+ efree(buf);
+ }
+}
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: sw=4 ts=4 fdm=marker
+ * vim<600: sw=4 ts=4
+ */
+
--- /dev/null
+
+/* $Id$ */
+
+#ifndef _PHPSTR_H_
+#define _PHPSTR_H_
+
+#ifdef PHP_WIN32
+# define PHPSTR_API __declspec(dllexport)
+#else
+# define PHPSTR_API
+#endif
+
+#define FREE_PHPSTR_PTR(STR) phpstr_dtor(STR)
+#define FREE_PHPSTR_VAL(STR) phpstr_free(STR)
+#define FREE_PHPSTR(free, STR) \
+ switch (free) \
+ { \
+ case PHPSTR_FREE_VAL: phpstr_free(STR); break; \
+ case PHPSTR_FREE_PTR: phpstr_dtor(STR); break; \
+ case PHPSTR_FREE_NOT: break; \
+ default: break; \
+ }
+
+#define RETURN_PHPSTR_PTR(STR) RETURN_PHPSTR((STR), PHPSTR_FREE_PTR)
+#define RETURN_PHPSTR_VAL(STR) RETURN_PHPSTR((STR), PHPSTR_FREE_VAL)
+#define RETURN_PHPSTR(STR, free) \
+ RETVAL_PHPSTR((STR), (free)); \
+ return;
+
+#define RETVAL_PHPSTR_PTR(STR) RETVAL_PHPSTR((STR), PHPSTR_FREE_PTR)
+#define RETVAL_PHPSTR_VAL(STR) RETVAL_PHPSTR((STR), PHPSTR_FREE_VAL)
+#define RETVAL_PHPSTR(STR, free) \
+ phpstr_fix(STR); \
+ RETVAL_STRINGL((STR)->data, (STR)->used, 1); \
+ FREE_PHPSTR((free), (STR));
+
+struct _phpstr {
+ size_t size;
+ char *data;
+ size_t used;
+ size_t free;
+};
+typedef struct _phpstr phpstr;
+
+enum _phpstr_free {
+ PHPSTR_FREE_NOT = 0,
+ PHPSTR_FREE_VAL = 1, /* phpstr_free() */
+ PHPSTR_FREE_PTR = 2 /* phpstr_dtor() */
+};
+typedef enum _phpstr_free phpstr_free_t;
+
+#define PHPSTR_PTR_FREE(STR) PHPSTR_FREE_PTR,(STR)
+#define PHPSTR_VAL_FREE(STR) PHPSTR_FREE_VAL,(STR)
+#define PHPSTR_NOT_FREE(STR) PHPSTR_FREE_NOT,(STR)
+
+/* create a new phpstr */
+#define phpstr_new() phpstr_init(NULL)
+#define phpstr_init(b) phpstr_init_ex(b, 0, 0)
+#define phpstr_clone(phpstr_pointer) phpstr_init_ex(NULL, (phpstr_pointer)->size, 0)
+PHPSTR_API phpstr *phpstr_init_ex(phpstr *buf, size_t chunk_size, zend_bool pre_alloc);
+
+/* create a phpstr from a zval or c-string */
+#define phpstr_from_zval(z) phpstr_from_string(Z_STRVAL(z), Z_STRLEN(z))
+#define phpstr_from_zval_ex(b, z) phpstr_from_string_ex(b, Z_STRVAL(z), Z_STRLEN(z))
+#define phpstr_from_string(s, l) phpstr_from_string_ex(NULL, (s), (l))
+PHPSTR_API phpstr *phpstr_from_string_ex(phpstr *buf, char *string, size_t length);
+
+/* usually only called from within the internal functions */
+#define phpstr_resize(b, s) phpstr_resize_ex((b), (s), 0)
+PHPSTR_API void phpstr_resize_ex(phpstr *buf, size_t len, size_t override_size);
+
+/* append data to the phpstr */
+#define phpstr_appends(b, a) phpstr_append((b), (a), sizeof(a)-1)
+#define phpstr_appendl(b, a) phpstr_append((b), (a), strlen(a))
+PHPSTR_API void phpstr_append(phpstr *buf, const char *append, size_t append_len);
+PHPSTR_API size_t phpstr_appendf(phpstr *buf, const char *format, ...);
+
+/* insert data at a specific position of the phpstr */
+#define phpstr_inserts(b, i, o) phpstr_insert((b), (i), sizeof(i)-1, (o))
+#define phpstr_insertl(b, i, o) phpstr_insert((b), (i), strlen(i), (o))
+PHPSTR_API void phpstr_insert(phpstr *buf, const char *insert, size_t insert_len, size_t offset);
+PHPSTR_API size_t phpstr_insertf(phpstr *buf, size_t offset, const char *format, ...);
+
+/* prepend data */
+#define phpstr_prepends(b, p) phpstr_prepend((b), (p), sizeof(p)-1)
+#define phpstr_prependl(b, p) phpstr_prepend((b), (p), strlen(p))
+PHPSTR_API void phpstr_prepend(phpstr *buf, const char *prepend, size_t prepend_len);
+PHPSTR_API size_t phpstr_prependf(phpstr *buf, const char *format, ...);
+
+/* get a zero-terminated string */
+PHPSTR_API char *phpstr_data(const phpstr *buf, char **into, size_t *len);
+
+/* get a part of the phpstr */
+#define phpstr_mid(b, o, l) phpstr_sub((b), (o), (l))
+#define phpstr_left(b, l) phpstr_sub((b), 0, (l))
+PHPSTR_API phpstr *phpstr_right(const phpstr *buf, size_t length);
+PHPSTR_API phpstr *phpstr_sub(const phpstr *buf, size_t offset, size_t len);
+
+/* remove a substring */
+PHPSTR_API ssize_t phpstr_cut(phpstr *buf, size_t offset, size_t length);
+
+/* get a complete phpstr duplicate */
+PHPSTR_API phpstr *phpstr_dup(const phpstr *buf);
+
+/* merge several phpstr objects
+ use like:
+
+ phpstr *final = phpstr_merge(3,
+ PHPSTR_NOT_FREE(&keep),
+ PHPSTR_PTR_FREE(middle_ptr),
+ PHPSTR_VAL_FREE(&local);
+*/
+PHPSTR_API phpstr *phpstr_merge(unsigned argc, ...);
+PHPSTR_API phpstr *phpstr_merge_ex(phpstr *buf, unsigned argc, ...);
+PHPSTR_API phpstr *phpstr_merge_va(phpstr *buf, unsigned argc, va_list argv);
+
+/* sets a trailing NUL byte */
+PHPSTR_API void phpstr_fix(phpstr *buf);
+
+/* free a phpstr objects data (resets used and free) */
+PHPSTR_API void phpstr_free(phpstr *buf);
+
+/* free a phpstr object (calls phpstr_free, too) */
+#define phpstr_del(b) phpstr_dtor(b)
+PHPSTR_API void phpstr_dtor(phpstr *buf);
+
+#endif
+
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: sw=4 ts=4 fdm=marker
+ * vim<600: sw=4 ts=4
+ */
+