diff --git a/src/basic/extract-word.c b/src/basic/extract-word.c index 1a53da334a..d64dddd641 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 ceea8176f5..41c2c3289e 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 6d366a3510..c4f86b4ee2 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 e0ed5cee8c..087fb7c907 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 e57dfff69b..bc0b04b56b 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 0834e0b969..b39fda0313 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;