From 9ff971eae5d311fd8066e13903589c7deb476934 Mon Sep 17 00:00:00 2001 From: Sebastian Harl Date: Tue, 19 Mar 2013 22:54:20 -0700 Subject: [PATCH] utils strbuf: Added an automatically growing string implementation. Whenever writing to the buffer, it will ensure that enough space is allocated to store all of the string. --- src/Makefile.am | 1 + src/include/utils/strbuf.h | 118 +++++++++++++++++++++++ src/utils/strbuf.c | 192 +++++++++++++++++++++++++++++++++++++ 3 files changed, 311 insertions(+) create mode 100644 src/include/utils/strbuf.h create mode 100644 src/utils/strbuf.c diff --git a/src/Makefile.am b/src/Makefile.am index b754beb..9876de6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -25,6 +25,7 @@ libsysdb_la_SOURCES = \ include/utils/data.h \ utils/error.c include/utils/error.h \ utils/llist.c include/utils/llist.h \ + utils/strbuf.c include/utils/strbuf.h \ utils/time.c include/utils/time.h \ utils/unixsock.c include/utils/unixsock.h libsysdb_la_CFLAGS = $(AM_CFLAGS) diff --git a/src/include/utils/strbuf.h b/src/include/utils/strbuf.h new file mode 100644 index 0000000..7b159ed --- /dev/null +++ b/src/include/utils/strbuf.h @@ -0,0 +1,118 @@ +/* + * SysDB - src/include/utils/strbuf.h + * Copyright (C) 2012 Sebastian 'tokkee' Harl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * SysDB string buffer: + * This is an implementation of an automatically growing string. Whenever + * writing to the buffer, it will be ensured that enough space is allocated to + * store all of the string. + */ + +#ifndef SDB_UTILS_STRBUF_H +#define SDB_UTILS_STRBUF_H 1 + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct sdb_strbuf sdb_strbuf_t; + +/* + * sdb_strbuf_create, sdb_strbuf_destroy: + * Allocate / deallocate string buffer objects. The initial size of a newly + * created string buffer is determined by the 'size' argument of the create + * function. + * + * sdb_strbuf_create returns: + * - the new string buffer object on success + * - NULL else + */ +sdb_strbuf_t * +sdb_strbuf_create(size_t size); + +void +sdb_strbuf_destroy(sdb_strbuf_t *strbuf); + +/* + * sdb_strbuf_vappend, sdb_strbuf_append: + * Append to an existing string buffer. The new text will be added at the end + * of the current content of the buffer. + * + * The 'fmt' and all following arguments are identical to those passed to the + * sprintf / vsprintf functions. + * + * Returns: + * - the number of bytes written + * - a negative value on error + */ +ssize_t +sdb_strbuf_vappend(sdb_strbuf_t *strbuf, const char *fmt, va_list ap); +ssize_t +sdb_strbuf_append(sdb_strbuf_t *strbuf, const char *fmt, ...); + +/* + * sdb_strbuf_vsprintf, sdb_strbuf_sprintf: + * Write to an existing string buffer, overwriting any previous content. + * + * The 'fmt' and all following arguments are identical to those passed to the + * sprintf / vsprintf functions. + * + * Returns: + * - the number of bytes written + * - a negative value on error + */ +ssize_t +sdb_strbuf_vsprintf(sdb_strbuf_t *strbuf, const char *fmt, va_list ap); +ssize_t +sdb_strbuf_sprintf(sdb_strbuf_t *strbuf, const char *fmt, ...); + +/* + * sdb_strbuf_string: + * Returns the content of the string buffer. The caller may not modify the + * string. + */ +const char * +sdb_strbuf_string(sdb_strbuf_t *strbuf); + +/* + * sdb_strbuf_len: + * Returns the length of the string buffer's content. + */ +size_t +sdb_strbuf_len(sdb_strbuf_t *strbuf); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* ! SDB_UTILS_STRBUF_H */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/src/utils/strbuf.c b/src/utils/strbuf.c new file mode 100644 index 0000000..df3ee4b --- /dev/null +++ b/src/utils/strbuf.c @@ -0,0 +1,192 @@ +/* + * SysDB - src/utils/strbuf.c + * Copyright (C) 2012 Sebastian 'tokkee' Harl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "utils/strbuf.h" + +#include + +#include +#include +#include + +/* + * private data structures + */ + +struct sdb_strbuf { + char *string; + size_t size; + size_t pos; +}; + +/* + * private helper functions + */ + +static int +strbuf_resize(sdb_strbuf_t *strbuf) +{ + char *tmp; + + assert(strbuf->size); + + tmp = realloc(strbuf->string, 2 * strbuf->size); + if (! tmp) + return -1; + + strbuf->string = tmp; + strbuf->size *= 2; + return 0; +} /* strbuf_resize */ + +/* + * public API + */ + +sdb_strbuf_t * +sdb_strbuf_create(size_t size) +{ + sdb_strbuf_t *strbuf; + + if (! size) + return NULL; + + strbuf = calloc(1, sizeof(*strbuf)); + if (! strbuf) + return NULL; + + strbuf->string = malloc(size); + if (! strbuf->string) { + free(strbuf); + return NULL; + } + + strbuf->string[0] = '\0'; + strbuf->size = size; + strbuf->pos = 0; + + return strbuf; +} /* sdb_strbuf_create */ + +void +sdb_strbuf_destroy(sdb_strbuf_t *strbuf) +{ + if (! strbuf) + return; + + free(strbuf->string); + free(strbuf); +} /* sdb_strbuf_destroy */ + +ssize_t +sdb_strbuf_vappend(sdb_strbuf_t *strbuf, const char *fmt, va_list ap) +{ + int status; + + if ((! strbuf) || (! fmt)) + return -1; + + assert(strbuf->string[strbuf->pos] == '\0'); + + if (strbuf->pos >= strbuf->size) + if (strbuf_resize(strbuf)) + return -1; + + status = vsnprintf(strbuf->string + strbuf->pos, + strbuf->size - strbuf->pos, fmt, ap); + + if (status < 0) + return status; + + if ((size_t)status >= strbuf->size - strbuf->pos) { + strbuf_resize(strbuf); + + /* reset string and try again */ + strbuf->string[strbuf->pos] = '\0'; + return sdb_strbuf_vappend(strbuf, fmt, ap); + } + + strbuf->pos += (size_t)status; + return (ssize_t)status; +} /* sdb_strbuf_vappend */ + +ssize_t +sdb_strbuf_append(sdb_strbuf_t *strbuf, const char *fmt, ...) +{ + va_list ap; + ssize_t status; + + va_start(ap, fmt); + status = sdb_strbuf_vappend(strbuf, fmt, ap); + va_end(ap); + + return status; +} /* sdb_strbuf_append */ + +ssize_t +sdb_strbuf_vsprintf(sdb_strbuf_t *strbuf, const char *fmt, va_list ap) +{ + if (! strbuf) + return -1; + + strbuf->string[0] = '\0'; + strbuf->pos = 0; + + return sdb_strbuf_vappend(strbuf, fmt, ap); +} /* sdb_strbuf_vsprintf */ + +ssize_t +sdb_strbuf_sprintf(sdb_strbuf_t *strbuf, const char *fmt, ...) +{ + va_list ap; + ssize_t status; + + va_start(ap, fmt); + status = sdb_strbuf_vsprintf(strbuf, fmt, ap); + va_end(ap); + + return status; +} /* sdb_strbuf_sprintf */ + +const char * +sdb_strbuf_string(sdb_strbuf_t *strbuf) +{ + if (! strbuf) + return NULL; + return strbuf->string; +} /* sdb_strbuf_string */ + +size_t +sdb_strbuf_len(sdb_strbuf_t *strbuf) +{ + if (! strbuf) + return 0; + return strbuf->pos; +} /* sdb_strbuf_string */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + -- 2.30.2