From 53cd7f337489433734c0d134b2a569727dd61a38 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Wed, 29 Jul 2020 14:06:26 +0200 Subject: [PATCH] basic: add string_contains_word() This wraps the common pattern of using extract_first_word() in a loop to look for a matching word. --- src/basic/string-util.c | 20 ++++++++++++++ src/basic/string-util.h | 1 + src/test/test-string-util.c | 54 +++++++++++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+) diff --git a/src/basic/string-util.c b/src/basic/string-util.c index 755a37f6675..6d366a3510f 100644 --- a/src/basic/string-util.c +++ b/src/basic/string-util.c @@ -8,6 +8,7 @@ #include "alloc-util.h" #include "escape.h" +#include "extract-word.h" #include "fileio.h" #include "gunicode.h" #include "locale-util.h" @@ -1207,3 +1208,22 @@ int string_extract_line(const char *s, size_t i, char **ret) { c++; } } + +int string_contains_word(const char *string, const char *separators, const char *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; + + for (const char *p = string;;) { + _cleanup_free_ char *w = NULL; + int r; + + r = extract_first_word(&p, &w, separators, flags); + if (r < 0) + return r; + if (r == 0) + return false; + if (streq(w, word)) + return true; + } +} diff --git a/src/basic/string-util.h b/src/basic/string-util.h index cf8c74b8229..e0ed5cee8c1 100644 --- a/src/basic/string-util.h +++ b/src/basic/string-util.h @@ -280,3 +280,4 @@ 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); diff --git a/src/test/test-string-util.c b/src/test/test-string-util.c index 33c5f835753..0834e0b9697 100644 --- a/src/test/test-string-util.c +++ b/src/test/test-string-util.c @@ -796,6 +796,59 @@ 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(void) { + log_info("/* %s */", __func__); + + assert_se( string_contains_word("a b cc", NULL, "a")); + assert_se( string_contains_word("a b cc", NULL, "b")); + assert_se(!string_contains_word("a b cc", NULL, "c")); + assert_se( string_contains_word("a b cc", NULL, "cc")); + assert_se(!string_contains_word("a b cc", NULL, "d")); + assert_se(!string_contains_word("a b cc", NULL, "a b")); + assert_se(!string_contains_word("a b cc", NULL, "a b c")); + assert_se(!string_contains_word("a b cc", NULL, "b c")); + assert_se(!string_contains_word("a b cc", NULL, "b cc")); + assert_se(!string_contains_word("a b cc", NULL, "a ")); + assert_se(!string_contains_word("a b cc", NULL, " b ")); + assert_se(!string_contains_word("a b cc", NULL, " cc")); + + assert_se( string_contains_word(" a b\t\tcc", NULL, "a")); + assert_se( string_contains_word(" a b\t\tcc", NULL, "b")); + assert_se(!string_contains_word(" a b\t\tcc", NULL, "c")); + assert_se( string_contains_word(" a b\t\tcc", NULL, "cc")); + assert_se(!string_contains_word(" a b\t\tcc", NULL, "d")); + assert_se(!string_contains_word(" a b\t\tcc", NULL, "a b")); + assert_se(!string_contains_word(" a b\t\tcc", NULL, "a b\t\tc")); + assert_se(!string_contains_word(" a b\t\tcc", NULL, "b\t\tc")); + assert_se(!string_contains_word(" a b\t\tcc", NULL, "b\t\tcc")); + assert_se(!string_contains_word(" a b\t\tcc", NULL, "a ")); + assert_se(!string_contains_word(" a b\t\tcc", NULL, " b ")); + assert_se(!string_contains_word(" a b\t\tcc", NULL, " cc")); + + assert_se(!string_contains_word(" a b\t\tcc", NULL, "")); + assert_se(!string_contains_word(" a b\t\tcc", NULL, " ")); + assert_se(!string_contains_word(" a b\t\tcc", NULL, " ")); + assert_se( string_contains_word(" a b\t\tcc", " ", "")); + assert_se( string_contains_word(" a b\t\tcc", "\t", "")); + assert_se( string_contains_word(" a b\t\tcc", WHITESPACE, "")); + + assert_se( string_contains_word("a:b:cc", ":#", "a")); + assert_se( string_contains_word("a:b:cc", ":#", "b")); + assert_se(!string_contains_word("a:b:cc", ":#", "c")); + assert_se( string_contains_word("a:b:cc", ":#", "cc")); + assert_se(!string_contains_word("a:b:cc", ":#", "d")); + assert_se(!string_contains_word("a:b:cc", ":#", "a:b")); + assert_se(!string_contains_word("a:b:cc", ":#", "a:b:c")); + assert_se(!string_contains_word("a:b:cc", ":#", "b:c")); + assert_se(!string_contains_word("a#b#cc", ":#", "b:cc")); + assert_se( string_contains_word("a#b#cc", ":#", "b")); + assert_se( string_contains_word("a#b#cc", ":#", "cc")); + assert_se(!string_contains_word("a:b:cc", ":#", "a:")); + assert_se(!string_contains_word("a:b cc", ":#", "b")); + assert_se( string_contains_word("a:b cc", ":#", "b cc")); + assert_se(!string_contains_word("a:b:cc", ":#", ":cc")); +} + int main(int argc, char *argv[]) { test_setup_logging(LOG_DEBUG); @@ -831,6 +884,7 @@ int main(int argc, char *argv[]) { test_memory_startswith_no_case(); test_string_truncate_lines(); test_string_extract_line(); + test_string_contains_word(); return 0; } -- 2.39.5