9base

revived minimalist port of Plan 9 userland to Unix
git clone git://git.suckless.org/9base
Log | Files | Refs | README | LICENSE

main.c (4832B)


      1 #define	EXTERN
      2 #include	"grep.h"
      3 
      4 char *validflags = "bchiLlnsv";
      5 void
      6 usage(void)
      7 {
      8 	fprint(2, "usage: grep [-%s] [-f file] [-e expr] [file ...]\n", validflags);
      9 	exits("usage");
     10 }
     11 
     12 void
     13 main(int argc, char *argv[])
     14 {
     15 	int i, status;
     16 
     17 	ARGBEGIN {
     18 	default:
     19 		if(utfrune(validflags, ARGC()) == nil)
     20 			usage();
     21 		flags[ARGC()]++;
     22 		break;
     23 
     24 	case 'q':	/* gnu grep -q means plan 9 grep -s */
     25 		flags['s']++;
     26 		break;
     27 
     28 	case 'E':	/* ignore, turns gnu grep into egrep */
     29 		break;
     30 
     31 	case 'e':
     32 		flags['e']++;
     33 		lineno = 0;
     34 		str2top(ARGF());
     35 		break;
     36 
     37 	case 'f':
     38 		flags['f']++;
     39 		filename = ARGF();
     40 		rein = Bopen(filename, OREAD);
     41 		if(rein == 0) {
     42 			fprint(2, "grep: can't open %s: %r\n", filename);
     43 			exits("open");
     44 		}
     45 		lineno = 1;
     46 		str2top(filename);
     47 		break;
     48 	} ARGEND
     49 
     50 	if(flags['f'] == 0 && flags['e'] == 0) {
     51 		if(argc <= 0)
     52 			usage();
     53 		str2top(argv[0]);
     54 		argc--;
     55 		argv++;
     56 	}
     57 
     58 	follow = mal(maxfollow*sizeof(*follow));
     59 	state0 = initstate(topre.beg);
     60 
     61 	Binit(&bout, 1, OWRITE);
     62 	switch(argc) {
     63 	case 0:
     64 		status = search(0, 0);
     65 		break;
     66 	case 1:
     67 		status = search(argv[0], 0);
     68 		break;
     69 	default:
     70 		status = 0;
     71 		for(i=0; i<argc; i++)
     72 			status |= search(argv[i], Hflag);
     73 		break;
     74 	}
     75 	if(status)
     76 		exits(0);
     77 	exits("no matches");
     78 }
     79 
     80 int
     81 search(char *file, int flag)
     82 {
     83 	State *s, *ns;
     84 	int c, fid, eof, nl, empty;
     85 	long count, lineno, n;
     86 	uchar *elp, *lp, *bol;
     87 
     88 	if(file == 0) {
     89 		file = "stdin";
     90 		fid = 0;
     91 		flag |= Bflag;
     92 	} else
     93 		fid = open(file, OREAD);
     94 
     95 	if(fid < 0) {
     96 		fprint(2, "grep: can't open %s: %r\n", file);
     97 		return 0;
     98 	}
     99 
    100 	if(flags['b'])
    101 		flag ^= Bflag;		/* dont buffer output */
    102 	if(flags['c'])
    103 		flag |= Cflag;		/* count */
    104 	if(flags['h'])
    105 		flag &= ~Hflag;		/* do not print file name in output */
    106 	if(flags['i'])
    107 		flag |= Iflag;		/* fold upper-lower */
    108 	if(flags['l'])
    109 		flag |= Llflag;		/* print only name of file if any match */
    110 	if(flags['L'])
    111 		flag |= LLflag;		/* print only name of file if any non match */
    112 	if(flags['n'])
    113 		flag |= Nflag;		/* count only */
    114 	if(flags['s'])
    115 		flag |= Sflag;		/* status only */
    116 	if(flags['v'])
    117 		flag |= Vflag;		/* inverse match */
    118 
    119 	s = state0;
    120 	lineno = 0;
    121 	count = 0;
    122 	eof = 0;
    123 	empty = 1;
    124 	nl = 0;
    125 	lp = u.u.buf;
    126 	bol = lp;
    127 
    128 loop0:
    129 	n = lp-bol;
    130 	if(n > sizeof(u.u.pre))
    131 		n = sizeof(u.u.pre);
    132 	memmove(u.u.buf-n, bol, n);
    133 	bol = u.u.buf-n;
    134 	n = read(fid, u.u.buf, sizeof(u.u.buf));
    135 	/* if file has no final newline, simulate one to emit matches to last line */
    136 	if(n > 0) {
    137 		empty = 0;
    138 		nl = u.u.buf[n-1]=='\n';
    139 	} else {
    140 		if(n < 0){
    141 			fprint(2, "grep: read error on %s: %r\n", file);
    142 			return count != 0;
    143 		}
    144 		if(!eof && !nl && !empty) {
    145 			u.u.buf[0] = '\n';
    146 			n = 1;
    147 			eof = 1;
    148 		}
    149 	}
    150 	if(n <= 0) {
    151 		close(fid);
    152 		if(flag & Cflag) {
    153 			if(flag & Hflag)
    154 				Bprint(&bout, "%s:", file);
    155 			Bprint(&bout, "%ld\n", count);
    156 		}
    157 		if(((flag&Llflag) && count != 0) || ((flag&LLflag) && count == 0))
    158 			Bprint(&bout, "%s\n", file);
    159 		Bflush(&bout);
    160 		return count != 0;
    161 	}
    162 	lp = u.u.buf;
    163 	elp = lp+n;
    164 	if(flag & Iflag)
    165 		goto loopi;
    166 
    167 /*
    168  * normal character loop
    169  */
    170 loop:
    171 	c = *lp;
    172 	ns = s->next[c];
    173 	if(ns == 0) {
    174 		increment(s, c);
    175 		goto loop;
    176 	}
    177 /*	if(flags['2']) */
    178 /*		if(s->match) */
    179 /*			print("%d: %.2x**\n", s, c); */
    180 /*		else */
    181 /*			print("%d: %.2x\n", s, c); */
    182 	lp++;
    183 	s = ns;
    184 	if(c == '\n') {
    185 		lineno++;
    186 		if(!!s->match == !(flag&Vflag)) {
    187 			count++;
    188 			if(flag & (Cflag|Sflag|Llflag|LLflag))
    189 				goto cont;
    190 			if(flag & Hflag)
    191 				Bprint(&bout, "%s:", file);
    192 			if(flag & Nflag)
    193 				Bprint(&bout, "%ld: ", lineno);
    194 			/* suppress extra newline at EOF unless we are labeling matches with file name */
    195 			Bwrite(&bout, bol, lp-bol-(eof && !(flag&Hflag)));
    196 			if(flag & Bflag)
    197 				Bflush(&bout);
    198 		}
    199 		if((lineno & Flshcnt) == 0)
    200 			Bflush(&bout);
    201 	cont:
    202 		bol = lp;
    203 	}
    204 	if(lp != elp)
    205 		goto loop;
    206 	goto loop0;
    207 
    208 /*
    209  * character loop for -i flag
    210  * for speed
    211  */
    212 loopi:
    213 	c = *lp;
    214 	if(c >= 'A' && c <= 'Z')
    215 		c += 'a'-'A';
    216 	ns = s->next[c];
    217 	if(ns == 0) {
    218 		increment(s, c);
    219 		goto loopi;
    220 	}
    221 	lp++;
    222 	s = ns;
    223 	if(c == '\n') {
    224 		lineno++;
    225 		if(!!s->match == !(flag&Vflag)) {
    226 			count++;
    227 			if(flag & (Cflag|Sflag|Llflag|LLflag))
    228 				goto conti;
    229 			if(flag & Hflag)
    230 				Bprint(&bout, "%s:", file);
    231 			if(flag & Nflag)
    232 				Bprint(&bout, "%ld: ", lineno);
    233 			/* suppress extra newline at EOF unless we are labeling matches with file name */
    234 			Bwrite(&bout, bol, lp-bol-(eof && !(flag&Hflag)));
    235 			if(flag & Bflag)
    236 				Bflush(&bout);
    237 		}
    238 		if((lineno & Flshcnt) == 0)
    239 			Bflush(&bout);
    240 	conti:
    241 		bol = lp;
    242 	}
    243 	if(lp != elp)
    244 		goto loopi;
    245 	goto loop0;
    246 }
    247 
    248 State*
    249 initstate(Re *r)
    250 {
    251 	State *s;
    252 	int i;
    253 
    254 	addcase(r);
    255 	if(flags['1'])
    256 		reprint("r", r);
    257 	nfollow = 0;
    258 	gen++;
    259 	fol1(r, Cbegin);
    260 	follow[nfollow++] = r;
    261 	qsort(follow, nfollow, sizeof(*follow), fcmp);
    262 
    263 	s = sal(nfollow);
    264 	for(i=0; i<nfollow; i++)
    265 		s->re[i] = follow[i];
    266 	return s;
    267 }