bug-grep
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] grep: -r with no args now searches "."


From: Paul Eggert
Subject: [PATCH] grep: -r with no args now searches "."
Date: Mon, 02 Jan 2012 04:22:52 -0800
User-agent: Mozilla/5.0 (X11; Linux i686; rv:8.0) Gecko/20111124 Thunderbird/8.0

This is a patch I've been meaning to write for years.
Currently, one must write "grep -r PAT ." to search the working
directory recursively, and that trailing " ." is an annoyance.
When I added support for "grep -r", I forgot to have "grep -r PAT"
search the working directory by default, instead of searching
standard input (which makes no sense, even if stdin is a directory).
This is not an upward compatible change, since "grep -r PAT <file"
will no longer search standard input, but that's OK; nobody should
be using "grep -r" that way anyway.
* NEWS: Document this.
* doc/grep.texi (File and Directory Selection, grep Programs, Usage):
Likewise.
* src/main.c (usage): Likewise.
(grepdir): If DIR is null, search the working directory, but do
not prepend "./" to the file names.
(main): If recursing and no operands are given, search ".".
* tests/Makefile.am (TESTS): Add r-dot.
* tests/r-dot: New file.
---
 NEWS              |    3 +++
 doc/grep.texi     |   13 ++++++-------
 src/main.c        |   48 +++++++++++++++++++++++++++++++++++-------------
 tests/Makefile.am |    1 +
 tests/r-dot       |   14 ++++++++++++++
 5 files changed, 59 insertions(+), 20 deletions(-)
 create mode 100755 tests/r-dot

diff --git a/NEWS b/NEWS
index d4475bc..e729e1b 100644
--- a/NEWS
+++ b/NEWS
@@ -35,6 +35,9 @@ GNU grep NEWS                                    -*- outline 
-*-
 
 ** New features
 
+  If no file operands are given, grep -r now searches the working directory.
+  Formerly it ignored the -r and searched standard input nonrecursively.
+
   grep now supports color highlighting of matches on MS-Windows.
 
 * Noteworthy changes in release 2.10 (2011-11-16) [stable]
diff --git a/doc/grep.texi b/doc/grep.texi
index 9889095..75980e0 100644
--- a/doc/grep.texi
+++ b/doc/grep.texi
@@ -669,7 +669,7 @@ Search only files whose base name matches @var{glob}
 @opindex --recursive
 @cindex recursive search
 @cindex searching directory trees
-For each directory mentioned on the command line,
+For each directory operand,
 read and process all files in that directory, recursively.
 This is the same as the @samp{--directories=recurse} option.
 
@@ -1010,10 +1010,12 @@ instead of strict equality with@ 2.
 @cindex variants of @command{gerp}
 
 @command{grep} searches the named input files
-(or standard input if no files are named,
-or the file name @file{-} is given)
 for lines containing a match to the given pattern.
 By default, @command{grep} prints the matching lines.
+A file named @file{-} stands for standard input.
+If no files are named, a recursive @command{grep}
+searches the working directory @file{.}, and a
+nonrecursive @command{grep} searches standard input.
 There are four major variants of @command{grep},
 controlled by the following options.
 
@@ -1492,14 +1494,11 @@ find /home/gigi -name '*.c' -print0 | xargs -0r grep -H 
'hello'
 This differs from the command:
 
 @example
-grep -rH 'hello' *.c
+grep -H 'hello' *.c
 @end example
 
 which merely looks for @samp{hello} in all files in the current
 directory whose names end in @samp{.c}.
-Here the @option{-r} is
-probably unnecessary, as recursion occurs only in the unlikely event
-that one of @samp{.c} files is a directory.
 The @samp{find ...} command line above is more similar to the command:
 
 @example
diff --git a/src/main.c b/src/main.c
index a1d590a..79d037f 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1348,6 +1348,7 @@ grepfile (char const *file, struct stats *stats)
 static int
 grepdir (char const *dir, struct stats const *stats)
 {
+  char const *dir_or_dot = (dir ? dir : ".");
   struct stats const *ancestor;
   char *name_space;
   int status = 1;
@@ -1372,38 +1373,50 @@ grepdir (char const *dir, struct stats const *stats)
         }
     }
 
