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;
+}
}
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 {
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);