diff --git a/builtin-grep.c b/builtin-grep.c
index 14471db7cb0de059c4e50648c100a20f6da892dd..36512d8a17abccb67654b5bcfcd74a441b3e4586 100644 (file)
--- a/builtin-grep.c
+++ b/builtin-grep.c
}
#define MAXARGS 1000
+#define ARGBUF 4096
+#define push_arg(a) do { \
+ if (nr < MAXARGS) argv[nr++] = (a); \
+ else die("maximum number of args exceeded"); \
+ } while (0)
static int external_grep(struct grep_opt *opt, const char **paths, int cached)
{
- int i, nr, argc, hit;
+ int i, nr, argc, hit, len;
const char *argv[MAXARGS+1];
+ char randarg[ARGBUF];
+ char *argptr = randarg;
struct grep_pat *p;
- nr = 0;
- argv[nr++] = "grep";
+ len = nr = 0;
+ push_arg("grep");
+ if (opt->fixed)
+ push_arg("-F");
+ if (opt->linenum)
+ push_arg("-n");
+ if (opt->regflags & REG_EXTENDED)
+ push_arg("-E");
if (opt->word_regexp)
- argv[nr++] = "-w";
+ push_arg("-w");
if (opt->name_only)
- argv[nr++] = "-l";
+ push_arg("-l");
+ if (opt->unmatch_name_only)
+ push_arg("-L");
+ if (opt->count)
+ push_arg("-c");
+ if (opt->post_context || opt->pre_context) {
+ if (opt->post_context != opt->pre_context) {
+ if (opt->pre_context) {
+ push_arg("-B");
+ len += snprintf(argptr, sizeof(randarg)-len,
+ "%u", opt->pre_context);
+ if (sizeof(randarg) <= len)
+ die("maximum length of args exceeded");
+ push_arg(argptr);
+ argptr += len;
+ }
+ if (opt->post_context) {
+ push_arg("-A");
+ len += snprintf(argptr, sizeof(randarg)-len,
+ "%u", opt->post_context);
+ if (sizeof(randarg) <= len)
+ die("maximum length of args exceeded");
+ push_arg(argptr);
+ argptr += len;
+ }
+ }
+ else {
+ push_arg("-C");
+ len += snprintf(argptr, sizeof(randarg)-len,
+ "%u", opt->post_context);
+ if (sizeof(randarg) <= len)
+ die("maximum length of args exceeded");
+ push_arg(argptr);
+ argptr += len;
+ }
+ }
for (p = opt->pattern_list; p; p = p->next) {
- argv[nr++] = "-e";
- argv[nr++] = p->pattern;
+ push_arg("-e");
+ push_arg(p->pattern);
+ }
+
+ if (NO_H_OPTION_IN_GREP)
+ push_arg("/dev/null");
+ else {
+ push_arg("-H");
+ push_arg("--");
}
- argv[nr++] = "--";
hit = 0;
argc = nr;
* Use the external "grep" command for the case where
* we grep through the checked-out files. It tends to
* be a lot more optimized
+ *
+ * Some grep implementations do not understand -H nor --
+ * but /dev/null can be used as a substitution in most
+ * cases.
+ *
+ * However -L and -c would slightly misbehave (-L would
+ * list /dev/null as a hit, and -c would report 0 hits
+ * from /dev/null); so do not use the external one on
+ * such platforms.
*/
- if (!cached) {
+ if (!cached &&
+ (!NO_H_OPTION_IN_GREP ||
+ (!opt->count && !opt->unmatch_name_only))) {
hit = external_grep(opt, paths, cached);
if (hit >= 0)
return hit;