diff options
| author | Dennis Camera <skonfig@dtnr.ch> | 2022-08-20 23:10:27 +0200 |
|---|---|---|
| committer | Dennis Camera <skonfig@dtnr.ch> | 2022-08-20 23:10:27 +0200 |
| commit | c3236907ef834555e460daea38369a4874ae5d5d (patch) | |
| tree | 2c20d69002d7018e10962a1991ff687d9298647c /src | |
| parent | 33c1ce5e7d72dd48b6b4c59ed085f27998173a5d (diff) | |
| download | skonfig-c-c3236907ef834555e460daea38369a4874ae5d5d.tar.gz skonfig-c-c3236907ef834555e460daea38369a4874ae5d5d.zip | |
[src/util/string.c] Add _r variants for strjoin functions
Diffstat (limited to 'src')
| -rw-r--r-- | src/util/string.c | 133 | ||||
| -rw-r--r-- | src/util/string.h | 74 |
2 files changed, 144 insertions, 63 deletions
diff --git a/src/util/string.c b/src/util/string.c index 2b24f4e..d5ad73b 100644 --- a/src/util/string.c +++ b/src/util/string.c @@ -20,92 +20,103 @@ char *strdup(const char *s) { } #endif -char *stranjoin(char sep, const char *a[], size_t nmemb) { - char *dst; +size_t stranjoin_r( + char *restrict buf, size_t buflen, char sep, const char *restrict a[], + size_t nmemb) { + size_t len = 0; + + if (NULL != buf && 0 < buflen) { + /* clear buf string */ + *buf = '\0'; + } - if (nmemb > 0) { - /* determine length of joined string */ - size_t len = 0; - for (size_t i = 0; i < nmemb; i++) { - len += strlen(a[i]) + 1; + for (size_t i = 0; i < nmemb; ++i) { + if (0 < len) { + /* add separator */ + if (NULL != buf && len < buflen) { + *(buf+len) = sep; + } + ++len; } - /* then, join strings */ - dst = calloc(len, sizeof(char)); - if (!dst) { - return NULL; + if (NULL != buf) { + /* append element */ + strncpy(buf+len, a[i], (buflen - len)); } + len += strlen(a[i]); + } - char *p = dst; - for (size_t i = 0; i < nmemb; i++) { - if (i > 0) - *p++ = sep; - size_t l = strlen(a[i]); - memcpy(p, a[i], l); - p += l; - } + return len; +} + +char *stranjoin(char sep, const char *a[], size_t nmemb) { + /* determine length of result string */ + size_t len = stranjoin_r(NULL, 0, sep, a, nmemb); - *p = '\0'; - } else { - dst = strdup(""); + /* allocate destination buffer */ + char *dest = malloc(len+1); + if (NULL != dest) { + (void)stranjoin_r(dest, len+1, sep, a, nmemb); } - return dst; + return dest; } -char *_strjoin(char sep, /* const char * */...) { +size_t _vstrjoin_r(char *restrict buf, size_t buflen, char sep, va_list ap) { const char *s; - char *dst, *p; - va_list ap; - size_t len, l; - - va_start(ap, sep); + size_t len = 0; - s = va_arg(ap, const char *); - - if (s) { - /* determine length of joined string */ - len = strlen(s) + 1; + if (NULL != buf && 0 < buflen) { + /* clear buf string */ + *buf = '\0'; + } - while ((s = va_arg(ap, const char *))) { - len += strlen(s) + 1; + while (NULL != (s = va_arg(ap, const char *restrict))) { + if (0 < len) { + /* add separator */ + if (NULL != buf && len < buflen) { + *(buf+len) = sep; + } + ++len; } - va_end(ap); - /* Then, join strings */ - dst = calloc(len, sizeof(char)); - if (!dst) { - return NULL; + if (NULL != buf) { + /* append element */ + strncpy(buf+len, s, (buflen - len)); } - p = dst; + len += strlen(s); + } - va_start(ap, sep); + return len; +} - /* copy first element */ - s = va_arg(ap, const char *); - l = strlen(s); - strcpy(dst, s); - p += l; +size_t _strjoin_r( + char *restrict buf, size_t buflen, char sep, /* const char *restrict */...) { + va_list ap; + va_start(ap, sep); + size_t len = _vstrjoin_r(buf, buflen, sep, ap); + va_end(ap); + return len; +} - /* then the others */ - while ((s = va_arg(ap, const char *))) { - l = strlen(s); +char *_strjoin(char sep, /* const char *restrict */...) { + va_list ap; - *p++ = sep; - strncpy(p, s, l); - p += l; - } + /* determine length of result string */ + va_start(ap, sep); + size_t len = _vstrjoin_r(NULL, 0, sep, ap); + va_end(ap); - *p = '\0'; - } else { - dst = strdup(""); + /* allocate destination buffer */ + char *dest = malloc(len+1); + if (NULL != dest) { + (void)_vstrjoin_r(dest, len+1, sep, ap); } - va_end(ap); - - return dst; + return dest; } + size_t strsplit(const char *restrict in, const char *restrict sep, void *buf) { size_t i = 0; char **arr = buf; diff --git a/src/util/string.h b/src/util/string.h index c244a29..1ef07d1 100644 --- a/src/util/string.h +++ b/src/util/string.h @@ -54,6 +54,25 @@ char *strdup(const char *s); #define strajoin(sep, a) stranjoin(sep, a, anullidx((void *)a)) /** + * strajoin_r: + * Joins a C string array using a separator character into a caller allocated + * buffer. + * + * NOTE: the return value of this function is the length of the result if the + * buffer would’ve been large enough. Use this to check for truncation. + * If the destination buffer wasn’t large enough, the resulting string won’t be + * NUL terminated. + * + * @param buf: the destination buffer (nothing will be written to it if NULL) + * @param buflen: the length of @buf + * @param sep: a char to insert between eaach element of the array + * @param a: the array to join (NULL terminated) + * @return the length of the full result string + */ +#define strajoin_r(buf, buflen, sep, a, nmemb) \ + stranjoin_r(buf, buflen, sep, a, anullidx((void *)a)) + +/** * stranjoin: * Joins a C string array using a separator character. * @@ -61,12 +80,37 @@ char *strdup(const char *s); * * @param sep: a char to insert between each element of the array * @param a: the array to join - * @param nmemb: the length of the array + * @param nmemb: the number of elements of @a * @return a newly-allocated C string containing all of the elements joined */ char *stranjoin(char sep, const char *a[], size_t nmemb); -char *_strjoin(char sep, /* const char * */...); /* internal */ +/** + * stranjoin_r: + * Joins a C string array using a separator character into a caller allocated + * buffer. + * + * NOTE: the return value of this function is the length of the result if the + * buffer would’ve been large enough. Use this to check for truncation. + * If the destination buffer wasn’t large enough, the resulting string won’t be + * NUL terminated. + * + * @param buf: the destination buffer (nothing will be written to it if NULL) + * @param buflen: the length of @buf + * @param sep: a char to insert between each element of @a + * @param a: the array to join (NULL terminated) + * @param nmemb: the number of elements of @a + * @return the length of the untruncated joined string + */ +size_t stranjoin_r( + char *restrict buf, size_t buflen, char sep, const char *restrict a[], + size_t nmemb); + + +char *_strjoin( /* internal */ + char sep, /* const char * */...); +size_t _strjoin_r( /* internal */ + char *restrict buf, size_t buflen, char sep, /* const char * */...); /** * strjoin: @@ -81,6 +125,19 @@ char *_strjoin(char sep, /* const char * */...); /* internal */ #define strjoin(sep, ...) _strjoin(sep, __VA_ARGS__, NULL) /** + * strjoin_r: + * Joins a number of strings together to form one long string stored in a + * caller-allocated buffer with the @separator inserted betwween each of them. + * + * @param buf: the destination buffer (nothing will be written to it if NULL) + * @param buflen: the length of @buf + * @param sep: a char to insert between each of the strings + * @param ...: a list of strings to join + * @return the length of the untruncated joined string + */ +#define strjoin_r(sep, ...) _strjoin_r(sep, __VA_ARGS__, NULL) + +/** * pathjoin: * Joins a number of path components together to form one single path. * The returned string should be free()d. @@ -91,6 +148,19 @@ char *_strjoin(char sep, /* const char * */...); /* internal */ #define pathjoin(...) strjoin(stringize(DIRSEP)[0], __VA_ARGS__) /** + * pathjoin_r: + * Joins a number of path components together to form one single path. + * The result is stored in a caller-allocated buffer. + * + * @param buf: the destination buffer (nothing will be weitten to it if NULL) + * @param buflen: the length of @buf + * @param ...: a list of path components to join + * @return the length of the untruncated joined string + */ +#define pathjoin_r(buf, buflen, ...) \ + strjoin_r(buf, buflen, stringize(DIRSEP)[0], __VA_ARGS__) + +/** * strsplit: * Splits a string into a NULL-terminated array by a given separator. * |
