[PATCH] Split grep arguments in a way that does not requires to add /dev/null.

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

 



  As adding /dev/null may create spurious output, and that grep applied to a
singleton does not works the same way than when it's applied to more than
one file, split the arguments in a way that the last batch has never a
singleton. Though, when there is only one file in the repository, force
adding /dev/null as we cannot do anything about it.

  Also, as we "spare" one argument from the batch before the last
(supposedly a full batch) we must be sure this batch with one element less
has at least 2 elements. Meaning that batches must have at least 3 available
slots for the algorithm to work. As it's a very unreasonable case (user
passing more than MAXARGS - 3 option flags !!!) die loudly.

Signed-off-by: Pierre Habouzit <madcoder@xxxxxxxxxx>
---
 builtin-grep.c  |   25 ++++++++++++++++++++++---
 t/t7002-grep.sh |    4 ++++
 2 files changed, 26 insertions(+), 3 deletions(-)

diff --git a/builtin-grep.c b/builtin-grep.c
index e13cb31..8f25020 100644
--- a/builtin-grep.c
+++ b/builtin-grep.c
@@ -189,7 +189,7 @@ static int exec_grep(int argc, const char **argv)
 
 static int external_grep(struct grep_opt *opt, const char **paths, int cached)
 {
-	int i, nr, argc, hit, len, status;
+	int i, nr, nbargs, argc, hit, len, status;
 	const char *argv[MAXARGS+1];
 	char randarg[ARGBUF];
 	char *argptr = randarg;
@@ -253,6 +253,15 @@ static int external_grep(struct grep_opt *opt, const char **paths, int cached)
 		push_arg(p->pattern);
 	}
 
+	for (nbargs = i = 0; i < active_nr; i++) {
+		struct cache_entry *ce = active_cache[i];
+		if (!S_ISREG(ntohl(ce->ce_mode)))
+			continue;
+		if (!pathspec_matches(paths, ce->name))
+			continue;
+		nbargs++;
+	}
+
 	/*
 	 * To make sure we get the header printed out when we want it,
 	 * add /dev/null to the paths to grep.  This is unnecessary
@@ -261,8 +270,16 @@ static int external_grep(struct grep_opt *opt, const char **paths, int cached)
 	 *
 	 * GNU grep has "-H", but this is portable.
 	 */
-	if (!opt->name_only && !opt->unmatch_name_only)
+	if (!opt->name_only && !opt->unmatch_name_only && nbargs == 1) {
 		push_arg("/dev/null");
+	}
+
+	/* for the algorithm that spares one file name if possible, we must have
+	 * at least 3 file name slots, so that sparing one, doesn't make a new
+	 * singleton, so rather than incorect output, die loudly.
+	 */
+	if (nr >= MAXARGS - 2)
+		die("You have an insanely long number of options");
 
 	hit = 0;
 	argc = nr;
@@ -281,12 +298,14 @@ static int external_grep(struct grep_opt *opt, const char **paths, int cached)
 			memcpy(name + 2, ce->name, len + 1);
 		}
 		argv[argc++] = name;
-		if (argc < MAXARGS && !ce_stage(ce))
+		/* if `nbargs + nr' overflows MAXARGS of one, spare one split now */
+		if (argc < MAXARGS - (nbargs + nr == MAXARGS + 1) && !ce_stage(ce))
 			continue;
 		status = exec_grep(argc, argv);
 		if (0 < status)
 			hit = 1;
 		argc = nr;
+		nbargs -= argc;
 		if (ce_stage(ce)) {
 			do {
 				i++;
diff --git a/t/t7002-grep.sh b/t/t7002-grep.sh
index 6bfb899..68b2b92 100755
--- a/t/t7002-grep.sh
+++ b/t/t7002-grep.sh
@@ -107,6 +107,10 @@ do
 		diff expected actual
 	'
 
+        test_expect_failure "grep -c $L (no /dev/null)" '
+		git grep -c test $H | grep -q "/dev/null"
+        '
+
 done
 
 test_done
-- 
1.5.3.1

-
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux