home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The C Users' Group Library 1994 August
/
wc-cdrom-cusersgrouplibrary-1994-08.iso
/
vol_100
/
189_01
/
grep.c
< prev
next >
Wrap
Text File
|
1985-08-21
|
12KB
|
449 lines
/* grep.c: attempt to get UNIX pattern-matching on a micro */
/* From DECUS C Tools package on DEC systems - for non-commercial
use only. Modifications by Chuck Allison, April-October 1985:
- handles quoted arguments (for embedded spaces)
- distinguishes case (ignore with -i)
- list filename only option (-l)
*/
#include <stdio.h>
#include <makearg.h>
#define LMAX 512
#define PMAX 256
#define CHAR 1
#define BOL 2
#define EOL 3
#define ANY 4
#define CLASS 5
#define NCLASS 6
#define STAR 7
#define PLUS 8
#define MINUS 9
#define ALPHA 10
#define DIGIT 11
#define NALPHA 12
#define WHITE 13
#define RANGE 14
#define ENDPAT 15
#define TRUE 1
#define FALSE 0
int cflag = FALSE,
fflag = FALSE,
lflag = FALSE,
nflag = FALSE,
vflag = FALSE,
iflag = FALSE;
char *pp,
lbuf[LMAX],
pbuf[PMAX];
extern char *trim_fspec();
main()
{
register char *p;
/* ..this must be first; processes args.. */
makeargv();
if (argc <= 1)
usage("No arguments");
while (--argc && **++argv == '-')
for (p = *argv+1; *p; ++p)
switch(tolower(*p))
{
case 'c':
cflag = !cflag;
break;
case 'f':
fflag = !fflag;
break;
case 'l':
lflag = !lflag;
break;
case 'n':
nflag = !nflag;
break;
case 'v':
vflag = !vflag;
break;
case 'i':
iflag = !iflag;
break;
default:
usage("Unknown flag");
}
if (argc <= 0)
error("no pattern\n");
compile(*argv);
if (argc == 1)
grep("");
else
{
/* ..check file switch.. */
if (argc > 2)
fflag = !fflag;
while (*++argv)
if (freopen(*argv,"r",stdin) != NULL)
grep(*argv);
else
fprintf(stderr,"can't open %s\n",*argv);
}
}
usage(s)
char *s;
{
fprintf(stderr, "grep: %s\n", s);
fprintf(stderr,
"Usage: grep [-cfilnv] pattern [file ...]\n");
exit(1);
}
compile(source)
char *source;
/* ..Compile the pattern into global pbuf[].. */
{
register char *s; /* Source string pointer */
register char *lp; /* Last pattern pointer */
register int c; /* Current character */
int o; /* Temp */
char *spp; /* Save beginning of pattern */
char *cclass(); /* Compile class routine */
s = source;
pp = pbuf;
while (c = *s++)
{
/* ..STAR, PLUS and MINUS are special.. */
if (c == '*' || c == '+' || c == '-')
{
if ( pp == pbuf ||
(o=pp[-1]) == BOL ||
o == EOL ||
o == STAR ||
o == PLUS ||
o == MINUS
)
badpat("Illegal occurrance op.", source, s);
store(ENDPAT);
store(ENDPAT);
spp = pp; /* Save pattern end */
while (--pp > lp) /* Move pattern down */
*pp = pp[-1]; /* one byte */
*pp = (c == '*') ? STAR :
(c == '-') ? MINUS : PLUS;
pp = spp; /* Restore pattern end */
continue;
}
/* ..All the rest.. */
lp = pp; /* ..Remember start.. */
switch(c)
{
case '^':
store(BOL);
break;
case '$':
store(EOL);
break;
case '.':
store(ANY);
break;
case '[':
s = cclass(source, s);
break;
case ':':
if (*s)
{
c = *s++;
switch(tolower(c))
{
case 'a':
store(ALPHA);
break;
case 'd':
store(DIGIT);
break;
case 'n':
store(NALPHA);
break;
case ' ':
store(WHITE);
break;
default:
badpat("Unknown : type", source, s);
}
break;
}
else
badpat("No : type", source, s);
case '\\':
if (*s)
c = *s++;
default:
store(CHAR);
store(iflag ? tolower(c) : c);
}
}
store(ENDPAT);
store('\0');
}
char *cclass(source, src)
char *source; /* ..Pattern start.. */
char *src; /* ..Class start.. */
/* ..Compile a class (within []).. */
{
register char *s; /* Source pointer */
register char *cp; /* Pattern start */
register int c; /* Current character */
int o; /* ..Temp.. */
s = src;
o = CLASS;
if (*s == '^')
{
++s;
o = NCLASS;
}
store(o);
cp = pp;
store(0); /* ..Byte count.. */
while ((c = *s++) && c!=']')
{
if (c == '\\')
{ /* ..Store quoted char.. */
if ((c = *s++) == '\0') /* ..Gotta get something.. */
badpat("Class terminates badly", source, s);
else
store(iflag ? tolower(c) : c);
}
else if (c == '-' && (pp - cp) > 1 && *s != ']' && *s != '\0')
{
c = pp[-1]; /* Range start */
pp[-1] = RANGE; /* Range signal */
store(c); /* Re-store start */
c = *s++; /* Get end char and*/
store(iflag ? tolower(c) : c);
}
else
store(iflag ? tolower(c) : c);
}
if (c != ']')
badpat("Unterminated class", source, s);
if ((c = (pp - cp)) >= 256)
badpat("Class too large", source, s);
if (c == 0)
badpat("Empty class", source, s);
*cp = c;
return(s);
}
store(op)
{
if (pp >= &pbuf[PMAX])
error("Pattern too complex\n");
*pp++ = op;
}
badpat(message, source)
char *message, /* ..Error message.. */
*source; /* ..Pattern start.. */
{
fprintf(stderr, "grep: %s, pattern is\"%s\"\n", message, source);
exit(1);
}
grep(fn)
char *fn; /* File name (for -f option) */
{
register int lno, count, m;
lno = 0;
count = 0;
while (fgets(lbuf, LMAX, stdin))
{
++lno;
m = match();
if ((m && !vflag) || (!m && vflag))
{
++count;
if (!cflag)
{
if (lflag)
{
puts(fn);
return;
}
if (fflag && fn)
{
fprintf(stdout,"\n\nFile: %s\n\n",fn);
fn = 0;
}
if (nflag)
printf("%5d: ", lno);
fputs(lbuf,stdout);
}
}
}
if (cflag)
{
if (fflag && fn)
printf("%-40.40s: ",trim_fspec(fn,40));
printf("%6d\n", count);
}
}
match()
/* ..Match the current line (in lbuf[]), return 1 if it does.. */
{
register char *l; /* ..Line pointer.. */
char *pmatch();
for (l = lbuf; *l; l++)
if (pmatch(l, pbuf))
return(1);
return(0);
}
char *pmatch(line, pattern)
char *line, /* ..(partial) line to match.. */
*pattern; /* ..(partial) pattern to match.. */
{
register char *l; /* ..Current line pointer.. */
register char *p; /* ..Current pattern pointer.. */
register char c; /* ..Current character.. */
register char d; /* ..Temporary character.. */
char *e; /* ..End for STAR and PLUS match.. */
int op; /* ..Pattern operation.. */
int n; /* ..Class counter.. */
char *are; /* ..Start of STAR match.. */
l = line;
p = pattern;
while ((op = *p++) != ENDPAT)
{
switch(op)
{
case CHAR:
c = iflag ? tolower(*l++) : *l++;
d = iflag ? tolower(*p++) : *p++;
if (c != d)
return(0);
break;
case BOL:
if (l != lbuf)
return(0);
break;
case EOL:
if (*l != '\0' && *l != '\n')
return(0);
break;
case ANY:
if (*l++ == '\0')
return(0);
break;
case DIGIT:
if (!isdigit(c = *l++))
return(0);
break;
case ALPHA:
if (!isalpha(c = *l++))
return(0);
break;
case NALPHA:
if (!isalnum(c = *l++))
return(0);
break;
case WHITE:
if (!isspace(c = *l++))
return(0);
break;
case CLASS:
case NCLASS:
c = iflag ? tolower(*l++) : *l++;
n = *p++ & 0x00ff;
do
{
if (*p == RANGE)
{
p += 3;
n -= 2;
if (c >= p[-2] && c <= p[-1])
break;
}
else if (c == *p++)
break;
} while (--n > 1);
if ((op == CLASS) == (n <= 1))
return(0);
if (op == CLASS)
p += n - 2;
break;
case MINUS:
e = pmatch(l, p); /* ..Look for a match.. */
while (*p++ != ENDPAT); /* ..Skip over pattern.. */
if (e) /* ..Got a match?.. */
l = e; /* ..Yes, update string.. */
break; /* ..Always succeeds.. */
case PLUS: /* ..One or more.. */
if ((l = pmatch(l, p)) == 0)
return(0); /* ..Gotta have a match.. */
case STAR: /* ..Zero or more.. */
are = l; /* ..Remember line start.. */
while (*l && (e = pmatch(l, p)))
l = e; /* ..Get longest match.. */
while (*p++ != ENDPAT); /* ..Skip over pattern.. */
while (l >= are)
{
/* ..Try to match rest.. */
if (e = pmatch(l, p))
return(e);
--l; /* ..Nope, try earlier.. */
}
return(0); /* ..Nothing else worked.. */
default:
fprintf(stderr,"Bad op code %d\n", op);
error("Cannot happen -- match\n");
}
}
return(l);
}
error(s)
char *s;
{
fputs(s,stderr);
exit(1);
}
>= are)
{
/* ..Try to match rest.. */
if (e = pmatch(l, p))