utils: add a trunkname() function to extract the trunk of a filename
authorPeter Hutterer <peter.hutterer@who-t.net>
Fri, 5 Feb 2021 04:36:16 +0000 (14:36 +1000)
committerPeter Hutterer <peter.hutterer@who-t.net>
Fri, 12 Feb 2021 04:31:50 +0000 (14:31 +1000)
/path/to/foo.bar returns "foo"

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

index 8d2aeb0158af49c1c5cf3e586e9b2c08aac33037..3e174806a12a2fcae5b7f62b0ec64cb571a24b01 100644 (file)
@@ -155,3 +155,34 @@ strv_join(char **strv, const char *joiner)
 
        return str;
 }
+
+/**
+ * Similar to basename() but returns the trunk only without the (last)
+ * trailing suffix, so that:
+ *
+ * - foo.c returns foo
+ * - foo.a.b returns foo.a
+ * - foo returns foo
+ * - foo/ returns ""
+ *
+ * @return an allocated string representing the trunk name of the file
+ */
+char *
+trunkname(const char *filename)
+{
+       /* See basename(3), there are two versions and they depend on
+        * whether libgen.h is included. We can't be sure which basename()
+        * applies here, so let's play it safe and assume it's the POSIX
+        * one. */
+       char *tmp = strdup(filename);
+       char *base = basename(tmp);
+       char *suffix;
+       char *trunk;
+
+       if ((suffix = rindex(base, '.')))
+           *suffix = '\0';
+
+       trunk = strdup(base);
+       free(tmp);
+       return trunk;
+}
index 7e9e8bca24eeb4816a77b3d526ab71fa74bd7d5b..ad007f6963f8bb2d0b87f8255469fa62d7d267bf 100644 (file)
@@ -391,3 +391,6 @@ strstartswith(const char *str, const char *prefix)
 
        return prefixlen > 0 ? strneq(str, prefix, strlen(prefix)) : false;
 }
+
+char *
+trunkname(const char *filename);
index 8cc3f22a14e0755d4cdd6564c0a6aa26e5013e82..f31b2e07c7f0e828286662680a8580273b7cd3d1 100644 (file)
@@ -1292,6 +1292,32 @@ START_TEST(strneq_test)
 }
 END_TEST
 
+START_TEST(trunkname_test)
+{
+       struct test {
+               const char *path;
+               const char *expected;
+       } tests[] = {
+               { "foo.c", "foo" },
+               { "/path/to/foo.h", "foo" },
+               { "../bar.foo", "bar" },
+               { "./bar.foo.baz", "bar.foo" },
+               { "./", "" },
+               { "/", "" },
+               { "/bar/", "" },
+               { "/bar", "bar" },
+               { "", "" },
+       };
+       struct test *t;
+
+       ARRAY_FOR_EACH(tests, t) {
+               char *result = trunkname(t->path);
+               ck_assert_str_eq(result, t->expected);
+               free(result);
+       }
+}
+END_TEST
+
 static Suite *
 litest_utils_suite(void)
 {
@@ -1335,6 +1361,7 @@ litest_utils_suite(void)
        tcase_add_test(tc, strverscmp_test);
        tcase_add_test(tc, streq_test);
        tcase_add_test(tc, strneq_test);
+       tcase_add_test(tc, trunkname_test);
 
        suite_add_tcase(s, tc);