summaryrefslogtreecommitdiffstats
path: root/usr.bin/grep
diff options
context:
space:
mode:
authorgabor <gabor@FreeBSD.org>2010-07-29 00:11:14 +0000
committergabor <gabor@FreeBSD.org>2010-07-29 00:11:14 +0000
commitd3f9c5a1b7e9d966652b4c688f2558356eb149d3 (patch)
tree1e1d5961f5ee38199f4b4fbd83cfffc86339e1c5 /usr.bin/grep
parent1e88e37ddc5c0145f7fc505a213d255161668879 (diff)
downloadFreeBSD-src-d3f9c5a1b7e9d966652b4c688f2558356eb149d3.zip
FreeBSD-src-d3f9c5a1b7e9d966652b4c688f2558356eb149d3.tar.gz
- Use the traditional behaviour for filename and directory name inclusion
and exclusion patterns [1] - Some improvements on the exiting code, like replacing memcpy with strlcpy/strcpy Approved by: delphij (mentor) Pointed out by: bf [1], des [1]
Diffstat (limited to 'usr.bin/grep')
-rw-r--r--usr.bin/grep/fastgrep.c3
-rw-r--r--usr.bin/grep/grep.150
-rw-r--r--usr.bin/grep/grep.c76
-rw-r--r--usr.bin/grep/grep.h12
-rw-r--r--usr.bin/grep/queue.c2
-rw-r--r--usr.bin/grep/util.c73
6 files changed, 148 insertions, 68 deletions
diff --git a/usr.bin/grep/fastgrep.c b/usr.bin/grep/fastgrep.c
index 265e457..5239a0e1 100644
--- a/usr.bin/grep/fastgrep.c
+++ b/usr.bin/grep/fastgrep.c
@@ -119,8 +119,7 @@ fastcomp(fastgrep_t *fg, const char *pat)
* string respectively.
*/
fg->pattern = grep_malloc(fg->len + 1);
- memcpy(fg->pattern, pat + (bol ? 1 : 0) + wflag, fg->len);
- fg->pattern[fg->len] = '\0';
+ strlcpy(fg->pattern, pat + (bol ? 1 : 0) + wflag, fg->len + 1);
/* Look for ways to cheat...er...avoid the full regex engine. */
for (i = 0; i < fg->len; i++) {
diff --git a/usr.bin/grep/grep.1 b/usr.bin/grep/grep.1
index 1f96a3e..38f9639 100644
--- a/usr.bin/grep/grep.1
+++ b/usr.bin/grep/grep.1
@@ -29,7 +29,7 @@
.\"
.\" @(#)grep.1 8.3 (Berkeley) 4/18/94
.\"
-.Dd September 19, 2009
+.Dd July 28, 2010
.Dt GREP 1
.Os
.Sh NAME
@@ -186,15 +186,31 @@ options are used to specify multiple patterns,
or when a pattern begins with a dash
.Pq Sq - .
.It Fl Fl exclude
-If
-.Fl R
-is specified, it excludes files matching the given
-filename pattern.
+If specified, it excludes files matching the given
+filename pattern from the search.
+Note that
+.Fl Fl exclude
+patterns take priority over
+.Fl Fl include
+patterns, and if no
+.Fl Fl include
+pattern is specified, all files are searched that are
+not excluded.
+Patterns are matched to the full path specified,
+not only to the filename component.
.It Fl Fl exclude-dir
If
.Fl R
is specified, it excludes directories matching the
-given filename pattern.
+given filename pattern from the search.
+Note that
+.Fl Fl exclude-dir
+patterns take priority over
+.Fl Fl include-dir
+patterns, and if no
+.Fl Fl include-dir
+pattern is specified, all directories are searched that are
+not excluded.
.It Fl F , Fl Fl fixed-strings
Interpret
.Ar pattern
@@ -238,15 +254,25 @@ By default,
.Nm grep
is case sensitive.
.It Fl Fl include
-If
-.Fl R
-is specified, it includes the files matching the
-given filename pattern.
+If specified, only files matching the
+given filename pattern are searched.
+Note that
+.Fl Fl exclude
+patterns take priority over
+.Fl Fl include
+patterns.
+Patterns are matched to the full path specified,
+not only to the filename component.
.It Fl Fl include-dir
If
.Fl R
-is specified, it includes the directories matching the
-given filename pattern.
+is specified, only directories matching the
+given filename pattern are searched.
+Note that
+.Fl Fl exclude-dir
+patterns take priority over
+.Fl Fl include-dir
+patterns.
.It Fl J, Fl Fl bz2decompress
Decompress the
.Xr bzip2 1
diff --git a/usr.bin/grep/grep.c b/usr.bin/grep/grep.c
index d8fc5c6..1de68d0 100644
--- a/usr.bin/grep/grep.c
+++ b/usr.bin/grep/grep.c
@@ -85,8 +85,9 @@ regex_t *r_pattern;
fastgrep_t *fg_pattern;
/* Filename exclusion/inclusion patterns */
-unsigned int epatterns, epattern_sz;
-struct epat *epattern;
+unsigned int fpatterns, fpattern_sz;
+unsigned int dpatterns, dpattern_sz;
+struct epat *dpattern, *fpattern;
/* For regex errors */
char re_error[RE_ERROR_BUF + 1];
@@ -112,7 +113,6 @@ bool wflag; /* -w: pattern must start and end on word boundaries */
bool xflag; /* -x: pattern must match entire line */
bool lbflag; /* --line-buffered */
bool nullflag; /* --null */
-bool exclflag; /* --exclude */
char *label; /* --label */
const char *color; /* --color */
int grepbehave = GREP_BASIC; /* -EFGP: type of the regex */
@@ -122,6 +122,9 @@ int devbehave = DEV_READ; /* -D: handling of devices */
int dirbehave = DIR_READ; /* -dRr: handling of directories */
int linkbehave = LINK_READ; /* -OpS: handling of symlinks */
+bool dexclude, dinclude; /* --exclude amd --include */
+bool fexclude, finclude; /* --exclude-dir and --include-dir */
+
enum {
BIN_OPT = CHAR_MAX + 1,
COLOR_OPT,
@@ -234,32 +237,44 @@ add_pattern(char *pat, size_t len)
--len;
/* pat may not be NUL-terminated */
pattern[patterns] = grep_malloc(len + 1);
- memcpy(pattern[patterns], pat, len);
- pattern[patterns][len] = '\0';
+ strlcpy(pattern[patterns], pat, len + 1);
++patterns;
}
/*
- * Adds an include/exclude pattern to the internal array.
+ * Adds a file include/exclude pattern to the internal array.
*/
static void
-add_epattern(char *pat, size_t len, int type, int mode)
+add_fpattern(const char *pat, int mode)
{
/* Increase size if necessary */
- if (epatterns == epattern_sz) {
- epattern_sz *= 2;
- epattern = grep_realloc(epattern, ++epattern_sz *
+ if (fpatterns == fpattern_sz) {
+ fpattern_sz *= 2;
+ fpattern = grep_realloc(fpattern, ++fpattern_sz *
sizeof(struct epat));
}
- if (len > 0 && pat[len - 1] == '\n')
- --len;
- epattern[epatterns].pat = grep_malloc(len + 1);
- memcpy(epattern[epatterns].pat, pat, len);
- epattern[epatterns].pat[len] = '\0';
- epattern[epatterns].type = type;
- epattern[epatterns].mode = mode;
- ++epatterns;
+ fpattern[fpatterns].pat = grep_strdup(pat);
+ fpattern[fpatterns].mode = mode;
+ ++fpatterns;
+}
+
+/*
+ * Adds a directory include/exclude pattern to the internal array.
+ */
+static void
+add_dpattern(const char *pat, int mode)
+{
+
+ /* Increase size if necessary */
+ if (dpatterns == dpattern_sz) {
+ dpattern_sz *= 2;
+ dpattern = grep_realloc(dpattern, ++dpattern_sz *
+ sizeof(struct epat));
+ }
+ dpattern[dpatterns].pat = grep_strdup(pat);
+ dpattern[dpatterns].mode = mode;
+ ++dpatterns;
}
/*
@@ -591,24 +606,20 @@ main(int argc, char *argv[])
nullflag = true;
break;
case R_INCLUDE_OPT:
- exclflag = true;
- add_epattern(basename(optarg), strlen(basename(optarg)),
- FILE_PAT, INCL_PAT);
+ finclude = true;
+ add_fpattern(optarg, INCL_PAT);
break;
case R_EXCLUDE_OPT:
- exclflag = true;
- add_epattern(basename(optarg), strlen(basename(optarg)),
- FILE_PAT, EXCL_PAT);
+ fexclude = true;
+ add_fpattern(optarg, EXCL_PAT);
break;
case R_DINCLUDE_OPT:
- exclflag = true;
- add_epattern(basename(optarg), strlen(basename(optarg)),
- DIR_PAT, INCL_PAT);
+ dexclude = true;
+ add_dpattern(optarg, INCL_PAT);
break;
case R_DEXCLUDE_OPT:
- exclflag = true;
- add_epattern(basename(optarg), strlen(basename(optarg)),
- DIR_PAT, EXCL_PAT);
+ dinclude = true;
+ add_dpattern(optarg, EXCL_PAT);
break;
case HELP_OPT:
default:
@@ -680,8 +691,11 @@ main(int argc, char *argv[])
if (dirbehave == DIR_RECURSE)
c = grep_tree(aargv);
else
- for (c = 0; aargc--; ++aargv)
+ for (c = 0; aargc--; ++aargv) {
+ if ((finclude || fexclude) && !file_matching(*aargv))
+ continue;
c+= procfile(*aargv);
+ }
#ifndef WITHOUT_NLS
catclose(catalog);
diff --git a/usr.bin/grep/grep.h b/usr.bin/grep/grep.h
index 4a2d43f..bb5e5f9 100644
--- a/usr.bin/grep/grep.h
+++ b/usr.bin/grep/grep.h
@@ -71,8 +71,6 @@ extern const char *errstr[];
#define LINK_EXPLICIT 1
#define LINK_SKIP 2
-#define FILE_PAT 0
-#define DIR_PAT 1
#define EXCL_PAT 0
#define INCL_PAT 1
@@ -98,7 +96,6 @@ struct str {
struct epat {
char *pat;
int mode;
- int type;
};
typedef struct {
@@ -118,7 +115,7 @@ extern int cflags, eflags;
extern bool Eflag, Fflag, Gflag, Hflag, Lflag,
bflag, cflag, hflag, iflag, lflag, mflag, nflag, oflag,
qflag, sflag, vflag, wflag, xflag;
-extern bool exclflag, nullflag;
+extern bool dexclude, dinclude, fexclude, finclude, nullflag;
extern unsigned long long Aflag, Bflag, mcount;
extern char *label;
extern const char *color;
@@ -126,9 +123,9 @@ extern int binbehave, devbehave, dirbehave, filebehave, grepbehave, linkbehave;
extern bool first, matchall, notfound, prev;
extern int tail;
-extern unsigned int epatterns, patterns;
+extern unsigned int dpatterns, fpatterns, patterns;
extern char **pattern;
-extern struct epat *epattern;
+extern struct epat *dpattern, *fpattern;
extern regex_t *er_pattern, *r_pattern;
extern fastgrep_t *fg_pattern;
@@ -137,11 +134,14 @@ extern fastgrep_t *fg_pattern;
extern char re_error[RE_ERROR_BUF + 1]; /* Seems big enough */
/* util.c */
+bool dir_matching(const char *dname);
+bool file_matching(const char *fname);
int procfile(const char *fn);
int grep_tree(char **argv);
void *grep_malloc(size_t size);
void *grep_calloc(size_t nmemb, size_t size);
void *grep_realloc(void *ptr, size_t size);
+char *grep_strdup(const char *str);
void printline(struct str *line, int sep, regmatch_t *matches, int m);
/* queue.c */
diff --git a/usr.bin/grep/queue.c b/usr.bin/grep/queue.c
index dcef7f8..29a6c2f 100644
--- a/usr.bin/grep/queue.c
+++ b/usr.bin/grep/queue.c
@@ -60,7 +60,7 @@ enqueue(struct str *x)
item->data.len = x->len;
item->data.line_no = x->line_no;
item->data.off = x->off;
- memcpy(item->data.dat, x->dat, x->len);
+ strcpy(item->data.dat, x->dat);
item->data.file = x->file;
STAILQ_INSERT_TAIL(&queue, item, list);
diff --git a/usr.bin/grep/util.c b/usr.bin/grep/util.c
index 4de36a7..95a68b3 100644
--- a/usr.bin/grep/util.c
+++ b/usr.bin/grep/util.c
@@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$");
#include <fnmatch.h>
#include <fts.h>
#include <libgen.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -51,6 +52,45 @@ __FBSDID("$FreeBSD$");
static int linesqueued;
static int procline(struct str *l, int);
+bool
+file_matching(const char *fname)
+{
+ bool ret;
+
+ ret = finclude ? false : true;
+
+ for (unsigned int i = 0; i < fpatterns; ++i) {
+ if (fnmatch(fpattern[i].pat,
+ fname, 0) == 0 || fnmatch(fpattern[i].pat,
+ basename(fname), 0) == 0) {
+ if (fpattern[i].mode == EXCL_PAT)
+ return (false);
+ else
+ ret = true;
+ }
+ }
+ return (ret);
+}
+
+bool
+dir_matching(const char *dname)
+{
+ bool ret;
+
+ ret = dinclude ? false : true;
+
+ for (unsigned int i = 0; i < dpatterns; ++i) {
+ if (dname != NULL &&
+ fnmatch(dname, dpattern[i].pat, 0) == 0) {
+ if (dpattern[i].mode == EXCL_PAT)
+ return (false);
+ else
+ ret = true;
+ }
+ }
+ return (ret);
+}
+
/*
* Processes a directory when a recursive search is performed with
* the -R option. Each appropriate file is passed to procfile().
@@ -61,7 +101,6 @@ grep_tree(char **argv)
FTS *fts;
FTSENT *p;
char *d, *dir = NULL;
- unsigned int i;
int c, fts_flags;
bool ok;
@@ -102,30 +141,19 @@ grep_tree(char **argv)
default:
/* Check for file exclusion/inclusion */
ok = true;
- if (exclflag) {
+ if (dexclude || dinclude) {
if ((d = strrchr(p->fts_path, '/')) != NULL) {
dir = grep_malloc(sizeof(char) *
(d - p->fts_path + 2));
strlcpy(dir, p->fts_path,
(d - p->fts_path + 1));
}
- for (i = 0; i < epatterns; ++i) {
- switch(epattern[i].type) {
- case FILE_PAT:
- if (fnmatch(epattern[i].pat,
- basename(p->fts_path), 0) == 0)
- ok = epattern[i].mode != EXCL_PAT;
- break;
- case DIR_PAT:
- if (dir != NULL && strstr(dir,
- epattern[i].pat) != NULL)
- ok = epattern[i].mode != EXCL_PAT;
- break;
- }
- }
+ ok = dir_matching(dir);
free(dir);
dir = NULL;
}
+ if (fexclude || finclude)
+ ok &= file_matching(p->fts_path);
if (ok)
c += procfile(p->fts_path);
@@ -409,6 +437,19 @@ grep_realloc(void *ptr, size_t size)
}
/*
+ * Safe strdup() for internal use.
+ */
+char *
+grep_strdup(const char *str)
+{
+ char *ret;
+
+ if ((ret = strdup(str)) == NULL)
+ err(2, "strdup");
+ return (ret);
+}
+
+/*
* Prints a matching line according to the command line options.
*/
void
OpenPOWER on IntegriCloud