hare

[hare] The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

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:
Mfs/util.ha | 13+++++--------
Mpath/stack.ha | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
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.