tee.ha (1138B)
1 use fmt; 2 use fs; 3 use getopt; 4 use io; 5 use main; 6 use os; 7 8 export fn utilmain() (main::error | void) = { 9 const cmd = getopt::parse(os::args, 10 "read from standard input and write to standard output and files", 11 ('a', "append the output to the files"), 12 ('i', "ignore the SIGINT signal"), 13 "file...", 14 ); 15 defer getopt::finish(&cmd); 16 17 let flags = fs::flag::WRONLY; 18 for (let i = 0z; i < len(cmd.opts); i += 1) { 19 const opt = cmd.opts[i]; 20 switch (opt.0) { 21 case 'a' => 22 flags |= fs::flag::APPEND; 23 case 'i' => 24 abort("TODO: Ignore SIGINT"); 25 case => 26 abort(); // Invariant 27 }; 28 }; 29 30 let source = os::stdin; 31 let files: []io::file = []; 32 defer { 33 for (let i = 0z; i < len(files); i += 1) { 34 io::close(files[i])!; 35 }; 36 free(files); 37 }; 38 39 for (let i = 0z; i < len(cmd.args); i += 1) { 40 const file = match (os::create(cmd.args[i], 0o666, flags)) { 41 case let err: fs::error => 42 fmt::fatalf("Error opening '{}' for writing: {}", 43 cmd.args[i], fs::strerror(err)); 44 case let file: io::file => 45 yield file; 46 }; 47 source = &io::tee(source, file); 48 append(files, file); 49 }; 50 51 io::copy(os::stdout, source)?; 52 return; 53 };