]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
util: Allow non-separator coalescing parsing in extract_first_word
authorRichard Maw <richard.maw@codethink.co.uk>
Tue, 23 Jun 2015 17:00:40 +0000 (17:00 +0000)
committerRichard Maw <richard.maw@codethink.co.uk>
Fri, 7 Aug 2015 15:50:42 +0000 (15:50 +0000)
If EXTRACT_DONT_COALESCE_SEPARATORS is passed, then leading separators,
trailing separators and spans of multiple separators aren't skipped, and
empty arguments from before, after or between separators may be extracted.

src/basic/util.c
src/basic/util.h
src/test/test-util.c

index d4c385fcef57ae01cde56f1992367c9311436e06..0b974b2ab5690a36e75603effe52bf452a9bc7fe 100644 (file)
@@ -5735,10 +5735,20 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra
                 switch (state) {
 
                 case START:
-                        if (c == 0)
+                        if (c == 0) {
+                                if (flags & EXTRACT_DONT_COALESCE_SEPARATORS)
+                                        if (!GREEDY_REALLOC(s, allocated, sz+1))
+                                                return -ENOMEM;
                                 goto finish_force_terminate;
-                        else if (strchr(separators, c))
+                        } else if (strchr(separators, c)) {
+                                if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) {
+                                        if (!GREEDY_REALLOC(s, allocated, sz+1))
+                                                return -ENOMEM;
+                                        (*p) ++;
+                                        goto finish_force_next;
+                                }
                                 break;
+                        }
 
                         state = VALUE;
                         /* fallthrough */
@@ -5758,9 +5768,13 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra
                                         return -ENOMEM;
 
                                 state = DOUBLE_QUOTE;
-                        } else if (strchr(separators, c))
+                        } else if (strchr(separators, c)) {
+                                if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) {
+                                        (*p) ++;
+                                        goto finish_force_next;
+                                }
                                 state = SEPARATOR;
-                        else {
+                        else {
                                 if (!GREEDY_REALLOC(s, allocated, sz+2))
                                         return -ENOMEM;
 
@@ -5857,10 +5871,11 @@ end_escape:
 
                 case SEPARATOR:
                         if (c == 0)
-                                goto finish;
+                                goto finish_force_terminate;
+                        if (flags & EXTRACT_DONT_COALESCE_SEPARATORS)
+                                goto finish_force_next;
                         if (!strchr(separators, c))
                                 goto finish;
-
                         break;
                 }
 
@@ -5876,6 +5891,7 @@ finish:
                 return 0;
         }
 
+finish_force_next:
         s[sz] = 0;
         *ret = s;
         s = NULL;
index 82fb771e20653ef6521fde029c8c12825c6c27dd..4d6a8abb574ab1029a3683dedbc0b0243dfba131 100644 (file)
@@ -859,6 +859,7 @@ typedef enum ExtractFlags {
         EXTRACT_CUNESCAPE       = 2,
         EXTRACT_CUNESCAPE_RELAX = 4,
         EXTRACT_QUOTES          = 8,
+        EXTRACT_DONT_COALESCE_SEPARATORS = 16,
 } ExtractFlags;
 
 int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags);
index 40f5d34de3249decc470329a1845c332306ae00f..fc7a3de106e9608dd4dc876a63d89577123d5ba7 100644 (file)
@@ -1744,6 +1744,38 @@ static void test_extract_first_word(void) {
         assert_se(streq(t, ""));
         free(t);
         assert_se(isempty(p));
+
+        p = original = ":foo\\:bar::waldo:";
+        assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1);
+        assert_se(t);
+        assert_se(streq(t, ""));
+        free(t);
+        assert_se(p == original + 1);
+
+        assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1);
+        assert_se(streq(t, "foo:bar"));
+        free(t);
+        assert_se(p == original + 10);
+
+        assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1);
+        assert_se(t);
+        assert_se(streq(t, ""));
+        free(t);
+        assert_se(p == original + 11);
+
+        assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1);
+        assert_se(streq(t, "waldo"));
+        free(t);
+        assert_se(p == original + 17);
+
+        assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1);
+        assert_se(streq(t, ""));
+        free(t);
+        assert_se(p == NULL);
+
+        assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 0);
+        assert_se(!t);
+        assert_se(!p);
 }
 
 static void test_extract_first_word_and_warn(void) {