summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Eggert <eggert@cs.ucla.edu>2012-05-06 15:50:58 -0700
committerPaul Eggert <eggert@cs.ucla.edu>2012-05-06 15:52:21 -0700
commit58195fabc7559541b3736400e08e901011acd61f (patch)
treee970657b01977d56bbad428f4e5f18276b1f9d3c
parentc1ac4ab87042fd0d18d6bda9db75677c7913341f (diff)
downloadgrep-58195fabc7559541b3736400e08e901011acd61f.tar.gz
exclude: process exclude and include directives in order
Also, change exclude and include directives so that they apply to command-line arguments too. This restores the pre-2.6 behavior, and fixes a bug reported by Quentin Arce in <http://lists.gnu.org/archive/html/bug-grep/2012-04/msg00056.html>. * NEWS: Document this. * src/main.c (included_patterns): Remove. All uses removed. (skipped_file): New function. (grepdirent): New arg command_line; all callers changed. This is needed because non-command-line files can invoke fts_open, and their directory entries need to be distinguished from top-level directory entries. Move code into the new skipped_file function. (grepdesc): Check whether a command-line argument should be skipped. (main): --include and --exclude options now share excluded_patterns rather than having separate variables included_patterns and excluded_patterns. * tests/include-exclude: Add a test to detect the fixed bug.
-rw-r--r--NEWS7
-rw-r--r--src/main.c52
-rwxr-xr-xtests/include-exclude5
3 files changed, 41 insertions, 23 deletions
diff --git a/NEWS b/NEWS
index eb779193..9bd7e67c 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,13 @@ GNU grep NEWS -*- outline -*-
* Noteworthy changes in release ?.? (????-??-??) [?]
+** Bug fixes
+
+ --include and --exclude can again be combined, and again apply to
+ the command line, e.g., "grep --include='*.[ch]' --exclude='system.h'
+ PATTERN *" again reads all *.c and *.h files except for system.h.
+ [bug introduced in grep-2.6]
+
** Dropped features
Bootstrapping with Makefile.boot has been broken since grep 2.6,
diff --git a/src/main.c b/src/main.c
index cb6da2ca..b91a0420 100644
--- a/src/main.c
+++ b/src/main.c
@@ -272,7 +272,6 @@ static const struct color_cap color_dict[] =
};
static struct exclude *excluded_patterns;
-static struct exclude *included_patterns;
static struct exclude *excluded_directory_patterns;
/* Short options. */
static char const short_options[] =
@@ -449,6 +448,20 @@ context_length_arg (char const *str, intmax_t *out)
}
}
+/* Return nonzero if the file with NAME should be skipped.
+ If COMMAND_LINE is nonzero, it is a command-line argument.
+ If IS_DIR is nonzero, it is a directory. */
+static int
+skipped_file (char const *name, int command_line, int is_dir)
+{
+ return (is_dir
+ ? (directories == SKIP_DIRECTORIES
+ || (! (command_line && filename_prefix_len != 0)
+ && excluded_directory_patterns
+ && excluded_file_name (excluded_directory_patterns, name)))
+ : (excluded_patterns
+ && excluded_file_name (excluded_patterns, name)));
+}
/* Hairy buffering mechanism for grep. The intent is to keep
all reads aligned on a page boundary and multiples of the
@@ -1207,11 +1220,11 @@ grep (int fd, struct stat const *st)
}
static int
-grepdirent (FTS *fts, FTSENT *ent)
+grepdirent (FTS *fts, FTSENT *ent, int command_line)
{
int follow, dirdesc;
- int command_line = ent->fts_level == FTS_ROOTLEVEL;
struct stat *st = ent->fts_statp;
+ command_line &= ent->fts_level == FTS_ROOTLEVEL;
if (ent->fts_info == FTS_DP)
{
@@ -1220,17 +1233,9 @@ grepdirent (FTS *fts, FTSENT *ent)
return 1;
}
- if ((ent->fts_info == FTS_D || ent->fts_info == FTS_DC
- || ent->fts_info == FTS_DNR)
- ? (directories == SKIP_DIRECTORIES
- || (! (command_line && filename_prefix_len != 0)
- && excluded_directory_patterns
- && excluded_file_name (excluded_directory_patterns,
- ent->fts_name)))
- : ((included_patterns
- && excluded_file_name (included_patterns, ent->fts_name))
- || (excluded_patterns
- && excluded_file_name (excluded_patterns, ent->fts_name))))
+ if (skipped_file (ent->fts_name, command_line,
+ (ent->fts_info == FTS_D || ent->fts_info == FTS_DC
+ || ent->fts_info == FTS_DNR)))
{
fts_set (fts, ent, FTS_SKIP);
return 1;
@@ -1336,6 +1341,11 @@ grepdesc (int desc, int command_line)
suppressible_error (filename, errno);
goto closeout;
}
+
+ if (desc != STDIN_FILENO && command_line
+ && skipped_file (filename, 1, S_ISDIR (st.st_mode)))
+ goto closeout;
+
if (desc != STDIN_FILENO
&& directories == RECURSE_DIRECTORIES && S_ISDIR (st.st_mode))
{
@@ -1360,7 +1370,7 @@ grepdesc (int desc, int command_line)
if (!fts)
xalloc_die ();
while ((ent = fts_read (fts)))
- status &= grepdirent (fts, ent);
+ status &= grepdirent (fts, ent, command_line);
if (errno)
suppressible_error (filename, errno);
if (fts_close (fts) != 0)
@@ -2076,9 +2086,12 @@ main (int argc, char **argv)
break;
case EXCLUDE_OPTION:
+ case INCLUDE_OPTION:
if (!excluded_patterns)
excluded_patterns = new_exclude ();
- add_exclude (excluded_patterns, optarg, EXCLUDE_WILDCARDS);
+ add_exclude (excluded_patterns, optarg,
+ (EXCLUDE_WILDCARDS
+ | (opt == INCLUDE_OPTION ? EXCLUDE_INCLUDE : 0)));
break;
case EXCLUDE_FROM_OPTION:
if (!excluded_patterns)
@@ -2096,13 +2109,6 @@ main (int argc, char **argv)
add_exclude (excluded_directory_patterns, optarg, EXCLUDE_WILDCARDS);
break;
- case INCLUDE_OPTION:
- if (!included_patterns)
- included_patterns = new_exclude ();
- add_exclude (included_patterns, optarg,
- EXCLUDE_WILDCARDS | EXCLUDE_INCLUDE);
- break;
-
case GROUP_SEPARATOR_OPTION:
group_separator = optarg;
break;
diff --git a/tests/include-exclude b/tests/include-exclude
index 406e0d49..28465cb9 100755
--- a/tests/include-exclude
+++ b/tests/include-exclude
@@ -19,6 +19,11 @@ grep -r --exclude='a*' . x > out || fail=1
sort out > k && mv k out
compare exp-not-a out || fail=1
+grep -r --exclude='Rumpelstiltskin' --include='a*' --exclude='a*' . x > out ||
+ fail=1
+sort out > k && mv k out
+compare exp-not-a out || fail=1
+
grep -r --exclude='[ab]' . x > out || fail=1
sort out > k && mv k out
compare exp-not-ab out || fail=1