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:
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)?;