hare

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

commit 9db5898c0e901560f5a1d71e14d5319124369ef9
parent 5ba3db310014d4e788d51f984fe29b0bbb66e588
Author: Drew DeVault <sir@cmpwn.com>
Date:   Sat,  8 Jan 2022 10:04:17 +0100

pathbuf: add join

Signed-off-by: Drew DeVault <sir@cmpwn.com>

Diffstat:
Mpathbuf/README | 5+++--
Mpathbuf/buffer.ha | 22+++++++++++-----------
Apathbuf/ops.ha | 40++++++++++++++++++++++++++++++++++++++++
Mscripts/gen-stdlib | 3++-
Mstdlib.mk | 6++++--
5 files changed, 60 insertions(+), 16 deletions(-)

diff --git a/pathbuf/README b/pathbuf/README @@ -3,9 +3,10 @@ filesystem paths through the [[buffer]] type. let buf = pathbuf::init(); pathbuf::join(&buf, "/", "foo", "bar", "baz.txt"); - io::println(pathbuf::string()); // "/foo/bar/baz.txt" + io::println(pathbuf::path(&buf)); // "/foo/bar/baz.txt" + pathbuf::join(&buf, "../.././hello.txt"); - io::println(pathbuf::string()); // "/foo/hello.txt" + io::println(pathbuf::path(&buf)); // "/foo/hello.txt" The buffer object includes an array of length [[path::PATH_MAX]], which can be somewhat large - on Linux it's 4096. You can allocate this on the stack in most diff --git a/pathbuf/buffer.ha b/pathbuf/buffer.ha @@ -23,6 +23,15 @@ export fn init_static(buf: *buffer) void = { reset(buf); }; +// Initializes a new path buffer and sets its initial value from a set of path +// components. +export fn initfrom(items: str...) (buffer | errors::overflow) = { + let buf = buffer { ... }; + reset(&buf); + join(&buf, items...)?; + return buf; +}; + // Resets a path buffer to its initial state (an empty path). export fn reset(buf: *buffer) void = { buf.cur = buf.buf[..0]; @@ -53,17 +62,8 @@ export fn path(buf: *buffer) str = { // Overwrites the contents of a [[buffer]] with an arbitrary path. export fn setpath(buf: *buffer, path: str) (void | errors::overflow) = { - const path = strings::toutf8(path); - const tok = bytes::tokenize(path, [path::PATHSEP]); - for (true) { - const next = match (bytes::next_token(&tok)) { - case let tok: []u8 => - yield tok; - case void => - break; - }; - appendnorm(buf, next)?; - }; + reset(buf); + join(buf, path)?; }; // Normalizes and appends a path component to a buffer. diff --git a/pathbuf/ops.ha b/pathbuf/ops.ha @@ -0,0 +1,40 @@ +use bytes; +use errors; +use path; +use strings; + +// Joins several path elements together and appends them to a path buffer. +export fn join(buf: *buffer, items: str...) (void | errors::overflow) = { + for (let i = 0z; i < len(items); i += 1) { + const elem = strings::toutf8(items[i]); + const tok = bytes::tokenize(elem, [path::PATHSEP]); + for (let j = 0z; true; j += 1) { + const next = match (bytes::next_token(&tok)) { + case let tok: []u8 => + yield tok; + case void => + break; + }; + if (len(next) == 0 && j == 0) { + // Handles the join("/foo") case as + // join("/", "foo"); + appendnorm(buf, "/")?; + }; + appendnorm(buf, next)?; + }; + }; +}; + +@test fn join() void = { + let buf = init(); + join(&buf, "foo", "bar", "baz")!; + assert(path(&buf) == "foo/bar/baz"); + + reset(&buf); + join(&buf, "/foo/bar", "baz")!; + assert(path(&buf) == "/foo/bar/baz"); + + reset(&buf); + join(&buf, "/", "foo/bar", "baz")!; + assert(path(&buf) == "/foo/bar/baz"); +}; diff --git a/scripts/gen-stdlib b/scripts/gen-stdlib @@ -922,7 +922,8 @@ path() { pathbuf() { gen_srcs pathbuf \ - buffer.ha + buffer.ha \ + ops.ha gen_ssa pathbuf path } diff --git a/stdlib.mk b/stdlib.mk @@ -1495,7 +1495,8 @@ $(HARECACHE)/path/path-any.ssa: $(stdlib_path_any_srcs) $(stdlib_rt) $(stdlib_st # pathbuf (+any) stdlib_pathbuf_any_srcs= \ - $(STDLIB)/pathbuf/buffer.ha + $(STDLIB)/pathbuf/buffer.ha \ + $(STDLIB)/pathbuf/ops.ha $(HARECACHE)/pathbuf/pathbuf-any.ssa: $(stdlib_pathbuf_any_srcs) $(stdlib_rt) $(stdlib_path_$(PLATFORM)) @printf 'HAREC \t$@\n' @@ -3298,7 +3299,8 @@ $(TESTCACHE)/path/path-any.ssa: $(testlib_path_any_srcs) $(testlib_rt) $(testlib # pathbuf (+any) testlib_pathbuf_any_srcs= \ - $(STDLIB)/pathbuf/buffer.ha + $(STDLIB)/pathbuf/buffer.ha \ + $(STDLIB)/pathbuf/ops.ha $(TESTCACHE)/pathbuf/pathbuf-any.ssa: $(testlib_pathbuf_any_srcs) $(testlib_rt) $(testlib_path_$(PLATFORM)) @printf 'HAREC \t$@\n'