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>
This commit is contained in:
Peter Hutterer 2021-02-18 13:43:23 +10:00
parent fd9d165a77
commit 671eb8cbbb
3 changed files with 66 additions and 12 deletions

View file

@ -156,6 +156,30 @@ strv_join(char **strv, const char *joiner)
return str; return str;
} }
/**
* 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) * Similar to basename() but returns the trunk only without the (last)
* trailing suffix, so that: * trailing suffix, so that:
@ -170,19 +194,15 @@ strv_join(char **strv, const char *joiner)
char * char *
trunkname(const char *filename) trunkname(const char *filename)
{ {
/* See basename(3), there are two versions and they depend on const char *base = safe_basename(filename);
* 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 *suffix;
char *trunk;
if ((suffix = rindex(base, '.'))) if (base == NULL)
*suffix = '\0'; return strdup("");
trunk = strdup(base); suffix = rindex(base, '.');
free(tmp); if (suffix == NULL)
return trunk; return strdup(base);
else
return strndup(base, suffix-base);
} }

View file

@ -392,5 +392,8 @@ strstartswith(const char *str, const char *prefix)
return prefixlen > 0 ? strneq(str, prefix, strlen(prefix)) : false; return prefixlen > 0 ? strneq(str, prefix, strlen(prefix)) : false;
} }
const char *
safe_basename(const char *filename);
char * char *
trunkname(const char *filename); trunkname(const char *filename);

View file

@ -1292,6 +1292,35 @@ START_TEST(strneq_test)
} }
END_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) START_TEST(trunkname_test)
{ {
struct test { struct test {
@ -1300,6 +1329,7 @@ START_TEST(trunkname_test)
} tests[] = { } tests[] = {
{ "foo.c", "foo" }, { "foo.c", "foo" },
{ "/path/to/foo.h", "foo" }, { "/path/to/foo.h", "foo" },
{ "/path/to/foo", "foo" },
{ "../bar.foo", "bar" }, { "../bar.foo", "bar" },
{ "./bar.foo.baz", "bar.foo" }, { "./bar.foo.baz", "bar.foo" },
{ "./", "" }, { "./", "" },
@ -1362,6 +1392,7 @@ litest_utils_suite(void)
tcase_add_test(tc, streq_test); tcase_add_test(tc, streq_test);
tcase_add_test(tc, strneq_test); tcase_add_test(tc, strneq_test);
tcase_add_test(tc, trunkname_test); tcase_add_test(tc, trunkname_test);
tcase_add_test(tc, basename_test);
suite_add_tcase(s, tc); suite_add_tcase(s, tc);