commit a5a086e570b3c77a83505f12fea0fbd2ece6c2ec
parent 98d0f573a8cf5d63546d03114167d1f21660a90b
Author: Autumn! <autumnull@posteo.net>
Date: Sun, 7 May 2023 01:43:24 +0000
path: implement pop()
Signed-off-by: Autumn! <autumnull@posteo.net>
Diffstat:
2 files changed, 57 insertions(+), 8 deletions(-)
diff --git a/fs/util.ha b/fs/util.ha
@@ -116,30 +116,27 @@ export fn rmdirall(fs: *fs, path: str) (void | error) = {
};
fn rmdirall_path(fs: *fs, buf: *path::buffer) (void | error) = {
- let path = path::string(buf);
- let it = iter(fs, path)?;
+ let it = iter(fs, path::string(buf))?;
for (true) {
match (next(it)) {
case let ent: dirent =>
if (ent.name == "." || ent.name == "..") {
continue;
};
- path = path::push(buf, ent.name)!;
+ path::push(buf, ent.name)!;
switch (ent.ftype & mode::DIR) {
case mode::DIR =>
rmdirall_path(fs, buf)?;
case =>
- remove(fs, path)?;
+ remove(fs, path::string(buf))?;
};
- path = path::push(buf, "..")!;
+ path::pop(buf);
case void =>
break;
};
};
- if (path != "") {
- return rmdir(fs, path);
- };
+ return rmdir(fs, path::string(buf));
};
// Canonicalizes a path in this filesystem by resolving all symlinks and
diff --git a/path/stack.ha b/path/stack.ha
@@ -60,6 +60,58 @@ export fn push(buf: *buffer, items: str...) (str | errors::overflow) = {
free(s);
};
+// Remove and return the final path segment in a buffer.
+// Returns void if the path is empty or is the root dir.
+export fn pop(buf: *buffer) (str | void) = {
+ let trimmed = bytes::rtrim(buf.buf[..buf.end], PATHSEP);
+ if (len(trimmed) == 0) return void;
+ match (bytes::rindex(trimmed, PATHSEP)) {
+ case void =>
+ defer buf.end = 0;
+ return strings::fromutf8_unsafe(buf.buf[..buf.end]);
+ case let i: size =>
+ defer buf.end = i+1;
+ return strings::fromutf8_unsafe(buf.buf[i+1..buf.end]);
+ };
+};
+
+@test fn pop() void = {
+ // empty
+ let buf = init()!;
+ assert(pop(&buf) is void);
+ assert(string(&buf) == ".");
+
+ // root dir
+ buf.end = 0;
+ push(&buf, pathsepstr)!;
+ assert(pop(&buf) is void);
+ assert(string(&buf) == pathsepstr);
+
+ // relative file
+ buf.end = 0;
+ push(&buf, "foo")!;
+ assert(pop(&buf) as str == "foo");
+ assert(string(&buf) == ".");
+
+ // abs file
+ buf.end = 0;
+ push(&buf, pathsepstr, "foo")!;
+ assert(pop(&buf) as str == "foo");
+ assert(string(&buf) == pathsepstr);
+
+ // relative dir
+ buf.end = 0;
+ push(&buf, "foo/")!;
+ assert(pop(&buf) as str == "foo/");
+ assert(string(&buf) == ".");
+
+ // abs dir
+ buf.end = 0;
+ push(&buf, pathsepstr, "foo/")!;
+ assert(pop(&buf) as str == "foo/");
+ assert(string(&buf) == pathsepstr);
+};
+
// Joins a list of path components together, normalizes it, and returns the
// resulting string. The caller must free the return value. If the resulting
// path would exceed [[PATH_MAX]], the program aborts.