diff options
Diffstat (limited to 'appl/cmd/look.b')
| -rwxr-xr-x | appl/cmd/look.b | 393 |
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'; +} |
