From b40694f5fc21317af617f37bb03304c84ca993c8 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Mon, 10 Feb 2025 19:03:08 +0100 Subject: [PATCH 1/5] string-util: introduce strprepend() helper --- src/basic/string-util.c | 14 ++++++++++++++ src/basic/string-util.h | 2 ++ src/test/test-string-util.c | 13 +++++++++++++ 3 files changed, 29 insertions(+) diff --git a/src/basic/string-util.c b/src/basic/string-util.c index b2919164d6..dace8a606d 100644 --- a/src/basic/string-util.c +++ b/src/basic/string-util.c @@ -46,6 +46,20 @@ char* first_word(const char *s, const char *word) { return (char*) nw; } +char* strprepend(char **x, const char *s) { + assert(x); + + if (isempty(s) && *x) + return *x; + + char *p = strjoin(strempty(s), *x); + if (!p) + return NULL; + + free_and_replace(*x, p); + return *x; +} + char* strnappend(const char *s, const char *suffix, size_t b) { size_t a; char *r; diff --git a/src/basic/string-util.h b/src/basic/string-util.h index 1bcb1c40e3..1b2f097061 100644 --- a/src/basic/string-util.h +++ b/src/basic/string-util.h @@ -106,6 +106,8 @@ static inline const char* empty_or_dash_to_null(const char *p) { char* first_word(const char *s, const char *word) _pure_; +char* strprepend(char **x, const char *s); + char* strnappend(const char *s, const char *suffix, size_t length); #define strjoin(a, ...) strextend_with_separator_internal(NULL, NULL, a, __VA_ARGS__, NULL) diff --git a/src/test/test-string-util.c b/src/test/test-string-util.c index fbfb3990e4..1b447abda9 100644 --- a/src/test/test-string-util.c +++ b/src/test/test-string-util.c @@ -1348,6 +1348,19 @@ TEST(strextendn) { x = mfree(x); } +TEST(strprepend) { + _cleanup_free_ char *x = NULL; + + ASSERT_STREQ(strprepend(&x, NULL), ""); + x = mfree(x); + + ASSERT_STREQ(strprepend(&x, ""), ""); + + ASSERT_STREQ(strprepend(&x, "xxx"), "xxx"); + ASSERT_STREQ(strprepend(&x, "bar"), "barxxx"); + ASSERT_STREQ(strprepend(&x, "foo"), "foobarxxx"); +} + TEST(strlevenshtein) { assert_se(strlevenshtein(NULL, NULL) == 0); assert_se(strlevenshtein("", "") == 0); From ce0a5106678b49fc67a9650c433f58781e3a0f1f Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Mon, 10 Feb 2025 19:04:08 +0100 Subject: [PATCH 2/5] cryptsetup: port to strprepend() --- src/cryptsetup/cryptsetup.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c index 6fd10613d1..d109d0914f 100644 --- a/src/cryptsetup/cryptsetup.c +++ b/src/cryptsetup/cryptsetup.c @@ -600,14 +600,15 @@ static int parse_one_option(const char *option) { * - text descriptions prefixed with "%:" or "%keyring:". * - text description with no prefix. * - numeric keyring id (ignored in current patch set). */ - if (IN_SET(*val, '@', '%')) - keyring = strndup(val, sep - val); - else - /* add type prefix if missing (crypt_set_keyring_to_link() expects it) */ - keyring = strnappend("%:", val, sep - val); + keyring = strndup(val, sep - val); if (!keyring) return log_oom(); + /* add type prefix if missing (crypt_set_keyring_to_link() expects it) */ + if (!IN_SET(*keyring, '@', '%')) + if (!strprepend(&keyring, "%:")) + return log_oom(); + sep += 2; /* % is optional (and defaults to 'user') */ From ea5fbc3938576af874486efc4a69a425f2358f3e Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Mon, 10 Feb 2025 19:04:29 +0100 Subject: [PATCH 3/5] env-util: use strextendn() instead of strnappend() where appropriate --- src/basic/env-util.c | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/src/basic/env-util.c b/src/basic/env-util.c index 99ce1a1842..09c8e7c28f 100644 --- a/src/basic/env-util.c +++ b/src/basic/env-util.c @@ -695,7 +695,7 @@ int replace_env_full( _cleanup_strv_free_ char **unset_variables = NULL, **bad_variables = NULL; const char *e, *word = format, *test_value = NULL; /* test_value is initialized to appease gcc */ _cleanup_free_ char *s = NULL; - char ***pu, ***pb, *k; + char ***pu, ***pb; size_t i, len = 0; /* len is initialized to appease gcc */ int nest = 0, r; @@ -717,33 +717,24 @@ int replace_env_full( case CURLY: if (*e == '{') { - k = strnappend(s, word, e-word-1); - if (!k) + if (!strextendn(&s, word, e-word-1)) return -ENOMEM; - free_and_replace(s, k); - word = e-1; state = VARIABLE; nest++; } else if (*e == '$') { - k = strnappend(s, word, e-word); - if (!k) + if (!strextendn(&s, word, e-word)) return -ENOMEM; - free_and_replace(s, k); - word = e+1; state = WORD; } else if (FLAGS_SET(flags, REPLACE_ENV_ALLOW_BRACELESS) && strchr(VALID_BASH_ENV_NAME_CHARS, *e)) { - k = strnappend(s, word, e-word-1); - if (!k) + if (!strextendn(&s, word, e-word-1)) return -ENOMEM; - free_and_replace(s, k); - word = e-1; state = VARIABLE_RAW; From 146b2ed6a661c6bd3023d06c57b04c01de35e008 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Mon, 10 Feb 2025 19:05:17 +0100 Subject: [PATCH 4/5] string-util: drop now unused strnappend() --- src/basic/string-util.c | 31 ------------------------------- src/basic/string-util.h | 2 -- 2 files changed, 33 deletions(-) diff --git a/src/basic/string-util.c b/src/basic/string-util.c index dace8a606d..196f3ff1a1 100644 --- a/src/basic/string-util.c +++ b/src/basic/string-util.c @@ -60,37 +60,6 @@ char* strprepend(char **x, const char *s) { return *x; } -char* strnappend(const char *s, const char *suffix, size_t b) { - size_t a; - char *r; - - if (!s && !suffix) - return strdup(""); - - if (!s) - return strndup(suffix, b); - - if (!suffix) - return strdup(s); - - assert(s); - assert(suffix); - - a = strlen(s); - if (b > SIZE_MAX - a) - return NULL; - - r = new(char, a+b+1); - if (!r) - return NULL; - - memcpy(r, s, a); - memcpy(r+a, suffix, b); - r[a+b] = 0; - - return r; -} - char* strstrip(char *s) { if (!s) return NULL; diff --git a/src/basic/string-util.h b/src/basic/string-util.h index 1b2f097061..6a30193746 100644 --- a/src/basic/string-util.h +++ b/src/basic/string-util.h @@ -108,8 +108,6 @@ char* first_word(const char *s, const char *word) _pure_; char* strprepend(char **x, const char *s); -char* strnappend(const char *s, const char *suffix, size_t length); - #define strjoin(a, ...) strextend_with_separator_internal(NULL, NULL, a, __VA_ARGS__, NULL) #define strjoina(a, ...) \ From 63ed6115796ac59ca12e1348cbace820bab373bc Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Mon, 10 Feb 2025 19:14:49 +0100 Subject: [PATCH 5/5] string-util: modernize strextendn() a bit l == SIZE_MAX requires no special handling, since we assert on (s || l == 0) above. --- src/basic/string-util.c | 51 +++++++++++++++++++---------------------- src/basic/string-util.h | 3 +-- 2 files changed, 25 insertions(+), 29 deletions(-) diff --git a/src/basic/string-util.c b/src/basic/string-util.c index 196f3ff1a1..7f4be13b62 100644 --- a/src/basic/string-util.c +++ b/src/basic/string-util.c @@ -60,6 +60,30 @@ char* strprepend(char **x, const char *s) { return *x; } +char* strextendn(char **x, const char *s, size_t l) { + assert(x); + assert(s || l == 0); + + if (l > 0) + l = strnlen(s, l); /* ignore trailing noise */ + + if (l > 0 || !*x) { + size_t q; + char *m; + + q = strlen_ptr(*x); + m = realloc(*x, q + l + 1); + if (!m) + return NULL; + + *mempcpy_typesafe(m + q, s, l) = 0; + + *x = m; + } + + return *x; +} + char* strstrip(char *s) { if (!s) return NULL; @@ -958,33 +982,6 @@ oom: return -ENOMEM; } -char* strextendn(char **x, const char *s, size_t l) { - assert(x); - assert(s || l == 0); - - if (l == SIZE_MAX) - l = strlen_ptr(s); - else if (l > 0) - l = strnlen(s, l); /* ignore trailing noise */ - - if (l > 0 || !*x) { - size_t q; - char *m; - - q = strlen_ptr(*x); - m = realloc(*x, q + l + 1); - if (!m) - return NULL; - - memcpy_safe(m + q, s, l); - m[q + l] = 0; - - *x = m; - } - - return *x; -} - char* strrep(const char *s, unsigned n) { char *r, *p; size_t l; diff --git a/src/basic/string-util.h b/src/basic/string-util.h index 6a30193746..8a5df741cc 100644 --- a/src/basic/string-util.h +++ b/src/basic/string-util.h @@ -107,6 +107,7 @@ static inline const char* empty_or_dash_to_null(const char *p) { char* first_word(const char *s, const char *word) _pure_; char* strprepend(char **x, const char *s); +char* strextendn(char **x, const char *s, size_t l); #define strjoin(a, ...) strextend_with_separator_internal(NULL, NULL, a, __VA_ARGS__, NULL) @@ -193,8 +194,6 @@ char* strextend_with_separator_internal(char **x, const char *separator, ...) _s #define strextend_with_separator(x, separator, ...) strextend_with_separator_internal(x, separator, __VA_ARGS__, NULL) #define strextend(x, ...) strextend_with_separator_internal(x, NULL, __VA_ARGS__, NULL) -char* strextendn(char **x, const char *s, size_t l); - int strextendf_with_separator(char **x, const char *separator, const char *format, ...) _printf_(3,4); #define strextendf(x, ...) strextendf_with_separator(x, NULL, __VA_ARGS__)