+/*
+ * grep -- print lines matching (or not matching) a pattern
+ *
+ * status returns:
+ * 0 - ok, and some matches
+ * 1 - ok, but no matches
+ * 2 - some error
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/param.h>
+
+#define CBRA 1
+#define CCHR 2
+#define CDOT 4
+#define CCL 6
+#define NCCL 8
+#define CDOL 10
+#define CEOF 11
+#define CKET 12
+#define CBACK 18
+
+#define STAR 01
+
+#define LBSIZE 512
+#define ESIZE 256
+#define NBRA 9
+
+char expbuf[ESIZE];
+long lnum;
+char linebuf[LBSIZE+1];
+char ybuf[ESIZE];
+int bflag;
+int lflag;
+int nflag;
+int cflag;
+int vflag;
+int nfile;
+int hflag = 1;
+int sflag;
+int yflag;
+int circf;
+long tln;
+int nsucc;
+char *braslist[NBRA];
+char *braelist[NBRA];
+char bittab[] = {
+ 1,
+ 2,
+ 4,
+ 8,
+ 16,
+ 32,
+ 64,
+ 128
+};
+
+main(argc, argv)
+char **argv;
+{
+ while (--argc > 0 && (++argv)[0][0]=='-')
+ switch (argv[0][1]) {
+
+ case 'y':
+ yflag++;
+ continue;
+
+ case 'h':
+ hflag = 0;
+ continue;
+
+ case 's':
+ sflag++;
+ continue;
+
+ case 'v':
+ vflag++;
+ continue;
+
+ case 'b':
+ bflag++;
+ continue;
+
+ case 'l':
+ lflag++;
+ continue;
+
+ case 'c':
+ cflag++;
+ continue;
+
+ case 'n':
+ nflag++;
+ continue;
+
+ case 'e':
+ --argc;
+ ++argv;
+ goto out;
+
+ default:
+ errexit("grep: unknown flag\n", (char *)NULL);
+ continue;
+ }
+out:
+ if (argc<=0)
+ exit(2);
+ if (yflag) {
+ register char *p, *s;
+ for (s = ybuf, p = *argv; *p; ) {
+ if (*p == '\\') {
+ *s++ = *p++;
+ if (*p)
+ *s++ = *p++;
+ } else if (*p == '[') {
+ while (*p != '\0' && *p != ']')
+ *s++ = *p++;
+ } else if (islower(*p)) {
+ *s++ = '[';
+ *s++ = toupper(*p);
+ *s++ = *p++;
+ *s++ = ']';
+ } else
+ *s++ = *p++;
+ if (s >= ybuf+ESIZE-5)
+ errexit("grep: argument too long\n", (char *)NULL);
+ }
+ *s = '\0';
+ *argv = ybuf;
+ }
+ compile(*argv);
+ nfile = --argc;
+ if (argc<=0) {
+ if (lflag)
+ exit(1);
+ execute((char *)NULL);
+ } else while (--argc >= 0) {
+ argv++;
+ execute(*argv);
+ }
+ exit(nsucc == 0);
+}
+
+compile(astr)
+char *astr;
+{
+ register c;
+ register char *ep, *sp;
+ char *cstart;
+ char *lastep;
+ int cclcnt;
+ char bracket[NBRA], *bracketp;
+ int closed;
+ char numbra;
+ char neg;
+
+ ep = expbuf;
+ sp = astr;
+ lastep = 0;
+ bracketp = bracket;
+ closed = numbra = 0;
+ if (*sp == '^') {
+ circf++;
+ sp++;
+ }
+ for (;;) {
+ if (ep >= &expbuf[ESIZE])
+ goto cerror;
+ if ((c = *sp++) != '*')
+ lastep = ep;
+ switch (c) {
+
+ case '\0':
+ *ep++ = CEOF;
+ return;
+
+ case '.':
+ *ep++ = CDOT;
+ continue;
+
+ case '*':
+ if (lastep==0 || *lastep==CBRA || *lastep==CKET)
+ goto defchar;
+ *lastep |= STAR;
+ continue;
+
+ case '$':
+ if (*sp != '\0')
+ goto defchar;
+ *ep++ = CDOL;
+ continue;
+
+ case '[':
+ if(&ep[17] >= &expbuf[ESIZE])
+ goto cerror;
+ *ep++ = CCL;
+ neg = 0;
+ if((c = *sp++) == '^') {
+ neg = 1;
+ c = *sp++;
+ }
+ cstart = sp;
+ do {
+ if (c=='\0')
+ goto cerror;
+ if (c=='-' && sp>cstart && *sp!=']') {
+ for (c = sp[-2]; c<*sp; c++)
+ ep[c>>3] |= bittab[c&07];
+ sp++;
+ }
+ ep[c>>3] |= bittab[c&07];
+ } while((c = *sp++) != ']');
+ if(neg) {
+ for(cclcnt = 0; cclcnt < 16; cclcnt++)
+ ep[cclcnt] ^= -1;
+ ep[0] &= 0376;
+ }
+
+ ep += 16;
+
+ continue;
+
+ case '\\':
+ if((c = *sp++) == '(') {
+ if(numbra >= NBRA) {
+ goto cerror;
+ }
+ *bracketp++ = numbra;
+ *ep++ = CBRA;
+ *ep++ = numbra++;
+ continue;
+ }
+ if(c == ')') {
+ if(bracketp <= bracket) {
+ goto cerror;
+ }
+ *ep++ = CKET;
+ *ep++ = *--bracketp;
+ closed++;
+ continue;
+ }
+
+ if(c >= '1' && c <= '9') {
+ if((c -= '1') >= closed)
+ goto cerror;
+ *ep++ = CBACK;
+ *ep++ = c;
+ continue;
+ }
+
+ defchar:
+ default:
+ *ep++ = CCHR;
+ *ep++ = c;
+ }
+ }
+ cerror:
+ errexit("grep: RE error\n", (char *)NULL);
+}
+
+execute(file)
+char *file;
+{
+ register char *p1, *p2;
+ register c;
+
+ if (file) {
+ if (freopen(file, "r", stdin) == NULL)
+ errexit("grep: can't open %s\n", file);
+ }
+ lnum = 0;
+ tln = 0;
+ for (;;) {
+ lnum++;
+ p1 = linebuf;
+ while ((c = getchar()) != '\n') {
+ if (c == EOF) {
+ if (cflag) {
+ if (nfile>1)
+ printf("%s:", file);
+ printf("%D\n", tln);
+ }
+ return;
+ }
+ *p1++ = c;
+ if (p1 >= &linebuf[LBSIZE-1])
+ break;
+ }
+ *p1++ = '\0';
+ p1 = linebuf;
+ p2 = expbuf;
+ if (circf) {
+ if (advance(p1, p2))
+ goto found;
+ goto nfound;
+ }
+ /* fast check for first character */
+ if (*p2==CCHR) {
+ c = p2[1];
+ do {
+ if (*p1!=c)
+ continue;
+ if (advance(p1, p2))
+ goto found;
+ } while (*p1++);
+ goto nfound;
+ }
+ /* regular algorithm */
+ do {
+ if (advance(p1, p2))
+ goto found;
+ } while (*p1++);
+ nfound:
+ if (vflag)
+ succeed(file);
+ continue;
+ found:
+ if (vflag==0)
+ succeed(file);
+ }
+}
+
+advance(lp, ep)
+register char *lp, *ep;
+{
+ register char *curlp;
+ char c;
+ char *bbeg;
+ int ct;
+
+ for (;;) switch (*ep++) {
+
+ case CCHR:
+ if (*ep++ == *lp++)
+ continue;
+ return(0);
+
+ case CDOT:
+ if (*lp++)
+ continue;
+ return(0);
+
+ case CDOL:
+ if (*lp==0)
+ continue;
+ return(0);
+
+ case CEOF:
+ return(1);
+
+ case CCL:
+ c = *lp++ & 0177;
+ if(ep[c>>3] & bittab[c & 07]) {
+ ep += 16;
+ continue;
+ }
+ return(0);
+ case CBRA:
+ braslist[*ep++] = lp;
+ continue;
+
+ case CKET:
+ braelist[*ep++] = lp;
+ continue;
+
+ case CBACK:
+ bbeg = braslist[*ep];
+ if (braelist[*ep]==0)
+ return(0);
+ ct = braelist[*ep++] - bbeg;
+ if(ecmp(bbeg, lp, ct)) {
+ lp += ct;
+ continue;
+ }
+ return(0);
+
+ case CBACK|STAR:
+ bbeg = braslist[*ep];
+ if (braelist[*ep]==0)
+ return(0);
+ ct = braelist[*ep++] - bbeg;
+ curlp = lp;
+ while(ecmp(bbeg, lp, ct))
+ lp += ct;
+ while(lp >= curlp) {
+ if(advance(lp, ep)) return(1);
+ lp -= ct;
+ }
+ return(0);
+
+
+ case CDOT|STAR:
+ curlp = lp;
+ while (*lp++);
+ goto star;
+
+ case CCHR|STAR:
+ curlp = lp;
+ while (*lp++ == *ep);
+ ep++;
+ goto star;
+
+ case CCL|STAR:
+ curlp = lp;
+ do {
+ c = *lp++ & 0177;
+ } while(ep[c>>3] & bittab[c & 07]);
+ ep += 16;
+ goto star;
+
+ star:
+ if(--lp == curlp) {
+ continue;
+ }
+
+ if(*ep == CCHR) {
+ c = ep[1];
+ do {
+ if(*lp != c)
+ continue;
+ if(advance(lp, ep))
+ return(1);
+ } while(lp-- > curlp);
+ return(0);
+ }
+
+ do {
+ if (advance(lp, ep))
+ return(1);
+ } while (lp-- > curlp);
+ return(0);
+
+ default:
+ errexit("grep RE botch\n", (char *)NULL);
+ }
+}
+
+succeed(f)
+char *f;
+{
+ long ftell();
+ nsucc = 1;
+ if (sflag)
+ return;
+ if (cflag) {
+ tln++;
+ return;
+ }
+ if (lflag) {
+ printf("%s\n", f);
+ fseek(stdin, 0l, 2);
+ return;
+ }
+ if (nfile > 1 && hflag)
+ printf("%s:", f);
+ if (bflag)
+ printf("%ld:", (ftell(stdin)-1)/BSIZE);
+ if (nflag)
+ printf("%ld:", lnum);
+ printf("%s\n", linebuf);
+}
+
+ecmp(a, b, count)
+char *a, *b;
+{
+ register cc = count;
+ while(cc--)
+ if(*a++ != *b++) return(0);
+ return(1);
+}
+
+errexit(s, f)
+char *s, *f;
+{
+ fprintf(stderr, s, f);
+ exit(2);
+}