hautils

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

commit c1f3bd94162c07f4890655a426c2262adb4ecd57
parent f7db4cf8582d596d7c81c04f2b63642111cddf02
Author: Byron Torres <b@torresjrjr.com>
Date:   Fri, 20 Aug 2021 11:16:51 +0100

nl: new command

Only implements -iswv flags for now.
Does not implement logical page delimiters.

Diffstat:
M.gitignore | 5+++--
MMakefile | 2++
Anl.ha | 110+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 115 insertions(+), 2 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -1,6 +1,7 @@ cat false -true +head +nl tee +true uname -head diff --git a/Makefile b/Makefile @@ -7,6 +7,7 @@ utils=\ cat \ false \ head \ + nl \ tee \ true \ uname @@ -25,6 +26,7 @@ clean: cat: cat.ha main/main.ha false: false.ha head: head.ha +nl: nl.ha tee: tee.ha true: true.ha uname: uname.ha diff --git a/nl.ha b/nl.ha @@ -0,0 +1,110 @@ +use bufio; +use fmt; +use fs; +use getopt; +use io; +use main; +use os; +use strconv; + +export fn utilmain() (void | main::error) = { + const helplist: [_]getopt::help = [ + "line numbering filter", + ('p', "do not restart numbering at logical page delimiters"), + ('b', "type", "set body line numbering strategy"), + ('d', "delim", "set delimiter for new pages"), + ('f', "type", "set footer line numbering strategy"), + ('h', "type", "set header line numbering strategy"), + ('i', "incr", "amount to increment each page"), + ('l', "num", "number of consecutive blank lines considered one"), + ('n', "format", "set line number format"), + ('s', "sep", "set separator to place between line number and text"), + ('v', "startnum", "initial value for each page"), + ('w', "width", "number of columns for numbers"), + "[file]" + ]; + const cmd = getopt::parse(os::args, helplist...); + defer getopt::finish(&cmd); + + let incr = 1; + let sep = "\t"; + let width: uint = 6; + let startnum = 1; + + for (let i = 0z; i < len(cmd.opts); i += 1) { + const opt = cmd.opts[i]; + switch (opt.0) { + 'b' => abort("TODO: implement -b flag"), + 'd' => abort("TODO: implement -d flag"), + 'f' => abort("TODO: implement -f flag"), + 'h' => abort("TODO: implement -h flag"), + 'i' => incr = match (strconv::stoi(opt.1)) { + (strconv::invalid | strconv::overflow) => + fmt::fatal("Error: -i: argument must be an integer"), + incr: int => incr, + }, + 'l' => abort("TODO: implement -l flag"), + 'n' => abort("TODO: implement -n flag"), + 'p' => abort("TODO: implement -p flag"), + 's' => sep = opt.1, + 'w' => width = match (strconv::stou(opt.1)) { + (strconv::invalid | strconv::overflow) => + fmt::fatal("Error: -w: argument must be an ingeter"), + width: uint => + if (width <= 0) + fmt::fatal("Error: -w: width must be greater than 0") + else + width, + }, + 'v' => startnum = match (strconv::stoi(opt.1)) { + (strconv::invalid | strconv::overflow) => { + fmt::errorln("Error: -v: argument must be an integer")?; + getopt::printusage(os::stderr, os::args[0], helplist); + os::exit(1); + }, + startnum: int => startnum, + }, + }; + }; + + if (len(cmd.args) > 1) { + getopt::printusage(os::stderr, os::args[0], helplist); + os::exit(1); + }; + + const use_file = len(cmd.args) == 1 && cmd.args[0] != "-"; + const input = switch (use_file) { + true => match (os::open(cmd.args[0])) { + err: fs::error => fmt::fatal("Error opening '{}': {}", + cmd.args[0], fs::strerror(err)), + file: *io::stream => { + static const rbuf: [os::BUFSIZ]u8 = [0...]; + static const wbuf: [os::BUFSIZ]u8 = [0...]; + bufio::buffered(file, rbuf, wbuf); + }, + }, + false => os::stdin, + }; + defer io::close(input); + + // prepares line number format string, e.g.: "{0:6}{1}" + const fmtstr = fmt::asprintf("{{0:{0}}}{{1}}", width); + + let linenum = startnum; + + for (true) { + const line = match (bufio::scanline(input)) { + err: io::error => return err, + io::EOF => break, + line: []u8 => line, + }; + defer free(line); + + if (len(line) != 0) { + fmt::printf(fmtstr, linenum, sep)?; + linenum += incr; + }; + io::write(os::stdout, line)?; + fmt::println()?; + }; +};