summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Bugaev <bugaevc@gmail.com>2019-10-02 22:40:52 +0300
committerAndreas Kling <awesomekling@gmail.com>2019-10-03 08:23:54 +0200
commitafdc5688ec90a58591e359e794d07eff18baa0a6 (patch)
treef2124d54fbbd147e490fecbf51c594e8c2044736
parent8fbcfa934afaca709c8ffed3f972e7e0ffb62d0d (diff)
downloadserenity-afdc5688ec90a58591e359e794d07eff18baa0a6.zip
LibC: Implement dirname() and basename()
And write section 3 man pages for them.
-rw-r--r--Base/usr/share/man/man3/basename.md53
-rw-r--r--Base/usr/share/man/man3/dirname.md54
-rw-r--r--Libraries/LibC/Makefile3
-rw-r--r--Libraries/LibC/libgen.cpp58
-rw-r--r--Libraries/LibC/libgen.h10
5 files changed, 177 insertions, 1 deletions
diff --git a/Base/usr/share/man/man3/basename.md b/Base/usr/share/man/man3/basename.md
new file mode 100644
index 0000000000..716ef8f29e
--- /dev/null
+++ b/Base/usr/share/man/man3/basename.md
@@ -0,0 +1,53 @@
+## Name
+
+basename - extract file name from a path
+
+## Synopsis
+
+```**c++
+#include <libgen.h>
+
+char* basename(char* path);
+```
+
+## Description
+
+Given a file path, `basename()` returns that file's name. `basename()` works
+purely lexically, meaning it only manipulates the path as a string, and does
+not check if such a file actually exists.
+
+A call to `basename()` may reuse and modify the passed in `path` buffer. Do not
+expect it to have the same value after calling `basename()`.
+
+## Return value
+
+`basename()` returns the file name as a string. This string may be allocated
+in static memory, or it may point to some part of the original `path` buffer.
+Do not `free()` the returned string, and do not `free()` the original `path`
+buffer while using the returned string.
+
+## Examples
+
+```c++
+#include <AK/LogStream.h>
+#include <libgen.h>
+
+int main()
+{
+ char path1[] = "/home/anon/ReadMe.md";
+ dbg() << basename(path1); // should be "ReadMe.md"
+
+ char path2[] = "foo/bar/";
+ dbg() << basename(path2); // should be "bar"
+
+ char path3[] = "foo";
+ dbg() << basename(path3); // should be "foo"
+
+ char path4[] = "/";
+ dbg() << basename(path4); // should be "/"
+}
+```
+
+## See also
+
+* [`dirname`(3)](dirname.md)
diff --git a/Base/usr/share/man/man3/dirname.md b/Base/usr/share/man/man3/dirname.md
new file mode 100644
index 0000000000..6a101d9dbf
--- /dev/null
+++ b/Base/usr/share/man/man3/dirname.md
@@ -0,0 +1,54 @@
+## Name
+
+dirname - get a file's containing directory path
+
+## Synopsis
+
+```**c++
+#include <libgen.h>
+
+char* dirname(char* path);
+```
+
+## Description
+
+Given a file path, `dirname()` returns a path to the directory that contains the
+file. `dirname()` works purely lexically, meaning it only manipulates the path
+as a string, and does not check if such a file or its containing directory
+actually exist.
+
+A call to `dirname()` may reuse and modify the passed in `path` buffer. Do not
+expect it to have the same value after calling `dirname()`.
+
+## Return value
+
+`dirname()` returns the directory path as a string. This string may be allocated
+in static memory, or it may point to some part of the original `path` buffer.
+Do not `free()` the returned string, and do not `free()` the original `path`
+buffer while using the returned string.
+
+## Examples
+
+```c++
+#include <AK/LogStream.h>
+#include <libgen.h>
+
+int main()
+{
+ char path1[] = "/home/anon/ReadMe.md";
+ dbg() << dirname(path1); // should be "/home/anon"
+
+ char path2[] = "foo/bar/";
+ dbg() << dirname(path2); // should be "foo"
+
+ char path3[] = "foo";
+ dbg() << dirname(path3); // should be "."
+
+ char path4[] = "/";
+ dbg() << dirname(path4); // should be "/"
+}
+```
+
+## See also
+
+* [`basename`(3)](basename.md)
diff --git a/Libraries/LibC/Makefile b/Libraries/LibC/Makefile
index af5580266a..7541f10136 100644
--- a/Libraries/LibC/Makefile
+++ b/Libraries/LibC/Makefile
@@ -51,7 +51,8 @@ LIBC_OBJS = \
arpa/inet.o \
netdb.o \
sched.o \
- dlfcn.o
+ dlfcn.o \
+ libgen.o
ASM_OBJS = setjmp.ao crti.ao crtn.ao
diff --git a/Libraries/LibC/libgen.cpp b/Libraries/LibC/libgen.cpp
new file mode 100644
index 0000000000..04b2e7dac9
--- /dev/null
+++ b/Libraries/LibC/libgen.cpp
@@ -0,0 +1,58 @@
+#include <AK/Assertions.h>
+#include <libgen.h>
+#include <string.h>
+
+static char dot[] = ".";
+static char slash[] = "/";
+
+char* dirname(char* path)
+{
+ if (path == nullptr)
+ return dot;
+
+ int len = strlen(path);
+ if (len == 0)
+ return dot;
+
+ while (len > 1 && path[len - 1] == '/') {
+ path[len - 1] = 0;
+ len--;
+ }
+
+ char* last_slash = strrchr(path, '/');
+ if (last_slash == nullptr)
+ return dot;
+
+ if (last_slash == path)
+ return slash;
+
+ *last_slash = 0;
+ return path;
+}
+
+char* basename(char* path)
+{
+ if (path == nullptr)
+ return dot;
+
+ int len = strlen(path);
+ if (len == 0)
+ return dot;
+
+ while (len > 1 && path[len - 1] == '/') {
+ path[len - 1] = 0;
+ len--;
+ }
+
+ char* last_slash = strrchr(path, '/');
+ if (last_slash == nullptr)
+ return path;
+
+ if (len == 1) {
+ ASSERT(last_slash == path);
+ ASSERT(path[0] == '/');
+ return slash;
+ }
+
+ return last_slash + 1;
+}
diff --git a/Libraries/LibC/libgen.h b/Libraries/LibC/libgen.h
new file mode 100644
index 0000000000..e8b5af9f0b
--- /dev/null
+++ b/Libraries/LibC/libgen.h
@@ -0,0 +1,10 @@
+#pragma once
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+char* dirname(char* path);
+char* basename(char* path);
+
+__END_DECLS