Implement grep -F

This commit is contained in:
sin 2014-11-20 14:35:23 +00:00
parent 728f36aa77
commit 6866bcdec8
2 changed files with 35 additions and 18 deletions

26
grep.1
View File

@ -3,7 +3,7 @@
grep \- search files for a pattern grep \- search files for a pattern
.SH SYNOPSIS .SH SYNOPSIS
.B grep .B grep
.RB [ \-EHchilnqsv ] .RB [ \-EFHchilnqsv ]
.RB [ \-e .RB [ \-e
.I pattern ] .I pattern ]
.I pattern .I pattern
@ -22,14 +22,18 @@ status code is 2.
.SH OPTIONS .SH OPTIONS
.TP .TP
.B \-E .B \-E
matches using extended regex. Matches using extended regex.
.TP
.B \-F
Match using fixed strings. Treat each pattern specified as a string instead of a regular
expression.
.TP .TP
.B \-H .B \-H
prefixes each matching line with its filename in the output. This is the Prefixes each matching line with its filename in the output. This is the
default when there is more than one file specified. default when there is more than one file specified.
.TP .TP
.B \-c .B \-c
prints only a count of matching lines. Prints only a count of matching lines.
.TP .TP
.B \-e pattern .B \-e pattern
Specify a pattern used during the search of the input: an input Specify a pattern used during the search of the input: an input
@ -39,26 +43,26 @@ specify multiple patterns, or when a pattern begins with a dash
(`-'). (`-').
.TP .TP
.B \-h .B \-h
do not prefix each line with 'filename:' prefix. Do not prefix each line with 'filename:' prefix.
.TP .TP
.B \-i .B \-i
matches lines case insensitively. Matches lines case insensitively.
.TP .TP
.B \-l .B \-l
prints only the names of files with matching lines. Prints only the names of files with matching lines.
.TP .TP
.B \-n .B \-n
prefixes each matching line with its line number in the input. Prefixes each matching line with its line number in the input.
.TP .TP
.B \-q .B \-q
prints nothing, only returns status. Prints nothing, only returns status.
.TP .TP
.B \-s .B \-s
Suppress the error messages ordinarily written for nonexistent or unreadable files. Suppress the error messages ordinarily written for nonexistent or unreadable files.
.TP .TP
.B \-v .B \-v
selects lines which do Selects lines which do
.B not .B not
match the pattern. Match the pattern.
.SH SEE ALSO .SH SEE ALSO
.IR regex (7) .IR regex (7)

15
grep.c
View File

@ -14,6 +14,7 @@ enum { Match = 0, NoMatch = 1, Error = 2 };
static void addpattern(const char *); static void addpattern(const char *);
static int grep(FILE *, const char *); static int grep(FILE *, const char *);
static int Fflag;
static int Hflag; static int Hflag;
static int eflag; static int eflag;
static int hflag; static int hflag;
@ -33,7 +34,7 @@ static SLIST_HEAD(phead, pattern) phead;
static void static void
usage(void) usage(void)
{ {
enprintf(Error, "usage: %s [-EHcilnqsv] [-e pattern] pattern [files...]\n", argv0); enprintf(Error, "usage: %s [-EFHcilnqsv] [-e pattern] pattern [files...]\n", argv0);
} }
int int
@ -49,6 +50,9 @@ main(int argc, char *argv[])
case 'E': case 'E':
flags |= REG_EXTENDED; flags |= REG_EXTENDED;
break; break;
case 'F':
Fflag = 1;
break;
case 'H': case 'H':
Hflag = 1; Hflag = 1;
break; break;
@ -88,6 +92,7 @@ main(int argc, char *argv[])
argv++; argv++;
} }
if (!Fflag)
/* Compile regex for all search patterns */ /* Compile regex for all search patterns */
SLIST_FOREACH(pnode, &phead, entry) SLIST_FOREACH(pnode, &phead, entry)
enregcomp(Error, &pnode->preg, pnode->pattern, flags); enregcomp(Error, &pnode->preg, pnode->pattern, flags);
@ -111,6 +116,7 @@ main(int argc, char *argv[])
while (!SLIST_EMPTY(&phead)) { while (!SLIST_EMPTY(&phead)) {
pnode = SLIST_FIRST(&phead); pnode = SLIST_FIRST(&phead);
SLIST_REMOVE_HEAD(&phead, entry); SLIST_REMOVE_HEAD(&phead, entry);
if (!Fflag)
regfree(&pnode->preg); regfree(&pnode->preg);
free(pnode->pattern); free(pnode->pattern);
free(pnode); free(pnode);
@ -142,8 +148,15 @@ grep(FILE *fp, const char *str)
if (len && buf[len - 1] == '\n') if (len && buf[len - 1] == '\n')
buf[len - 1] = '\0'; buf[len - 1] = '\0';
SLIST_FOREACH(pnode, &phead, entry) { SLIST_FOREACH(pnode, &phead, entry) {
if (!Fflag) {
if (regexec(&pnode->preg, buf, 0, NULL, 0) ^ vflag) if (regexec(&pnode->preg, buf, 0, NULL, 0) ^ vflag)
continue; continue;
} else {
match = strstr(buf, pnode->pattern) ? Match : NoMatch;
match ^= vflag;
if (match)
continue;
}
switch (mode) { switch (mode) {
case 'c': case 'c':
c++; c++;