diff --git a/builtin-grep.c b/builtin-grep.c
index a762c48a5a3de70c47814df830aae0760549d163..fead35662944070f8502ed0484fe6b6085d7ac86 100644 (file)
--- a/builtin-grep.c
+++ b/builtin-grep.c
unsigned unmatch_name_only:1;
unsigned count:1;
unsigned word_regexp:1;
unsigned unmatch_name_only:1;
unsigned count:1;
unsigned word_regexp:1;
+ unsigned fixed:1;
#define GREP_BINARY_DEFAULT 0
#define GREP_BINARY_NOMATCH 1
#define GREP_BINARY_TEXT 2
#define GREP_BINARY_DEFAULT 0
#define GREP_BINARY_NOMATCH 1
#define GREP_BINARY_TEXT 2
return 0;
}
return 0;
}
+static int fixmatch(const char *pattern, char *line, regmatch_t *match)
+{
+ char *hit = strstr(line, pattern);
+ if (!hit) {
+ match->rm_so = match->rm_eo = -1;
+ return REG_NOMATCH;
+ }
+ else {
+ match->rm_so = hit - line;
+ match->rm_eo = match->rm_so + strlen(pattern);
+ return 0;
+ }
+}
+
static int grep_buffer(struct grep_opt *opt, const char *name,
char *buf, unsigned long size)
{
static int grep_buffer(struct grep_opt *opt, const char *name,
char *buf, unsigned long size)
{
*eol = 0;
for (p = opt->pattern_list; p; p = p->next) {
*eol = 0;
for (p = opt->pattern_list; p; p = p->next) {
- regex_t *exp = &p->regexp;
- hit = !regexec(exp, bol, ARRAY_SIZE(pmatch),
- pmatch, 0);
+ if (!opt->fixed) {
+ regex_t *exp = &p->regexp;
+ hit = !regexec(exp, bol, ARRAY_SIZE(pmatch),
+ pmatch, 0);
+ }
+ else {
+ hit = !fixmatch(p->pattern, bol, pmatch);
+ }
if (hit && opt->word_regexp) {
/* Match beginning must be either
if (hit && opt->word_regexp) {
/* Match beginning must be either
die("regexp returned nonsense");
if (pmatch[0].rm_so != 0 &&
word_char(bol[pmatch[0].rm_so-1]))
die("regexp returned nonsense");
if (pmatch[0].rm_so != 0 &&
word_char(bol[pmatch[0].rm_so-1]))
- continue; /* not a word boundary */
- if ((eol-bol) < pmatch[0].rm_eo &&
+ hit = 0;
+ if (pmatch[0].rm_eo != (eol-bol) &&
word_char(bol[pmatch[0].rm_eo]))
word_char(bol[pmatch[0].rm_eo]))
- continue; /* not a word boundary */
+ hit = 0;
}
if (hit)
break;
}
if (hit)
break;
int cmd_grep(int argc, const char **argv, char **envp)
{
int hit = 0;
int cmd_grep(int argc, const char **argv, char **envp)
{
int hit = 0;
- int no_more_flags = 0;
int cached = 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;
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;
/*
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++;
while (1 < argc) {
const char *arg = argv[1];
argc--; argv++;
opt.regflags |= REG_EXTENDED;
continue;
}
opt.regflags |= REG_EXTENDED;
continue;
}
+ if (!strcmp("-F", arg) ||
+ !strcmp("--fixed-strings", arg)) {
+ opt.fixed = 1;
+ continue;
+ }
if (!strcmp("-G", arg) ||
!strcmp("--basic-regexp", arg)) {
opt.regflags &= ~REG_EXTENDED;
if (!strcmp("-G", arg) ||
!strcmp("--basic-regexp", arg)) {
opt.regflags &= ~REG_EXTENDED;
usage(builtin_grep_usage);
patterns = fopen(argv[1], "r");
if (!patterns)
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')
while (fgets(buf, sizeof(buf), patterns)) {
int len = strlen(buf);
if (buf[len-1] == '\n')
}
usage(builtin_grep_usage);
}
}
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);
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;
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;
}
}
* loop.
*/
argc++; argv--;
break;
}
}
+
if (!opt.pattern_list)
die("no pattern given.");
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];
+ if ((opt.regflags != REG_NEWLINE) && opt.fixed)
+ die("cannot mix --fixed-strings and regexp");
+ if (!opt.fixed)
+ compile_patterns(&opt);
+
+ /* Check revs and then paths */
+ for (i = 1; i < argc; i++) {
+ const char *arg = argv[i];
unsigned char sha1[20];
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; j++)
+ 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;
else if (prefix) {
paths = xcalloc(2, sizeof(const char *));
paths[0] = prefix;