Signed-off-by: Nguyán ThÃi Ngác Duy <pclouds@xxxxxxxxx> --- builtin/grep.c | 130 ++++++------------------------------------------------- 1 files changed, 15 insertions(+), 115 deletions(-) diff --git a/builtin/grep.c b/builtin/grep.c index 6bd5728..a56cdd6 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -333,106 +333,6 @@ static int grep_config(const char *var, const char *value, void *cb) return 0; } -/* - * 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, int max_depth) -{ - int namelen, i; - if (!paths || !*paths) - 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 (is_subdir(name, namelen, match, matchlen, max_depth)) - return 1; - if (!fnmatch(match, name, 0)) - return 1; - if (name[namelen-1] != '/') - continue; - - /* We are being asked if the directory ("name") is worth - * descending into. - * - * Find the longest leading directory name that does - * not have metacharacter in the pathspec; the name - * we are looking at must overlap with that directory. - */ - for (cp = match, meta = NULL; cp - match < matchlen; cp++) { - char ch = *cp; - if (ch == '*' || ch == '[' || ch == '?') { - meta = cp; - break; - } - } - if (!meta) - meta = cp; /* fully literal */ - - if (namelen <= meta - match) { - /* Looking at "Documentation/" and - * the pattern says "Documentation/howto/", or - * "Documentation/diff*.txt". The name we - * have should match prefix. - */ - if (!memcmp(match, name, namelen)) - return 1; - continue; - } - - if (meta - match < namelen) { - /* Looking at "Documentation/howto/" and - * the pattern says "Documentation/h*"; - * match up to "Do.../h"; this avoids descending - * into "Documentation/technical/". - */ - if (!memcmp(match, name, meta - match)) - return 1; - continue; - } - } - return 0; -} - static void *lock_and_read_sha1_file(const unsigned char *sha1, enum object_type *type, unsigned long *size) { void *data; @@ -632,39 +532,37 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec, struct tree_desc *tree, char *base, int baselen, int tree_name_len) { - int hit = 0; + int hit = 0, matched = 0; struct name_entry entry; while (tree_entry(tree, &entry)) { int te_len = tree_entry_len(entry.path, entry.sha1); - int len = baselen; - memcpy(base + baselen, entry.path, te_len+1); - len += te_len; - if (S_ISDIR(entry.mode)) { - /* Match "abc/" against pathspec to - * decide if we want to descend into "abc" - * directory. - */ - base[len++] = '/'; - base[len] = 0; + if (matched != 2) { + matched = tree_entry_interesting(&entry, base, baselen, pathspec); + if (matched == -1) + break; /* no more matches */ + if (!matched) + continue; } - if (!pathspec_matches(pathspec->raw, base, opt->max_depth)) - ; - else if (S_ISREG(entry.mode)) { + memcpy(base + baselen, entry.path, te_len+1); + if (S_ISREG(entry.mode)) hit |= grep_sha1(opt, entry.sha1, base-tree_name_len, tree_name_len); - } else if (S_ISDIR(entry.mode)) { enum object_type type; struct tree_desc sub; void *data; unsigned long size; + int len = baselen + te_len; data = lock_and_read_sha1_file(entry.sha1, &type, &size); if (!data) die("unable to read tree (%s)", sha1_to_hex(entry.sha1)); + + base[len++] = '/'; + base[len] = 0; init_tree_desc(&sub, data, size); hit |= grep_tree(opt, pathspec, &sub, base, len, tree_name_len); free(data); @@ -1069,6 +967,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix) paths[1] = NULL; } init_pathspec(&pathspec, paths); + pathspec.max_depth = opt.max_depth; + pathspec.recursive = 1; if (show_in_pager && (cached || list.nr)) die("--open-files-in-pager only works on the worktree"); -- 1.7.3.3.476.g10a82 -- 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