]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Add archive_string_dirname()
authorDag-Erling Smørgrav <des@des.no>
Tue, 14 Oct 2025 00:08:44 +0000 (02:08 +0200)
committerDag-Erling Smørgrav <des@des.no>
Tue, 14 Oct 2025 00:08:44 +0000 (02:08 +0200)
This function performs the equivalent of POSIX dirname(3) on a
struct archive_string.

libarchive/archive_string.c
libarchive/archive_string.h
libarchive/test/test_archive_string.c

index 3bb978335eb876a635d93cb21a96d285fe9dcffe..740308b6e4e3e6cf3eb859e8015c152507f6d9de 100644 (file)
@@ -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
 
 /*
index e8987867d3ce7e8b828fea925f389ab1eb91a429..d5f5c03aca30c8bf3e38555a6245bdd5f5c13a84 100644 (file)
@@ -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,
index 30f7a800eae8e4526acf2778ae8af79b576d5f74..bf822c0d5e82fb6c3dea98090adb014cd6e8e027 100644 (file)
@@ -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[] =