From 1546f528c670a4a55d0016a754a8f062674a9efe Mon Sep 17 00:00:00 2001 From: Philipp Takacs Date: Thu, 21 Sep 2023 12:27:02 +0200 Subject: [PATCH] Added charstring "class" manual cherry-picked from nmh Author: David Levine commit c61294eca5edf4f245c2d8818bf53d3bdc3d80c1 --- h/charstring.h | 34 ++++++++++++ h/mh.h | 1 + sbr/Makefile.in | 1 + sbr/charstring.c | 154 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 190 insertions(+) create mode 100644 h/charstring.h create mode 100644 sbr/charstring.c diff --git a/h/charstring.h b/h/charstring.h new file mode 100644 index 0000000..b2a4fed --- /dev/null +++ b/h/charstring.h @@ -0,0 +1,34 @@ +/* charstring.h -- dynamically-sized char array that can report size + * in both characters and bytes + * + * This code is Copyright (c) 2017, by the authors of nmh. See the + * COPYRIGHT file in the root directory of the nmh distribution for + * complete copyright information. */ + +/* + * char array that keeps track of size in both bytes and characters + * Usage note: + * Don't store return value of charstring_buffer() and use later + * after intervening push_back's; use charstring_buffer_copy() + * instead. + */ + +typedef struct charstring *charstring_t; + +charstring_t charstring_create(size_t); +charstring_t charstring_copy(const charstring_t) NONNULL(1); +void charstring_free(charstring_t); +/* Append a single-byte character: */ +void charstring_push_back(charstring_t, const char) NONNULL(1); +/* Append possibly multi-byte character(s): */ +void charstring_push_back_chars(charstring_t, const char [], size_t) NONNULL(1); +void charstring_append(charstring_t, const charstring_t) NONNULL(2); +void charstring_append_cstring(charstring_t, const char []) NONNULL(2); +void charstring_clear(charstring_t) NONNULL(1); +/* 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) NONNULL(1); +/* User is responsible for free'ing result of buffer copy. */ +char *charstring_buffer_copy(const charstring_t) NONNULL(1); +size_t charstring_bytes(const charstring_t) NONNULL(1) PURE; +size_t charstring_chars(const charstring_t) NONNULL(1) PURE; diff --git a/h/mh.h b/h/mh.h index 88bcde5..3326185 100644 --- a/h/mh.h +++ b/h/mh.h @@ -326,4 +326,5 @@ extern char *version; extern char *lib_version; extern char *whatnowproc; +#include #include diff --git a/sbr/Makefile.in b/sbr/Makefile.in index 142a7f2..cee1c45 100644 --- a/sbr/Makefile.in +++ b/sbr/Makefile.in @@ -52,6 +52,7 @@ SRCS = addrsbr.c ambigsw.c brkstring.c \ context_find.c context_read.c \ context_replace.c context_save.c \ cpydata.c crawl_folders.c \ + charstring.c \ dtime.c dtimep.c \ error.c execprog.c ext_hook.c folder_addmsg.c folder_delmsgs.c \ folder_free.c folder_read.c \ 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; +} -- 1.7.10.4