From: Luca Boccassi Date: Tue, 7 Jul 2020 16:12:48 +0000 (+0100) Subject: strv: add strv_split_colon_pairs function X-Git-Tag: v247-rc1~446^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a082edd53ac9da4a8e06281360754eb15bd1389f;p=thirdparty%2Fsystemd.git strv: add strv_split_colon_pairs function Given a string in the format 'one:two three four:five', returns a string vector with each word. If the second element of the tuple is not present, an empty string is returned in its place, so that the vector can be processed in pairs. [zjs: use EXTRACT_UNESCAPE_SEPARATORS instead of EXTRACT_CUNESCAPE_RELAX. This way we do escaping exactly once and in normal strict mode.] --- diff --git a/src/basic/strv.c b/src/basic/strv.c index 858e1e62ecc..a172ca2fe91 100644 --- a/src/basic/strv.c +++ b/src/basic/strv.c @@ -353,6 +353,58 @@ int strv_split_extract(char ***t, const char *s, const char *separators, Extract return (int) n; } +int strv_split_colon_pairs(char ***t, const char *s) { + _cleanup_strv_free_ char **l = NULL; + size_t n = 0, allocated = 0; + int r; + + assert(t); + assert(s); + + for (;;) { + _cleanup_free_ char *first = NULL, *second = NULL, *tuple = NULL, *second_or_empty = NULL; + + r = extract_first_word(&s, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE); + if (r < 0) + return r; + if (r == 0) + break; + + const char *p = tuple; + r = extract_many_words(&p, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, + &first, &second, NULL); + if (r < 0) + return r; + if (r == 0) + continue; + /* Enforce that at most 2 colon-separated words are contained in each group */ + if (!isempty(p)) + return -EINVAL; + + second_or_empty = strdup(strempty(second)); + if (!second_or_empty) + return -ENOMEM; + + if (!GREEDY_REALLOC(l, allocated, n + 3)) + return -ENOMEM; + + l[n++] = TAKE_PTR(first); + l[n++] = TAKE_PTR(second_or_empty); + + l[n] = NULL; + } + + if (!l) { + l = new0(char*, 1); + if (!l) + return -ENOMEM; + } + + *t = TAKE_PTR(l); + + return (int) n; +} + char *strv_join_prefix(char * const *l, const char *separator, const char *prefix) { char * const *s; char *r, *e; diff --git a/src/basic/strv.h b/src/basic/strv.h index 2ad927bce51..e57dfff69be 100644 --- a/src/basic/strv.h +++ b/src/basic/strv.h @@ -80,6 +80,11 @@ char **strv_split_newlines(const char *s); int strv_split_extract(char ***t, const char *s, const char *separators, ExtractFlags flags); +/* Given a string containing white-space separated tuples of words themselves separated by ':', + * returns a vector of strings. If the second element in a tuple is missing, the corresponding + * string in the vector is an empty string. */ +int strv_split_colon_pairs(char ***t, const char *s); + char *strv_join_prefix(char * const *l, const char *separator, const char *prefix); static inline char *strv_join(char * const *l, const char *separator) { return strv_join_prefix(l, separator, NULL); diff --git a/src/test/test-strv.c b/src/test/test-strv.c index cba5441d4b3..fda5948f499 100644 --- a/src/test/test-strv.c +++ b/src/test/test-strv.c @@ -407,6 +407,35 @@ static void test_strv_split_extract(void) { assert_se(streq_ptr(l[5], NULL)); } +static void test_strv_split_colon_pairs(void) { + _cleanup_strv_free_ char **l = NULL; + const char *str = "one:two three four:five six seven:eight\\:nine ten\\:eleven\\\\", + *str_inval="one:two three:four:five"; + int r; + + log_info("/* %s */", __func__); + + r = strv_split_colon_pairs(&l, str); + assert_se(r == (int) strv_length(l)); + assert_se(r == 12); + assert_se(streq_ptr(l[0], "one")); + assert_se(streq_ptr(l[1], "two")); + assert_se(streq_ptr(l[2], "three")); + assert_se(streq_ptr(l[3], "")); + assert_se(streq_ptr(l[4], "four")); + assert_se(streq_ptr(l[5], "five")); + assert_se(streq_ptr(l[6], "six")); + assert_se(streq_ptr(l[7], "")); + assert_se(streq_ptr(l[8], "seven")); + assert_se(streq_ptr(l[9], "eight:nine")); + assert_se(streq_ptr(l[10], "ten:eleven\\")); + assert_se(streq_ptr(l[11], "")); + assert_se(streq_ptr(l[12], NULL)); + + r = strv_split_colon_pairs(&l, str_inval); + assert_se(r == -EINVAL); +} + static void test_strv_split_newlines(void) { unsigned i = 0; char **s; @@ -998,6 +1027,7 @@ int main(int argc, char *argv[]) { test_strv_split(); test_strv_split_empty(); test_strv_split_extract(); + test_strv_split_colon_pairs(); test_strv_split_newlines(); test_strv_split_nulstr(); test_strv_parse_nulstr();