#include "php.h"
#include "phpstr.h"
-PHPSTR_API phpstr *phpstr_init_ex(phpstr *buf, size_t chunk_size, int pre_alloc)
+#define NOMEM ((size_t) -1)
+
+PHPSTR_API phpstr *phpstr_init_ex(phpstr *buf, size_t chunk_size, int flags)
{
if (!buf) {
- buf = emalloc(sizeof(phpstr));
+ buf = pemalloc(sizeof(phpstr), flags & PHPSTR_INIT_PERSISTENT);
}
- buf->size = chunk_size > 0 ? chunk_size : PHPSTR_DEFAULT_SIZE;
- buf->data = pre_alloc ? emalloc(buf->size) : NULL;
- buf->free = pre_alloc ? buf->size : 0;
- buf->used = 0;
-
+ if (buf) {
+ buf->size = (chunk_size > 0) ? chunk_size : PHPSTR_DEFAULT_SIZE;
+ buf->pmem = (flags & PHPSTR_INIT_PERSISTENT) ? 1 : 0;
+ buf->data = (flags & PHPSTR_INIT_PREALLOC) ? pemalloc(buf->size, buf->pmem) : NULL;
+ buf->free = (flags & PHPSTR_INIT_PREALLOC) ? buf->size : 0;
+ buf->used = 0;
+ }
+
return buf;
}
PHPSTR_API phpstr *phpstr_from_string_ex(phpstr *buf, const char *string, size_t length)
{
- buf = phpstr_init(buf);
- phpstr_append(buf, string, length);
+ if (buf = phpstr_init(buf)) {
+ if (NOMEM == phpstr_append(buf, string, length)) {
+ pefree(buf, buf->pmem);
+ buf = NULL;
+ }
+ }
return buf;
}
-PHPSTR_API void phpstr_resize_ex(phpstr *buf, size_t len, size_t override_size)
+PHPSTR_API size_t 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);
+ char *ptr = perealloc(buf->data, buf->used + buf->free + size, buf->pmem);
+
+ if (ptr) {
+ buf->data = ptr;
+ } else {
+ return NOMEM;
+ }
} else {
- buf->data = emalloc(size);
+ buf->data = pemalloc(size, buf->pmem);
+
+ if (!buf->data) {
+ return NOMEM;
+ }
}
buf->free += size;
+ return size;
}
+ return 0;
}
PHPSTR_API size_t phpstr_append(phpstr *buf, const char *append, size_t append_len)
{
- phpstr_resize(buf, append_len);
+ if (NOMEM == phpstr_resize(buf, append_len)) {
+ return NOMEM;
+ }
memcpy(buf->data + buf->used, append, append_len);
buf->used += append_len;
buf->free -= append_len;
{
va_list argv;
char *append;
- size_t append_len;
+ size_t append_len, alloc;
va_start(argv, format);
append_len = vspprintf(&append, 0, format, argv);
va_end(argv);
- phpstr_append(buf, append, append_len);
+ alloc = phpstr_append(buf, append, append_len);
efree(append);
+ if (NOMEM == alloc) {
+ return NOMEM;
+ }
return append_len;
}
PHPSTR_API size_t phpstr_insert(phpstr *buf, const char *insert, size_t insert_len, size_t offset)
{
- phpstr_resize(buf, insert_len);
+ if (NOMEM == phpstr_resize(buf, insert_len)) {
+ return NOMEM;
+ }
memmove(buf->data + offset + insert_len, buf->data + offset, insert_len);
memcpy(buf->data + offset, insert, insert_len);
buf->used += insert_len;
{
va_list argv;
char *insert;
- size_t insert_len;
+ size_t insert_len, alloc;
va_start(argv, format);
insert_len = vspprintf(&insert, 0, format, argv);
va_end(argv);
- phpstr_insert(buf, insert, insert_len, offset);
+ alloc = phpstr_insert(buf, insert, insert_len, offset);
efree(insert);
+ if (NOMEM == alloc) {
+ return NOMEM;
+ }
return insert_len;
}
PHPSTR_API size_t phpstr_prepend(phpstr *buf, const char *prepend, size_t prepend_len)
{
- phpstr_resize(buf, prepend_len);
+ if (NOMEM == phpstr_resize(buf, prepend_len)) {
+ return NOMEM;
+ }
memmove(buf->data + prepend_len, buf->data, buf->used);
memcpy(buf->data, prepend, prepend_len);
buf->used += prepend_len;
{
va_list argv;
char *prepend;
- size_t prepend_len;
+ size_t prepend_len, alloc;
va_start(argv, format);
prepend_len = vspprintf(&prepend, 0, format, argv);
va_end(argv);
- phpstr_prepend(buf, prepend, prepend_len);
+ alloc = phpstr_prepend(buf, prepend, prepend_len);
efree(prepend);
+ if (NOMEM == alloc) {
+ return NOMEM;
+ }
return prepend_len;
}
PHPSTR_API phpstr *phpstr_dup(const phpstr *buf)
{
phpstr *dup = phpstr_clone(buf);
- phpstr_append(dup, buf->data, buf->used);
+ if (NOMEM == phpstr_append(dup, buf->data, buf->used)) {
+ phpstr_free(&dup);
+ }
return dup;
}
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;
+ phpstr *sub = phpstr_init_ex(NULL, need, PHPSTR_INIT_PREALLOC | (buf->pmem ? PHPSTR_INIT_PERSISTENT:0));
+ if (sub) {
+ if (NOMEM == phpstr_append(sub, buf->data + offset, need)) {
+ phpstr_free(&sub);
+ } else {
+ sub->size = buf->size;
+ }
+ }
return sub;
}
}
PHPSTR_API phpstr *phpstr_merge_va(phpstr *buf, unsigned argc, va_list argv)
{
- unsigned i = 0;
+ unsigned f = 0, 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);
+ if (buf) {
+ while (argc > i++) {
+ phpstr_free_t f = va_arg(argv, phpstr_free_t);
+ phpstr *current = va_arg(argv, phpstr *);
+ if (NOMEM == phpstr_append(buf, current->data, current->used)) {
+ f = 1;
+ }
+ FREE_PHPSTR(f, current);
+ }
+
+ if (f) {
+ phpstr_free(&buf);
+ }
}
return buf;
return ret;
}
-PHPSTR_API void phpstr_fix(phpstr *buf)
+PHPSTR_API phpstr *phpstr_fix(phpstr *buf)
{
- phpstr_resize_ex(buf, 1, 1);
+ if (NOMEM == phpstr_resize_ex(buf, 1, 1)) {
+ return NULL;
+ }
buf->data[buf->used] = '\0';
+ return buf;
}
PHPSTR_API int phpstr_cmp(phpstr *left, phpstr *right)
PHPSTR_API void phpstr_dtor(phpstr *buf)
{
- STR_SET(buf->data, NULL);
+ if (buf->data) {
+ pefree(buf->data, buf->pmem);
+ buf->data = NULL;
+ }
buf->used = 0;
buf->free = 0;
}
{
if (*buf) {
phpstr_dtor(*buf);
- efree(*buf);
+ pefree(*buf, (*buf)->pmem);
*buf = NULL;
}
}
*chunk = NULL;
if (!*s) {
- *s = phpstr_init_ex(NULL, chunk_size * 2, chunk_size ? 1 : 0);
+ *s = phpstr_init_ex(NULL, chunk_size * 2, chunk_size ? PHPSTR_INIT_PREALLOC : 0);
}
storage = *s;
#define PHPSTR_VAL(p) (PHPSTR(p))->data
#define PHPSTR_LEN(p) (PHPSTR(p))->used
-#define FREE_PHPSTR_PTR(STR) efree(STR)
+#define FREE_PHPSTR_PTR(STR) pefree(STR, STR->pmem)
#define FREE_PHPSTR_VAL(STR) phpstr_dtor(STR)
#define FREE_PHPSTR_ALL(STR) phpstr_free(&(STR))
#define FREE_PHPSTR(free, STR) \
switch (free) \
{ \
- case PHPSTR_FREE_NOT: break; \
- case PHPSTR_FREE_PTR: efree(STR); break; \
- case PHPSTR_FREE_VAL: phpstr_dtor(STR); break; \
+ case PHPSTR_FREE_NOT: break; \
+ case PHPSTR_FREE_PTR: pefree(STR, STR->pmem); break; \
+ case PHPSTR_FREE_VAL: phpstr_dtor(STR); break; \
case PHPSTR_FREE_ALL: \
{ \
phpstr *PTR = (STR); \
phpstr_free(&PTR); \
} \
break; \
- default: break; \
+ default: break; \
}
#define RETURN_PHPSTR_PTR(STR) RETURN_PHPSTR((STR), PHPSTR_FREE_PTR, 0)
char *data;
size_t used;
size_t free;
+ int pmem;
} phpstr;
typedef enum {
PHPSTR_FREE_NOT = 0,
- PHPSTR_FREE_PTR, /* efree() */
+ PHPSTR_FREE_PTR, /* pefree() */
PHPSTR_FREE_VAL, /* phpstr_dtor() */
PHPSTR_FREE_ALL /* phpstr_free() */
} phpstr_free_t;
#define PHPSTR_VAL_FREE(STR) PHPSTR_FREE_VAL,(STR)
#define PHPSTR_NOT_FREE(STR) PHPSTR_FREE_NOT,(STR)
+#define PHPSTR_INIT_PREALLOC 0x01
+#define PHPSTR_INIT_PERSISTENT 0x02
+
/* 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, int pre_alloc);
+#define phpstr_clone(phpstr_pointer) phpstr_init_ex(NULL, (phpstr_pointer)->size, (phpstr_pointer)->pmem ? PHPSTR_INIT_PERSISTENT:0)
+PHPSTR_API phpstr *phpstr_init_ex(phpstr *buf, size_t chunk_size, int flags);
/* create a phpstr from a zval or c-string */
#define phpstr_from_zval(z) phpstr_from_string(Z_STRVAL(z), Z_STRLEN(z))
/* 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);
+PHPSTR_API size_t 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)
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);
+PHPSTR_API phpstr *phpstr_fix(phpstr *buf);
/* memcmp for phpstr objects */
PHPSTR_API int phpstr_cmp(phpstr *left, phpstr *right);