summaryrefslogtreecommitdiff
path: root/appl/cmd/wc.b
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
committerCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
commit37da2899f40661e3e9631e497da8dc59b971cbd0 (patch)
treecbc6d4680e347d906f5fa7fca73214418741df72 /appl/cmd/wc.b
parent54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff)
20060303a
Diffstat (limited to 'appl/cmd/wc.b')
-rw-r--r--appl/cmd/wc.b303
1 files changed, 303 insertions, 0 deletions
diff --git a/appl/cmd/wc.b b/appl/cmd/wc.b
new file mode 100644
index 00000000..c0a57d35
--- /dev/null
+++ b/appl/cmd/wc.b
@@ -0,0 +1,303 @@
+implement Wc;
+
+#
+# wc -- count things in utf-encoded text files
+# Bugs:
+# The only white space characters recognized are ' ', '\t' and '\n', even though
+# ISO 10646 has many more blanks scattered through it.
+# Should count characters that cannot occur in any rune (hex f0-ff) separately.
+# Should count non-canonical runes (e.g. hex c1,80 instead of hex 40).
+#
+
+include "sys.m";
+ sys: Sys;
+
+include "draw.m";
+
+Wc: module
+{
+ init: fn(ctxt: ref Draw->Context, args: list of string);
+};
+
+NBUF: con 8*1024;
+
+stderr: ref Sys->FD;
+nline, tnline, pline: int;
+nword, tnword, pword: int;
+nchar, tnchar, pchar: int;
+nbadr, tnbadr, pbadr: int;
+nbyte, tnbyte, pbyte: int;
+
+init(nil: ref Draw->Context, argv: list of string)
+{
+ sys = load Sys Sys->PATH;
+ stderr = sys->fildes(2);
+
+ for(argv = tl argv; argv != nil; argv = tl argv){
+ arg := hd argv;
+ if(len arg < 2 || arg[0] != '-' || arg[1] == '-')
+ break;
+ for(i := 1; i < len arg; i++){
+ case arg[i]{
+ 'l' => pline++;
+ 'w' => pword++;
+ 'c' => pchar++;
+ 'e' => pbadr++;
+ 'b' => pbyte++;
+ * =>
+ sys->fprint(stderr, "usage: wc [-lwcbe] [file ...]\n");
+ raise "fail:usage";
+ }
+ }
+ }
+ if(pline+pword+pchar+pbadr+pbyte == 0)
+ pline = pword = pchar = 1;
+ argc := len argv;
+ if(argc == 0)
+ count(sys->fildes(0), "");
+ else{
+ for(; argv != nil; argv = tl argv){
+ name := hd argv;
+ f := sys->open(name, sys->OREAD);
+ if(f == nil)
+ sys->fprint(stderr, "wc: can't open %s: %r\n", name);
+ else{
+ count(f, name);
+ tnline += nline;
+ tnword += nword;
+ tnchar += nchar;
+ tnbadr += nbadr;
+ tnbyte += nbyte;
+ f = nil;
+ }
+ }
+ if(argc > 1)
+ report(tnline, tnword, tnchar, tnbadr, tnbyte, "total");
+ }
+ exit;
+}
+report(nline, nword, nchar, nbadr, nbyte: int, fname: string)
+{
+ line := "";
+ if(pline)
+ line += sys->sprint(" %7d", nline);
+ if(pword)
+ line += sys->sprint(" %7d", nword);
+ if(pchar)
+ line += sys->sprint(" %7d", nchar);
+ if(pbadr)
+ line += sys->sprint(" %7d", nbadr);
+ if(pbyte)
+ line += sys->sprint(" %7d", nbyte);
+ if(fname != nil)
+ line += sys->sprint(" %s", fname);
+ sys->print("%s\n", line[1:]);
+}
+#
+# How it works. Start in statesp. Each time we read a character,
+# increment various counts, and do state transitions according to the
+# following table. If we're not in statesp or statewd when done, the
+# file ends with a partial rune.
+# | character
+# state |09,20| 0a |00-7f|80-bf|c0-df|e0-ef|f0-ff
+# -------+-----+-----+-----+-----+-----+-----+-----
+# statesp|ASP |ASPN |AWDW |AWDWX|AC2W |AC3W |AWDWX
+# statewd|ASP |ASPN |AWD |AWDX |AC2 |AC3 |AWDX
+# statec2|ASPX |ASPNX|AWDX |AWDR |AC2X |AC3X |AWDX
+# statec3|ASPX |ASPNX|AWDX |AC2R |AC2X |AC3X |AWDX
+#
+ # actions
+ AC2, # enter statec2
+ AC2R, # enter statec2, don't count a rune
+ AC2W, # enter statec2, count a word
+ AC2X, # enter statec2, count a bad rune
+ AC3, # enter statec3
+ AC3W, # enter statec3, count a word
+ AC3X, # enter statec3, count a bad rune
+ ASP, # enter statesp
+ ASPN, # enter statesp, count a newline
+ ASPNX, # enter statesp, count a newline, count a bad rune
+ ASPX, # enter statesp, count a bad rune
+ AWD, # enter statewd
+ AWDR, # enter statewd, don't count a rune
+ AWDW, # enter statewd, count a word
+ AWDWX, # enter statewd, count a word, count a bad rune
+ AWDX: # enter statewd, count a bad rune
+ con byte iota;
+
+statesp := array[256] of{ # looking for the start of a word
+AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, # 00-07
+AWDW, ASP, ASPN, AWDW, AWDW, AWDW, AWDW, AWDW, # 08-0f
+AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, # 10-17
+AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, # 18-1f
+ASP, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, # 20-27
+AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, # 28-2f
+AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, # 30-37
+AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, # 38-3f
+AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, # 40-47
+AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, # 48-4f
+AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, # 50-57
+AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, # 58-5f
+AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, # 60-67
+AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, # 68-6f
+AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, # 70-77
+AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, # 78-7f
+AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,# 80-87
+AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,# 88-8f
+AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,# 90-97
+AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,# 98-9f
+AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,# a0-a7
+AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,# a8-af
+AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,# b0-b7
+AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,# b8-bf
+AC2W, AC2W, AC2W, AC2W, AC2W, AC2W, AC2W, AC2W, # c0-c7
+AC2W, AC2W, AC2W, AC2W, AC2W, AC2W, AC2W, AC2W, # c8-cf
+AC2W, AC2W, AC2W, AC2W, AC2W, AC2W, AC2W, AC2W, # d0-d7
+AC2W, AC2W, AC2W, AC2W, AC2W, AC2W, AC2W, AC2W, # d8-df
+AC3W, AC3W, AC3W, AC3W, AC3W, AC3W, AC3W, AC3W, # e0-e7
+AC3W, AC3W, AC3W, AC3W, AC3W, AC3W, AC3W, AC3W, # e8-ef
+AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,# f0-f7
+AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,# f8-ff
+};
+statewd := array[256] of { # looking for the next character in a word
+AWD, AWD, AWD, AWD, AWD, AWD, AWD, AWD, # 00-07
+AWD, ASP, ASPN, AWD, AWD, AWD, AWD, AWD, # 08-0f
+AWD, AWD, AWD, AWD, AWD, AWD, AWD, AWD, # 10-17
+AWD, AWD, AWD, AWD, AWD, AWD, AWD, AWD, # 18-1f
+ASP, AWD, AWD, AWD, AWD, AWD, AWD, AWD, # 20-27
+AWD, AWD, AWD, AWD, AWD, AWD, AWD, AWD, # 28-2f
+AWD, AWD, AWD, AWD, AWD, AWD, AWD, AWD, # 30-37
+AWD, AWD, AWD, AWD, AWD, AWD, AWD, AWD, # 38-3f
+AWD, AWD, AWD, AWD, AWD, AWD, AWD, AWD, # 40-47
+AWD, AWD, AWD, AWD, AWD, AWD, AWD, AWD, # 48-4f
+AWD, AWD, AWD, AWD, AWD, AWD, AWD, AWD, # 50-57
+AWD, AWD, AWD, AWD, AWD, AWD, AWD, AWD, # 58-5f
+AWD, AWD, AWD, AWD, AWD, AWD, AWD, AWD, # 60-67
+AWD, AWD, AWD, AWD, AWD, AWD, AWD, AWD, # 68-6f
+AWD, AWD, AWD, AWD, AWD, AWD, AWD, AWD, # 70-77
+AWD, AWD, AWD, AWD, AWD, AWD, AWD, AWD, # 78-7f
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, # 80-87
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, # 88-8f
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, # 90-97
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, # 98-9f
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, # a0-a7
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, # a8-af
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, # b0-b7
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, # b8-bf
+AC2, AC2, AC2, AC2, AC2, AC2, AC2, AC2, # c0-c7
+AC2, AC2, AC2, AC2, AC2, AC2, AC2, AC2, # c8-cf
+AC2, AC2, AC2, AC2, AC2, AC2, AC2, AC2, # d0-d7
+AC2, AC2, AC2, AC2, AC2, AC2, AC2, AC2, # d8-df
+AC3, AC3, AC3, AC3, AC3, AC3, AC3, AC3, # e0-e7
+AC3, AC3, AC3, AC3, AC3, AC3, AC3, AC3, # e8-ef
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, # f0-f7
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, # f8-ff
+};
+statec2 := array[256] of { # looking for 10xxxxxx to complete a rune
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, # 00-07
+AWDX, ASPX, ASPNX,AWDX, AWDX, AWDX, AWDX, AWDX, # 08-0f
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, # 10-17
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, # 18-1f
+ASPX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, # 20-27
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, # 28-2f
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, # 30-37
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, # 38-3f
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, # 40-47
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, # 48-4f
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, # 50-57
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, # 58-5f
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, # 60-67
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, # 68-6f
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, # 70-77
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, # 78-7f
+AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, # 80-87
+AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, # 88-8f
+AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, # 90-97
+AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, # 98-9f
+AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, # a0-a7
+AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, # a8-af
+AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, # b0-b7
+AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, # b8-bf
+AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, # c0-c7
+AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, # c8-cf
+AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, # d0-d7
+AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, # d8-df
+AC3X, AC3X, AC3X, AC3X, AC3X, AC3X, AC3X, AC3X, # e0-e7
+AC3X, AC3X, AC3X, AC3X, AC3X, AC3X, AC3X, AC3X, # e8-ef
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, # f0-f7
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, # f8-ff
+};
+statec3 := array[256] of { # looking for 10xxxxxx,10xxxxxx to complete a rune
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, # 00-07
+AWDX, ASPX, ASPNX,AWDX, AWDX, AWDX, AWDX, AWDX, # 08-0f
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, # 10-17
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, # 18-1f
+ASPX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, # 20-27
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, # 28-2f
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, # 30-37
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, # 38-3f
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, # 40-47
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, # 48-4f
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, # 50-57
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, # 58-5f
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, # 60-67
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, # 68-6f
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, # 70-77
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, # 78-7f
+AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, # 80-87
+AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, # 88-8f
+AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, # 90-97
+AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, # 98-9f
+AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, # a0-a7
+AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, # a8-af
+AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, # b0-b7
+AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, # b8-bf
+AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, # c0-c7
+AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, # c8-cf
+AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, # d0-d7
+AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, # d8-df
+AC3X, AC3X, AC3X, AC3X, AC3X, AC3X, AC3X, AC3X, # e0-e7
+AC3X, AC3X, AC3X, AC3X, AC3X, AC3X, AC3X, AC3X, # e8-ef
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, # f0-f7
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, # f8-ff
+};
+buf := array[NBUF] of byte;
+count(f: ref Sys->FD, name: string)
+{
+ state := statesp;
+ nline = nword = nchar = nbadr = nbyte = 0;
+ n := 0;
+ for(;;){
+ n = sys->read(f, buf, NBUF);
+ if(n <= 0)
+ break;
+ nbyte += n;
+ nchar += n; # might be too large, gets decreased later
+ i := 0;
+ do{
+ case int state[int buf[i++]]{
+ int AC2 => state = statec2;
+ int AC2R => state = statec2; nchar--;
+ int AC2W => state = statec2; nword++;
+ int AC2X => state = statec2; nbadr++;
+ int AC3 => state = statec3;
+ int AC3W => state = statec3; nword++;
+ int AC3X => state = statec3; nbadr++;
+ int ASP => state = statesp;
+ int ASPN => state = statesp; nline++;
+ int ASPNX => state = statesp; nline++; nbadr++;
+ int ASPX => state = statesp; nbadr++;
+ int AWD => state = statewd;
+ int AWDR => state = statewd; nchar--;
+ int AWDW => state = statewd; nword++;
+ int AWDWX => state = statewd; nword++; nbadr++;
+ int AWDX => state = statewd; nbadr++;
+ }
+ }while(i < n);
+ }
+ if(state!=statesp && state!=statewd)
+ nbadr++;
+ if(n < 0)
+ sys->fprint(stderr, "wc: error reading %s: %r\n", name);
+ report(nline, nword, nchar, nbadr, nbyte, name);
+}