commit cf3272fc2d1559247b1777b9b780a120285f6c0f
parent 4c35f03fc6bf45a28326c48cd9a94b02f31c0e5b
Author: Drew DeVault <sir@cmpwn.com>
Date: Thu, 8 Jul 2021 14:19:35 -0400
tee: new command
Diffstat:
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;
+};