/* * grep -- print lines matching (or not matching) a pattern * */ /* * Changed to prevent grep exiting when it can't open a file * Also told about longs and other stuff to do with the new 'C' * compiler. * B.Palmer Apr 79 */ /* * Added '-' option to classes, as per em ([a-d] == [abcd]), escapes * are also handled. ([ab\-z] == [abz] + [-]) * Fixed so grep would not bomb on '*' as the pattern. * * Michael Rourke May 79 */ /* * Exit status returned (as per CSU): * * 0 : matches, no errors * 1 : no matches * 2 : file open error * 3 : RE syntax error * 4 : Incorrect usage * 5 : Program error (`RE botch') */ #define CCHR 2 #define CDOT 4 #define CCL 6 #define NCCL 8 #define CDOL 10 #define CEOF 11 #define STAR 01 #define LBSIZE 256 #define ESIZE 256 char ibuf[512]; char expbuf[ESIZE]; char linebuf[LBSIZE+1]; int bflag; int nflag; int cflag; int vflag; int nfile; /* number of files */ int circf; /* tie expression to start of line */ int blkno; /* block nr - `-b' option */ int matches; /* at least one match */ int errs; /* file open error */ unsigned lnum; /* line number */ unsigned tln; /* number of matches - `-c' option */ main(argc, argv) char **argv; { extern fout; fout = dup(1); while (--argc > 0 && (++argv)[0][0] == '-') switch(argv[0][1]) { case 'v': /* find lines NOT matching */ vflag++; continue; case 'b': /* print out block nrs - god knows why */ bflag++; continue; case 'c': /* count of lines only */ cflag++; continue; case 'n': /* print out line number too */ nflag++; continue; default: goto usage; } if (argc <= 0) { usage: prints(2, "Usage: grep [-b][-c][-n][-v] reg-exp [files]\n"); exit(4); } compile(*argv); nfile = --argc; if (argc <= 0) { execute(0); flush(); } else while (--argc >= 0) { argv++; execute(*argv); flush(); } exit(errs ? 2 : matches ? 0 : 1); } compile(astr) char *astr; { register c; register char *ep, *sp; char *lastep 0; int cclcnt; ep = expbuf; sp = astr; 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 = ep; goto defchar; } *lastep =| STAR; continue; case '$': if (*sp != '\0') goto defchar; *ep++ = CDOL; continue; case '[': *ep++ = CCL; *ep++ = 0; cclcnt = 1; if ((c = *sp++) == '^') { c = *sp++; ep[-2] = NCCL; } do { if (c == '-' && cclcnt > 1) { if ((c = *sp++) == '\0' || c <= ep[-1] || ep >= &expbuf[ESIZE - 2]) goto cerror; *ep++ = '\0'; *ep++ = c; cclcnt =+ 2; continue; } else if (c == '\\') c = *sp++; *ep++ = c; cclcnt++; if (c == '\0' || ep >= &expbuf[ESIZE]) goto cerror; } while ((c = *sp++) != ']'); lastep[1] = cclcnt; continue; case '\\': if ((c = *sp++) == '\0') goto cerror; defchar: default: *ep++ = CCHR; *ep++ = c; } } cerror: prints(2, "Regular expression syntax error\n"); exit(3); } execute(file) { register char *p1, *p2; register c; int f; char *ebp, *cbp; if (file) { if ((f = open(file, 0)) < 0) { flush(); perror(file); errs = 1; return; } } else f = 0; ebp = ibuf; cbp = ibuf; lnum = 0; tln = 0; blkno = -1; for (;;) { lnum++; p1 = linebuf; p2 = cbp; for (;;) { if (p2 >= ebp) { if ((c = read(f, ibuf, 512)) <= 0) { close(f); if (cflag) { if (nfile > 1) printf("%s:", file); printf("%u\n",tln); } return; } blkno++; p2 = ibuf; ebp = ibuf+c; } if ((c = *p2++) == '\n') break; if (c) if (p1 < &linebuf[LBSIZE-1]) *p1++ = c; } *p1++ = 0; cbp = p2; 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(alp, aep) { register char *lp, *ep, *curlp; char *nextep; lp = alp; ep = aep; 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: if (cclass(ep, *lp++, 1)) { ep =+ *ep; continue; } return(0); case NCCL: if (cclass(ep, *lp++, 0)) { ep =+ *ep; continue; } 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: case NCCL|STAR: curlp = lp; while (cclass(ep, *lp++, ep[-1] == (CCL|STAR))); ep =+ *ep; goto star; star: do { lp--; if (advance(lp, ep)) return(1); } while (lp > curlp); return(0); default: prints(2, "RE botch - seek help!\n"); exit(5); } } cclass(aset, ac, af) { register char *set, c; register n; set = aset; if ((c = ac) == 0) return(0); n = *set++; while (--n) if (*set == '\0') { if (c > set[-1] && c <= set[1]) return af; set =+ 2; n--; } else if (*set++ == c) return af; return(!af); } succeed(f) { matches = 1; if (cflag) { tln++; return; } if (nfile > 1) printf("%s:", f); if (bflag) printf("%u:", blkno); if (nflag) printf("%u:", lnum); printf("%s\n", linebuf); }