From bb8ad9eacaaf08078ad08e289c4cef08c7c38663 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 28 Nov 2017 16:37:53 +0100 Subject: [PATCH] string-util: rework strextend() to optionally inset separators between each appended string This adds a new flavour of strextend(), called strextend_with_separator(), which takes an optional separator string. If specified, the separator is inserted between each appended string, as well as before the first one, but only if the original string was non-empty. This new call is particularly useful when appending new options to mount option strings and suchlike, which need to be comma-separated, and initially start out from an empty string. --- src/basic/string-util.c | 28 +++++++++++++++++++++++----- src/basic/string-util.h | 4 +++- src/test/test-string-util.c | 35 ++++++++++++++++++++++++++++++++--- 3 files changed, 58 insertions(+), 9 deletions(-) diff --git a/src/basic/string-util.c b/src/basic/string-util.c index 312e83433e..e916000b25 100644 --- a/src/basic/string-util.c +++ b/src/basic/string-util.c @@ -734,16 +734,20 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz) { return obuf; } -char *strextend(char **x, ...) { - va_list ap; - size_t f, l; +char *strextend_with_separator(char **x, const char *separator, ...) { + bool need_separator; + size_t f, l, l_separator; char *r, *p; + va_list ap; assert(x); l = f = strlen_ptr(*x); - va_start(ap, x); + need_separator = !isempty(*x); + l_separator = strlen_ptr(separator); + + va_start(ap, separator); for (;;) { const char *t; size_t n; @@ -753,22 +757,29 @@ char *strextend(char **x, ...) { break; n = strlen(t); + + if (need_separator) + n += l_separator; + if (n > ((size_t) -1) - l) { va_end(ap); return NULL; } l += n; + need_separator = true; } va_end(ap); + need_separator = !isempty(*x); + r = realloc(*x, l+1); if (!r) return NULL; p = r + f; - va_start(ap, x); + va_start(ap, separator); for (;;) { const char *t; @@ -776,10 +787,17 @@ char *strextend(char **x, ...) { if (!t) break; + if (need_separator && separator) + p = stpcpy(p, separator); + p = stpcpy(p, t); + + need_separator = true; } va_end(ap); + assert(p == r + l); + *p = 0; *x = r; diff --git a/src/basic/string-util.h b/src/basic/string-util.h index 684af0f3e4..09a737ad37 100644 --- a/src/basic/string-util.h +++ b/src/basic/string-util.h @@ -179,7 +179,9 @@ char *strreplace(const char *text, const char *old_string, const char *new_strin char *strip_tab_ansi(char **p, size_t *l); -char *strextend(char **x, ...) _sentinel_; +char *strextend_with_separator(char **x, const char *separator, ...) _sentinel_; + +#define strextend(x, ...) strextend_with_separator(x, NULL, __VA_ARGS__) char *strrep(const char *s, unsigned n); diff --git a/src/test/test-string-util.c b/src/test/test-string-util.c index 7a14b8efd3..07ee98465c 100644 --- a/src/test/test-string-util.c +++ b/src/test/test-string-util.c @@ -104,9 +104,37 @@ static void test_strstrip(void) { } static void test_strextend(void) { - _cleanup_free_ char *str = strdup("0123"); - strextend(&str, "456", "78", "9", NULL); - assert_se(streq(str, "0123456789")); + _cleanup_free_ char *str = NULL; + + assert_se(strextend(&str, NULL)); + assert_se(streq_ptr(str, "")); + assert_se(strextend(&str, "", "0", "", "", "123", NULL)); + assert_se(streq_ptr(str, "0123")); + assert_se(strextend(&str, "456", "78", "9", NULL)); + assert_se(streq_ptr(str, "0123456789")); +} + +static void test_strextend_with_separator(void) { + _cleanup_free_ char *str = NULL; + + assert_se(strextend_with_separator(&str, NULL, NULL)); + assert_se(streq_ptr(str, "")); + str = mfree(str); + + assert_se(strextend_with_separator(&str, "...", NULL)); + assert_se(streq_ptr(str, "")); + assert_se(strextend_with_separator(&str, "...", NULL)); + assert_se(streq_ptr(str, "")); + str = mfree(str); + + assert_se(strextend_with_separator(&str, "xyz", "a", "bb", "ccc", NULL)); + assert_se(streq_ptr(str, "axyzbbxyzccc")); + str = mfree(str); + + assert_se(strextend_with_separator(&str, ",", "start", "", "1", "234", NULL)); + assert_se(streq_ptr(str, "start,,1,234")); + assert_se(strextend_with_separator(&str, ";", "more", "5", "678", NULL)); + assert_se(streq_ptr(str, "start,,1,234;more;5;678")); } static void test_strrep(void) { @@ -399,6 +427,7 @@ int main(int argc, char *argv[]) { test_streq_ptr(); test_strstrip(); test_strextend(); + test_strextend_with_separator(); test_strrep(); test_strappend(); test_string_has_cc();