]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib: strfuncs - Add str_ends_with() & str_ends_icase_with()
authorMarco Bettini <marco.bettini@open-xchange.com>
Thu, 1 Aug 2024 12:33:02 +0000 (12:33 +0000)
committerAki Tuomi <aki.tuomi@open-xchange.com>
Fri, 17 Jan 2025 08:39:59 +0000 (10:39 +0200)
src/lib/strfuncs.h
src/lib/test-strfuncs.c

index 7111e9ee150cea507b940836bdb879f5b8be54c5..f48021a9a1aae69865ef51adc6503fce9d4dca5e 100644 (file)
@@ -130,6 +130,26 @@ str_begins_builtin_success(const char *haystack, size_t needle_len,
          str_begins_builtin_success((h), strlen(n), suffix_r)))
 #endif
 
+static inline ATTR_PURE bool
+str_ends_with(const char *haystack, const char *suffix)
+{
+       size_t haystack_len = strlen(haystack);
+       size_t suffix_len = strlen(suffix);
+       if (haystack_len < suffix_len)
+               return FALSE;
+       return strcmp(haystack + haystack_len - suffix_len, suffix) == 0;
+}
+
+static inline ATTR_PURE bool
+str_ends_icase_with(const char *haystack, const char *suffix)
+{
+       size_t haystack_len = strlen(haystack);
+       size_t suffix_len = strlen(suffix);
+       if (haystack_len < suffix_len)
+               return FALSE;
+       return strcasecmp(haystack + haystack_len - suffix_len, suffix) == 0;
+}
+
 /* Get length of a prefix segment.
 
   Calculates the length (in bytes) of the initial segment of s which consists
index fc59ae3acd3d22bf6a7c5b7a0b34123f5164ac73..d9f5bd82af31b1e625a802b1d8970f4eafb5989b 100644 (file)
@@ -618,6 +618,39 @@ test_str_match_icase(void)
        test_end();
 }
 
+static void test_str_ends_with(void)
+{
+       const struct {
+               const char *haystack, *suffix;
+               bool result;
+       } tests[] = {
+               { "", "", TRUE },
+               { "abc", "", TRUE },
+               { "abc", "c", TRUE },
+               { "abc", "bc", TRUE },
+               { "abc", "abc", TRUE },
+               { "abc", "xabc", FALSE },
+               { "abc", "axc", FALSE },
+               { "", "a", FALSE },
+       };
+
+       test_begin("str_ends_with() and str_ends_icase_with()");
+       for (unsigned int i = 0; i < N_ELEMENTS(tests); i++) {
+               test_assert(str_ends_with(tests[i].haystack,
+                                         tests[i].suffix) == tests[i].result);
+               test_assert(str_ends_icase_with(tests[i].haystack,
+                                               tests[i].suffix) ==
+                           tests[i].result);
+               if (tests[i].haystack[0] != '\0' && tests[i].suffix[0] != '\0' &&
+                   tests[i].result) {
+                       const char *haystack_ucase = t_str_ucase(tests[i].haystack);
+                       test_assert(!str_ends_with(haystack_ucase, tests[i].suffix));
+                       test_assert(str_ends_icase_with(haystack_ucase, tests[i].suffix));
+               }
+       }
+       test_end();
+}
+
 static void test_memspn(void)
 {
 #undef TEST_CASE
@@ -743,6 +776,7 @@ void test_strfuncs(void)
        test_dec2str_buf();
        test_str_match();
        test_str_match_icase();
+       test_str_ends_with();
        test_memspn();
        test_memcspn();
 }