From a99fc753a590d7dd1cf19d083af504cb3ec9a8d4 Mon Sep 17 00:00:00 2001 From: Mark Pulford Date: Fri, 15 Apr 2011 23:34:12 +0930 Subject: Add functions for new strbuf API and tidy - Support strbuf_free() when strbuf is not dynamically created. - Ensure strbuf_free_to_string() returns a null terminated string. - Tidy API function naming. - Add strbuf_append_string(), strbuf_string(). - Allocate initial buffer in strbuf_init(). --- strbuf.c | 64 +++++++++++++++++++++++++++++++++++++++++++--------------------- strbuf.h | 56 +++++++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 86 insertions(+), 34 deletions(-) diff --git a/strbuf.c b/strbuf.c index f823884..9f0d212 100644 --- a/strbuf.c +++ b/strbuf.c @@ -18,10 +18,14 @@ static void die(const char *format, ...) void strbuf_init(strbuf_t *s) { - s->data = NULL; + s->buf = NULL; s->size = 0; s->length = 0; s->increment = STRBUF_DEFAULT_INCREMENT; + s->dynamic = 0; + + strbuf_resize(s, 0); + strbuf_ensure_null(s); } strbuf_t *strbuf_new() @@ -34,6 +38,9 @@ strbuf_t *strbuf_new() strbuf_init(s); + /* Dynamic strbuf allocation / deallocation */ + s->dynamic = 1; + return s; } @@ -47,22 +54,26 @@ void strbuf_set_increment(strbuf_t *s, int increment) void strbuf_free(strbuf_t *s) { - if (s->data) - free(s->data); - free(s); + if (s->buf) + free(s->buf); + if (s->dynamic) + free(s); } -char *strbuf_to_char(strbuf_t *s, int *len) +char *strbuf_free_to_string(strbuf_t *s, int *len) { - char *data; + char *buf; - data = s->data; + strbuf_ensure_null(s); + + buf = s->buf; if (len) *len = s->length; - free(s); + if (s->dynamic) + free(s); - return data; + return buf; } /* Ensure strbuf can handle a string length bytes long (ignoring NULL @@ -71,28 +82,41 @@ void strbuf_resize(strbuf_t *s, int len) { int newsize; - /* Esnure there is room for optional NULL termination */ + /* Ensure there is room for optional NULL termination */ newsize = len + 1; /* Round up to the next increment */ newsize = ((newsize + s->increment - 1) / s->increment) * s->increment; s->size = newsize; - s->data = realloc(s->data, s->size); - if (!s->data) + s->buf = realloc(s->buf, s->size); + if (!s->buf) die("Out of memory"); } void strbuf_append_mem(strbuf_t *s, const char *c, int len) { - if (len > strbuf_emptylen(s)) + if (len > strbuf_empty_length(s)) strbuf_resize(s, s->length + len); - memcpy(s->data + s->length, c, len); + memcpy(s->buf + s->length, c, len); s->length += len; } -void strbuf_ensure_null(strbuf_t *s) +void strbuf_append_string(strbuf_t *s, const char *str) { - s->data[s->length] = 0; + int space, i; + + space = strbuf_empty_length(s); + + for (i = 0; str[i]; i++) { + if (space < 1) { + strbuf_resize(s, s->length + s->increment); + space = strbuf_empty_length(s); + } + + s->buf[s->length] = str[i]; + s->length++; + space--; + } } void strbuf_append_fmt(strbuf_t *s, const char *fmt, ...) @@ -108,11 +132,9 @@ void strbuf_append_fmt(strbuf_t *s, const char *fmt, ...) /* Append the new formatted string */ /* fmt_len is the length of the string required, excluding the * trailing NULL */ - empty_len = strbuf_emptylen(s); - /* Add 1 since there is also space for the terminating NULL. - * If the string hasn't been allocated then empty_len == -1, - * and vsprintf() won't store anything on the first pass */ - fmt_len = vsnprintf(s->data + s->length, empty_len + 1, fmt, arg); + empty_len = strbuf_empty_length(s); + /* Add 1 since there is also space to store the terminating NULL. */ + fmt_len = vsnprintf(s->buf + s->length, empty_len + 1, fmt, arg); va_end(arg); if (fmt_len <= empty_len) diff --git a/strbuf.h b/strbuf.h index fb07e6f..96dd97b 100644 --- a/strbuf.h +++ b/strbuf.h @@ -1,32 +1,49 @@ #include #include +/* Size: Total bytes allocated to *buf + * Length: String length, excluding optional NULL terminator. + * Increment: Allocation increments when resizing the string buffer. + * Dynamic: True if created via strbuf_new() + */ + typedef struct { - char *data; - int size; /* Bytes allocated */ - int length; /* Current length of string, not including NULL */ - int increment; /* Allocation Increments */ + char *buf; + int size; + int length; + int increment; + int dynamic; } strbuf_t; #ifndef STRBUF_DEFAULT_INCREMENT #define STRBUF_DEFAULT_INCREMENT 8 #endif -extern void strbuf_init(strbuf_t *s); +/* Initialise */ extern strbuf_t *strbuf_new(); +extern void strbuf_init(strbuf_t *s); +extern void strbuf_set_increment(strbuf_t *s, int increment); + +/* Release */ extern void strbuf_free(strbuf_t *s); -extern char *strbuf_to_char(strbuf_t *s, int *len); +extern char *strbuf_free_to_string(strbuf_t *s, int *len); -extern void strbuf_set_increment(strbuf_t *s, int increment); +/* Management */ extern void strbuf_resize(strbuf_t *s, int len); +static int strbuf_empty_length(strbuf_t *s); +static int strbuf_length(strbuf_t *s); +static char *strbuf_string(strbuf_t *s, int *len); + +/* Update */ extern void strbuf_append_fmt(strbuf_t *s, const char *format, ...); extern void strbuf_append_mem(strbuf_t *s, const char *c, int len); -extern void strbuf_ensure_null(strbuf_t *s); +extern void strbuf_append_string(strbuf_t *s, const char *str); +static void strbuf_append_char(strbuf_t *s, const char c); +static void strbuf_ensure_null(strbuf_t *s); /* Return bytes remaining in the string buffer - * Ensure there is space for a NULL. - * Returns -1 if the string has not been allocated yet */ -static inline int strbuf_emptylen(strbuf_t *s) + * Ensure there is space for a NULL terminator. */ +static inline int strbuf_empty_length(strbuf_t *s) { return s->size - s->length - 1; } @@ -38,10 +55,23 @@ static inline int strbuf_length(strbuf_t *s) static inline void strbuf_append_char(strbuf_t *s, const char c) { - if (strbuf_emptylen(s) < 1) + if (strbuf_empty_length(s) < 1) strbuf_resize(s, s->length + 1); - s->data[s->length++] = c; + s->buf[s->length++] = c; +} + +static inline void strbuf_ensure_null(strbuf_t *s) +{ + s->buf[s->length] = 0; +} + +static inline char *strbuf_string(strbuf_t *s, int *len) +{ + if (len) + *len = s->length; + + return s->buf; } /* vi:ai et sw=4 ts=4: -- cgit v1.2.3-55-g6feb