From f88e6be5ee31ff0e45fabcdedaf26d3be0d4817a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 10 Nov 2014 23:44:34 +0100 Subject: [PATCH] strv: rework strv_split_quoted() to use unquote_first_word() This should make the unquoting scheme a bit less naive. --- src/journal-remote/journal-remote.c | 2 +- src/locale/localed.c | 6 +-- src/shared/strv.c | 69 +++++++++++++++-------------- src/shared/strv.h | 3 +- src/shared/util.c | 2 +- src/test/test-strv.c | 12 ++--- 6 files changed, 48 insertions(+), 46 deletions(-) diff --git a/src/journal-remote/journal-remote.c b/src/journal-remote/journal-remote.c index 7239b8cc6..b3f5c828d 100644 --- a/src/journal-remote/journal-remote.c +++ b/src/journal-remote/journal-remote.c @@ -149,7 +149,7 @@ static int spawn_getter(const char *getter, const char *url) { _cleanup_strv_free_ char **words = NULL; assert(getter); - r = strv_split_quoted(&words, getter); + r = strv_split_quoted(&words, getter, false); if (r < 0) { log_error("Failed to split getter option: %s", strerror(-r)); return r; diff --git a/src/locale/localed.c b/src/locale/localed.c index 552ffdf87..9377ce501 100644 --- a/src/locale/localed.c +++ b/src/locale/localed.c @@ -224,7 +224,7 @@ static int x11_read_data(Context *c) { if (in_section && first_word(l, "Option")) { _cleanup_strv_free_ char **a = NULL; - r = strv_split_quoted(&a, l); + r = strv_split_quoted(&a, l, false); if (r < 0) return r; @@ -247,7 +247,7 @@ static int x11_read_data(Context *c) { } else if (!in_section && first_word(l, "Section")) { _cleanup_strv_free_ char **a = NULL; - r = strv_split_quoted(&a, l); + r = strv_split_quoted(&a, l, false); if (r < 0) return -ENOMEM; @@ -533,7 +533,7 @@ static int read_next_mapping(FILE *f, unsigned *n, char ***a) { if (l[0] == 0 || l[0] == '#') continue; - r = strv_split_quoted(&b, l); + r = strv_split_quoted(&b, l, false); if (r < 0) return r; diff --git a/src/shared/strv.c b/src/shared/strv.c index 00857e40a..aeb93eac6 100644 --- a/src/shared/strv.c +++ b/src/shared/strv.c @@ -248,40 +248,6 @@ char **strv_split(const char *s, const char *separator) { return r; } -int strv_split_quoted(char ***t, const char *s) { - const char *word, *state; - size_t l; - unsigned n, i; - char **r; - - assert(s); - - n = 0; - FOREACH_WORD_QUOTED(word, l, s, state) - n++; - if (!isempty(state)) - /* bad syntax */ - return -EINVAL; - - r = new(char*, n+1); - if (!r) - return -ENOMEM; - - i = 0; - FOREACH_WORD_QUOTED(word, l, s, state) { - r[i] = cunescape_length(word, l); - if (!r[i]) { - strv_free(r); - return -ENOMEM; - } - i++; - } - - r[i] = NULL; - *t = r; - return 0; -} - char **strv_split_newlines(const char *s) { char **l; unsigned n; @@ -307,6 +273,41 @@ char **strv_split_newlines(const char *s) { return l; } +int strv_split_quoted(char ***t, const char *s, bool relax) { + size_t n = 0, allocated = 0; + _cleanup_strv_free_ char **l = NULL; + int r; + + assert(t); + assert(s); + + for (;;) { + _cleanup_free_ char *word = NULL; + + r = unquote_first_word(&s, &word, relax); + if (r < 0) + return r; + if (r == 0) + break; + + if (!GREEDY_REALLOC(l, allocated, n + 2)) + return -ENOMEM; + + l[n++] = word; + word = NULL; + + l[n] = NULL; + } + + if (!l) + l = new0(char*, 1); + + *t = l; + l = NULL; + + return 0; +} + char *strv_join(char **l, const char *separator) { char *r, *e; char **s; diff --git a/src/shared/strv.h b/src/shared/strv.h index 9c9633c51..47618bd26 100644 --- a/src/shared/strv.h +++ b/src/shared/strv.h @@ -63,9 +63,10 @@ static inline bool strv_isempty(char * const *l) { } char **strv_split(const char *s, const char *separator); -int strv_split_quoted(char ***t, const char *s); char **strv_split_newlines(const char *s); +int strv_split_quoted(char ***t, const char *s, bool relax); + char *strv_join(char **l, const char *separator); char *strv_join_quoted(char **l); diff --git a/src/shared/util.c b/src/shared/util.c index f0e0c0dd3..2f4fa237d 100644 --- a/src/shared/util.c +++ b/src/shared/util.c @@ -3292,7 +3292,7 @@ char **replace_env_argv(char **argv, char **env) { if (e) { int r; - r = strv_split_quoted(&m, e); + r = strv_split_quoted(&m, e, true); if (r < 0) { ret[k] = NULL; strv_free(ret); diff --git a/src/test/test-strv.c b/src/test/test-strv.c index 915fa4675..180f06239 100644 --- a/src/test/test-strv.c +++ b/src/test/test-strv.c @@ -165,7 +165,7 @@ static void test_strv_quote_unquote(const char* const *split, const char *quoted assert_se(p); assert_se(streq(p, quoted)); - r = strv_split_quoted(&s, quoted); + r = strv_split_quoted(&s, quoted, false); assert_se(r == 0); assert_se(s); STRV_FOREACH(t, s) { @@ -182,7 +182,7 @@ static void test_strv_unquote(const char *quoted, const char **list) { char **t; int r; - r = strv_split_quoted(&s, quoted); + r = strv_split_quoted(&s, quoted, false); assert_se(r == 0); assert_se(s); j = strv_join(s, " | "); @@ -199,7 +199,7 @@ static void test_invalid_unquote(const char *quoted) { char **s = NULL; int r; - r = strv_split_quoted(&s, quoted); + r = strv_split_quoted(&s, quoted, false); assert_se(s == NULL); assert_se(r == -EINVAL); } @@ -482,12 +482,12 @@ int main(int argc, char *argv[]) { test_strv_unquote(" \"x'\" ", (const char*[]) { "x'", NULL }); test_strv_unquote("a '--b=c \"d e\"'", (const char*[]) { "a", "--b=c \"d e\"", NULL }); - test_invalid_unquote("a --b='c \"d e\"'"); - test_invalid_unquote("a --b='c \"d e\" '"); + test_invalid_unquote("a --b='c \"d e\"''"); + test_invalid_unquote("a --b='c \"d e\" '\""); test_invalid_unquote("a --b='c \"d e\"garbage"); test_invalid_unquote("'"); test_invalid_unquote("\""); - test_invalid_unquote("'x'y"); + test_invalid_unquote("'x'y'g"); test_strv_split(); test_strv_split_newlines(); -- 2.30.2