utils: add strstartswith() and strendswith() utility functions
authorPeter Hutterer <peter.hutterer@who-t.net>
Tue, 16 Jun 2020 22:58:44 +0000 (08:58 +1000)
committerPeter Hutterer <peter.hutterer@who-t.net>
Wed, 17 Jun 2020 07:52:00 +0000 (07:52 +0000)
Modeled after Python's str.startswith() and str.endswith()

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
src/util-strings.h
test/test-utils.c

index 73c23d902d5d14c58de05c247e1d5e1a695d27bc..2c31ff8034dc214105f190f17e79ef1bac304e1f 100644 (file)
@@ -338,3 +338,29 @@ strstrip(const char *input, const char *what)
 
        return str;
 }
+
+/**
+ * Return true if str ends in suffix, false otherwise. If the suffix is the
+ * empty string, strendswith() always returns false.
+ */
+static inline bool
+strendswith(const char *str, const char *suffix)
+{
+       size_t slen = strlen(str);
+       size_t suffixlen = strlen(suffix);
+       size_t offset;
+
+       if (slen == 0 || suffixlen == 0 || suffixlen > slen)
+               return false;
+
+       offset = slen - suffixlen;
+       return strneq(&str[offset], suffix, suffixlen);
+}
+
+static inline bool
+strstartswith(const char *str, const char *prefix)
+{
+       size_t prefixlen = strlen(prefix);
+
+       return prefixlen > 0 ? strneq(str, prefix, strlen(prefix)) : false;
+}
index 007a9411c4a1cb7bfa53fcf4eb4b23f1dc45a5f5..5faec0e4b00da8a44577d6b2e699d3e46d866afc 100644 (file)
@@ -1102,6 +1102,54 @@ START_TEST(strstrip_test)
 }
 END_TEST
 
+START_TEST(strendswith_test)
+{
+       struct strendswith_test {
+               const char *string;
+               const char *suffix;
+               bool expected;
+       } tests[] = {
+               { "foobar", "bar", true },
+               { "foobar", "foo", false },
+               { "foobar", "foobar", true },
+               { "foo", "foobar", false },
+               { "foobar", "", false },
+               { "", "", false },
+               { "", "foo", false },
+               { NULL, NULL, false },
+       };
+
+       for (struct strendswith_test *t = tests; t->string; t++) {
+               ck_assert_int_eq(strendswith(t->string, t->suffix),
+                                t->expected);
+       }
+}
+END_TEST
+
+START_TEST(strstartswith_test)
+{
+       struct strstartswith_test {
+               const char *string;
+               const char *suffix;
+               bool expected;
+       } tests[] = {
+               { "foobar", "foo", true },
+               { "foobar", "bar", false },
+               { "foobar", "foobar", true },
+               { "foo", "foobar", false },
+               { "foo", "", false },
+               { "", "", false },
+               { "foo", "", false },
+               { NULL, NULL, false },
+       };
+
+       for (struct strstartswith_test *t = tests; t->string; t++) {
+               ck_assert_int_eq(strstartswith(t->string, t->suffix),
+                                t->expected);
+       }
+}
+END_TEST
+
 START_TEST(list_test_insert)
 {
        struct list_test {
@@ -1208,6 +1256,8 @@ litest_utils_suite(void)
        tcase_add_test(tc, kvsplit_double_test);
        tcase_add_test(tc, strjoin_test);
        tcase_add_test(tc, strstrip_test);
+       tcase_add_test(tc, strendswith_test);
+       tcase_add_test(tc, strstartswith_test);
        tcase_add_test(tc, time_conversion);
        tcase_add_test(tc, human_time);