summaryrefslogtreecommitdiff
path: root/appl/cmd/look.b
diff options
context:
space:
mode:
Diffstat (limited to 'appl/cmd/look.b')
-rwxr-xr-xappl/cmd/look.b393
1 files changed, 393 insertions, 0 deletions
diff --git a/appl/cmd/look.b b/appl/cmd/look.b
new file mode 100755
index 00000000..8465db45
--- /dev/null
+++ b/appl/cmd/look.b
@@ -0,0 +1,393 @@
+implement Look;
+
+#
+# Copyright © 2002 Lucent Technologies Inc.
+# transliteration of the Plan 9 command; subject to the Lucent Public License 1.02
+# -r option added by Caerwyn Jones to print a range
+#
+
+include "sys.m";
+ sys: Sys;
+
+include "draw.m";
+
+include "bufio.m";
+ bufio: Bufio;
+ Iobuf: import bufio;
+
+include "arg.m";
+
+Look: module
+{
+ init: fn(nil: ref Draw->Context, nil: list of string);
+};
+
+filename := "/lib/words";
+dfile: ref Iobuf;
+bout: ref Iobuf;
+debug := 0;
+fold, direc, exact, iflag, range: int;
+rev := 1; # -1 for reverse-ordered file, not implemented
+tab := '\t';
+nflag := 0;
+entry: string;
+word: string;
+key: string;
+orig: string;
+targ: string;
+latin_fold_tab := array[64] of {
+ # Table to fold latin 1 characters to ASCII equivalents
+ # based at Rune value 0xc0
+ #
+ # À Á Â Ã Ä Å Æ Ç
+ # È É Ê Ë Ì Í Î Ï
+ # Ð Ñ Ò Ó Ô Õ Ö ×
+ # Ø Ù Ú Û Ü Ý Þ ß
+ # à á â ã ä å æ ç
+ # è é ê ë ì í î ï
+ # ð ñ ò ó ô õ ö ÷
+ # ø ù ú û ü ý þ ÿ
+ #
+ 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'c',
+ 'e', 'e', 'e', 'e', 'i', 'i', 'i', 'i',
+ 'd', 'n', 'o', 'o', 'o', 'o', 'o', 0,
+ 'o', 'u', 'u', 'u', 'u', 'y', 0, 0,
+ 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'c',
+ 'e', 'e', 'e', 'e', 'i', 'i', 'i', 'i',
+ 'd', 'n', 'o', 'o', 'o', 'o', 'o', 0,
+ 'o', 'u', 'u', 'u', 'u', 'y', 0, 'y',
+};
+
+init(nil: ref Draw->Context, args: list of string)
+{
+ sys = load Sys Sys->PATH;
+ bufio = load Bufio Bufio->PATH;
+ arg := load Arg Arg->PATH;
+
+ arg->init(args);
+ arg->setusage(arg->progname()+" -[dfinx] [-r orig] [-t c] [string] [file]");
+ while((c := arg->opt()) != 0)
+ case c {
+ 'd' =>
+ direc++;
+ 'f' =>
+ fold++;
+ 'i' =>
+ iflag++;
+ 'n' =>
+ nflag = 1;
+ 't' =>
+ tab = (arg->earg())[0];
+ 'x' =>
+ exact++;
+ 'r' =>
+ range++;
+ orig = arg->earg();
+ targ = rcanon(orig);
+ * =>
+ sys->fprint(sys->fildes(2), "%s: bad option %c\n", arg->progname(), c);
+ sys->fprint(sys->fildes(2), "usage: %s -[dfinx] [-t c] [-r limit] [string] [file]\n", arg->progname());
+ raise "fail:usage";
+ }
+ args = arg->argv();
+ arg = nil;
+
+ bin := bufio->fopen(sys->fildes(0), Sys->OREAD);
+ bout = bufio->fopen(sys->fildes(1), Sys->OWRITE);
+ if(!iflag)
+ if(args != nil){
+ orig = hd args;
+ args = tl args;
+ key = rcanon(orig);
+ }else
+ iflag++;
+ if(args == nil){
+ direc++;
+ fold++;
+ }else
+ filename = hd args;
+ if(debug)
+ sys->fprint(sys->fildes(2), "orig %s key %s %s\n", orig, key, filename);
+ dfile = bufio->open(filename, Sys->OREAD);
+ if(dfile == nil){
+ sys->fprint(sys->fildes(2), "look: can't open %s\n", filename);
+ raise "fail:no dictionary";
+ }
+ if(!iflag)
+ if(!locate() && !range && exact)
+ raise "fail:not found";
+ do{
+ if(iflag){
+ bout.flush();
+ if((orig = bin.gets('\n')) == nil)
+ exit;
+ key = rcanon(orig);
+ if(!locate())
+ continue;
+ }
+ if(range){
+ if(compare(key, word) <= 0 && compare(word, targ) <= 0)
+ bout.puts(entry);
+ }else if(!exact || !compare(word, key))
+ bout.puts(entry);
+ while((entry = dfile.gets('\n')) != nil){
+ word = rcanon(entry);
+ if(range)
+ n := compare(word, targ);
+ else
+ n = compare(key, word);
+ if(debug)
+ sys->print("compare %d\n", n);
+ case n {
+ -2 =>
+ if(range){
+ bout.puts(entry);
+ continue;
+ }
+ -1 =>
+ if(exact)
+ break;
+ if(!exact || !compare(word, key))
+ bout.puts(entry);
+ continue;
+ 0 =>
+ if(!exact || !compare(word, key))
+ bout.puts(entry);
+ continue;
+ }
+ break;
+ }
+ }while(iflag);
+ bout.flush();
+}
+
+locate(): int
+{
+ bot := big 0;
+ top := dfile.seek(big 0, 2);
+ mid: big;
+Search:
+ for(;;){
+ mid = (top+bot)/big 2;
+ if(debug)
+ sys->fprint(sys->fildes(2), "locate %bd %bd %bd\n", top, mid, bot);
+ dfile.seek(mid, 0);
+ c: int;
+ do
+ c = dfile.getc();
+ while(c >= 0 && c != '\n');
+ mid = dfile.offset();
+ if((entry = dfile.gets('\n')) == nil)
+ break;
+ word = rcanon(entry);
+ if(debug)
+ sys->fprint(sys->fildes(2), "mid %bd key: %s entry: %s\n", mid, key, word);
+ n := compare(key, word);
+ if(debug)
+ sys->fprint(sys->fildes(2), "compare: %d\n", n);
+ case n {
+ -2 or -1 or 0 =>
+ if(top <= mid)
+ break Search;
+ top = mid;
+ 1 or 2 =>
+ bot = mid;
+ }
+ }
+ if(debug)
+ sys->fprint(sys->fildes(2), "locate %bd %bd %bd\n", top, mid, bot);
+ bot = dfile.seek(big bot, 0);
+ while((entry = dfile.gets('\n')) != nil){
+ word = rcanon(entry);
+ if(debug)
+ sys->fprint(sys->fildes(2), "seekbot %bd key: %s entry: %s\n", bot, key, word);
+ n := compare(key, word);
+ if(debug)
+ sys->fprint(sys->fildes(2), "compare: %d\n", n);
+ case n {
+ -2 =>
+ return 0;
+ -1 =>
+ if(exact)
+ return 0;
+ return 1;
+ 0 =>
+ return 1;
+ 1 or 2 =>
+ continue;
+ }
+ }
+ return 0;
+}
+
+compare(s, t: string): int
+{
+ if(nflag)
+ return ncomp(s, t);
+ else
+ return acomp(s, t);
+}
+
+#
+# acomp(s, t) returns:
+# -2 if s strictly precedes t
+# -1 if s is a prefix of t
+# 0 if s is the same as t
+# 1 if t is a prefix of s
+# 2 if t strictly precedes s
+#
+acomp(s, t: string): int
+{
+ if(s == t)
+ return 0;
+ l := len s;
+ if(l > len t)
+ l = len t;
+ cs, ct: int;
+ for(i := 0; i < l; i++) {
+ cs = s[i];
+ ct = t[i];
+ if(cs != ct)
+ break;
+ }
+ if(i == len s)
+ return -1;
+ if(i == len t)
+ return 1;
+ if(cs < ct)
+ return -2;
+ return 2;
+}
+
+rcanon(s: string): string
+{
+ if(s != nil && s[len s - 1] == '\n')
+ s = s[0: len s - 1];
+ o := 0;
+ for(i := 0; i < len s && (r := s[i]) != tab; i++){
+ if(16rc0 <= r && r <= 16rff && (mr := latin_fold_tab[r-16rc0]) != 0)
+ r = mr;
+ if(direc)
+ if(!(isalnum(r) || r == ' ' || r == '\t'))
+ continue;
+ if(fold)
+ if(isupper(r))
+ r = tolower(r);
+ if(r != s[o]) # avoid copying s unless necessary
+ s[o] = r;
+ o++;
+ }
+ if(o != i)
+ return s[0:o];
+ return s;
+}
+
+sgn(v: int): int
+{
+ if(v < 0)
+ return -1;
+ if(v > 0)
+ return 1;
+ return 0;
+}
+
+ncomp(s: string, t: string): int
+{
+ while(len s > 0 && isspace(s[0]))
+ s = s[1:];
+ while(len t > 0 && isspace(t[0]))
+ t = t[1:];
+ ssgn := tsgn := -2*rev;
+ if(s != nil && s[0] == '-'){
+ s = s[1: ];
+ ssgn = -ssgn;
+ }
+ if(t != nil && t[0] == '-'){
+ t = t[1:];
+ tsgn = -tsgn;
+ }
+ for(i := 0; i < len s && isdigit(s[i]); i++)
+ ;
+ is := s[0:i];
+ js := s[i:];
+ for(i = 0; i < len t && isdigit(t[i]); i++)
+ ;
+ it := t[0:i];
+ jt := t[i:];
+ a := 0;
+ i = len is;
+ j := len it;
+ if(ssgn == tsgn){
+ while(j > 0 && i > 0)
+ if((b := it[--j] - is[--i]) != 0)
+ a = b;
+ }
+ while(i > 0)
+ if(is[--i] != '0')
+ return -ssgn;
+ while(j > 0)
+ if(it[--i] != '0')
+ return tsgn;
+ if(a)
+ return sgn(a)*ssgn;
+ s = js;
+ if(len s > 0 && s[0] == '.')
+ s = s[1: ];
+ t = jt;
+ if(len t > 0 && t[0] == '.')
+ t = t[1: ];
+ if(ssgn == tsgn)
+ while((len s > 0 && isdigit(s[0])) && (len t > 0 && isdigit(t[0]))){
+ if(a = t[0] - s[0])
+ return sgn(a)*ssgn;
+ s = s[1:];
+ t = t[1:];
+ }
+ for(; len s > 0 && isdigit(s[0]); s = s[1:])
+ if(s[0] != '0')
+ return -ssgn;
+ for(; len t > 0 && isdigit(t[0]); t = t[1:])
+ if(t[0] != '0')
+ return tsgn;
+ return 0;
+}
+
+isupper(c: int): int
+{
+ return c >= 'A' && c <= 'Z';
+}
+
+islower(c: int): int
+{
+ return c >= 'a' && c <= 'z';
+}
+
+isalpha(c: int): int
+{
+ return islower(c) || isupper(c);
+}
+
+islatin1(c: int): int
+{
+ return c >= 16rC0 && c <= 16rFF;
+}
+
+isdigit(c: int): int
+{
+ return c >= '0' && c <= '9';
+}
+
+isalnum(c: int): int
+{
+ return isdigit(c) || islower(c) || isupper(c);
+}
+
+isspace(c: int): int
+{
+ return c == ' ' || c == '\t' || c >= 16r0A && c <= 16r0D;
+}
+
+tolower(c: int): int
+{
+ return c-'A'+'a';
+}