diff --git a/src/basic/string-util.c b/src/basic/string-util.c index 0a40683493..07b11d4fc8 100644 --- a/src/basic/string-util.c +++ b/src/basic/string-util.c @@ -128,7 +128,7 @@ static size_t strcspn_escaped(const char *s, const char *reject) { } /* Split a string into words. */ -const char* split(const char **state, size_t *l, const char *separator, bool quoted) { +const char* split(const char **state, size_t *l, const char *separator, SplitFlags flags) { const char *current; current = *state; @@ -144,20 +144,24 @@ const char* split(const char **state, size_t *l, const char *separator, bool quo return NULL; } - if (quoted && strchr("\'\"", *current)) { + if (flags & SPLIT_QUOTES && strchr("\'\"", *current)) { char quotechars[2] = {*current, '\0'}; *l = strcspn_escaped(current + 1, quotechars); if (current[*l + 1] == '\0' || current[*l + 1] != quotechars[0] || (current[*l + 2] && !strchr(separator, current[*l + 2]))) { /* right quote missing or garbage at the end */ + if (flags & SPLIT_RELAX) { + *state = current + *l + 1 + (current[*l + 1] != '\0'); + return current + 1; + } *state = current; return NULL; } *state = current++ + *l + 2; - } else if (quoted) { + } else if (flags & SPLIT_QUOTES) { *l = strcspn_escaped(current, separator); - if (current[*l] && !strchr(separator, current[*l])) { + if (current[*l] && !strchr(separator, current[*l]) && !(flags & SPLIT_RELAX)) { /* unfinished escape */ *state = current; return NULL; diff --git a/src/basic/string-util.h b/src/basic/string-util.h index fcd12f3a30..a337dbc35f 100644 --- a/src/basic/string-util.h +++ b/src/basic/string-util.h @@ -81,16 +81,21 @@ char *endswith_no_case(const char *s, const char *postfix) _pure_; char *first_word(const char *s, const char *word) _pure_; -const char* split(const char **state, size_t *l, const char *separator, bool quoted); +typedef enum SplitFlags { + SPLIT_QUOTES = 0x01 << 0, + SPLIT_RELAX = 0x01 << 1, +} SplitFlags; + +const char* split(const char **state, size_t *l, const char *separator, SplitFlags flags); #define FOREACH_WORD(word, length, s, state) \ - _FOREACH_WORD(word, length, s, WHITESPACE, false, state) + _FOREACH_WORD(word, length, s, WHITESPACE, 0, state) #define FOREACH_WORD_SEPARATOR(word, length, s, separator, state) \ - _FOREACH_WORD(word, length, s, separator, false, state) + _FOREACH_WORD(word, length, s, separator, 0, state) -#define _FOREACH_WORD(word, length, s, separator, quoted, state) \ - for ((state) = (s), (word) = split(&(state), &(length), (separator), (quoted)); (word); (word) = split(&(state), &(length), (separator), (quoted))) +#define _FOREACH_WORD(word, length, s, separator, flags, state) \ + for ((state) = (s), (word) = split(&(state), &(length), (separator), (flags)); (word); (word) = split(&(state), &(length), (separator), (flags))) char *strappend(const char *s, const char *suffix); char *strnappend(const char *s, const char *suffix, size_t length); diff --git a/src/basic/strv.c b/src/basic/strv.c index 0647a472d7..1bab723e88 100644 --- a/src/basic/strv.c +++ b/src/basic/strv.c @@ -245,7 +245,7 @@ int strv_extend_strv_concat(char ***a, char **b, const char *suffix) { return 0; } -char **strv_split_full(const char *s, const char *separator, bool quoted) { +char **strv_split_full(const char *s, const char *separator, SplitFlags flags) { const char *word, *state; size_t l; size_t n, i; @@ -261,7 +261,7 @@ char **strv_split_full(const char *s, const char *separator, bool quoted) { return new0(char*, 1); n = 0; - _FOREACH_WORD(word, l, s, separator, quoted, state) + _FOREACH_WORD(word, l, s, separator, flags, state) n++; r = new(char*, n+1); @@ -269,7 +269,7 @@ char **strv_split_full(const char *s, const char *separator, bool quoted) { return NULL; i = 0; - _FOREACH_WORD(word, l, s, separator, quoted, state) { + _FOREACH_WORD(word, l, s, separator, flags, state) { r[i] = strndup(word, l); if (!r[i]) { strv_free(r); diff --git a/src/basic/strv.h b/src/basic/strv.h index 03fb5cc2b2..e9e6063f58 100644 --- a/src/basic/strv.h +++ b/src/basic/strv.h @@ -9,6 +9,7 @@ #include "alloc-util.h" #include "extract-word.h" #include "macro.h" +#include "string-util.h" #include "util.h" char *strv_find(char **l, const char *name) _pure_; @@ -66,9 +67,9 @@ static inline bool strv_isempty(char * const *l) { return !l || !*l; } -char **strv_split_full(const char *s, const char *separator, bool quoted); +char **strv_split_full(const char *s, const char *separator, SplitFlags flags); static inline char **strv_split(const char *s, const char *separator) { - return strv_split_full(s, separator, false); + return strv_split_full(s, separator, 0); } char **strv_split_newlines(const char *s);