commit cd47ebf8e8ced89b6310c1463a6a178dae8e8e66
parent 06340e832c686eefef414710cdb5bc2fa405e1c9
Author: thing1 <thing1@seacrossedlovers.xyz>
Date: Tue, 24 Feb 2026 12:09:52 +0000
added wc
Diffstat:
6 files changed, 166 insertions(+), 5 deletions(-)
diff --git a/Makefile b/Makefile
@@ -7,7 +7,7 @@ DESTDIR=
PREFIX=/usr/local
BINDIR=$(PREFIX)/bin
-all: bin/ls bin/rainbow bin/cat bin/uniq
+all: bin/ls bin/rainbow bin/cat bin/uniq bin/split bin/wc
clean:
rm -rf bin/*
@@ -23,7 +23,12 @@ bin/rainbow: cmd/rainbow.ha
bin/cat: cmd/cat.ha
$(HARE) build $(HAREFLAGS) -o $@ cmd/cat.ha
-
-
bin/uniq: cmd/uniq.ha
$(HARE) build $(HAREFLAGS) -o $@ cmd/uniq.ha
+
+bin/split: cmd/split.ha
+ $(HARE) build $(HAREFLAGS) -o $@ cmd/split.ha
+
+bin/wc: cmd/wc.ha
+ $(HARE) build $(HAREFLAGS) -o $@ cmd/wc.ha
+
diff --git a/TODO.md b/TODO.md
@@ -1,6 +1,5 @@
-- split
+- yes
- fmt
-- wc
- build system
- shell
- redo ls's colors in a more idiomatic way
diff --git a/cmd/rcsh/spec b/cmd/rcsh/spec
@@ -0,0 +1,50 @@
+rcsh - the "really cool shell"
+
+BNF:
+
+prog : imports fns exprs
+
+imports : import imports
+ | import
+
+import : "import" NAME
+
+fns : fn fns
+ | fn
+
+fn : "func" NAME(args) '{' exprs '}'
+
+args : arg ',' args
+ | arg
+
+arg : NAME
+
+exprs : expr exprs
+ | expr
+
+expr : fcall
+ | try '{' exprs '}' catch '{' exprs '}'
+ | "throw" except
+ | value '>' '{' exprs '}' // makes exprs stdin NAME
+ | value '<' '{' exprs '}' // makes exprs stdout NAME
+ | value '<' '<' '{' exprs '}' // makes exprs stdout NAME (append)
+ | value '<>' '{' exprs '}' // makes exprs stdin and stdout NAME
+ | expr | value
+ | expr > value
+ | expr < value
+ | expr >> value
+ | NAME '=' value
+ | cd value
+
+
+value : '$' NAME
+ | STRING
+ | $(expr) // makes stdout the value
+ | fcall
+
+fcall : NAME '(' values ')'
+
+values : value, values
+ | value
+
+except : EPERM | ENOENT | ESRCH | EINTR | EIO | ENXIO | E2BIG | ENOEXEC | EBADF | ECHILD | EAGAIN | ENOMEM | EACCES | EFAULT | ENOTBLK | EBUSY | EEXIST | EXDEV | ENODEV | ENOTDIR | EISDIR | EINVAL | ENFILE | EMFILE | ENOTTY | ETXTBSY | EFBIG | ENOSPC | ESPIPE | EROFS | EMLINK | EPIPE | EDOM | ERANGE | EDEADLK | ENAMETOOLONG | ENOLCK | ENOSYS | ENOTEMPTY | ELOOP | ENOMSG | EIDRM | ECHRNG | EL2NSYNC | EL3HLT | EL3RST | ELNRNG | EUNATCH | ENOCSI | EL2HLT | EBADE | EBADR | EXFULL | ENOANO | EBADRQC | EBADSLT | EBFONT | ENOSTR | ENODATA | ETIME | ENOSR | ENONET | ENOPKG | EREMOTE | ENOLINK | EADV | ESRMNT | ECOMM | EPROTO | EMULTIHOP | EDOTDOT | EBADMSG | EOVERFLOW | ENOTUNIQ | EBADFD | EREMCHG | ELIBACC | ELIBBAD | ELIBSCN | ELIBMAX | ELIBEXEC | EILSEQ | ERESTART | ESTRPIPE | EUSERS | ENOTSOCK | EDESTADDRREQ | EMSGSIZE | EPROTOTYPE | ENOPROTOOPT | EPROTONOSUPPORT | ESOCKTNOSUPPORT | EOPNOTSUPP
diff --git a/cmd/split.ha b/cmd/split.ha
@@ -0,0 +1,49 @@
+use fmt;
+use io;
+use os;
+use strings;
+use bufio;
+use encoding::utf8;
+use getopt;
+
+use util;
+
+let delim = " ";
+
+fn run() void = {
+ let sc = bufio::newscanner(os::stdin);
+ defer bufio::finish(&sc);
+
+ for (true) {
+ match (bufio::scan_string(&sc, delim)) {
+ case let s: str => fmt::println(s)!;
+ case io::EOF => break;
+ case let e: io::error => util::die(io::strerror(e));
+ };
+ };
+
+ match (bufio::scan_line(&sc)) {
+ case let s: str => fmt::println(s)!;
+ case io::EOF => return;
+ case let e: io::error => util::die(io::strerror(e));
+ case let e: utf8::invalid => util::die(utf8::strerror(e));
+ };
+};
+
+export fn main() void = {
+ let cmd = getopt::parse(os::args,
+ "split",
+ ('d', "delim", "set a deliminer between tokens"),
+ );
+ defer getopt::finish(&cmd);
+
+ for (let opt .. cmd.opts) {
+ switch (opt.0) {
+ case 'd' =>
+ delim = util::escape(opt.1);
+ case => abort();
+ };
+ };
+
+ run();
+};
diff --git a/cmd/wc.ha b/cmd/wc.ha
@@ -0,0 +1,57 @@
+use fmt;
+use io;
+use os;
+use strings;
+use bufio;
+use encoding::utf8;
+use getopt;
+
+use util;
+
+let delim = " ";
+
+fn run() size = {
+ let sc = bufio::newscanner(os::stdin);
+ defer bufio::finish(&sc);
+
+ let count = 0z;
+
+ for (true) {
+ match (bufio::scan_string(&sc, delim)) {
+ case let s: str =>
+ let ss = strings::split(s, "\n")!;
+ count += len(ss);
+ free(ss);
+ case io::EOF => return count + 1;
+ case let e: io::error => util::die(io::strerror(e));
+ };
+ };
+};
+
+export fn main() void = {
+ let cmd = getopt::parse(os::args,
+ "word count",
+ ('l', "count lines"),
+ ('w', "count words (default)"),
+ ('c', "count charaters"),
+ );
+ defer getopt::finish(&cmd);
+
+ for (let opt .. cmd.opts) {
+ switch (opt.0) {
+ case 'l' => delim = "\n";
+ case 'w' => delim = " ";
+ case 'c' => delim = "";
+ case => abort();
+ };
+ };
+
+ if (len(delim) == 0) {
+ free(match (io::drain(os::stdin)) {
+ case let buf: []u8 =>
+ fmt::println(len(buf))!;
+ yield buf;
+ case let e: io::error => util::die(io::strerror(e));
+ });
+ } else fmt::println(run())!;
+};
diff --git a/newcmd.sh b/newcmd.sh
@@ -2,3 +2,4 @@
echo "bin/$1: cmd/$1.ha"
echo " \$(HARE) build \$(HAREFLAGS) -o \$@ cmd/$1.ha"
+echo