ref: 3efb5bbb4061056e523858b134c555949591efe2
dir: /appl/cmd/grep.b/
implement Grep; include "sys.m"; sys: Sys; FD: import Sys; stdin, stderr, stdout: ref FD; include "draw.m"; Context: import Draw; include "regex.m"; regex: Regex; Re: import regex; include "bufio.m"; bufio: Bufio; Iobuf: import bufio; include "arg.m"; Grep: module { init: fn(ctxt: ref Context, argv: list of string); }; multi: int; lflag, nflag, vflag, iflag, Lflag, sflag: int = 0; badmodule(path: string) { sys->fprint(stderr, "grep: cannot load %s: %r\n", path); raise "fail:bad module"; } init(nil: ref Context, argv: list of string) { sys = load Sys Sys->PATH; stdin = sys->fildes(0); stdout = sys->fildes(1); stderr = sys->fildes(2); arg := load Arg Arg->PATH; if (arg == nil) badmodule(Arg->PATH); regex = load Regex Regex->PATH; if(regex == nil) badmodule(Regex->PATH); bufio = load Bufio Bufio->PATH; if(bufio == nil) badmodule(Bufio->PATH); arg->init(argv); while ((opt := arg->opt()) != 0) { case opt { 'l' => lflag = 1; 'n' => nflag = 1; 'v' => vflag = 1; 'i' => iflag = 1; 'L' => Lflag = 1; 's' => sflag = 1; * => usage(); } } argv = arg->argv(); arg = nil; if(argv == nil) usage(); pattern := hd argv; argv = tl argv; if (iflag) pattern = tolower(pattern); (re, err) := regex->compile(pattern,0); if(re == nil) { sys->fprint(stderr, "grep: %s\n", err); raise "fail:bad regex"; } matched := 0; if(argv == nil) matched = grep(re, bufio->fopen(stdin, Bufio->OREAD), "stdin"); else { multi = (tl argv != nil); for (; argv != nil; argv = tl argv) { f := bufio->open(hd argv, Bufio->OREAD); if(f == nil) sys->fprint(stderr, "grep: cannot open %s: %r\n", hd argv); else matched += grep(re, f, hd argv); } } if (!matched) raise "fail:no matches"; } usage() { sys->fprint(stderr, "usage: grep [-lnviLs] pattern [file...]\n"); raise "fail:usage"; } grep(re: Re, f: ref Iobuf, file: string): int { matched := 0; for(line := 1; ; line++) { s := t := f.gets('\n'); if(s == nil) break; if (iflag) s = tolower(s); if((regex->executese(re, s, (0, len s-1), 1, 1) != nil) ^ vflag) { matched = 1; if(lflag || sflag) { if (!sflag) sys->print("%s\n", file); return matched; } if (!Lflag) { if(nflag) if(multi) sys->print("%s:%d: %s", file, line, t); else sys->print("%d:%s", line, t); else if(multi) sys->print("%s: %s", file, t); else sys->print("%s", t); } } } if (Lflag && matched == 0 && !sflag) sys->print("%s\n", file); return matched; } tolower(s: string): string { for (i := 0; i < len s; i++) { c := s[i]; if (c >= 'A' && c <= 'Z') s[i] = c - 'A' + 'a'; } return s; }