summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Hutterer <peter.hutterer@who-t.net>2021-02-18 13:43:23 +1000
committerPeter Hutterer <peter.hutterer@who-t.net>2021-02-23 10:56:53 +1000
commit671eb8cbbb4dc5c88d38c935c176d61604154584 (patch)
tree5c5c00feea0c24c16ca73d1fbc83a340dc6a96fa
parentfd9d165a7724dd518f4ad2a92187637130345389 (diff)
downloadlibinput-671eb8cbbb4dc5c88d38c935c176d61604154584.tar.gz
utils: add a safe version of basename
So we don't need to worry about the libgen.h include game. And we can switch trunkname over to that, making it a bit simpler. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
-rw-r--r--src/util-strings.c44
-rw-r--r--src/util-strings.h3
-rw-r--r--test/test-utils.c31
3 files changed, 66 insertions, 12 deletions
diff --git a/src/util-strings.c b/src/util-strings.c
index 3e174806..7d4c4628 100644
--- a/src/util-strings.c
+++ b/src/util-strings.c
@@ -157,6 +157,30 @@ strv_join(char **strv, const char *joiner)
}
/**
+ * Return a pointer to the basename within filename.
+ * If the filename the empty string or a directory (i.e. the last char of
+ * filename is '/') NULL is returned.
+ */
+const char *
+safe_basename(const char *filename)
+{
+ const char *basename;
+
+ if (*filename == '\0')
+ return NULL;
+
+ basename = strrchr(filename, '/');
+ if (basename == NULL)
+ return filename;
+
+ if (*(basename + 1) == '\0')
+ return NULL;
+
+ return basename + 1;
+}
+
+
+/**
* Similar to basename() but returns the trunk only without the (last)
* trailing suffix, so that:
*
@@ -170,19 +194,15 @@ strv_join(char **strv, const char *joiner)
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);
+ const char *base = safe_basename(filename);
char *suffix;
- char *trunk;
- if ((suffix = rindex(base, '.')))
- *suffix = '\0';
+ if (base == NULL)
+ return strdup("");
- trunk = strdup(base);
- free(tmp);
- return trunk;
+ suffix = rindex(base, '.');
+ if (suffix == NULL)
+ return strdup(base);
+ else
+ return strndup(base, suffix-base);
}
diff --git a/src/util-strings.h b/src/util-strings.h
index ad007f69..9d044067 100644
--- a/src/util-strings.h
+++ b/src/util-strings.h
@@ -392,5 +392,8 @@ strstartswith(const char *str, const char *prefix)
return prefixlen > 0 ? strneq(str, prefix, strlen(prefix)) : false;
}
+const char *
+safe_basename(const char *filename);
+
char *
trunkname(const char *filename);
diff --git a/test/test-utils.c b/test/test-utils.c
index f31b2e07..dbd58031 100644
--- a/test/test-utils.c
+++ b/test/test-utils.c
@@ -1292,6 +1292,35 @@ START_TEST(strneq_test)
}
END_TEST
+START_TEST(basename_test)
+{
+ struct test {
+ const char *path;
+ const char *expected;
+ } tests[] = {
+ { "a", "a" },
+ { "foo.c", "foo.c" },
+ { "foo", "foo" },
+ { "/path/to/foo.h", "foo.h" },
+ { "../bar.foo", "bar.foo" },
+ { "./bar.foo.baz", "bar.foo.baz" },
+ { "./", NULL },
+ { "/", NULL },
+ { "/bar/", NULL },
+ { "/bar", "bar" },
+ { "", NULL },
+ };
+ struct test *t;
+
+ ARRAY_FOR_EACH(tests, t) {
+ const char *result = safe_basename(t->path);
+ if (t->expected == NULL)
+ ck_assert(result == NULL);
+ else
+ ck_assert_str_eq(result, t->expected);
+ }
+}
+END_TEST
START_TEST(trunkname_test)
{
struct test {
@@ -1300,6 +1329,7 @@ START_TEST(trunkname_test)
} tests[] = {
{ "foo.c", "foo" },
{ "/path/to/foo.h", "foo" },
+ { "/path/to/foo", "foo" },
{ "../bar.foo", "bar" },
{ "./bar.foo.baz", "bar.foo" },
{ "./", "" },
@@ -1362,6 +1392,7 @@ litest_utils_suite(void)
tcase_add_test(tc, streq_test);
tcase_add_test(tc, strneq_test);
tcase_add_test(tc, trunkname_test);
+ tcase_add_test(tc, basename_test);
suite_add_tcase(s, tc);