521 lines
10 KiB
C
521 lines
10 KiB
C
/*
|
|
* 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 <stdlib.h>
|
|
#include <ctype.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 CBRC 14
|
|
#define CLET 15
|
|
#define CBACK 18
|
|
|
|
#define STAR 01
|
|
|
|
#define LBSIZE BUFSIZ
|
|
#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 wflag;
|
|
int retcode = 0;
|
|
int circf;
|
|
int blkno;
|
|
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 'i':
|
|
case 'y':
|
|
yflag++;
|
|
continue;
|
|
|
|
case 'w':
|
|
wflag++;
|
|
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(retcode != 0 ? retcode : 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++;
|
|
}
|
|
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 || *lastep==CBRA || *lastep==CKET ||
|
|
*lastep == CBRC || *lastep == CLET)
|
|
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++) == 0)
|
|
goto cerror;
|
|
if(c == '<') {
|
|
*ep++ = CBRC;
|
|
continue;
|
|
}
|
|
if(c == '>') {
|
|
*ep++ = CLET;
|
|
continue;
|
|
}
|
|
if(c == '(') {
|
|
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) {
|
|
perror(file);
|
|
retcode = 2;
|
|
}
|
|
}
|
|
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);
|
|
fflush(stdout);
|
|
}
|
|
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);
|
|
|
|
case CBRC:
|
|
if (lp == expbuf)
|
|
continue;
|
|
#define uletter(c) (isalpha(c) || (c) == '_')
|
|
if (uletter(*lp) || isdigit(*lp))
|
|
if (!uletter(lp[-1]) && !isdigit(lp[-1]))
|
|
continue;
|
|
return (0);
|
|
|
|
case CLET:
|
|
if (!uletter(*lp) && !isdigit(*lp))
|
|
continue;
|
|
return (0);
|
|
|
|
default:
|
|
errexit("grep RE botch\n", (char *)NULL);
|
|
}
|
|
}
|
|
|
|
succeed(f)
|
|
char *f;
|
|
{
|
|
nsucc = 1;
|
|
if (sflag)
|
|
return;
|
|
if (cflag) {
|
|
tln++;
|
|
return;
|
|
}
|
|
if (lflag) {
|
|
printf("%s\n", f);
|
|
fflush(stdout);
|
|
fseek(stdin, 0l, 2);
|
|
return;
|
|
}
|
|
if (nfile > 1 && hflag)
|
|
printf("%s:", f);
|
|
if (bflag)
|
|
printf("%u:", blkno);
|
|
if (nflag)
|
|
printf("%ld:", lnum);
|
|
printf("%s\n", linebuf);
|
|
fflush(stdout);
|
|
}
|
|
|
|
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);
|
|
}
|