hautils

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

commit 02c289707bbb69398aae135989183b748127e15e
parent 394ddc08a8d6f1e3549843c66802418a2c964a1f
Author: Drew DeVault <sir@cmpwn.com>
Date:   Fri,  4 Mar 2022 12:27:06 +0100

rm: new utility

Skipped the interactive mode (-i) intentionally

Diffstat:
M.gitignore | 3++-
MMakefile | 1+
Arm.ha | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 72 insertions(+), 1 deletion(-)

diff --git a/.gitignore b/.gitignore @@ -5,9 +5,10 @@ env false head nl +pwd +rm sleep tee true uname wc -pwd diff --git a/Makefile b/Makefile @@ -12,6 +12,7 @@ utils=\ head \ nl \ pwd \ + rm \ sleep \ tee \ true \ diff --git a/rm.ha b/rm.ha @@ -0,0 +1,69 @@ +use fmt; +use fs; +use getopt; +use main; +use os; + +type config = struct { + status: int, + force: bool, + recur: bool, +}; + +export fn utilmain() (void | main::error) = { + const cmd = getopt::parse(os::args, + "remove files", + ('f', "remove read-only files and ignore errors"), + ('r', "remove directories and their contents"), + "files..."); + defer getopt::finish(&cmd); + + let conf = config { ... }; + for (let i = 0z; i < len(cmd.opts); i += 1) { + switch (cmd.opts[i].0) { + case 'f' => + conf.force = true; + case 'r' => + conf.recur = true; + case => abort(); + }; + }; + + for (let i = 0z; i < len(cmd.args); i += 1) { + const target = cmd.args[i]; + match (remove(&conf, target)) { + case let err: fs::error => + conf.status = 1; + if (!conf.force) { + fmt::errorfln("{}: Error: {}", + target, fs::strerror(err))!; + }; + case void => void; + }; + }; + + os::exit(conf.status); +}; + +fn remove(conf: *config, path: str) (void | fs::error) = { + const st = os::stat(path)?; + if (fs::isdir(st.mode) && !conf.recur) { + if (!conf.force) { + conf.status = 1; + fmt::errorfln("{}: skipping directory", path)?; + }; + return; + }; + + if (!os::access(path, os::amode::W_OK)? && !conf.force) { + conf.status = 1; + fmt::errorfln("{}: skipping read-only file", path)?; + return; + }; + + if (fs::isdir(st.mode)) { + os::rmdirall(path)?; + } else { + os::remove(path)?; + }; +};