jehanne/sys/src/cmd/grep/main.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 = sys_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 = jehanne_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) {
sys_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;
}