hare

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

commit 57fbb5d81c32021f7df3badba39638c80890f598
parent 509a15202c2d2d599a792cb0703dc50fd16b717e
Author: Autumn! <autumnull@posteo.net>
Date:   Sun,  7 May 2023 01:43:21 +0000

path: refactor init() to take varargs, drop reset()

Signed-off-by: Autumn! <autumnull@posteo.net>

Diffstat:
Mcmd/hare/plan.ha | 2+-
Mcmd/hare/release.ha | 4++--
Mcmd/hare/schedule.ha | 3+--
Mdirs/xdg.ha | 2+-
Mfs/util.ha | 6++----
Mhare/module/context.ha | 2+-
Mhare/module/scan.ha | 2+-
Mpath/README | 29++++++++++++++++++++---------
Mpath/buffer.ha | 57++++++++++++++++-----------------------------------------
Mpath/join.ha | 8++++----
Mtime/chrono/tzdb.ha | 3+--
11 files changed, 50 insertions(+), 68 deletions(-)

diff --git a/cmd/hare/plan.ha b/cmd/hare/plan.ha @@ -86,7 +86,7 @@ fn mkplan( // Look up the most appropriate hare.sc file let ntag = 0z; - const buf = path::init(); + const buf = path::init()!; const iter = os::iter(rtdir)!; defer os::finish(iter); for (true) match (fs::next(iter)) { diff --git a/cmd/hare/release.ha b/cmd/hare/release.ha @@ -235,7 +235,7 @@ fn choosekey() (str | release_error) = { "id_rsa", "id_dsa", ]; - let buf = path::init(); + let buf = path::init()!; const home = os::getenv("HOME") as str; for (let i = 0z; i < len(paths); i += 1) { const cand = path::set(&buf, home, ".ssh", paths[i])!; @@ -279,7 +279,7 @@ fn signtag(tmpdir: str, name: str, tag: str, key: str) (void | release_error) = // This could work without the agent if it were not for the fact that // ssh-keygen is bloody stupid when it comes to prompting you for your // password. - let buf = path::init(); + let buf = path::init()!; const socket = path::set(&buf, tmpdir, "agent")!; const agent = exec::cmd("ssh-agent", "-Da", socket)?; exec::nullstd(&agent); diff --git a/cmd/hare/schedule.ha b/cmd/hare/schedule.ha @@ -302,8 +302,7 @@ fn sched_hare_object( let td = fmt::asprintf("{}.td", version); defer free(td); - let buf = path::init(); - path::set(&buf, plan.context.cache)!; + let buf = path::init(plan.context.cache)!; path::add(&buf, namespace...)!; const path = path::string(&buf); match (os::mkdirs(path, 0o755)) { diff --git a/dirs/xdg.ha b/dirs/xdg.ha @@ -14,7 +14,7 @@ use unix; fn lookup(prog: str, var: str, default: str) str = { static let buf = path::buffer { ... }; - path::reset(&buf); + path::set(&buf)!; match (os::getenv(var)) { case let s: str => const path = path::add(&buf, s, prog)!; diff --git a/fs/util.ha b/fs/util.ha @@ -111,8 +111,7 @@ export fn dirents_free(d: []dirent) void = { // Removes a directory, and anything in it. export fn rmdirall(fs: *fs, path: str) (void | error) = { - let buf = path::init(); - path::set(&buf, path)!; + let buf = path::init(path)!; return rmdirall_path(fs, &buf); }; @@ -148,8 +147,7 @@ fn rmdirall_path(fs: *fs, buf: *path::buffer) (void | error) = { // allocated and will be overwritten on subsequent calls. export fn realpath(fs: *fs, path: str) (str | error) = { static let buf = path::buffer { ... }; - path::reset(&buf); - + path::set(&buf)!; const iter = path::iter(path); for (true) { const item = match (path::next(&iter)) { diff --git a/hare/module/context.ha b/hare/module/context.ha @@ -93,7 +93,7 @@ export fn identpath(name: ast::ident) str = { if (len(name) == 0) { return strings::dup("."); }; - let buf = path::init(); + let buf = path::init()!; for (let i = 0z; i < len(name); i += 1) { path::add(&buf, name[i])!; }; diff --git a/hare/module/scan.ha b/hare/module/scan.ha @@ -137,7 +137,7 @@ fn scan_directory( strings::freeall(dirs); }; - let pathbuf = path::init(); + let pathbuf = path::init()!; for (true) { const ent = match (fs::next(iter)) { case void => diff --git a/path/README b/path/README @@ -5,26 +5,37 @@ of non-UTF-8 paths (ideally for only as long as it takes to delete or rename those files), see the low-level functions available from [[rt]]. Use of the [[buffer]] type is recommended for efficient and consistent -manipulation of filesystem paths. +manipulation of filesystem paths. The path will always be +normalized, which is to say that it will not include any of the following: - let buf = path::init(); - path::add(&buf, "/", "foo", "bar", "baz.txt")!; - fmt::println(path::string(&buf))!; // "/foo/bar/baz.txt" +- Redundant ".." components +- Redundant path separators +- Any "." components, except in the case of "." - path::add(&buf, "../.././hello.txt")!; - fmt::println(path::string(&buf))!; // "/foo/hello.txt" +Assuming that PATHSEP is '/', "/usr//bin/../bin/./hare" becomes +"/usr/bin/hare" and "../../foo/bar" is unchanged. The path will only end in +a slash if the last item which was added ended in a slash, like so: + + let buf = path::init("foo", "bar")!; + assert(path::string(&buf) == "foo/bar"); + + path::set(&buf, "foo", "bar/")!; + assert(path::string(&buf) == "foo/bar/"); + + path::set(&buf, "foo", "bar", "/")!; + assert(path::string(&buf) == "foo/bar/"); The buffer object includes an array of length [[PATH_MAX]], which can be somewhat large; on Linux it's 4096 bytes. You can allocate this on the stack in most cases, but you may prefer to allocate it elsewhere depending on your needs. // Stack allocated - let buf = path::init(); + let buf = path::init()!; // Statically allocated static let buf = path::buffer { ... }; - path::reset(&buf); + path::set(&buf); // Heap allocated - let buf = alloc(path::init()); + let buf = alloc(path::init()!); defer free(buf); diff --git a/path/buffer.ha b/path/buffer.ha @@ -11,47 +11,22 @@ export type buffer = struct { }; // Initializes a new path buffer. -export fn init() buffer = { +export fn init(items: str...) (buffer | errors::overflow) = { let buf = buffer { ... }; - reset(&buf); + add(&buf, items...)?; return buf; }; -// Resets a path buffer to its initial state. -export fn reset(buf: *buffer) void = { - buf.end = 0; -}; - // Sets the value of a path buffer to a list of components, overwriting any // previous value. Returns the new string value of the path. export fn set(buf: *buffer, items: str...) (str | errors::overflow) = { - reset(buf); + buf.end = 0; return add(buf, items...); }; -// Returns the current path stored in this buffer. The path will always be -// normalized, which is to say that it will not include any of the following: -// -// - Redundant ".." components -// - Redundant path separators -// - Any "." components, except in the case of "." -// -// Assuming that PATHSEP is '/', "/usr//bin/../bin/./hare" becomes -// "/usr/bin/hare" and "../../foo/bar" is unchanged. The path will only end in a -// slash if the last item which was added ended in PATHSEP, like so: -// -// let buf = path::init(); -// path::set(&buf, "foo", "bar")!; -// assert(path::string(&buf) == "foo/bar"); -// -// path::set(&buf, "foo", "bar/")!; -// assert(path::string(&buf) == "foo/bar/"); -// -// path::set(&buf, "foo", "bar", "/")!; -// assert(path::string(&buf) == "foo/bar/"); -// -// The return value is borrowed from the buffer. Use [[allocate]] to extend the -// lifetime of the string. +// Returns the current path stored in this buffer. +// The return value is borrowed from the buffer. Use [[allocate]] to extend +// the lifetime of the string. export fn string(buf: *buffer) str = { const value = strings::fromutf8_unsafe(buf.buf[..buf.end]); if (value == "") { @@ -60,8 +35,8 @@ export fn string(buf: *buffer) str = { return value; }; -// Like [[string]] but the return value is copied to the heap and must be freed -// by the caller. +// Like [[string]] but the return value is copied to the heap and must be +// freed by the caller. export fn allocate(buf: *buffer) str = { return strings::dup(string(buf)); }; @@ -119,7 +94,7 @@ fn parent(buf: *buffer) (void | errors::overflow) = { }; // XXX: This is not super efficient const name = dirname(string(buf)); - reset(buf); + buf.end = 0; add(buf, name)?; }; @@ -136,7 +111,7 @@ fn doappend(buf: *buffer, elem: []u8) (void | errors::overflow) = { }; @test fn appendnorm() void = { - let buf = init(); + let buf = init()!; assert(string(&buf) == "."); appendnorm(&buf, "foo")!; appendnorm(&buf, "bar")!; @@ -151,7 +126,7 @@ fn doappend(buf: *buffer, elem: []u8) (void | errors::overflow) = { assert(string(&buf) == s); free(s); - reset(&buf); + buf.end = 0; appendnorm(&buf, pathsepstr)!; appendnorm(&buf, "foo")!; appendnorm(&buf, "bar")!; @@ -163,13 +138,13 @@ fn doappend(buf: *buffer, elem: []u8) (void | errors::overflow) = { assert(string(&buf) == s); free(s); - reset(&buf); + buf.end = 0; appendnorm(&buf, pathsepstr)!; appendnorm(&buf, pathsepstr)!; appendnorm(&buf, pathsepstr)!; assert(string(&buf) == pathsepstr); - reset(&buf); + buf.end = 0; appendnorm(&buf, ".")!; appendnorm(&buf, "foo")!; assert(string(&buf) == "foo"); @@ -178,7 +153,7 @@ fn doappend(buf: *buffer, elem: []u8) (void | errors::overflow) = { appendnorm(&buf, "..")!; assert(string(&buf) == ".."); - reset(&buf); + buf.end = 0; appendnorm(&buf, "..")!; assert(string(&buf) == ".."); appendnorm(&buf, "..")!; @@ -190,7 +165,7 @@ fn doappend(buf: *buffer, elem: []u8) (void | errors::overflow) = { assert(string(&buf) == s); free(s); - reset(&buf); + buf.end = 0; appendnorm(&buf, "foo")!; appendnorm(&buf, "bar")!; s = strings::join(pathsepstr, "foo", "bar"); @@ -226,7 +201,7 @@ fn doappend(buf: *buffer, elem: []u8) (void | errors::overflow) = { assert(string(&buf) == s); free(s); - reset(&buf); + buf.end = 0; appendnorm(&buf, "a")!; appendnorm(&buf, "b")!; s = strings::join(pathsepstr, "a", "b"); diff --git a/path/join.ha b/path/join.ha @@ -29,13 +29,13 @@ export fn add(buf: *buffer, items: str...) (str | errors::overflow) = { }; @test fn add() void = { - let buf = init(); + let buf = init()!; add(&buf, "foo", "bar", "baz")!; let s = strings::join(pathsepstr, "foo", "bar", "baz"); assert(string(&buf) == s); free(s); - reset(&buf); + buf.end = 0; s = strings::join(pathsepstr, "", "foo", "bar"); add(&buf, s, "baz")!; free(s); @@ -43,7 +43,7 @@ export fn add(buf: *buffer, items: str...) (str | errors::overflow) = { assert(string(&buf) == s); free(s); - reset(&buf); + buf.end = 0; s = strings::join(pathsepstr, "foo", "bar"); add(&buf, pathsepstr, s, "baz")!; free(s); @@ -51,7 +51,7 @@ export fn add(buf: *buffer, items: str...) (str | errors::overflow) = { assert(string(&buf) == s); free(s); - reset(&buf); + buf.end = 0; s = strings::join(pathsepstr, ".", "foo", "bar"); add(&buf, s)!; free(s); diff --git a/time/chrono/tzdb.ha b/time/chrono/tzdb.ha @@ -26,8 +26,7 @@ export type invalidtzif = !void; // All localities provided default to the [[utc]] [[timescale]] and // [[EARTH_DAY]] day-length. export fn tz(name: str) (locality | tzdberror) = { - const filepath = path::init(); - path::add(&filepath, ZONEINFO_PREFIX, name)!; + const filepath = path::init(ZONEINFO_PREFIX, name)!; const fpath = path::string(&filepath); const file = os::open(fpath)?;