xref: /inferno-os/appl/cmd/grep.b (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1implement Grep;
2
3include "sys.m";
4	sys: Sys;
5	FD: import Sys;
6	stdin, stderr, stdout: ref FD;
7
8include "draw.m";
9	Context: import Draw;
10
11include "regex.m";
12	regex: Regex;
13	Re: import regex;
14
15include "bufio.m";
16	bufio: Bufio;
17	Iobuf: import bufio;
18
19include "arg.m";
20
21
22Grep: module
23{
24	init:	fn(ctxt: ref Context, argv: list of string);
25};
26
27multi: int;
28lflag, nflag, vflag, iflag, Lflag, sflag: int = 0;
29
30badmodule(path: string)
31{
32	sys->fprint(stderr, "grep: cannot load %s: %r\n", path);
33	raise "fail:bad module";
34}
35
36init(nil: ref Context, argv: list of string)
37{
38	sys = load Sys Sys->PATH;
39	stdin = sys->fildes(0);
40	stdout = sys->fildes(1);
41	stderr = sys->fildes(2);
42
43	arg := load Arg Arg->PATH;
44	if (arg == nil)
45		badmodule(Arg->PATH);
46
47	regex = load Regex Regex->PATH;
48	if(regex == nil)
49		badmodule(Regex->PATH);
50
51	bufio = load Bufio Bufio->PATH;
52	if(bufio == nil)
53		badmodule(Bufio->PATH);
54
55	arg->init(argv);
56	while ((opt := arg->opt()) != 0) {
57		case opt {
58		'l' =>
59			lflag = 1;
60		'n' =>
61			nflag = 1;
62		'v' =>
63			vflag = 1;
64		'i' =>
65			iflag = 1;
66		'L' =>
67			Lflag = 1;
68		's' =>
69			sflag = 1;
70		* =>
71			usage();
72		}
73	}
74	argv = arg->argv();
75	arg = nil;
76
77	if(argv == nil)
78		usage();
79	pattern := hd argv;
80	argv = tl argv;
81	if (iflag)
82		pattern = tolower(pattern);
83	(re, err) := regex->compile(pattern,0);
84	if(re == nil) {
85		sys->fprint(stderr, "grep: %s\n", err);
86		raise "fail:bad regex";
87	}
88
89	matched := 0;
90	if(argv == nil)
91		matched = grep(re, bufio->fopen(stdin, Bufio->OREAD), "stdin");
92	else {
93		multi = (tl argv != nil);
94		for (; argv != nil; argv = tl argv) {
95			f := bufio->open(hd argv, Bufio->OREAD);
96			if(f == nil)
97				sys->fprint(stderr, "grep: cannot open %s: %r\n", hd argv);
98			else
99				matched += grep(re, f, hd argv);
100		}
101	}
102	if (!matched)
103		raise "fail:no matches";
104}
105
106usage()
107{
108	sys->fprint(stderr, "usage: grep [-lnviLs] pattern [file...]\n");
109	raise "fail:usage";
110}
111
112grep(re: Re, f: ref Iobuf, file: string): int
113{
114	matched := 0;
115	for(line := 1; ; line++) {
116		s := t := f.gets('\n');
117		if(s == nil)
118			break;
119		if (iflag)
120			s = tolower(s);
121		if((regex->executese(re, s, (0, len s-1), 1, 1) != nil) ^ vflag) {
122			matched = 1;
123			if(lflag || sflag) {
124				if (!sflag)
125					sys->print("%s\n", file);
126				return matched;
127			}
128			if (!Lflag) {
129				if(nflag)
130					if(multi)
131						sys->print("%s:%d: %s", file, line, t);
132					else
133						sys->print("%d:%s", line, t);
134				else
135					if(multi)
136						sys->print("%s: %s", file, t);
137					else
138						sys->print("%s", t);
139			}
140		}
141	}
142	if (Lflag && matched == 0 && !sflag)
143		sys->print("%s\n", file);
144	return matched;
145}
146
147tolower(s: string): string
148{
149	for (i := 0; i < len s; i++) {
150		c := s[i];
151		if (c >= 'A' && c <= 'Z')
152			s[i] = c - 'A' + 'a';
153	}
154	return s;
155}
156