]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
strv: introduce 'relax' mode to strv_split_full()
authorYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 26 Sep 2018 13:17:40 +0000 (22:17 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 26 Sep 2018 13:48:17 +0000 (22:48 +0900)
If SPLIT_RELAX is specified, then it accepts unfinished quotes or
missing separator after right quote.

src/basic/string-util.c
src/basic/string-util.h
src/basic/strv.c
src/basic/strv.h

index 0a40683493c70601ff6c49451e10dbdc325d76f0..07b11d4fc8b3de4348c30f7c2797216fef49a557 100644 (file)
@@ -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;
index fcd12f3a305d73d5cc90eb6afeb180bebb9f647c..a337dbc35f769d3b8761aa93199453d6661b6905 100644 (file)
@@ -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);
index 0647a472d70482af8df22cb8e6a9eb0a541003a1..1bab723e88d807a3df1a22ad4126a112c864493e 100644 (file)
@@ -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);
index 03fb5cc2b2488d82373f3efe3ccea403548f7f56..e9e6063f5895746e019a6b0524f167e4ca23fc9c 100644 (file)
@@ -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);