summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Maw <richard.maw@codethink.co.uk>2015-06-23 17:00:40 +0000
committerRichard Maw <richard.maw@codethink.co.uk>2015-08-07 15:50:42 +0000
commit206644aedeb8859801051ac170ec562c6a113a79 (patch)
tree88ba118333423abc16871dc490a74cd911218b3d
parent12ba2c44dde4d7cfc0e531dbc3cbd0581c323637 (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.c28
-rw-r--r--src/basic/util.h1
-rw-r--r--src/test/test-util.c32
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) {