summaryrefslogtreecommitdiff
path: root/builtin-grep.c
diff options
context:
space:
mode:
authorJunio C Hamano <junkio@cox.net>2006-05-02 22:40:49 (GMT)
committerJunio C Hamano <junkio@cox.net>2006-05-02 22:45:48 (GMT)
commitf9b9faf6f8a408b7129e2c95234f698da2171f4b (patch)
treeed395ce594bf4c38798596a732484b5723c3f6e3 /builtin-grep.c
parentf462ebb48bf9126335671e878336e3faf3914802 (diff)
downloadgit-f9b9faf6f8a408b7129e2c95234f698da2171f4b.zip
git-f9b9faf6f8a408b7129e2c95234f698da2171f4b.tar.gz
git-f9b9faf6f8a408b7129e2c95234f698da2171f4b.tar.bz2
builtin-grep: allow more than one patterns.
Signed-off-by: Junio C Hamano <junkio@cox.net>
Diffstat (limited to 'builtin-grep.c')
-rw-r--r--builtin-grep.c72
1 files changed, 51 insertions, 21 deletions
diff --git a/builtin-grep.c b/builtin-grep.c
index a551d34..b835120 100644
--- a/builtin-grep.c
+++ b/builtin-grep.c
@@ -75,9 +75,16 @@ static int pathspec_matches(const char **paths, const char *name)
return 0;
}
-struct grep_opt {
+struct grep_pat {
+ struct grep_pat *next;
const char *pattern;
regex_t regexp;
+};
+
+struct grep_opt {
+ struct grep_pat *pattern_list;
+ struct grep_pat **pattern_tail;
+ regex_t regexp;
unsigned linenum:1;
unsigned invert:1;
unsigned name_only:1;
@@ -86,6 +93,29 @@ struct grep_opt {
unsigned post_context;
};
+static void add_pattern(struct grep_opt *opt, const char *pat)
+{
+ struct grep_pat *p = xcalloc(1, sizeof(*p));
+ p->pattern = pat;
+ *opt->pattern_tail = p;
+ opt->pattern_tail = &p->next;
+ p->next = NULL;
+}
+
+static void compile_patterns(struct grep_opt *opt)
+{
+ struct grep_pat *p;
+ for (p = opt->pattern_list; p; p = p->next) {
+ int err = regcomp(&p->regexp, p->pattern, opt->regflags);
+ if (err) {
+ char errbuf[1024];
+ regerror(err, &p->regexp, errbuf, 1024);
+ regfree(&p->regexp);
+ die("'%s': %s", p->pattern, errbuf);
+ }
+ }
+}
+
static char *end_of_line(char *cp, unsigned long *left)
{
unsigned long l = *left;
@@ -128,14 +158,24 @@ static int grep_buffer(struct grep_opt *opt, const char *name,
while (left) {
regmatch_t pmatch[10];
char *eol, ch;
- int hit;
+ int hit = 0;
+ struct grep_pat *p;
eol = end_of_line(bol, &left);
ch = *eol;
*eol = 0;
- hit = !regexec(&opt->regexp, bol, ARRAY_SIZE(pmatch),
- pmatch, 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 (hit)
+ break;
+ }
+ /* "grep -v -e foo -e bla" should list lines
+ * that do not have either, so inversion should
+ * be done outside.
+ */
if (opt->invert)
hit = !hit;
if (hit) {
@@ -344,7 +384,6 @@ static const char builtin_grep_usage[] =
int cmd_grep(int argc, const char **argv, char **envp)
{
- int err;
int hit = 0;
int no_more_flags = 0;
int seen_noncommit = 0;
@@ -355,6 +394,7 @@ int cmd_grep(int argc, const char **argv, char **envp)
const char **paths = NULL;
memset(&opt, 0, sizeof(opt));
+ opt.pattern_tail = &opt.pattern_list;
opt.regflags = REG_NEWLINE;
/*
@@ -440,12 +480,8 @@ int cmd_grep(int argc, const char **argv, char **envp)
}
if (!strcmp("-e", arg)) {
if (1 < argc) {
- /* We probably would want to do
- * -e pat1 -e pat2 as well later...
- */
- if (opt.pattern)
- die("more than one pattern?");
- opt.pattern = *++argv;
+ add_pattern(&opt, argv[1]);
+ argv++;
argc--;
continue;
}
@@ -458,8 +494,8 @@ int cmd_grep(int argc, const char **argv, char **envp)
/* Either unrecognized option or a single pattern */
if (!no_more_flags && *arg == '-')
usage(builtin_grep_usage);
- if (!opt.pattern) {
- opt.pattern = arg;
+ if (!opt.pattern_list) {
+ add_pattern(&opt, arg);
break;
}
else {
@@ -471,15 +507,9 @@ int cmd_grep(int argc, const char **argv, char **envp)
break;
}
}
- if (!opt.pattern)
+ if (!opt.pattern_list)
die("no pattern given.");
- err = regcomp(&opt.regexp, opt.pattern, opt.regflags);
- if (err) {
- char errbuf[1024];
- regerror(err, &opt.regexp, errbuf, 1024);
- regfree(&opt.regexp);
- die("'%s': %s", opt.pattern, errbuf);
- }
+ compile_patterns(&opt);
tail = &object_list;
while (1 < argc) {
struct object *object;