From 206644aedeb8859801051ac170ec562c6a113a79 Mon Sep 17 00:00:00 2001 From: Richard Maw Date: Tue, 23 Jun 2015 17:00:40 +0000 Subject: [PATCH] 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. --- src/basic/util.c | 28 ++++++++++++++++++++++------ src/basic/util.h | 1 + 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 d4c385f..0b974b2 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 82fb771..4d6a8ab 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 40f5d34..fc7a3de 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) { -- 2.7.4