summaryrefslogtreecommitdiff
path: root/builtin-grep.c
diff options
context:
space:
mode:
authorJunio C Hamano <junkio@cox.net>2006-05-09 06:55:47 (GMT)
committerJunio C Hamano <junkio@cox.net>2006-05-09 06:55:47 (GMT)
commit5acd64edec37a7d9783af1a2be99772d466e8f02 (patch)
tree5cfc7699a2e5ac229ca34098489666f2971b104a /builtin-grep.c
parent1c57119c70332faf206b5c7e2f3639b96a221717 (diff)
downloadgit-5acd64edec37a7d9783af1a2be99772d466e8f02.zip
git-5acd64edec37a7d9783af1a2be99772d466e8f02.tar.gz
git-5acd64edec37a7d9783af1a2be99772d466e8f02.tar.bz2
builtin-grep: tighten argument parsing.
I mistyped git grep next -e '"^@"' '*.c' and got many hits that contain "next" without complaint. Obviously what I meant to say was: git grep -e '"^@"' next -- '*.c' This tightens the argument parsing rule a bit: - All "grep" parameters should come first; - If there is no -e nor -f to specify pattern, the first non option string is the parameter; - After that, zero or more revs can follow. - An optional '--' can be present, and is skipped. - All the rest are pathspecs. If '--' was not there, they must be paths that exist in the working tree. Signed-off-by: Junio C Hamano <junkio@cox.net>
Diffstat (limited to 'builtin-grep.c')
-rw-r--r--builtin-grep.c76
1 files changed, 50 insertions, 26 deletions
diff --git a/builtin-grep.c b/builtin-grep.c
index a762c48..26a3fc3 100644
--- a/builtin-grep.c
+++ b/builtin-grep.c
@@ -494,20 +494,30 @@ static const char builtin_grep_usage[] =
int cmd_grep(int argc, const char **argv, char **envp)
{
int hit = 0;
- int no_more_flags = 0;
int cached = 0;
+ int seen_dashdash = 0;
struct grep_opt opt;
struct object_list *list, **tail, *object_list = NULL;
const char *prefix = setup_git_directory();
const char **paths = NULL;
+ int i;
memset(&opt, 0, sizeof(opt));
opt.pattern_tail = &opt.pattern_list;
opt.regflags = REG_NEWLINE;
/*
- * No point using rev_info, really.
+ * If there is no -- then the paths must exist in the working
+ * tree. If there is no explicit pattern specified with -e or
+ * -f, we take the first unrecognized non option to be the
+ * pattern, but then what follows it must be zero or more
+ * valid refs up to the -- (if exists), and then existing
+ * paths. If there is an explicit pattern, then the first
+ * unrecocnized non option is the beginning of the refs list
+ * that continues up to the -- (if exists), and then paths.
*/
+
+ tail = &object_list;
while (1 < argc) {
const char *arg = argv[1];
argc--; argv++;
@@ -618,7 +628,7 @@ int cmd_grep(int argc, const char **argv, char **envp)
usage(builtin_grep_usage);
patterns = fopen(argv[1], "r");
if (!patterns)
- die("'%s': %s", strerror(errno));
+ die("'%s': %s", argv[1], strerror(errno));
while (fgets(buf, sizeof(buf), patterns)) {
int len = strlen(buf);
if (buf[len-1] == '\n')
@@ -642,47 +652,61 @@ int cmd_grep(int argc, const char **argv, char **envp)
}
usage(builtin_grep_usage);
}
- if (!strcmp("--", arg)) {
- no_more_flags = 1;
- continue;
- }
- /* Either unrecognized option or a single pattern */
- if (!no_more_flags && *arg == '-')
+ if (!strcmp("--", arg))
+ break;
+ if (*arg == '-')
usage(builtin_grep_usage);
+
+ /* First unrecognized non-option token */
if (!opt.pattern_list) {
add_pattern(&opt, arg, "command line", 0);
break;
}
else {
/* We are looking at the first path or rev;
- * it is found at argv[0] after leaving the
+ * it is found at argv[1] after leaving the
* loop.
*/
argc++; argv--;
break;
}
}
+
if (!opt.pattern_list)
die("no pattern given.");
compile_patterns(&opt);
- tail = &object_list;
- while (1 < argc) {
- struct object *object;
- struct object_list *elem;
- const char *arg = argv[1];
+
+ /* Check revs and then paths */
+ for (i = 1; i < argc; i++) {
+ const char *arg = argv[i];
unsigned char sha1[20];
- if (get_sha1(arg, sha1) < 0)
- break;
- object = parse_object(sha1);
- if (!object)
- die("bad object %s", arg);
- elem = object_list_insert(object, tail);
- elem->name = arg;
- tail = &elem->next;
- argc--; argv++;
+ /* Is it a rev? */
+ if (!get_sha1(arg, sha1)) {
+ struct object *object = parse_object(sha1);
+ struct object_list *elem;
+ if (!object)
+ die("bad object %s", arg);
+ elem = object_list_insert(object, tail);
+ elem->name = arg;
+ tail = &elem->next;
+ continue;
+ }
+ if (!strcmp(arg, "--")) {
+ i++;
+ seen_dashdash = 1;
+ }
+ break;
}
- if (1 < argc)
- paths = get_pathspec(prefix, argv + 1);
+
+ /* The rest are paths */
+ if (!seen_dashdash) {
+ int j;
+ for (j = i; j < argc; i++)
+ verify_filename(prefix, argv[j]);
+ }
+
+ if (i < argc)
+ paths = get_pathspec(prefix, argv + i);
else if (prefix) {
paths = xcalloc(2, sizeof(const char *));
paths[0] = prefix;