From 70b6ee6110375222b6d102812d38e3e2bd19970f Mon Sep 17 00:00:00 2001 From: Luca Boccassi Date: Thu, 17 Jun 2021 13:12:57 +0100 Subject: [PATCH] basic/extract-word: add EXTRACT_RETAIN_SEPARATORS flag Makes the helpers avoid skipping over the separator(s) in the input string --- src/basic/extract-word.c | 21 ++++++++------- src/basic/extract-word.h | 1 + src/test/test-extract-word.c | 52 ++++++++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 9 deletions(-) diff --git a/src/basic/extract-word.c b/src/basic/extract-word.c index 0c440db691..9f9bb0c791 100644 --- a/src/basic/extract-word.c +++ b/src/basic/extract-word.c @@ -51,7 +51,8 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra goto finish_force_terminate; else if (strchr(separators, c)) { if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) { - (*p)++; + if (!(flags & EXTRACT_RETAIN_SEPARATORS)) + (*p)++; goto finish_force_next; } } else { @@ -153,16 +154,18 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra break; } else if (strchr(separators, c)) { if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) { - (*p)++; + if (!(flags & EXTRACT_RETAIN_SEPARATORS)) + (*p)++; goto finish_force_next; } - /* Skip additional coalesced separators. */ - for (;; (*p)++, c = **p) { - if (c == 0) - goto finish_force_terminate; - if (!strchr(separators, c)) - break; - } + if (!(flags & EXTRACT_RETAIN_SEPARATORS)) + /* Skip additional coalesced separators. */ + for (;; (*p)++, c = **p) { + if (c == 0) + goto finish_force_terminate; + if (!strchr(separators, c)) + break; + } goto finish; } diff --git a/src/basic/extract-word.h b/src/basic/extract-word.h index f415872fac..c82ad761ef 100644 --- a/src/basic/extract-word.h +++ b/src/basic/extract-word.h @@ -12,6 +12,7 @@ typedef enum ExtractFlags { EXTRACT_UNQUOTE = 1 << 5, /* Ignore separators in quoting with "" and '', and remove the quotes. */ EXTRACT_DONT_COALESCE_SEPARATORS = 1 << 6, /* Don't treat multiple adjacent separators as one */ EXTRACT_RETAIN_ESCAPE = 1 << 7, /* Treat escape character '\' as any other character without special meaning */ + EXTRACT_RETAIN_SEPARATORS = 1 << 8, /* Do not advance the original string pointer past the separator(s) */ /* Note that if no flags are specified, escaped escape characters will be silently stripped. */ } ExtractFlags; diff --git a/src/test/test-extract-word.c b/src/test/test-extract-word.c index a392ec7588..8cf0b63a4c 100644 --- a/src/test/test-extract-word.c +++ b/src/test/test-extract-word.c @@ -482,6 +482,58 @@ static void test_extract_first_word(void) { assert_se(extract_first_word(&p, &t, ",", EXTRACT_UNQUOTE) > 0); assert_se(streq(t, "context=system_u:object_r:svirt_sandbox_file_t:s0:c0,c1")); free(t); + + p = "a:b"; + assert_se(extract_first_word(&p, &t, ":", EXTRACT_RETAIN_SEPARATORS) == 1); + assert_se(streq(t, "a")); + assert_se(streq(p, ":b")); + free(t); + assert_se(extract_first_word(&p, &t, ":", EXTRACT_RETAIN_SEPARATORS) == 1); + assert_se(streq(t, "b")); + free(t); + + p = "a>:b"; + assert_se(extract_first_word(&p, &t, ">:", EXTRACT_RETAIN_SEPARATORS) == 1); + assert_se(streq(t, "a")); + assert_se(streq(p, ">:b")); + free(t); + assert_se(extract_first_word(&p, &t, ">:", EXTRACT_RETAIN_SEPARATORS) == 1); + assert_se(streq(t, "b")); + free(t); + + p = "a>:b"; + assert_se(extract_first_word(&p, &t, ">:", EXTRACT_RETAIN_SEPARATORS|EXTRACT_DONT_COALESCE_SEPARATORS) == 1); + assert_se(streq(t, "a")); + assert_se(streq(p, ">:b")); + free(t); + assert_se(extract_first_word(&p, &t, ">:", EXTRACT_RETAIN_SEPARATORS|EXTRACT_DONT_COALESCE_SEPARATORS) == 1); + assert_se(streq(t, "")); + assert_se(streq(p, ">:b")); + free(t); + + p = "a\\:b"; + assert_se(extract_first_word(&p, &t, ":", EXTRACT_RETAIN_SEPARATORS|EXTRACT_RETAIN_ESCAPE) == 1); + assert_se(streq(t, "a\\")); + assert_se(streq(p, ":b")); + free(t); + + p = "a\\:b"; + assert_se(extract_first_word(&p, &t, ":", EXTRACT_RETAIN_SEPARATORS) == 1); + assert_se(streq(t, "a:b")); + assert_se(!p); + free(t); + + p = "a\\:b"; + assert_se(extract_first_word(&p, &t, ":", EXTRACT_RETAIN_SEPARATORS|EXTRACT_UNESCAPE_SEPARATORS) == 1); + assert_se(streq(t, "a:b")); + assert_se(!p); + free(t); + + p = "a\\:a:b"; + assert_se(extract_first_word(&p, &t, ":", EXTRACT_RETAIN_SEPARATORS|EXTRACT_UNESCAPE_SEPARATORS) == 1); + assert_se(streq(t, "a:a")); + assert_se(streq(p, ":b")); + free(t); } static void test_extract_first_word_and_warn(void) {