commit 95768c62d4e6a041f6a4dd7f21f2603b8108e506
parent 161e211a774b0865864dbad7dbaa46d77d3bac9b
Author: Drew DeVault <sir@cmpwn.com>
Date: Fri, 7 Jan 2022 13:05:54 +0100
pwd: implement -P flag
Diffstat:
M | pwd.ha | | | 65 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- |
1 file changed, 61 insertions(+), 4 deletions(-)
diff --git a/pwd.ha b/pwd.ha
@@ -1,7 +1,11 @@
+use errors;
+use fmt;
+use fs;
use getopt;
use main;
use os;
-use fmt;
+use path;
+use strings;
type mode = enum {
NORM,
@@ -29,12 +33,65 @@ export fn utilmain() (main::error | void) = {
};
};
+ // TODO: Update me following https://todo.sr.ht/~sircmpwn/hare/540
+ // Maybe our resolvelinks function should become os::resolve?
+ const cwd = os::tryenv("PWD", os::getcwd());
const path = switch (mode) {
case mode::NORM =>
- yield os::resolve(os::getcwd());
+ yield os::resolve(cwd);
case mode::NORMLINK =>
- abort(); // TODO
+ yield resolvelinks(cwd)?;
};
-
+ defer free(path);
fmt::println(path)?;
};
+
+// Reads all links in a path. The caller must free the return value.
+fn resolvelinks(path: str) (str | fs::error) = {
+ let path = strings::dup(path);
+ defer free(path);
+ let parts: []str = [];
+ defer free(parts);
+
+ let iter = path::iter(path);
+ for (true) {
+ let item = match (path::next(&iter)) {
+ case let item: str =>
+ yield item;
+ case void =>
+ break;
+ };
+ append(parts, item);
+
+ const temp = path::join(parts...);
+ defer free(temp);
+
+ let link = match (os::readlink(temp)) {
+ case let link: str =>
+ yield link;
+ case fs::wrongtype =>
+ continue;
+ case let err: fs::error =>
+ return err;
+ };
+
+ if (!path::abs(link)) {
+ delete(parts[len(parts) - 1]);
+ append(parts, link);
+ let temp = path::join(parts...);
+ defer free(temp);
+ let newlink = os::resolve(temp);
+ free(link);
+ link = newlink;
+ };
+
+ // Reset state and start over with the link target
+ free(path);
+ path = link;
+ iter = path::iter(path);
+ free(parts);
+ parts = [];
+ };
+
+ return path::join(parts...);
+};