270 lines
5.1 KiB
C
270 lines
5.1 KiB
C
|
/*
|
||
|
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||
|
* terms in the LICENSE file found in the top-level directory of this
|
||
|
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||
|
* part of the UCB release of Plan 9, including this file, may be copied,
|
||
|
* modified, propagated, or distributed except according to the terms contained
|
||
|
* in the LICENSE file.
|
||
|
*/
|
||
|
|
||
|
#define EXTERN
|
||
|
#include "grep.h"
|
||
|
|
||
|
char *validflags = "bchiLlnsv";
|
||
|
void
|
||
|
usage(void)
|
||
|
{
|
||
|
fprint(2, "usage: grep [-%s] [-e pattern] [-f patternfile] [file ...]\n",
|
||
|
validflags);
|
||
|
exits("usage");
|
||
|
}
|
||
|
|
||
|
void
|
||
|
main(int argc, char *argv[])
|
||
|
{
|
||
|
int i, status;
|
||
|
|
||
|
ARGBEGIN {
|
||
|
default:
|
||
|
if (utfrune(validflags, ARGC()) == nil)
|
||
|
usage();
|
||
|
flags[ARGC()]++;
|
||
|
break;
|
||
|
|
||
|
case 'e':
|
||
|
flags['e']++;
|
||
|
lineno = 0;
|
||
|
str2top(EARGF(usage()));
|
||
|
break;
|
||
|
|
||
|
case 'f':
|
||
|
flags['f']++;
|
||
|
filename = EARGF(usage());
|
||
|
rein = Bopen(filename, OREAD);
|
||
|
if (rein == 0) {
|
||
|
fprint(2, "grep: can't open %s: %r\n", filename);
|
||
|
exits("open");
|
||
|
}
|
||
|
lineno = 1;
|
||
|
str2top(filename);
|
||
|
break;
|
||
|
}
|
||
|
ARGEND if (flags['f'] == 0 && flags['e'] == 0) {
|
||
|
if (argc <= 0)
|
||
|
usage();
|
||
|
str2top(argv[0]);
|
||
|
argc--;
|
||
|
argv++;
|
||
|
}
|
||
|
|
||
|
follow = mal(maxfollow * sizeof(*follow));
|
||
|
state0 = initstate(topre.beg);
|
||
|
|
||
|
Binit(&bout, 1, OWRITE);
|
||
|
switch (argc) {
|
||
|
case 0:
|
||
|
status = search(0, 0);
|
||
|
break;
|
||
|
case 1:
|
||
|
status = search(argv[0], 0);
|
||
|
break;
|
||
|
default:
|
||
|
status = 0;
|
||
|
for (i = 0; i < argc; i++)
|
||
|
status |= search(argv[i], Hflag);
|
||
|
break;
|
||
|
}
|
||
|
if (status)
|
||
|
exits(0);
|
||
|
exits("no matches");
|
||
|
}
|
||
|
|
||
|
int
|
||
|
search(char *file, int flag)
|
||
|
{
|
||
|
State *s, *ns;
|
||
|
int c, fid, eof, nl, empty;
|
||
|
int32_t count, lineno, n;
|
||
|
uint8_t *elp, *lp, *bol;
|
||
|
|
||
|
if (file == 0) {
|
||
|
file = "stdin";
|
||
|
fid = 0;
|
||
|
flag |= Bflag;
|
||
|
} else
|
||
|
fid = open(file, OREAD);
|
||
|
|
||
|
if (fid < 0) {
|
||
|
fprint(2, "grep: can't open %s: %r\n", file);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
if (flags['b'])
|
||
|
flag ^= Bflag; /* dont buffer output */
|
||
|
if (flags['c'])
|
||
|
flag |= Cflag; /* count */
|
||
|
if (flags['h'])
|
||
|
flag &= ~Hflag; /* do not print file name in output */
|
||
|
if (flags['i'])
|
||
|
flag |= Iflag; /* fold upper-lower */
|
||
|
if (flags['l'])
|
||
|
flag |= Llflag; /* print only name of file if any match */
|
||
|
if (flags['L'])
|
||
|
flag |= LLflag; /* print only name of file if any non match */
|
||
|
if (flags['n'])
|
||
|
flag |= Nflag; /* count only */
|
||
|
if (flags['s'])
|
||
|
flag |= Sflag; /* status only */
|
||
|
if (flags['v'])
|
||
|
flag |= Vflag; /* inverse match */
|
||
|
|
||
|
s = state0;
|
||
|
lineno = 0;
|
||
|
count = 0;
|
||
|
eof = 0;
|
||
|
empty = 1;
|
||
|
nl = 0;
|
||
|
lp = u.buf;
|
||
|
bol = lp;
|
||
|
|
||
|
loop0:
|
||
|
n = lp - bol;
|
||
|
if (n > sizeof(u.pre))
|
||
|
n = sizeof(u.pre);
|
||
|
memmove(u.buf - n, bol, n);
|
||
|
bol = u.buf - n;
|
||
|
n = read(fid, u.buf, sizeof(u.buf));
|
||
|
/* if file has no final newline, simulate one to emit matches to last line */
|
||
|
if (n > 0) {
|
||
|
empty = 0;
|
||
|
nl = u.buf[n - 1] == '\n';
|
||
|
} else {
|
||
|
if (n < 0) {
|
||
|
fprint(2, "grep: read error on %s: %r\n", file);
|
||
|
return count != 0;
|
||
|
}
|
||
|
if (!eof && !nl && !empty) {
|
||
|
u.buf[0] = '\n';
|
||
|
n = 1;
|
||
|
eof = 1;
|
||
|
}
|
||
|
}
|
||
|
if (n <= 0) {
|
||
|
close(fid);
|
||
|
if (flag & Cflag) {
|
||
|
if (flag & Hflag)
|
||
|
Bprint(&bout, "%s:", file);
|
||
|
Bprint(&bout, "%ld\n", count);
|
||
|
}
|
||
|
if (((flag & Llflag) && count != 0) || ((flag & LLflag) && count == 0))
|
||
|
Bprint(&bout, "%s\n", file);
|
||
|
Bflush(&bout);
|
||
|
return count != 0;
|
||
|
}
|
||
|
lp = u.buf;
|
||
|
elp = lp + n;
|
||
|
if (flag & Iflag)
|
||
|
goto loopi;
|
||
|
|
||
|
/*
|
||
|
* normal character loop
|
||
|
*/
|
||
|
loop:
|
||
|
c = *lp;
|
||
|
ns = s->next[c];
|
||
|
if (ns == 0) {
|
||
|
increment(s, c);
|
||
|
goto loop;
|
||
|
}
|
||
|
// if(flags['2'])
|
||
|
// if(s->match)
|
||
|
// print("%d: %.2x**\n", s, c);
|
||
|
// else
|
||
|
// print("%d: %.2x\n", s, c);
|
||
|
lp++;
|
||
|
s = ns;
|
||
|
if (c == '\n') {
|
||
|
lineno++;
|
||
|
if (! !s->match == !(flag & Vflag)) {
|
||
|
count++;
|
||
|
if (flag & (Cflag | Sflag | Llflag | LLflag))
|
||
|
goto cont;
|
||
|
if (flag & Hflag)
|
||
|
Bprint(&bout, "%s:", file);
|
||
|
if (flag & Nflag)
|
||
|
Bprint(&bout, "%ld: ", lineno);
|
||
|
/* suppress extra newline at EOF unless we are labeling matches with file name */
|
||
|
Bwrite(&bout, bol, lp - bol - (eof && !(flag & Hflag)));
|
||
|
if (flag & Bflag)
|
||
|
Bflush(&bout);
|
||
|
}
|
||
|
if ((lineno & Flshcnt) == 0)
|
||
|
Bflush(&bout);
|
||
|
cont:
|
||
|
bol = lp;
|
||
|
}
|
||
|
if (lp != elp)
|
||
|
goto loop;
|
||
|
goto loop0;
|
||
|
|
||
|
/*
|
||
|
* character loop for -i flag
|
||
|
* for speed
|
||
|
*/
|
||
|
loopi:
|
||
|
c = *lp;
|
||
|
if (c >= 'A' && c <= 'Z')
|
||
|
c += 'a' - 'A';
|
||
|
ns = s->next[c];
|
||
|
if (ns == 0) {
|
||
|
increment(s, c);
|
||
|
goto loopi;
|
||
|
}
|
||
|
lp++;
|
||
|
s = ns;
|
||
|
if (c == '\n') {
|
||
|
lineno++;
|
||
|
if (! !s->match == !(flag & Vflag)) {
|
||
|
count++;
|
||
|
if (flag & (Cflag | Sflag | Llflag | LLflag))
|
||
|
goto conti;
|
||
|
if (flag & Hflag)
|
||
|
Bprint(&bout, "%s:", file);
|
||
|
if (flag & Nflag)
|
||
|
Bprint(&bout, "%ld: ", lineno);
|
||
|
/* suppress extra newline at EOF unless we are labeling matches with file name */
|
||
|
Bwrite(&bout, bol, lp - bol - (eof && !(flag & Hflag)));
|
||
|
if (flag & Bflag)
|
||
|
Bflush(&bout);
|
||
|
}
|
||
|
if ((lineno & Flshcnt) == 0)
|
||
|
Bflush(&bout);
|
||
|
conti:
|
||
|
bol = lp;
|
||
|
}
|
||
|
if (lp != elp)
|
||
|
goto loopi;
|
||
|
goto loop0;
|
||
|
}
|
||
|
|
||
|
State *
|
||
|
initstate(Re * r)
|
||
|
{
|
||
|
State *s;
|
||
|
int i;
|
||
|
|
||
|
addcase(r);
|
||
|
if (flags['1'])
|
||
|
reprint("r", r);
|
||
|
nfollow = 0;
|
||
|
gen++;
|
||
|
fol1(r, Cbegin);
|
||
|
follow[nfollow++] = r;
|
||
|
qsort(follow, nfollow, sizeof(*follow), fcmp);
|
||
|
|
||
|
s = sal(nfollow);
|
||
|
for (i = 0; i < nfollow; i++)
|
||
|
s->re[i] = follow[i];
|
||
|
return s;
|
||
|
}
|