From 46bf625aca8aa6f1f8608611dccddce948ded4d6 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Thu, 30 Jul 2020 10:34:44 +0200 Subject: [PATCH] Add string_contains_word_strv() I had to move STRV_MAKE to macro.h. There is a circular dependency between extract-word.h, strv.h, and string-util.h that makes it hard to define the inline function otherwise. --- src/basic/extract-word.c | 1 + src/basic/macro.h | 3 +++ src/basic/string-util.c | 17 +++++++++++++---- src/basic/string-util.h | 6 +++++- src/basic/strv.h | 4 ---- src/test/test-string-util.c | 30 ++++++++++++++++++++++++++++++ 6 files changed, 52 insertions(+), 9 deletions(-) diff --git a/src/basic/extract-word.c b/src/basic/extract-word.c index 1a53da334a2..d64dddd641d 100644 --- a/src/basic/extract-word.c +++ b/src/basic/extract-word.c @@ -14,6 +14,7 @@ #include "log.h" #include "macro.h" #include "string-util.h" +#include "strv.h" #include "utf8.h" int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags) { diff --git a/src/basic/macro.h b/src/basic/macro.h index ceea8176f5b..41c2c3289e8 100644 --- a/src/basic/macro.h +++ b/src/basic/macro.h @@ -538,6 +538,9 @@ static inline int __coverity_check_and_return__(int condition) { (y) = (_t); \ } while (false) +#define STRV_MAKE(...) ((char**) ((const char*[]) { __VA_ARGS__, NULL })) +#define STRV_MAKE_EMPTY ((char*[1]) { NULL }) + /* Iterates through a specified list of pointers. Accepts NULL pointers, but uses (void*) -1 as internal marker for EOL. */ #define FOREACH_POINTER(p, x, ...) \ for (typeof(p) *_l = (typeof(p)[]) { ({ p = x; }), ##__VA_ARGS__, (void*) -1 }; \ diff --git a/src/basic/string-util.c b/src/basic/string-util.c index 6d366a3510f..c4f86b4ee2f 100644 --- a/src/basic/string-util.c +++ b/src/basic/string-util.c @@ -15,6 +15,7 @@ #include "macro.h" #include "memory-util.h" #include "string-util.h" +#include "strv.h" #include "terminal-util.h" #include "utf8.h" #include "util.h" @@ -1209,11 +1210,13 @@ int string_extract_line(const char *s, size_t i, char **ret) { } } -int string_contains_word(const char *string, const char *separators, const char *word) { +int string_contains_word_strv(const char *string, const char *separators, char **words, const char **ret_word) { /* In the default mode with no separators specified, we split on whitespace and * don't coalesce separators. */ const ExtractFlags flags = separators ? EXTRACT_DONT_COALESCE_SEPARATORS : 0; + const char *found = NULL; + for (const char *p = string;;) { _cleanup_free_ char *w = NULL; int r; @@ -1222,8 +1225,14 @@ int string_contains_word(const char *string, const char *separators, const char if (r < 0) return r; if (r == 0) - return false; - if (streq(w, word)) - return true; + break; + + found = strv_find(words, w); + if (found) + break; } + + if (ret_word) + *ret_word = found; + return !!found; } diff --git a/src/basic/string-util.h b/src/basic/string-util.h index e0ed5cee8c1..087fb7c9071 100644 --- a/src/basic/string-util.h +++ b/src/basic/string-util.h @@ -280,4 +280,8 @@ char* string_erase(char *x); int string_truncate_lines(const char *s, size_t n_lines, char **ret); int string_extract_line(const char *s, size_t i, char **ret); -int string_contains_word(const char *string, const char *separators, const char *word); + +int string_contains_word_strv(const char *string, const char *separators, char **words, const char **ret_word); +static inline int string_contains_word(const char *string, const char *separators, const char *word) { + return string_contains_word_strv(string, separators, STRV_MAKE(word), NULL); +} diff --git a/src/basic/strv.h b/src/basic/strv.h index e57dfff69be..bc0b04b56b3 100644 --- a/src/basic/strv.h +++ b/src/basic/strv.h @@ -123,10 +123,6 @@ bool strv_overlap(char * const *a, char * const *b) _pure_; char **strv_sort(char **l); void strv_print(char * const *l); -#define STRV_MAKE(...) ((char**) ((const char*[]) { __VA_ARGS__, NULL })) - -#define STRV_MAKE_EMPTY ((char*[1]) { NULL }) - #define strv_from_stdarg_alloca(first) \ ({ \ char **_l; \ diff --git a/src/test/test-string-util.c b/src/test/test-string-util.c index 0834e0b9697..b39fda0313b 100644 --- a/src/test/test-string-util.c +++ b/src/test/test-string-util.c @@ -796,6 +796,35 @@ static void test_string_extract_line(void) { test_string_extract_lines_one("\n\n\nx\n", 3, "x", false); } +static void test_string_contains_word_strv(void) { + log_info("/* %s */", __func__); + + const char *w; + + assert_se(string_contains_word_strv("a b cc", NULL, STRV_MAKE("a", "b"), NULL)); + + assert_se(string_contains_word_strv("a b cc", NULL, STRV_MAKE("a", "b"), &w)); + assert_se(streq(w, "a")); + + assert_se(!string_contains_word_strv("a b cc", NULL, STRV_MAKE("d"), &w)); + assert_se(w == NULL); + + assert_se(string_contains_word_strv("a b cc", NULL, STRV_MAKE("b", "a"), &w)); + assert_se(streq(w, "a")); + + assert_se(string_contains_word_strv("b a b cc", NULL, STRV_MAKE("b", "a", "b"), &w)); + assert_se(streq(w, "b")); + + assert_se(string_contains_word_strv("a b cc", NULL, STRV_MAKE("b", ""), &w)); + assert_se(streq(w, "b")); + + assert_se(!string_contains_word_strv("a b cc", NULL, STRV_MAKE(""), &w)); + assert_se(w == NULL); + + assert_se(string_contains_word_strv("a b cc", " ", STRV_MAKE(""), &w)); + assert_se(streq(w, "")); +} + static void test_string_contains_word(void) { log_info("/* %s */", __func__); @@ -884,6 +913,7 @@ int main(int argc, char *argv[]) { test_memory_startswith_no_case(); test_string_truncate_lines(); test_string_extract_line(); + test_string_contains_word_strv(); test_string_contains_word(); return 0; -- 2.39.2