summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 5010cb5)
raw | patch | inline | side by side (parent: 5010cb5)
author | Junio C Hamano <junkio@cox.net> | |
Mon, 1 May 2006 19:27:56 +0000 (12:27 -0700) | ||
committer | Junio C Hamano <junkio@cox.net> | |
Mon, 1 May 2006 19:31:04 +0000 (12:31 -0700) |
This tweaks the pathspec wildcard used in builtin-grep to match
that of ls-files. With this:
git grep -e DEBUG -- '*/Kconfig*'
would work like the shell script version, and you could even do:
git grep -e DEBUG --cached -- '*/Kconfig*' ;# from index
git grep -e DEBUG v2.6.12 -- '*/Kconfig*' ;# from rev
Signed-off-by: Junio C Hamano <junkio@cox.net>
that of ls-files. With this:
git grep -e DEBUG -- '*/Kconfig*'
would work like the shell script version, and you could even do:
git grep -e DEBUG --cached -- '*/Kconfig*' ;# from index
git grep -e DEBUG v2.6.12 -- '*/Kconfig*' ;# from rev
Signed-off-by: Junio C Hamano <junkio@cox.net>
builtin-grep.c | patch | blob | history |
diff --git a/builtin-grep.c b/builtin-grep.c
index 36150bf4ef3486f653ec31c75a15d9a55a3b32ab..653b65ea1040a6d4e41f0c32df6c6766e04bc8d0 100644 (file)
--- a/builtin-grep.c
+++ b/builtin-grep.c
#include "revision.h"
#include "builtin.h"
#include <regex.h>
+#include <fnmatch.h>
+/*
+ * git grep pathspecs are somewhat different from diff-tree pathspecs;
+ * pathname wildcards are allowed.
+ */
static int pathspec_matches(struct diff_options *opt, const char *name)
{
- int i, j;
- int namelen;
+ int namelen, i;
if (!opt->nr_paths)
return 1;
namelen = strlen(name);
for (i = 0; i < opt->nr_paths; i++) {
const char *match = opt->paths[i];
int matchlen = opt->pathlens[i];
- if (matchlen <= namelen) {
- if (!strncmp(name, match, matchlen))
- return 1;
+ const char *slash, *cp;
+
+ if ((matchlen <= namelen) &&
+ !strncmp(name, match, matchlen) &&
+ (match[matchlen-1] == '/' ||
+ name[matchlen] == '\0' || name[matchlen] == '/'))
+ return 1;
+ if (!fnmatch(match, name, 0))
+ return 1;
+ if (name[namelen-1] != '/')
continue;
- }
- /* If name is "Documentation" and pathspec is
- * "Documentation/", they should match. Maybe
- * we would want to strip it in get_pathspec()???
+
+ /* We are being asked if the name directory 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.
*/
- if (strncmp(name, match, namelen))
- continue;
- for (j = namelen; j < matchlen; j++)
- if (match[j] != '/')
+ for (cp = match, slash = NULL; cp - match < matchlen; cp++) {
+ char ch = *cp;
+ if (ch == '/')
+ slash = cp;
+ if (ch == '*' || ch == '[')
break;
- if (matchlen <= j)
- return 1;
+ }
+ if (!slash)
+ slash = match; /* toplevel */
+ else
+ slash++;
+ if (namelen <= slash - match) {
+ /* Looking at "Documentation/" and
+ * the pattern says "Documentation/howto/", or
+ * "Documentation/diff*.txt".
+ */
+ if (!memcmp(match, name, namelen))
+ return 1;
+ }
+ else {
+ /* Looking at "Documentation/howto/" and
+ * the pattern says "Documentation/h*".
+ */
+ if (!memcmp(match, name, slash - match))
+ return 1;
+ }
}
return 0;
}
int hit = 0;
const char *path;
const unsigned char *sha1;
- char *down_base;
+ char *down;
char *path_buf = xmalloc(PATH_MAX + strlen(tree_name) + 100);
if (tree_name[0]) {
int offset = sprintf(path_buf, "%s:", tree_name);
- down_base = path_buf + offset;
- strcat(down_base, base);
+ down = path_buf + offset;
+ strcat(down, base);
}
else {
- down_base = path_buf;
- strcpy(down_base, base);
+ down = path_buf;
+ strcpy(down, base);
}
len = strlen(path_buf);
pathlen = strlen(path);
strcpy(path_buf + len, path);
- if (!pathspec_matches(&revs->diffopt, down_base))
+ if (S_ISDIR(mode))
+ /* Match "abc/" against pathspec to
+ * decide if we want to descend into "abc"
+ * directory.
+ */
+ strcpy(path_buf + len + pathlen, "/");
+
+ if (!pathspec_matches(&revs->diffopt, down))
;
else if (S_ISREG(mode))
hit |= grep_sha1(opt, sha1, path_buf);
if (!data)
die("unable to read tree (%s)",
sha1_to_hex(sha1));
- strcpy(path_buf + len + pathlen, "/");
sub.buf = data;
- hit = grep_tree(opt, revs, &sub, tree_name, down_base);
+ hit |= grep_tree(opt, revs, &sub, tree_name, down);
free(data);
}
update_tree_entry(tree);