hautils

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

commit b4069f3954e1a571db9811229ae3ced3fc0dda82
parent 88a0384d03f43cc1def1d7a45b2db0bbb8e9697a
Author: Drew DeVault <sir@cmpwn.com>
Date:   Sat, 25 Dec 2021 15:01:16 +0100

env: new command

Diffstat:
M.gitignore | 1+
MMakefile | 1+
Aenv.ha | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mmain/main.ha | 5++++-
4 files changed, 71 insertions(+), 1 deletion(-)

diff --git a/.gitignore b/.gitignore @@ -1,6 +1,7 @@ basename cat dirname +env false head nl diff --git a/Makefile b/Makefile @@ -7,6 +7,7 @@ utils=\ basename \ cat \ dirname \ + env \ false \ head \ nl \ diff --git a/env.ha b/env.ha @@ -0,0 +1,65 @@ +use fmt; +use getopt; +use main; +use os::exec; +use os; +use strings; + +export fn utilmain() (main::error | void) = { + const help: []getopt::help = [ + "set the environment for command invocation", + ('i', "ignore the parent environment"), + "[command [arguments...]]", + ]; + const cmd = getopt::parse(os::args, help...); + defer getopt::finish(&cmd); + + let clear = false; + for (let i = 0z; i < len(cmd.opts); i += 1) { + switch (cmd.opts[i].0) { + case 'i' => + clear = true; + case => void; + }; + }; + + let environ: []str = cmd.args, args: []str = []; + for (let i = 0z; i < len(cmd.args); i += 1) { + if (!strings::contains(cmd.args[i], '=')) { + environ = cmd.args[..i]; + args = cmd.args[i..]; + break; + }; + }; + + if (len(args) == 0) { + return printenv(environ, clear); + }; + + let cmd = match (exec::cmd(args[0], args[1..]...)) { + case let cmd: exec::command => + yield cmd; + case exec::nocmd => + fmt::errorfln("{}: command not found", args[0])!; + os::exit(127); + case let err: exec::error => + return err; + }; + if (clear) { + exec::clearenv(&cmd); + }; + for (let i = 0z; i < len(environ); i += 1) { + let env = strings::cut(environ[i], "="); + exec::setenv(&cmd, env.0, env.1); + }; + exec::exec(&cmd); +}; + +fn printenv(environ: []str, clear: bool) (void | main::error) = { + if (!clear) { + printenv(os::getenvs(), true)?; + }; + for (let i = 0z; i < len(environ); i += 1) { + fmt::println(environ[i])?; + }; +}; diff --git a/main/main.ha b/main/main.ha @@ -1,8 +1,9 @@ use fmt; use fs; use io; +use os::exec; -export type error = !(io::error | fs::error); +export type error = !(io::error | fs::error | exec::error); @symbol("utilmain") fn utilmain() (main::error | void); @@ -13,6 +14,8 @@ export @symbol("main") fn main() void = { fmt::fatal("I/O error: {}", io::strerror(err)); case let err: fs::error => fmt::fatal("Filesystem error: {}", fs::strerror(err)); + case let err: exec::error => + fmt::fatal("Exec error: {}", exec::strerror(err)); case void => void; }; };