xref: /plan9/sys/src/cmd/grep/main.c (revision a7529a1d594550a832531a572a2b23b6cce7f7a4)
17dd7cddfSDavid du Colombier #define	EXTERN
27dd7cddfSDavid du Colombier #include	"grep.h"
37dd7cddfSDavid du Colombier 
4*a7529a1dSDavid du Colombier char *validflags = "bchiLlnsv";
57dd7cddfSDavid du Colombier void
usage(void)67dd7cddfSDavid du Colombier usage(void)
77dd7cddfSDavid du Colombier {
8*a7529a1dSDavid du Colombier 	fprint(2, "usage: grep [-%s] [-e pattern] [-f patternfile] [file ...]\n", validflags);
97dd7cddfSDavid du Colombier 	exits("usage");
107dd7cddfSDavid du Colombier }
117dd7cddfSDavid du Colombier 
127dd7cddfSDavid du Colombier void
main(int argc,char * argv[])137dd7cddfSDavid du Colombier main(int argc, char *argv[])
147dd7cddfSDavid du Colombier {
157dd7cddfSDavid du Colombier 	int i, status;
167dd7cddfSDavid du Colombier 
177dd7cddfSDavid du Colombier 	ARGBEGIN {
187dd7cddfSDavid du Colombier 	default:
197dd7cddfSDavid du Colombier 		if(utfrune(validflags, ARGC()) == nil)
207dd7cddfSDavid du Colombier 			usage();
217dd7cddfSDavid du Colombier 		flags[ARGC()]++;
227dd7cddfSDavid du Colombier 		break;
237dd7cddfSDavid du Colombier 
247dd7cddfSDavid du Colombier 	case 'e':
257dd7cddfSDavid du Colombier 		flags['e']++;
267dd7cddfSDavid du Colombier 		lineno = 0;
2712fd1c83SDavid du Colombier 		str2top(EARGF(usage()));
287dd7cddfSDavid du Colombier 		break;
297dd7cddfSDavid du Colombier 
307dd7cddfSDavid du Colombier 	case 'f':
317dd7cddfSDavid du Colombier 		flags['f']++;
3212fd1c83SDavid du Colombier 		filename = EARGF(usage());
337dd7cddfSDavid du Colombier 		rein = Bopen(filename, OREAD);
347dd7cddfSDavid du Colombier 		if(rein == 0) {
357dd7cddfSDavid du Colombier 			fprint(2, "grep: can't open %s: %r\n", filename);
367dd7cddfSDavid du Colombier 			exits("open");
377dd7cddfSDavid du Colombier 		}
387dd7cddfSDavid du Colombier 		lineno = 1;
397dd7cddfSDavid du Colombier 		str2top(filename);
407dd7cddfSDavid du Colombier 		break;
417dd7cddfSDavid du Colombier 	} ARGEND
427dd7cddfSDavid du Colombier 
437dd7cddfSDavid du Colombier 	if(flags['f'] == 0 && flags['e'] == 0) {
447dd7cddfSDavid du Colombier 		if(argc <= 0)
457dd7cddfSDavid du Colombier 			usage();
467dd7cddfSDavid du Colombier 		str2top(argv[0]);
477dd7cddfSDavid du Colombier 		argc--;
487dd7cddfSDavid du Colombier 		argv++;
497dd7cddfSDavid du Colombier 	}
507dd7cddfSDavid du Colombier 
517dd7cddfSDavid du Colombier 	follow = mal(maxfollow*sizeof(*follow));
527dd7cddfSDavid du Colombier 	state0 = initstate(topre.beg);
537dd7cddfSDavid du Colombier 
547dd7cddfSDavid du Colombier 	Binit(&bout, 1, OWRITE);
557dd7cddfSDavid du Colombier 	switch(argc) {
567dd7cddfSDavid du Colombier 	case 0:
577dd7cddfSDavid du Colombier 		status = search(0, 0);
587dd7cddfSDavid du Colombier 		break;
597dd7cddfSDavid du Colombier 	case 1:
607dd7cddfSDavid du Colombier 		status = search(argv[0], 0);
617dd7cddfSDavid du Colombier 		break;
627dd7cddfSDavid du Colombier 	default:
637dd7cddfSDavid du Colombier 		status = 0;
647dd7cddfSDavid du Colombier 		for(i=0; i<argc; i++)
657dd7cddfSDavid du Colombier 			status |= search(argv[i], Hflag);
667dd7cddfSDavid du Colombier 		break;
677dd7cddfSDavid du Colombier 	}
687dd7cddfSDavid du Colombier 	if(status)
697dd7cddfSDavid du Colombier 		exits(0);
707dd7cddfSDavid du Colombier 	exits("no matches");
717dd7cddfSDavid du Colombier }
727dd7cddfSDavid du Colombier 
737dd7cddfSDavid du Colombier int
search(char * file,int flag)747dd7cddfSDavid du Colombier search(char *file, int flag)
757dd7cddfSDavid du Colombier {
767dd7cddfSDavid du Colombier 	State *s, *ns;
779a747e4fSDavid du Colombier 	int c, fid, eof, nl, empty;
787dd7cddfSDavid du Colombier 	long count, lineno, n;
797dd7cddfSDavid du Colombier 	uchar *elp, *lp, *bol;
807dd7cddfSDavid du Colombier 
817dd7cddfSDavid du Colombier 	if(file == 0) {
827dd7cddfSDavid du Colombier 		file = "stdin";
837dd7cddfSDavid du Colombier 		fid = 0;
8459cc4ca5SDavid du Colombier 		flag |= Bflag;
857dd7cddfSDavid du Colombier 	} else
867dd7cddfSDavid du Colombier 		fid = open(file, OREAD);
877dd7cddfSDavid du Colombier 
887dd7cddfSDavid du Colombier 	if(fid < 0) {
897dd7cddfSDavid du Colombier 		fprint(2, "grep: can't open %s: %r\n", file);
907dd7cddfSDavid du Colombier 		return 0;
917dd7cddfSDavid du Colombier 	}
927dd7cddfSDavid du Colombier 
9359cc4ca5SDavid du Colombier 	if(flags['b'])
9459cc4ca5SDavid du Colombier 		flag ^= Bflag;		/* dont buffer output */
957dd7cddfSDavid du Colombier 	if(flags['c'])
967dd7cddfSDavid du Colombier 		flag |= Cflag;		/* count */
977dd7cddfSDavid du Colombier 	if(flags['h'])
987dd7cddfSDavid du Colombier 		flag &= ~Hflag;		/* do not print file name in output */
997dd7cddfSDavid du Colombier 	if(flags['i'])
1007dd7cddfSDavid du Colombier 		flag |= Iflag;		/* fold upper-lower */
1017dd7cddfSDavid du Colombier 	if(flags['l'])
1027dd7cddfSDavid du Colombier 		flag |= Llflag;		/* print only name of file if any match */
1037dd7cddfSDavid du Colombier 	if(flags['L'])
1047dd7cddfSDavid du Colombier 		flag |= LLflag;		/* print only name of file if any non match */
1057dd7cddfSDavid du Colombier 	if(flags['n'])
1067dd7cddfSDavid du Colombier 		flag |= Nflag;		/* count only */
1077dd7cddfSDavid du Colombier 	if(flags['s'])
1087dd7cddfSDavid du Colombier 		flag |= Sflag;		/* status only */
1097dd7cddfSDavid du Colombier 	if(flags['v'])
1107dd7cddfSDavid du Colombier 		flag |= Vflag;		/* inverse match */
1117dd7cddfSDavid du Colombier 
1127dd7cddfSDavid du Colombier 	s = state0;
1137dd7cddfSDavid du Colombier 	lineno = 0;
1147dd7cddfSDavid du Colombier 	count = 0;
1159a747e4fSDavid du Colombier 	eof = 0;
1169a747e4fSDavid du Colombier 	empty = 1;
1179a747e4fSDavid du Colombier 	nl = 0;
1187dd7cddfSDavid du Colombier 	lp = u.buf;
1197dd7cddfSDavid du Colombier 	bol = lp;
1207dd7cddfSDavid du Colombier 
1217dd7cddfSDavid du Colombier loop0:
1227dd7cddfSDavid du Colombier 	n = lp-bol;
1237dd7cddfSDavid du Colombier 	if(n > sizeof(u.pre))
1247dd7cddfSDavid du Colombier 		n = sizeof(u.pre);
1257dd7cddfSDavid du Colombier 	memmove(u.buf-n, bol, n);
1267dd7cddfSDavid du Colombier 	bol = u.buf-n;
1277dd7cddfSDavid du Colombier 	n = read(fid, u.buf, sizeof(u.buf));
1289a747e4fSDavid du Colombier 	/* if file has no final newline, simulate one to emit matches to last line */
1299a747e4fSDavid du Colombier 	if(n > 0) {
1309a747e4fSDavid du Colombier 		empty = 0;
1319a747e4fSDavid du Colombier 		nl = u.buf[n-1]=='\n';
1329a747e4fSDavid du Colombier 	} else {
1339a747e4fSDavid du Colombier 		if(n < 0){
1349a747e4fSDavid du Colombier 			fprint(2, "grep: read error on %s: %r\n", file);
1359a747e4fSDavid du Colombier 			return count != 0;
1369a747e4fSDavid du Colombier 		}
1379a747e4fSDavid du Colombier 		if(!eof && !nl && !empty) {
1389a747e4fSDavid du Colombier 			u.buf[0] = '\n';
1399a747e4fSDavid du Colombier 			n = 1;
1409a747e4fSDavid du Colombier 			eof = 1;
1419a747e4fSDavid du Colombier 		}
1429a747e4fSDavid du Colombier 	}
1437dd7cddfSDavid du Colombier 	if(n <= 0) {
1447dd7cddfSDavid du Colombier 		close(fid);
1457dd7cddfSDavid du Colombier 		if(flag & Cflag) {
1467dd7cddfSDavid du Colombier 			if(flag & Hflag)
1477dd7cddfSDavid du Colombier 				Bprint(&bout, "%s:", file);
1487dd7cddfSDavid du Colombier 			Bprint(&bout, "%ld\n", count);
1497dd7cddfSDavid du Colombier 		}
1507dd7cddfSDavid du Colombier 		if(((flag&Llflag) && count != 0) || ((flag&LLflag) && count == 0))
1517dd7cddfSDavid du Colombier 			Bprint(&bout, "%s\n", file);
1527dd7cddfSDavid du Colombier 		Bflush(&bout);
1537dd7cddfSDavid du Colombier 		return count != 0;
1547dd7cddfSDavid du Colombier 	}
1557dd7cddfSDavid du Colombier 	lp = u.buf;
1567dd7cddfSDavid du Colombier 	elp = lp+n;
1577dd7cddfSDavid du Colombier 	if(flag & Iflag)
1587dd7cddfSDavid du Colombier 		goto loopi;
1597dd7cddfSDavid du Colombier 
1607dd7cddfSDavid du Colombier /*
1617dd7cddfSDavid du Colombier  * normal character loop
1627dd7cddfSDavid du Colombier  */
1637dd7cddfSDavid du Colombier loop:
1647dd7cddfSDavid du Colombier 	c = *lp;
1657dd7cddfSDavid du Colombier 	ns = s->next[c];
1667dd7cddfSDavid du Colombier 	if(ns == 0) {
1677dd7cddfSDavid du Colombier 		increment(s, c);
1687dd7cddfSDavid du Colombier 		goto loop;
1697dd7cddfSDavid du Colombier 	}
1707dd7cddfSDavid du Colombier //	if(flags['2'])
1717dd7cddfSDavid du Colombier //		if(s->match)
1727dd7cddfSDavid du Colombier //			print("%d: %.2x**\n", s, c);
1737dd7cddfSDavid du Colombier //		else
1747dd7cddfSDavid du Colombier //			print("%d: %.2x\n", s, c);
1757dd7cddfSDavid du Colombier 	lp++;
1767dd7cddfSDavid du Colombier 	s = ns;
1777dd7cddfSDavid du Colombier 	if(c == '\n') {
1787dd7cddfSDavid du Colombier 		lineno++;
1797dd7cddfSDavid du Colombier 		if(!!s->match == !(flag&Vflag)) {
1807dd7cddfSDavid du Colombier 			count++;
1817dd7cddfSDavid du Colombier 			if(flag & (Cflag|Sflag|Llflag|LLflag))
1827dd7cddfSDavid du Colombier 				goto cont;
1837dd7cddfSDavid du Colombier 			if(flag & Hflag)
1847dd7cddfSDavid du Colombier 				Bprint(&bout, "%s:", file);
1857dd7cddfSDavid du Colombier 			if(flag & Nflag)
1867dd7cddfSDavid du Colombier 				Bprint(&bout, "%ld: ", lineno);
1879a747e4fSDavid du Colombier 			/* suppress extra newline at EOF unless we are labeling matches with file name */
1889a747e4fSDavid du Colombier 			Bwrite(&bout, bol, lp-bol-(eof && !(flag&Hflag)));
18959cc4ca5SDavid du Colombier 			if(flag & Bflag)
1907dd7cddfSDavid du Colombier 				Bflush(&bout);
1917dd7cddfSDavid du Colombier 		}
19259cc4ca5SDavid du Colombier 		if((lineno & Flshcnt) == 0)
19359cc4ca5SDavid du Colombier 			Bflush(&bout);
1947dd7cddfSDavid du Colombier 	cont:
1957dd7cddfSDavid du Colombier 		bol = lp;
1967dd7cddfSDavid du Colombier 	}
1977dd7cddfSDavid du Colombier 	if(lp != elp)
1987dd7cddfSDavid du Colombier 		goto loop;
1997dd7cddfSDavid du Colombier 	goto loop0;
2007dd7cddfSDavid du Colombier 
2017dd7cddfSDavid du Colombier /*
2027dd7cddfSDavid du Colombier  * character loop for -i flag
2037dd7cddfSDavid du Colombier  * for speed
2047dd7cddfSDavid du Colombier  */
2057dd7cddfSDavid du Colombier loopi:
2067dd7cddfSDavid du Colombier 	c = *lp;
2077dd7cddfSDavid du Colombier 	if(c >= 'A' && c <= 'Z')
2087dd7cddfSDavid du Colombier 		c += 'a'-'A';
2097dd7cddfSDavid du Colombier 	ns = s->next[c];
2107dd7cddfSDavid du Colombier 	if(ns == 0) {
2117dd7cddfSDavid du Colombier 		increment(s, c);
2127dd7cddfSDavid du Colombier 		goto loopi;
2137dd7cddfSDavid du Colombier 	}
2147dd7cddfSDavid du Colombier 	lp++;
2157dd7cddfSDavid du Colombier 	s = ns;
2167dd7cddfSDavid du Colombier 	if(c == '\n') {
2177dd7cddfSDavid du Colombier 		lineno++;
2187dd7cddfSDavid du Colombier 		if(!!s->match == !(flag&Vflag)) {
2197dd7cddfSDavid du Colombier 			count++;
2207dd7cddfSDavid du Colombier 			if(flag & (Cflag|Sflag|Llflag|LLflag))
2217dd7cddfSDavid du Colombier 				goto conti;
2227dd7cddfSDavid du Colombier 			if(flag & Hflag)
2237dd7cddfSDavid du Colombier 				Bprint(&bout, "%s:", file);
2247dd7cddfSDavid du Colombier 			if(flag & Nflag)
2257dd7cddfSDavid du Colombier 				Bprint(&bout, "%ld: ", lineno);
2269a747e4fSDavid du Colombier 			/* suppress extra newline at EOF unless we are labeling matches with file name */
2279a747e4fSDavid du Colombier 			Bwrite(&bout, bol, lp-bol-(eof && !(flag&Hflag)));
22859cc4ca5SDavid du Colombier 			if(flag & Bflag)
2297dd7cddfSDavid du Colombier 				Bflush(&bout);
2307dd7cddfSDavid du Colombier 		}
23159cc4ca5SDavid du Colombier 		if((lineno & Flshcnt) == 0)
23259cc4ca5SDavid du Colombier 			Bflush(&bout);
2337dd7cddfSDavid du Colombier 	conti:
2347dd7cddfSDavid du Colombier 		bol = lp;
2357dd7cddfSDavid du Colombier 	}
2367dd7cddfSDavid du Colombier 	if(lp != elp)
2377dd7cddfSDavid du Colombier 		goto loopi;
2387dd7cddfSDavid du Colombier 	goto loop0;
2397dd7cddfSDavid du Colombier }
2407dd7cddfSDavid du Colombier 
2417dd7cddfSDavid du Colombier State*
initstate(Re * r)2427dd7cddfSDavid du Colombier initstate(Re *r)
2437dd7cddfSDavid du Colombier {
2447dd7cddfSDavid du Colombier 	State *s;
2457dd7cddfSDavid du Colombier 	int i;
2467dd7cddfSDavid du Colombier 
2477dd7cddfSDavid du Colombier 	addcase(r);
2487dd7cddfSDavid du Colombier 	if(flags['1'])
2497dd7cddfSDavid du Colombier 		reprint("r", r);
2507dd7cddfSDavid du Colombier 	nfollow = 0;
2517dd7cddfSDavid du Colombier 	gen++;
2527dd7cddfSDavid du Colombier 	fol1(r, Cbegin);
2537dd7cddfSDavid du Colombier 	follow[nfollow++] = r;
2547dd7cddfSDavid du Colombier 	qsort(follow, nfollow, sizeof(*follow), fcmp);
2557dd7cddfSDavid du Colombier 
2567dd7cddfSDavid du Colombier 	s = sal(nfollow);
2577dd7cddfSDavid du Colombier 	for(i=0; i<nfollow; i++)
2587dd7cddfSDavid du Colombier 		s->re[i] = follow[i];
2597dd7cddfSDavid du Colombier 	return s;
2607dd7cddfSDavid du Colombier }
261