X-Git-Url: http://git.marmaro.de/?a=blobdiff_plain;f=sbr%2Fcharstring.c;fp=sbr%2Fcharstring.c;h=ff311f10122c879cb9b3e59e59195e79fb434e27;hb=1546f528c670a4a55d0016a754a8f062674a9efe;hp=0000000000000000000000000000000000000000;hpb=b97368925e31edcfc6f69366d7b725e6a4d9881e;p=mmh diff --git a/sbr/charstring.c b/sbr/charstring.c new file mode 100644 index 0000000..ff311f1 --- /dev/null +++ b/sbr/charstring.c @@ -0,0 +1,154 @@ +/* charstring.c -- dynamically-sized char array that can report size + * in both characters and bytes + * + * This code is Copyright (c) 2014, by the authors of nmh. See the + * COPYRIGHT file in the root directory of the nmh distribution for + * complete copyright information. + */ + +#include +#include + +#define CHARSTRING_DEFAULT_SIZE 64 + +struct charstring { + char *buffer; /* the char array, not always null-terminated */ + size_t max; /* current size of the char array, in bytes */ + char *cur; /* size in bytes = cur - buffer, without trailing null */ +}; + + +static void +charstring_reserve(charstring_t s, size_t need) +{ + const size_t cur = s->cur - s->buffer; + + while (need >= s->max - cur) { + /* Insufficient capacity, so double it. */ + s->buffer = mh_xrealloc(s->buffer, s->max *= 2); + s->cur = s->buffer + cur; + } +} + +/* + * max is in characters + */ +charstring_t +charstring_create(size_t max) +{ + charstring_t s = mh_xcalloc(1, sizeof(*s)); + + s->max = max ? max : CHARSTRING_DEFAULT_SIZE; + s->cur = s->buffer = mh_xcalloc(s->max, 1); + + return s; +} + +charstring_t +charstring_copy(const charstring_t src) +{ + const size_t num = src->cur - src->buffer; + charstring_t s = mh_xcalloc(1, sizeof(*s)); + + s->max = src->max; + s->buffer = mh_xcalloc(s->max, 1); + memcpy(s->buffer, src->buffer, num); + s->cur = s->buffer + num; + + return s; +} + +/* + * OK to call charstring_free with a NULL argument. + */ +void +charstring_free(charstring_t s) +{ + if (s) { + free(s->buffer); + free(s); + } +} + +void +charstring_push_back(charstring_t s, const char c) +{ + charstring_reserve(s, s->cur - s->buffer + 1); + *s->cur++ = c; +} + +/* + * num is the number of bytes in c + */ +void +charstring_push_back_chars(charstring_t s, const char c[], size_t num) +{ + charstring_reserve(s, s->cur - s->buffer + num); + memcpy(s->cur, c, num); + s->cur += num; +} + +void +charstring_append(charstring_t dest, const charstring_t src) +{ + const size_t num = src->cur - src->buffer; + + if (num > 0) { + charstring_reserve(dest, dest->cur - dest->buffer + num); + memcpy(dest->cur, src->buffer, num); + dest->cur += num; + } +} + +void +charstring_append_cstring(charstring_t dest, const char src[]) +{ + const size_t num = strlen(src); + + if (num > 0) { + charstring_reserve(dest, dest->cur - dest->buffer + num); + memcpy(dest->cur, src, num); /* Exclude src's trailing NUL. */ + dest->cur += num; + } +} + +void +charstring_clear(charstring_t s) +{ + s->cur = s->buffer; +} + +/* + * Don't store return value of charstring_buffer() and use later after + * intervening push_back's; use charstring_buffer_copy() instead. + */ +const char * +charstring_buffer(const charstring_t s) +{ + charstring_reserve(s, s->cur - s->buffer + 1); + + /* This is the only place that we null-terminate the buffer. */ + *s->cur = '\0'; + /* Don't increment cur so that more can be appended later, and so + that charstring_bytes() behaves as strlen() by not counting the + null. */ + + return s->buffer; +} + +char * +charstring_buffer_copy(const charstring_t s) +{ + char *copy = mh_xcalloc(s->cur - s->buffer + 1, 1); + + /* Use charstring_buffer() to null terminate the buffer. */ + memcpy(copy, charstring_buffer(s), s->cur - s->buffer + 1); + + return copy; +} + +size_t +charstring_bytes(const charstring_t s) +{ + return s->cur - s->buffer; +}