-  name_space = savedir (dir, stats->stat.st_size, included_patterns,
+  name_space = savedir (dir_or_dot, stats->stat.st_size, included_patterns,
                         excluded_patterns, excluded_directory_patterns);
 
   if (! name_space)
     {
       if (errno)
-        suppressible_error (dir, errno);
+        suppressible_error (dir_or_dot, errno);
       else
         xalloc_die ();
     }
   else
     {
-      size_t dirlen = strlen (dir);
-      int needs_slash = ! (dirlen == FILE_SYSTEM_PREFIX_LEN (dir)
-                           || ISSLASH (dir[dirlen - 1]));
-      char *file = NULL;
+      size_t dirlen = 0;
+      int needs_slash = 0;
+      char *file_space = NULL;
       char const *namep = name_space;
       struct stats child;
+      if (dir)
+        {
+          dirlen = strlen (dir);
+          needs_slash = ! (dirlen == FILE_SYSTEM_PREFIX_LEN (dir)
+                           || ISSLASH (dir[dirlen - 1]));
+        }
       child.parent = stats;
       out_file += !no_filenames;
       while (*namep)
         {
           size_t namelen = strlen (namep);
-          file = xrealloc (file, dirlen + 1 + namelen + 1);
-          strcpy (file, dir);
-          file[dirlen] = '/';
-          strcpy (file + dirlen + needs_slash, namep);
+          char const *file;
+          if (! dir)
+            file = namep;
+          else
+            {
+              file_space = xrealloc (file_space, dirlen + 1 + namelen + 1);
+              strcpy (file_space, dir);
+              file_space[dirlen] = '/';
+              strcpy (file_space + dirlen + needs_slash, namep);
+              file = file_space;
+            }
           namep += namelen + 1;
           status &= grepfile (file, &child);
         }
       out_file -= !no_filenames;
-      free (file);
+      free (file_space);
       free (name_space);
     }
 
@@ -1509,8 +1522,9 @@ Context control:\n\
 \n"));
       fputs (_(after_options), stdout);
       printf (_("\
-With no FILE, or when FILE is -, read standard input.  If less than two 
FILEs\n\
-are given, assume -h.  Exit status is 0 if any line was selected, 1 
otherwise;\n\
+When FILE is -, read standard input.  With no FILE, read '.' if recursive,\n\
+standard input if not.  If fewer than two FILEs are given, assume -h.\n\
+Exit status is 0 if any line was selected, 1 otherwise;\n\
 if any error occurs and -q was not given, the exit status is 2.\n"));
       printf (_("\nReport bugs to: %s\n"), PACKAGE_BUGREPORT);
       printf (_("GNU Grep home page: <%s>\n"),
@@ -2233,6 +2247,14 @@ main (int argc, char **argv)
         }
       while (++optind < argc);
     }
+  else if (directories == RECURSE_DIRECTORIES)
+    {
+      status = 1;
+      if (stat (".", &stats_base.stat) == 0)
+        status = grepdir (NULL, &stats_base);
+      else
+        suppressible_error (".", errno);
+    }
   else
     status = grepfile ((char *) NULL, &stats_base);
 
diff --git a/tests/Makefile.am b/tests/Makefile.am
index df98e0b..77b670b 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -73,6 +73,7 @@ TESTS =                                               \
   pcre-abort                                   \
   pcre-z                                       \
   prefix-of-multibyte                          \
+  r-dot                                                \
   reversed-range-endpoints                     \
   sjis-mb                                      \
   spencer1                                     \
diff --git a/tests/r-dot b/tests/r-dot
new file mode 100755
index 0000000..73e593c
--- /dev/null
+++ b/tests/r-dot
@@ -0,0 +1,14 @@
+#!/bin/sh
+# Check that "grep -r PAT" reads ".".
+. "${srcdir=.}/init.sh"; path_prepend_ ../src
+
+mkdir dir || framework_failure_
+echo aaa > dir/a || framework_failure_
+echo bbb > dir/b || framework_failure_
+
+echo a:aaa > exp || framework_failure_
+
+(cd dir && grep -r aaa) > out || fail=1
+compare exp out || fail=1
+
+Exit $fail
-- 
1.7.6.4




reply via email to

[Prev in Thread] Current Thread [Next in Thread]