ref: babf901b4a508c3ec5d1f89655f10377bbdf9637
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;
}