commit b4069f3954e1a571db9811229ae3ced3fc0dda82
parent 88a0384d03f43cc1def1d7a45b2db0bbb8e9697a
Author: Drew DeVault <sir@cmpwn.com>
Date: Sat, 25 Dec 2021 15:01:16 +0100
env: new command
Diffstat:
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;
};
};