diff options
Diffstat (limited to 'builtin-grep.c')
-rw-r--r-- | builtin-grep.c | 80 |
1 files changed, 68 insertions, 12 deletions
diff --git a/builtin-grep.c b/builtin-grep.c index 73fc922c49..ad0e0a5385 100644 --- a/builtin-grep.c +++ b/builtin-grep.c @@ -11,6 +11,7 @@ #include "tree-walk.h" #include "builtin.h" #include "parse-options.h" +#include "userdiff.h" #include "grep.h" #ifndef NO_EXTERNAL_GREP @@ -30,6 +31,12 @@ static int grep_config(const char *var, const char *value, void *cb) { struct grep_opt *opt = cb; + switch (userdiff_config(var, value)) { + case 0: break; + case -1: return -1; + default: return 0; + } + if (!strcmp(var, "color.grep")) { opt->color = git_config_colorbool(var, value, -1); return 0; @@ -46,25 +53,57 @@ static int grep_config(const char *var, const char *value, void *cb) } /* + * Return non-zero if max_depth is negative or path has no more then max_depth + * slashes. + */ +static int accept_subdir(const char *path, int max_depth) +{ + if (max_depth < 0) + return 1; + + while ((path = strchr(path, '/')) != NULL) { + max_depth--; + if (max_depth < 0) + return 0; + path++; + } + return 1; +} + +/* + * Return non-zero if name is a subdirectory of match and is not too deep. + */ +static int is_subdir(const char *name, int namelen, + const char *match, int matchlen, int max_depth) +{ + if (matchlen > namelen || strncmp(name, match, matchlen)) + return 0; + + if (name[matchlen] == '\0') /* exact match */ + return 1; + + if (!matchlen || match[matchlen-1] == '/' || name[matchlen] == '/') + return accept_subdir(name + matchlen + 1, max_depth); + + return 0; +} + +/* * git grep pathspecs are somewhat different from diff-tree pathspecs; * pathname wildcards are allowed. */ -static int pathspec_matches(const char **paths, const char *name) +static int pathspec_matches(const char **paths, const char *name, int max_depth) { int namelen, i; if (!paths || !*paths) - return 1; + return accept_subdir(name, max_depth); namelen = strlen(name); for (i = 0; paths[i]; i++) { const char *match = paths[i]; int matchlen = strlen(match); const char *cp, *meta; - if (!matchlen || - ((matchlen <= namelen) && - !strncmp(name, match, matchlen) && - (match[matchlen-1] == '/' || - name[matchlen] == '\0' || name[matchlen] == '/'))) + if (is_subdir(name, namelen, match, matchlen, max_depth)) return 1; if (!fnmatch(match, name, 0)) return 1; @@ -278,6 +317,17 @@ static int flush_grep(struct grep_opt *opt, argc -= 2; } + if (opt->pre_context || opt->post_context) { + /* + * grep handles hunk marks between files, but we need to + * do that ourselves between multiple calls. + */ + if (opt->show_hunk_mark) + write_or_die(1, "--\n", 3); + else + opt->show_hunk_mark = 1; + } + status = exec_grep(argc, argv); if (kept_0) { @@ -403,7 +453,7 @@ static int external_grep(struct grep_opt *opt, const char **paths, int cached) int kept; if (!S_ISREG(ce->ce_mode)) continue; - if (!pathspec_matches(paths, ce->name)) + if (!pathspec_matches(paths, ce->name, opt->max_depth)) continue; name = ce->name; if (name[0] == '-') { @@ -460,7 +510,7 @@ static int grep_cache(struct grep_opt *opt, const char **paths, int cached, struct cache_entry *ce = active_cache[nr]; if (!S_ISREG(ce->ce_mode)) continue; - if (!pathspec_matches(paths, ce->name)) + if (!pathspec_matches(paths, ce->name, opt->max_depth)) continue; /* * If CE_VALID is on, we assume worktree file and its cache entry @@ -520,7 +570,7 @@ static int grep_tree(struct grep_opt *opt, const char **paths, strbuf_addch(&pathbuf, '/'); down = pathbuf.buf + tn_len; - if (!pathspec_matches(paths, down)) + if (!pathspec_matches(paths, down, opt->max_depth)) ; else if (S_ISREG(entry.mode)) hit |= grep_sha1(opt, entry.sha1, pathbuf.buf, tn_len); @@ -594,7 +644,7 @@ static int file_callback(const struct option *opt, const char *arg, int unset) patterns = fopen(arg, "r"); if (!patterns) - die("'%s': %s", arg, strerror(errno)); + die_errno("cannot open '%s'", arg); while (strbuf_getline(&sb, patterns, '\n') == 0) { /* ignore empty line like grep does */ if (sb.len == 0) @@ -674,6 +724,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix) OPT_SET_INT('I', NULL, &opt.binary, "don't match patterns in binary files", GREP_BINARY_NOMATCH), + { OPTION_INTEGER, 0, "max-depth", &opt.max_depth, "depth", + "descend at most <depth> levels", PARSE_OPT_NONEG, + NULL, 1 }, OPT_GROUP(""), OPT_BIT('E', "extended-regexp", &opt.regflags, "use extended POSIX regular expressions", REG_EXTENDED), @@ -710,6 +763,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix) "show <n> context lines after matches"), OPT_NUMBER_CALLBACK(&opt, "shortcut for -C NUM", context_callback), + OPT_BOOLEAN('p', "show-function", &opt.funcname, + "show a line with the function name before matches"), OPT_GROUP(""), OPT_CALLBACK('f', NULL, &opt, "file", "read patterns from file", file_callback), @@ -748,6 +803,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) opt.pathname = 1; opt.pattern_tail = &opt.pattern_list; opt.regflags = REG_NEWLINE; + opt.max_depth = -1; strcpy(opt.color_match, GIT_COLOR_RED GIT_COLOR_BOLD); opt.color = -1; @@ -778,7 +834,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) argc--; } - if (opt.color && !opt.color_external) + if ((opt.color && !opt.color_external) || opt.funcname) external_grep_allowed = 0; if (!opt.pattern_list) die("no pattern given."); |