From d0f69b355df45a86e90b4eaf9cebeb63c4c5e5d4 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Dag-Erling=20Sm=C3=B8rgrav?= Date: Tue, 14 Oct 2025 02:08:44 +0200 Subject: [PATCH] Add archive_string_dirname() This function performs the equivalent of POSIX dirname(3) on a struct archive_string. --- libarchive/archive_string.c | 20 ++++++++++++++ libarchive/archive_string.h | 4 +++ libarchive/test/test_archive_string.c | 38 +++++++++++++++++++++++++++ 3 files changed, 62 insertions(+) diff --git a/libarchive/archive_string.c b/libarchive/archive_string.c index 3bb978335..740308b6e 100644 --- a/libarchive/archive_string.c +++ b/libarchive/archive_string.c @@ -2054,6 +2054,26 @@ archive_strncat_l(struct archive_string *as, const void *_p, size_t n, return (r); } +struct archive_string * +archive_string_dirname(struct archive_string *as) +{ + /* strip trailing separators */ + while (as->length > 1 && as->s[as->length - 1] == '/') + as->length--; + /* strip final component */ + while (as->length > 0 && as->s[as->length - 1] != '/') + as->length--; + /* empty path -> cwd */ + if (as->length == 0) + return (archive_strcat(as, ".")); + /* strip separator(s) */ + while (as->length > 1 && as->s[as->length - 1] == '/') + as->length--; + /* terminate */ + as->s[as->length] = '\0'; + return (as); +} + #if HAVE_ICONV /* diff --git a/libarchive/archive_string.h b/libarchive/archive_string.h index e8987867d..d5f5c03ac 100644 --- a/libarchive/archive_string.h +++ b/libarchive/archive_string.h @@ -192,6 +192,10 @@ void archive_string_vsprintf(struct archive_string *, const char *, void archive_string_sprintf(struct archive_string *, const char *, ...) __LA_PRINTF(2, 3); +/* Equivalent to dirname(3) */ +struct archive_string * +archive_string_dirname(struct archive_string *); + /* Translates from MBS to Unicode. */ /* Returns non-zero if conversion failed in any way. */ int archive_wstring_append_from_mbs(struct archive_wstring *dest, diff --git a/libarchive/test/test_archive_string.c b/libarchive/test/test_archive_string.c index 30f7a800e..bf822c0d5 100644 --- a/libarchive/test/test_archive_string.c +++ b/libarchive/test/test_archive_string.c @@ -353,6 +353,43 @@ test_archive_string_sprintf(void) archive_string_free(&s); } +static void +test_archive_string_dirname(void) +{ + static struct pair { const char *str, *exp; } pairs[] = { + { "", "." }, + { "/", "/" }, + { "//", "/" }, + { "///", "/" }, + { "./", "." }, + { ".", "." }, + { "..", "." }, + { "foo", "." }, + { "foo/", "." }, + { "foo//", "." }, + { "foo/bar", "foo" }, + { "foo/bar/", "foo" }, + { "foo/bar//", "foo" }, + { "foo//bar", "foo" }, + { "foo//bar/", "foo" }, + { "foo//bar//", "foo" }, + { "/foo", "/" }, + { "//foo", "/" }, + { "//foo/", "/" }, + { "//foo//", "/" }, + { 0 }, + }; + struct pair *pair; + struct archive_string s; + + archive_string_init(&s); + for (pair = pairs; pair->str; pair++) { + archive_strcpy(&s, pair->str); + archive_string_dirname(&s); + assertEqualString(pair->exp, s.s); + } +} + DEFINE_TEST(test_archive_string) { test_archive_string_ensure(); @@ -364,6 +401,7 @@ DEFINE_TEST(test_archive_string) test_archive_string_concat(); test_archive_string_copy(); test_archive_string_sprintf(); + test_archive_string_dirname(); } static const char *strings[] = -- 2.47.3