hautils

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit 95768c62d4e6a041f6a4dd7f21f2603b8108e506
parent 161e211a774b0865864dbad7dbaa46d77d3bac9b
Author: Drew DeVault <sir@cmpwn.com>
Date:   Fri,  7 Jan 2022 13:05:54 +0100

pwd: implement -P flag

Diffstat:
Mpwd.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...); +};