hautils

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

commit cf3272fc2d1559247b1777b9b780a120285f6c0f
parent 4c35f03fc6bf45a28326c48cd9a94b02f31c0e5b
Author: Drew DeVault <sir@cmpwn.com>
Date:   Thu,  8 Jul 2021 14:19:35 -0400

tee: new command

Diffstat:
M.gitignore | 1+
MMakefile | 2++
Mmain/main.ha | 4+++-
Atee.ha | 49+++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 55 insertions(+), 1 deletion(-)

diff --git a/.gitignore b/.gitignore @@ -1,3 +1,4 @@ cat false true +tee diff --git a/Makefile b/Makefile @@ -5,6 +5,7 @@ HARE=hare utils=\ cat \ false \ + tee \ true all: $(utils) @@ -20,4 +21,5 @@ clean: cat: cat.ha main/main.ha false: false.ha +tee: tee.ha true: true.ha diff --git a/main/main.ha b/main/main.ha @@ -2,7 +2,9 @@ use fmt; use fs; use io; -@symbol("utilmain") fn utilmain() (io::error | fs::error | void); +export type error = (io::error | fs::error); + +@symbol("utilmain") fn utilmain() (main::error | void); // Shared main function for all utilities, to simplify error handling. export @symbol("main") fn main() void = { diff --git a/tee.ha b/tee.ha @@ -0,0 +1,49 @@ +use fmt; +use fs; +use getopt; +use io; +use main; +use os; + +export fn utilmain() (main::error | void) = { + const cmd = getopt::parse(os::args, + "read from standard input and write to standard output and files", + ('a', "append the output to the files"), + ('i', "ignore the SIGINT signal"), + "file...", + ); + defer getopt::finish(&cmd); + + let flags = fs::flags::WRONLY; + for (let i = 0z; i < len(cmd.opts); i += 1) { + const opt = cmd.opts[i]; + switch (opt.0) { + 'a' => flags |= fs::flags::APPEND, + 'i' => abort("TODO: Ignore SIGINT"), + * => abort(), // Invariant + }; + }; + + let source = os::stdin; + let files: []*io::stream = []; + defer { + for (let i = 0z; i < len(files); i += 1) { + io::close(files[i]); + }; + free(files); + }; + + for (let i = 0z; i < len(cmd.args); i += 1) { + const file = match (os::create(cmd.args[i], 0o666, flags)) { + err: fs::error => fmt::fatal( + "Error opening '{}' for writing: {}", + cmd.args[i], fs::strerror(err)), + file: *io::stream => file, + }; + source = io::tee(source, file); + append(files, file); + }; + + io::copy(os::stdout, source)?; + return; +};