BSD 2 development
[unix-history] / src / grep.c
/* Copyright (c) 1979 Regents of the University of California */
#include <stdio.h>
/*
* grep -- print lines matching (or not matching) a pattern
*/
#define CCHR 2
#define CDOT 4
#define CCL 6
#define NCCL 8
#define CDOL 10
#define CEOF 11
#define CBRC 14
#define CLET 15
#define STAR 01
#define LBSIZE 256
#define ESIZE 256
char expbuf[ESIZE];
long lnum;
char linebuf[LBSIZE+1];
int bflag;
int nflag;
int cflag;
int vflag;
int nfile;
int iflag;
int lflag;
int wflag;
int circf;
int blkno;
char ibuf[512];
long tln;
main(argc, argv)
char **argv;
{
char obuf[BUFSIZ];
setbuf(stdout, obuf);
while (--argc > 0 && (++argv)[0][0]=='-') {
char *cp = argv[0] + 1;
while (*cp) switch (*cp++) {
case 'v':
vflag++;
continue;
case 'b':
bflag++;
continue;
case 'i':
iflag++;
continue;
case 'l':
lflag++;
case 'c':
cflag++;
continue;
case 'w':
wflag++;
continue;
case 'n':
nflag++;
continue;
default:
fprintf(stderr, "Unknown flag\n");
continue;
}
}
if (argc<=0)
exit(2);
compile(*argv);
nfile = --argc;
if (argc<=0)
execute(0);
else while (--argc >= 0) {
argv++;
execute(*argv);
}
exit(0);
}
compile(astr)
char *astr;
{
register c;
register char *ep, *sp;
char *lastep;
int cclcnt;
ep = expbuf;
sp = astr;
if (*sp == '^') {
circf++;
sp++;
}
if (wflag)
*ep++ = CBRC;
for (;;) {
if (ep >= &expbuf[ESIZE])
goto cerror;
if ((c = *sp++) != '*')
lastep = ep;
switch (c) {
case '\0':
if (wflag)
*ep++ = CLET;
*ep++ = CEOF;
return;
case '.':
*ep++ = CDOT;
continue;
case '*':
if (lastep==0)
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 {
*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;
if (c == '<') {
*ep++ = CBRC;
continue;
}
if (c == '>') {
*ep++ = CLET;
continue;
}
defchar:
default:
*ep++ = CCHR;
*ep++ = c;
}
}
cerror:
fprintf(stderr, "RE error\n");
}
same(a, b)
register int a, b;
{
return (a == b || iflag && (a ^ b) == ' ' && letter(a) == letter(b));
}
letter(c)
register int c;
{
if (c >= 'a' && c <= 'z')
return (c);
if (c >= 'A' && c <= 'Z')
return (c + 'a' - 'A');
return (0);
}
execute(file)
{
register char *p1, *p2;
register c;
int f;
char *ebp, *cbp;
if (file) {
if ((f = open(file, 0)) < 0) {
fprintf(stderr, "Can't open %s\n", file);
}
} else
f = 0;
ebp = ibuf;
cbp = ibuf;
lnum = 0;
tln = 0;
blkno = -1;
for (;;) {
lnum++;
if((lnum&0377) == 0)
fflush(stdout);
p1 = linebuf;
p2 = cbp;
for (;;) {
if (p2 >= ebp) {
if ((c = read(f, ibuf, 512)) <= 0) {
close(f);
if (cflag) {
if (lflag) {
if (tln)
printf("%s\n", file);
} else {
if (nfile > 1)
printf("%s:", file);
printf("%ld\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 && (!iflag || (c ^ *p1) != ' '
|| letter(c) != letter(*p1)))
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 (!same(*ep, *lp))
return (0);
ep++, lp++;
continue;
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 (same(*lp, *ep))
lp++;
lp++;
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);
case CBRC:
if (lp == expbuf)
continue;
#define uletter(c) (letter(c) || c == '_')
if (uletter(*lp) && !uletter(lp[-1]) && !digit(lp[-1]))
continue;
return (0);
case CLET:
if (!uletter(*lp) && !digit(*lp))
continue;
return (0);
default:
fprintf(stderr, "RE botch\n");
}
}
cclass(aset, ac, af)
{
register char *set, c;
register n;
set = aset;
if ((c = ac) == 0)
return(0);
n = *set++;
while (--n)
if (n > 2 && set[1] == '-') {
if (c >= (set[0] & 0177) && c <= (set[2] & 0177))
return (af);
set =+ 3;
n -= 2;
} else
if ((*set++ & 0177) == c)
return(af);
return(!af);
}
succeed(f)
{
if (cflag) {
tln++;
return;
}
if (nfile > 1)
printf("%s:", f);
if (bflag)
printf("%l:", blkno);
if (nflag)
printf("%ld:", lnum);
printf("%s\n", linebuf);
}
digit(c)
char c;
{
return (c>='0' && c<='9');
}