[libc-commits] [libc] 29692c1 - [libc] Implement basename and dirname in libgen.h (#204554)
via libc-commits
libc-commits at lists.llvm.org
Fri Jun 19 08:44:33 PDT 2026
Author: Jeff Bailey
Date: 2026-06-19T15:44:27Z
New Revision: 29692c150f86d76cfb58e8bf2c0e97dc6afd2088
URL: https://github.com/llvm/llvm-project/commit/29692c150f86d76cfb58e8bf2c0e97dc6afd2088
DIFF: https://github.com/llvm/llvm-project/commit/29692c150f86d76cfb58e8bf2c0e97dc6afd2088.diff
LOG: [libc] Implement basename and dirname in libgen.h (#204554)
Added the POSIX standard functions basename and dirname under a new
libgen.h header. The implementations modify the input path in-place
using cpp::string_view to determine boundaries safely.
Added find_last_not_of to cpp::string_view to support trailing slash
removal.
Implemented:
* libc/include/libgen.yaml, libgen.h.def: Public API definitions.
* libc/src/libgen/basename.cpp, dirname.cpp: Generic implementations.
* libc/test/src/libgen/: Unit and hermetic tests.
Registered the new entrypoints for all active Linux targets (x86_64,
aarch64, arm, riscv) and added docgen configuration.
Assisted-by: Automated tooling, human reviewed.
Added:
libc/include/libgen.yaml
libc/src/libgen/CMakeLists.txt
libc/src/libgen/basename.cpp
libc/src/libgen/basename.h
libc/src/libgen/dirname.cpp
libc/src/libgen/dirname.h
libc/test/src/libgen/CMakeLists.txt
libc/test/src/libgen/basename_death_test.cpp
libc/test/src/libgen/basename_test.cpp
libc/test/src/libgen/dirname_death_test.cpp
libc/test/src/libgen/dirname_test.cpp
libc/utils/docgen/libgen.yaml
Modified:
libc/config/linux/aarch64/entrypoints.txt
libc/config/linux/arm/entrypoints.txt
libc/config/linux/riscv/entrypoints.txt
libc/config/linux/x86_64/entrypoints.txt
libc/docs/CMakeLists.txt
libc/docs/headers/index.rst
libc/include/CMakeLists.txt
libc/src/CMakeLists.txt
libc/src/__support/CPP/string_view.h
libc/test/src/CMakeLists.txt
Removed:
################################################################################
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 5cddf3dc89799..3072c3d22aa5f 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -109,6 +109,10 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.inttypes.strtoimax
libc.src.inttypes.strtoumax
+ # libgen.h entrypoints
+ libc.src.libgen.basename
+ libc.src.libgen.dirname
+
# stdbit.h entrypoints
libc.src.stdbit.stdc_bit_ceil_uc
libc.src.stdbit.stdc_bit_ceil_ui
diff --git a/libc/config/linux/arm/entrypoints.txt b/libc/config/linux/arm/entrypoints.txt
index c4ac53c4925a3..805738a3a5756 100644
--- a/libc/config/linux/arm/entrypoints.txt
+++ b/libc/config/linux/arm/entrypoints.txt
@@ -73,6 +73,10 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.inttypes.strtoimax
libc.src.inttypes.strtoumax
+ # libgen.h entrypoints
+ libc.src.libgen.basename
+ libc.src.libgen.dirname
+
# stdbit.h entrypoints
libc.src.stdbit.stdc_bit_ceil_uc
libc.src.stdbit.stdc_bit_ceil_ui
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index a57efbb8e464d..bcdcf2320f7bd 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -109,6 +109,10 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.inttypes.strtoimax
libc.src.inttypes.strtoumax
+ # libgen.h entrypoints
+ libc.src.libgen.basename
+ libc.src.libgen.dirname
+
# stdbit.h entrypoints
libc.src.stdbit.stdc_bit_ceil_uc
libc.src.stdbit.stdc_bit_ceil_ui
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index ce88a6749d9dc..f19da5902bba1 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -125,6 +125,10 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.inttypes.wcstoimax
libc.src.inttypes.wcstoumax
+ # libgen.h entrypoints
+ libc.src.libgen.basename
+ libc.src.libgen.dirname
+
# stdbit.h entrypoints
libc.src.stdbit.stdc_bit_ceil_uc
libc.src.stdbit.stdc_bit_ceil_ui
diff --git a/libc/docs/CMakeLists.txt b/libc/docs/CMakeLists.txt
index cf54edeae66de..ded99393f9390 100644
--- a/libc/docs/CMakeLists.txt
+++ b/libc/docs/CMakeLists.txt
@@ -54,6 +54,7 @@ if (SPHINX_FOUND)
float
glob
inttypes
+ libgen
locale
nl_types
net/if
diff --git a/libc/docs/headers/index.rst b/libc/docs/headers/index.rst
index e818e1549c0d1..893ddf839cccd 100644
--- a/libc/docs/headers/index.rst
+++ b/libc/docs/headers/index.rst
@@ -20,6 +20,7 @@ Implementation Status
float
glob
inttypes
+ libgen
locale
math/index.rst
net/if
diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt
index 549dbd9e4c3f8..e8168687109b0 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -130,6 +130,14 @@ add_header_macro(
.llvm-libc-macros.float_macros
)
+add_header_macro(
+ libgen
+ ../libc/include/libgen.yaml
+ libgen.h
+ DEPENDS
+ .llvm_libc_common_h
+)
+
add_header_macro(
limits
../libc/include/limits.yaml
diff --git a/libc/include/libgen.yaml b/libc/include/libgen.yaml
new file mode 100644
index 0000000000000..c79ab79259be6
--- /dev/null
+++ b/libc/include/libgen.yaml
@@ -0,0 +1,20 @@
+header: libgen.h
+standards:
+ - posix
+macros: []
+types: []
+enums: []
+objects: []
+functions:
+ - name: basename
+ standards:
+ - posix
+ return_type: char *
+ arguments:
+ - type: char *
+ - name: dirname
+ standards:
+ - posix
+ return_type: char *
+ arguments:
+ - type: char *
diff --git a/libc/src/CMakeLists.txt b/libc/src/CMakeLists.txt
index 9db314f54723b..56085c9632f59 100644
--- a/libc/src/CMakeLists.txt
+++ b/libc/src/CMakeLists.txt
@@ -7,6 +7,7 @@ add_subdirectory(dlfcn)
add_subdirectory(errno)
add_subdirectory(fenv)
add_subdirectory(inttypes)
+add_subdirectory(libgen)
add_subdirectory(link)
add_subdirectory(math)
add_subdirectory(netinet)
diff --git a/libc/src/__support/CPP/string_view.h b/libc/src/__support/CPP/string_view.h
index 6991fd46a4ace..7b98b7e5fb6c8 100644
--- a/libc/src/__support/CPP/string_view.h
+++ b/libc/src/__support/CPP/string_view.h
@@ -205,6 +205,15 @@ class string_view {
return npos;
}
+ LIBC_INLINE constexpr size_t find_last_not_of(const char c,
+ size_t end = npos) const {
+ end = end >= size() ? size() : end + 1;
+ for (; end > 0; --end)
+ if ((*this)[end - 1] != c)
+ return end - 1;
+ return npos;
+ }
+
// Finds the first character not equal to c in this view, starting at
// position From.
LIBC_INLINE constexpr size_t find_first_not_of(const char c,
diff --git a/libc/src/libgen/CMakeLists.txt b/libc/src/libgen/CMakeLists.txt
new file mode 100644
index 0000000000000..9c315a4e7b41d
--- /dev/null
+++ b/libc/src/libgen/CMakeLists.txt
@@ -0,0 +1,23 @@
+add_entrypoint_object(
+ basename
+ SRCS
+ basename.cpp
+ HDRS
+ basename.h
+ DEPENDS
+ libc.src.__support.CPP.string_view
+ libc.src.__support.common
+ libc.src.__support.macros.config
+)
+
+add_entrypoint_object(
+ dirname
+ SRCS
+ dirname.cpp
+ HDRS
+ dirname.h
+ DEPENDS
+ libc.src.__support.CPP.string_view
+ libc.src.__support.common
+ libc.src.__support.macros.config
+)
diff --git a/libc/src/libgen/basename.cpp b/libc/src/libgen/basename.cpp
new file mode 100644
index 0000000000000..acf53f2d446e9
--- /dev/null
+++ b/libc/src/libgen/basename.cpp
@@ -0,0 +1,42 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Implementation of basename.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/libgen/basename.h"
+#include "src/__support/CPP/string_view.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(char *, basename, (char *path)) {
+ if (path == nullptr || path[0] == '\0')
+ return const_cast<char *>(".");
+
+ cpp::string_view sv(path);
+ size_t last_non_slash = sv.find_last_not_of('/');
+
+ if (last_non_slash == cpp::string_view::npos)
+ return const_cast<char *>("/");
+
+ size_t last_slash = sv.substr(0, last_non_slash).find_last_of('/');
+
+ size_t start = (last_slash == cpp::string_view::npos) ? 0 : last_slash + 1;
+ size_t end = last_non_slash + 1;
+
+ if (end < sv.size())
+ path[end] = '\0';
+
+ return path + start;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/libgen/basename.h b/libc/src/libgen/basename.h
new file mode 100644
index 0000000000000..15239888aa97a
--- /dev/null
+++ b/libc/src/libgen/basename.h
@@ -0,0 +1,30 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Header for basename.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_LIBGEN_BASENAME_H
+#define LLVM_LIBC_SRC_LIBGEN_BASENAME_H
+
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+/// Return the last component of a pathname.
+///
+/// \param path Pointer to the null-terminated pathname string.
+/// \return Pointer to the last component of path, or "." if path is null or
+/// empty, or "/" if path is all slashes.
+char *basename(char *path);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_LIBGEN_BASENAME_H
diff --git a/libc/src/libgen/dirname.cpp b/libc/src/libgen/dirname.cpp
new file mode 100644
index 0000000000000..9dd958b63ce9f
--- /dev/null
+++ b/libc/src/libgen/dirname.cpp
@@ -0,0 +1,48 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Implementation of dirname.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/libgen/dirname.h"
+#include "src/__support/CPP/string_view.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(char *, dirname, (char *path)) {
+ if (path == nullptr || path[0] == '\0')
+ return const_cast<char *>(".");
+
+ cpp::string_view sv(path);
+ size_t last_non_slash = sv.find_last_not_of('/');
+
+ if (last_non_slash == cpp::string_view::npos)
+ return const_cast<char *>("/");
+
+ size_t last_slash = sv.substr(0, last_non_slash).find_last_of('/');
+
+ if (last_slash == cpp::string_view::npos)
+ return const_cast<char *>(".");
+
+ cpp::string_view dir_sv = sv.substr(0, last_slash);
+ size_t dir_last_non_slash = dir_sv.find_last_not_of('/');
+
+ if (dir_last_non_slash == cpp::string_view::npos) {
+ path[1] = '\0';
+ return path;
+ }
+
+ path[dir_last_non_slash + 1] = '\0';
+ return path;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/libgen/dirname.h b/libc/src/libgen/dirname.h
new file mode 100644
index 0000000000000..4909b2eb222ad
--- /dev/null
+++ b/libc/src/libgen/dirname.h
@@ -0,0 +1,30 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Header for dirname.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_LIBGEN_DIRNAME_H
+#define LLVM_LIBC_SRC_LIBGEN_DIRNAME_H
+
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+/// Return the directory component of a pathname.
+///
+/// \param path Pointer to the null-terminated pathname string.
+/// \return Pointer to the directory component of path, or "." if path is null
+/// or empty, or "/" if path is all slashes.
+char *dirname(char *path);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_LIBGEN_DIRNAME_H
diff --git a/libc/test/src/CMakeLists.txt b/libc/test/src/CMakeLists.txt
index dd232b29a7a7b..45815c9bba8ca 100644
--- a/libc/test/src/CMakeLists.txt
+++ b/libc/test/src/CMakeLists.txt
@@ -63,6 +63,7 @@ add_subdirectory(complex)
add_subdirectory(ctype)
add_subdirectory(errno)
add_subdirectory(fenv)
+add_subdirectory(libgen)
add_subdirectory(link)
add_subdirectory(math)
add_subdirectory(netinet)
diff --git a/libc/test/src/libgen/CMakeLists.txt b/libc/test/src/libgen/CMakeLists.txt
new file mode 100644
index 0000000000000..d3ee13a9f1cab
--- /dev/null
+++ b/libc/test/src/libgen/CMakeLists.txt
@@ -0,0 +1,43 @@
+add_custom_target(libc-libgen-tests)
+
+add_libc_test(
+ basename_test
+ SUITE
+ libc-libgen-tests
+ SRCS
+ basename_test.cpp
+ DEPENDS
+ libc.src.libgen.basename
+)
+
+add_libc_test(
+ dirname_test
+ SUITE
+ libc-libgen-tests
+ SRCS
+ dirname_test.cpp
+ DEPENDS
+ libc.src.libgen.dirname
+)
+
+add_libc_test(
+ basename_death_test
+ UNIT_TEST_ONLY
+ SUITE
+ libc-libgen-tests
+ SRCS
+ basename_death_test.cpp
+ DEPENDS
+ libc.src.libgen.basename
+)
+
+add_libc_test(
+ dirname_death_test
+ UNIT_TEST_ONLY
+ SUITE
+ libc-libgen-tests
+ SRCS
+ dirname_death_test.cpp
+ DEPENDS
+ libc.src.libgen.dirname
+)
diff --git a/libc/test/src/libgen/basename_death_test.cpp b/libc/test/src/libgen/basename_death_test.cpp
new file mode 100644
index 0000000000000..24100dc48aa1b
--- /dev/null
+++ b/libc/test/src/libgen/basename_death_test.cpp
@@ -0,0 +1,22 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Death tests for basename.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/libgen/basename.h"
+#include "test/UnitTest/Test.h"
+
+#ifdef ENABLE_SUBPROCESS_TESTS
+TEST(LlvmLibcBasenameTest, ModifyReturnValue) {
+ char *r = LIBC_NAMESPACE::basename(nullptr);
+ ASSERT_DEATH([r]() { r[0] = 'a'; }, WITH_SIGNAL(-1));
+}
+#endif
diff --git a/libc/test/src/libgen/basename_test.cpp b/libc/test/src/libgen/basename_test.cpp
new file mode 100644
index 0000000000000..2e8feef715137
--- /dev/null
+++ b/libc/test/src/libgen/basename_test.cpp
@@ -0,0 +1,62 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Unittests for basename.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/libgen/basename.h"
+#include "test/UnitTest/Test.h"
+
+TEST(LlvmLibcBasenameTest, NullPointer) {
+ ASSERT_STREQ(LIBC_NAMESPACE::basename(nullptr), ".");
+}
+
+TEST(LlvmLibcBasenameTest, EmptyString) {
+ char path[] = "";
+ ASSERT_STREQ(LIBC_NAMESPACE::basename(path), ".");
+}
+
+TEST(LlvmLibcBasenameTest, RegularPath) {
+ char path[] = "/usr/lib";
+ ASSERT_STREQ(LIBC_NAMESPACE::basename(path), "lib");
+}
+
+TEST(LlvmLibcBasenameTest, TrailingSlash) {
+ char path[] = "/usr/";
+ ASSERT_STREQ(LIBC_NAMESPACE::basename(path), "usr");
+ ASSERT_STREQ(path, "/usr");
+}
+
+TEST(LlvmLibcBasenameTest, SingleSlash) {
+ char path[] = "/";
+ ASSERT_STREQ(LIBC_NAMESPACE::basename(path), "/");
+}
+
+TEST(LlvmLibcBasenameTest, MultipleSlashes) {
+ char path[] = "///";
+ ASSERT_STREQ(LIBC_NAMESPACE::basename(path), "/");
+}
+
+TEST(LlvmLibcBasenameTest, SimpleName) {
+ char path[] = "a";
+ ASSERT_STREQ(LIBC_NAMESPACE::basename(path), "a");
+}
+
+TEST(LlvmLibcBasenameTest, SimpleNameTrailingSlash) {
+ char path[] = "a/";
+ ASSERT_STREQ(LIBC_NAMESPACE::basename(path), "a");
+ ASSERT_STREQ(path, "a");
+}
+
+TEST(LlvmLibcBasenameTest, ComplexPath) {
+ char path[] = "///a///";
+ ASSERT_STREQ(LIBC_NAMESPACE::basename(path), "a");
+ ASSERT_STREQ(path, "///a");
+}
diff --git a/libc/test/src/libgen/dirname_death_test.cpp b/libc/test/src/libgen/dirname_death_test.cpp
new file mode 100644
index 0000000000000..e135a4ce60cd6
--- /dev/null
+++ b/libc/test/src/libgen/dirname_death_test.cpp
@@ -0,0 +1,22 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Death tests for dirname.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/libgen/dirname.h"
+#include "test/UnitTest/Test.h"
+
+#ifdef ENABLE_SUBPROCESS_TESTS
+TEST(LlvmLibcDirnameTest, ModifyReturnValue) {
+ char *r = LIBC_NAMESPACE::dirname(nullptr);
+ ASSERT_DEATH([r]() { r[0] = 'a'; }, WITH_SIGNAL(-1));
+}
+#endif
diff --git a/libc/test/src/libgen/dirname_test.cpp b/libc/test/src/libgen/dirname_test.cpp
new file mode 100644
index 0000000000000..afd718fb6e559
--- /dev/null
+++ b/libc/test/src/libgen/dirname_test.cpp
@@ -0,0 +1,74 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Unittests for dirname.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/libgen/dirname.h"
+#include "test/UnitTest/Test.h"
+
+TEST(LlvmLibcDirnameTest, NullPointer) {
+ ASSERT_STREQ(LIBC_NAMESPACE::dirname(nullptr), ".");
+}
+
+TEST(LlvmLibcDirnameTest, EmptyString) {
+ char path[] = "";
+ ASSERT_STREQ(LIBC_NAMESPACE::dirname(path), ".");
+}
+
+TEST(LlvmLibcDirnameTest, RegularPath) {
+ char path[] = "/usr/lib";
+ ASSERT_STREQ(LIBC_NAMESPACE::dirname(path), "/usr");
+ ASSERT_STREQ(path, "/usr");
+}
+
+TEST(LlvmLibcDirnameTest, TrailingSlash) {
+ char path[] = "/usr/";
+ ASSERT_STREQ(LIBC_NAMESPACE::dirname(path), "/");
+ ASSERT_STREQ(path, "/");
+}
+
+TEST(LlvmLibcDirnameTest, SingleSlash) {
+ char path[] = "/";
+ ASSERT_STREQ(LIBC_NAMESPACE::dirname(path), "/");
+}
+
+TEST(LlvmLibcDirnameTest, MultipleSlashes) {
+ char path[] = "///";
+ ASSERT_STREQ(LIBC_NAMESPACE::dirname(path), "/");
+}
+
+TEST(LlvmLibcDirnameTest, SimpleName) {
+ char path[] = "a";
+ ASSERT_STREQ(LIBC_NAMESPACE::dirname(path), ".");
+}
+
+TEST(LlvmLibcDirnameTest, SimpleNameTrailingSlash) {
+ char path[] = "a/";
+ ASSERT_STREQ(LIBC_NAMESPACE::dirname(path), ".");
+}
+
+TEST(LlvmLibcDirnameTest, ComplexPath) {
+ char path[] = "///a///b///";
+ ASSERT_STREQ(LIBC_NAMESPACE::dirname(path), "///a");
+ ASSERT_STREQ(path, "///a");
+}
+
+TEST(LlvmLibcDirnameTest, SlashA) {
+ char path[] = "/a";
+ ASSERT_STREQ(LIBC_NAMESPACE::dirname(path), "/");
+ ASSERT_STREQ(path, "/");
+}
+
+TEST(LlvmLibcDirnameTest, MultipleSlashesA) {
+ char path[] = "///a";
+ ASSERT_STREQ(LIBC_NAMESPACE::dirname(path), "/");
+ ASSERT_STREQ(path, "/");
+}
diff --git a/libc/utils/docgen/libgen.yaml b/libc/utils/docgen/libgen.yaml
new file mode 100644
index 0000000000000..07aad5f1be55c
--- /dev/null
+++ b/libc/utils/docgen/libgen.yaml
@@ -0,0 +1,5 @@
+functions:
+ basename:
+ in-latest-posix: ''
+ dirname:
+ in-latest-posix: ''
More information about the libc-commits
mailing list