diff options
author | Richard Maw <richard.maw@codethink.co.uk> | 2015-06-23 17:00:40 +0000 |
---|---|---|
committer | Richard Maw <richard.maw@codethink.co.uk> | 2015-08-07 15:50:42 +0000 |
commit | 206644aedeb8859801051ac170ec562c6a113a79 (patch) | |
tree | 88ba118333423abc16871dc490a74cd911218b3d | |
parent | 12ba2c44dde4d7cfc0e531dbc3cbd0581c323637 (diff) |
util: Allow non-separator coalescing parsing in extract_first_word
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.
-rw-r--r-- | src/basic/util.c | 28 | ||||
-rw-r--r-- | src/basic/util.h | 1 | ||||
-rw-r--r-- | src/test/test-util.c | 32 |
3 files changed, 55 insertions, 6 deletions
diff --git a/src/basic/util.c b/src/basic/util.c index d4c385fcef..0b974b2ab5 100644 --- a/src/basic/util.c +++ b/src/basic/util.c @@ -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; diff --git a/src/basic/util.h b/src/basic/util.h index 82fb771e20..4d6a8abb57 100644 --- a/src/basic/util.h +++ b/src/basic/util.h @@ -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); diff --git a/src/test/test-util.c b/src/test/test-util.c index 40f5d34de3..fc7a3de106 100644 --- a/src/test/test-util.c +++ b/src/test/test-util.c @@ -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) { |