dc

Tiny reverse polish desk calculator
Log | Files | Refs | README | LICENSE

commit 9af0cd2a34a261e50b40439abed2d6abefe8f726
parent ae7c43183148c8699e9357076c5d02ef6db4ef2b
Author: Byron Torres <b@torresjrjr.com>
Date:   Wed, 24 Nov 2021 17:54:24 +0000

handle files

Diffstat:
Mdc.ha | 61+++++++++++++++++++++++++++++++++++++++++--------------------
1 file changed, 41 insertions(+), 20 deletions(-)

diff --git a/dc.ha b/dc.ha @@ -2,6 +2,7 @@ use ascii; use bufio; use encoding::utf8; use fmt; +use fs; use getopt; use io; use math; @@ -14,29 +15,41 @@ let S: []f64 = []; export fn main() void = { const help: [_]getopt::help = [ "desk calculator", - "[file]", + "[file ...]", ]; const cmd = getopt::parse(os::args, help...); defer getopt::finish(&cmd); - if (len(cmd.args) > 1) { - usage_exit(help); - }; + static const buf: [1]u8 = [0...]; - let filename: (str | void) = if (len(cmd.args) == 1) - switch (cmd.args[0]) { + for (let i = 0z; i < len(cmd.args); i += 1) { + const filename = switch (cmd.args[i]) { case "-" => fmt::fatal("dc: invalid filename '-'"); case "" => fmt::fatal("dc: invalid filename ''"); case => - yield cmd.args[0]; - } - else - void; + yield cmd.args[i]; + }; + + const file = match (os::open(filename)) { + case f: io::file => + yield f; + case err: fs::error => + fmt::fatal("dc: {} '{}'", fs::strerror(err), filename); + }; + defer io::close(file); + + const in = bufio::buffered(file, buf, []); + dc(in); + }; + + dc(os::stdin); +}; +fn dc(in: io::handle) void = { for (true) { - const r = match (bufio::scanrune(os::stdin)) { + const r = match (bufio::scanrune(in)) { case utf8::invalid => fmt::fatal("dc: invalid utf8 input"); case io::error => @@ -52,13 +65,13 @@ export fn main() void = { }; if (ascii::isdigit(r)) { - bufio::unreadrune(os::stdin, r); - push(scan_number()); + bufio::unreadrune(in, r); + push(scan_number(in)); continue; }; if (r == '_') { - push(-scan_number()); + push(-scan_number(in)); continue; }; @@ -69,13 +82,13 @@ export fn main() void = { // printing case 'p' => if (len(S) == 0) { - fmt::errorln("dc: stack has no elements")?; + fmt::errorln("dc: stack empty")?; continue; }; fmt::println(peek())?; case 'n' => if (len(S) == 0) { - fmt::errorln("dc: stack has no elements")?; + fmt::errorln("dc: stack empty")?; continue; }; fmt::println(pop())?; @@ -87,8 +100,16 @@ export fn main() void = { case 'c' => clear(); case 'd' => + if (len(S) == 0) { + fmt::errorln("dc: stack empty")?; + continue; + }; push(peek()); case 'r' => + if (len(S) < 2) { + fmt::errorln("dc: stack has too few elements")?; + continue; + }; const b = pop(); const a = pop(); push(b); @@ -102,7 +123,7 @@ export fn main() void = { const a = S[i]; delete(S[i]); append(S, a); - } else if (n < 1) { + } else if (n < -1) { const l = len(S): int; const n = if (-n < l) -n else l; const i = l - n; @@ -169,12 +190,12 @@ export fn main() void = { os::exit(1); }; -fn scan_number() f64 = { +fn scan_number(in: io::handle) f64 = { let num: []u8 = []; defer free(num); let seen_decimal = false; for (true) { - const r = match (bufio::scanrune(os::stdin)) { + const r = match (bufio::scanrune(in)) { case utf8::invalid => fmt::fatal("dc: invalid utf8 input"); case io::error => @@ -191,7 +212,7 @@ fn scan_number() f64 = { seen_decimal = true; }; } else { - bufio::unreadrune(os::stdin, r); + bufio::unreadrune(in, r); match (strconv::stof64(strings::fromutf8(num))) { case (strconv::invalid | strconv::overflow) => abort("dc: invalid numerical input");