From 7038c951485d1b2afa79c9a84b8dcdcb57c9bc54 Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Sun, 20 Mar 2005 17:31:41 +0000 Subject: [PATCH] * add phpstr --- phpstr/phpstr.c | 259 ++++++++++++++++++++++++++++++++++++++++++++++++ phpstr/phpstr.h | 138 ++++++++++++++++++++++++++ 2 files changed, 397 insertions(+) create mode 100644 phpstr/phpstr.c create mode 100644 phpstr/phpstr.h diff --git a/phpstr/phpstr.c b/phpstr/phpstr.c new file mode 100644 index 0000000..9992300 --- /dev/null +++ b/phpstr/phpstr.c @@ -0,0 +1,259 @@ + +/* $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 + */ + diff --git a/phpstr/phpstr.h b/phpstr/phpstr.h new file mode 100644 index 0000000..dc103e1 --- /dev/null +++ b/phpstr/phpstr.h @@ -0,0 +1,138 @@ + +/* $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 + */ + -- 2.30.2