/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* Copyright (c) 1980 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdio.h>
#include <ctype.h>
/*
* fgrep -- print all lines containing any of a set of keywords
*
* status returns:
* 0 - ok, and some matches
* 1 - ok, but no matches
* 2 - some error
*/
#define MAXSIZ 700
#define QSIZE 400
struct words {
char inp;
char out;
struct words *nst;
struct words *link;
struct words *fail;
}
*www, *smax, *q;
char buf[2*BUFSIZ];
int nsucc;
int need;
char *instr;
int inct;
int rflag;
int xargc;
char **xargv;
int numwords;
int nfound;
static int flag = 0;
extern void err();
extern void *zalloc();
static void cfail(void);
static void cgotofn(void);
static void execute(void);
static char gch(void);
static int new(struct words *x);
static void overflo(void);
int
fgrep(int argc, char **argv)
{
nsucc = need = inct = rflag = numwords = nfound = 0;
instr = 0;
flag = 0;
if (www == 0)
www = (struct words *)zalloc(MAXSIZ, sizeof (*www));
if (www == NULL)
err(gettext("Can't get space for machines"), 0);
for (q = www; q < www+MAXSIZ; q++) {
q->inp = 0; q->out = 0; q->nst = 0; q->link = 0; q->fail = 0;
}
xargc = argc-1;
xargv = argv+1;
while (xargc > 0 && xargv[0][0] == '-') {
switch (xargv[0][1]) {
case 'r': /* return value only */
rflag++;
break;
case 'n': /* number of answers needed */
need = (int)xargv[1];
xargv++; xargc--;
break;
case 'i':
instr = xargv[1];
inct = (int)xargv[2]+2;
#if D2
fprintf(stderr, "inct %d xargv.2. %o %d\n", inct, xargv[2], xargv[2]);
#endif
xargv += 2; xargc -= 2;
break;
}
xargv++; xargc--;
}
if (xargc <= 0) {
write(2, "bad fgrep call\n", 15);
exit(2);
}
#if D1
fprintf(stderr, "before cgoto\n");
#endif
cgotofn();
#if D1
fprintf(stderr, "before cfail\n");
#endif
cfail();
#if D1
fprintf(stderr, "before execute instr %.20s\n", instr? instr: "");
fprintf(stderr, "end of string %d %c %c %c\n", inct,
instr ? instr[inct-3] : '\0',
instr ? instr[inct-2] : '\0',
instr ? instr[inct-1] : '\0');
#endif
execute();
#if D1
fprintf(stderr, "returning nsucc %d\n", nsucc);
fprintf(stderr, "fgrep done www %o\n", www);
#endif
return (nsucc == 0);
}
static void
execute(void)
{
char *p;
struct words *c;
char ch;
int ccount;
int f;
char *nlp;
f = 0;
ccount = instr ? inct : 0;
nfound = 0;
p = instr ? instr : buf;
if (need == 0) need = numwords;
nlp = p;
c = www;
#if D2
fprintf(stderr, "in execute ccount %d inct %d\n", ccount, inct);
#endif
for (;;) {
#if D3
fprintf(stderr, "down ccount\n");
#endif
if (--ccount <= 0) {
#if D2
fprintf(stderr, "ex loop ccount %d instr %o\n", ccount, instr);
#endif
if (instr) break;
if (p == &buf[2*BUFSIZ]) p = buf;
if (p > &buf[BUFSIZ]) {
if ((ccount = read(f, p,
&buf[2*BUFSIZ] - p)) <= 0)
break;
} else if ((ccount = read(f, p, BUFSIZ)) <= 0) break;
#if D2
fprintf(stderr, " normal read %d bytres\n", ccount);
{
char xx[20];
sprintf(xx, "they are %%.%ds\n", ccount);
fprintf(stderr, xx, p);
}
#endif
}
nstate:
ch = *p;
#if D2
fprintf(stderr, "roaming along in ex ch %c c %o\n", ch, c);
#endif
if (isupper(ch)) ch |= 040;
if (c->inp == ch) {
c = c->nst;
} else if (c->link != 0) {
c = c->link;
goto nstate;
} else {
c = c->fail;
if (c == 0) {
c = www;
istate:
if (c->inp == ch) {
c = c->nst;
} else if (c->link != 0) {
c = c->link;
goto istate;
}
} else goto nstate;
}
if (c->out && new(c)) {
#if D2
fprintf(stderr, " found: nfound %d need %d\n", nfound, need);
#endif
if (++nfound >= need) {
#if D1
fprintf(stderr, "found, p %o nlp %o ccount %d buf %o buf[2*BUFSIZ] %o\n",
p, nlp, ccount, buf, buf+2*BUFSIZ);
#endif
if (instr == 0)
while (*p++ != '\n') {
#if D3
fprintf(stderr, "down ccount2\n");
#endif
if (--ccount <= 0) {
if (p == &buf[2*BUFSIZ])
p = buf;
if (p > &buf[BUFSIZ]) {
if ((ccount = read(f, p,
&buf[2*BUFSIZ] - p))
<= 0)
break;
} else if ((ccount = read(f, p,
BUFSIZ)) <= 0)
break;
#if D2
fprintf(stderr, " read %d bytes\n", ccount);
{ char xx[20]; sprintf(xx, "they are %%.%ds\n", ccount);
fprintf(stderr, xx, p);
}
#endif
}
}
nsucc = 1;
if (rflag == 0) {
#if D2
fprintf(stderr, "p %o nlp %o buf %o\n", p, nlp, buf);
if (p > nlp)
{write(2, "XX\n", 3); write(2, nlp, p-nlp); write(2, "XX\n", 3); }
#endif
if (p > nlp) write(1, nlp, p-nlp);
else {
write(1, nlp,
&buf[2*BUFSIZ] - nlp);
write(1, buf, p-&buf[0]);
}
if (p[-1] != '\n') write(1, "\n", 1);
}
if (instr == 0) {
nlp = p;
c = www;
nfound = 0;
}
} else
ccount++;
continue;
}
#if D2
fprintf(stderr, "nr end loop p %o\n", p);
#endif
if (instr)
p++;
else
if (*p++ == '\n')
{
nlp = p;
c = www;
nfound = 0;
}
}
if (instr == 0)
close(f);
}
static void
cgotofn(void)
{
char c;
struct words *s;
s = smax = www;
nword:
for (;;) {
#if D1
fprintf(stderr, " in for loop c now %o %c\n", c, c > ' ' ? c : ' ');
#endif
if ((c = gch()) == 0)
return;
else if (c == '\n') {
s->out = 1;
s = www;
} else {
loop:
if (s->inp == c) {
s = s->nst;
continue;
}
if (s->inp == 0) goto enter;
if (s->link == 0) {
if (smax >= &www[MAXSIZ - 1]) overflo();
s->link = ++smax;
s = smax;
goto enter;
}
s = s->link;
goto loop;
}
}
enter:
do {
s->inp = c;
if (smax >= &www[MAXSIZ - 1]) overflo();
s->nst = ++smax;
s = smax;
}
while ((c = gch()) != '\n')
;
smax->out = 1;
s = www;
numwords++;
goto nword;
}
static char
gch(void)
{
static char *s;
if (flag == 0) {
flag = 1;
s = *xargv++;
#if D1
fprintf(stderr, "next arg is %s xargc %d\n", xargc > 0 ? s : "", xargc);
#endif
if (xargc-- <= 0)
return (0);
}
if (*s)
return (*s++);
for (flag = 0; flag < 2*BUFSIZ; flag++)
buf[flag] = 0;
flag = 0;
return ('\n');
}
static void
overflo(void)
{
write(2, "wordlist too large\n", 19);
exit(2);
}
static void
cfail(void)
{
struct words *queue[QSIZE];
struct words **front, **rear;
struct words *state;
char c;
struct words *s;
s = www;
front = rear = queue;
init:
if ((s->inp) != 0) {
*rear++ = s->nst;
if (rear >= &queue[QSIZE - 1]) overflo();
}
if ((s = s->link) != 0) {
goto init;
}
while (rear != front) {
s = *front;
if (front == &queue[QSIZE-1])
front = queue;
else front++;
cloop:
if ((c = s->inp) != 0) {
*rear = (q = s->nst);
if (front < rear)
if (rear >= &queue[QSIZE-1])
if (front == queue) overflo();
else rear = queue;
else rear++;
else
if (++rear == front) overflo();
state = s->fail;
floop:
if (state == 0) state = www;
if (state->inp == c) {
q->fail = state->nst;
if ((state->nst)->out == 1) q->out = 1;
continue;
} else if ((state = state->link) != 0)
goto floop;
}
if ((s = s->link) != 0)
goto cloop;
}
}
static struct words *seen[50];
static int
new(struct words *x)
{
int i;
for (i = 0; i < nfound; i++)
if (seen[i] == x)
return (0);
seen[i] = x;
return (1);
}