aboutsummaryrefslogtreecommitdiff
path: root/grep.c
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2012-06-01 13:01:41 -0700
committerJunio C Hamano <gitster@pobox.com>2012-06-01 13:01:41 -0700
commit2147cb2762c67d0ec2101ab13a4c1b0ef8cab599 (patch)
tree7dccda03b60264e9922edc9bbcad3d4942d77f10 /grep.c
parente2d484c47a3445a288f4e45ee8365c912eebb26f (diff)
parentec83061156e18ce600384d3c57f90729a9295488 (diff)
downloadgit-2147cb2762c67d0ec2101ab13a4c1b0ef8cab599.tar.gz
git-2147cb2762c67d0ec2101ab13a4c1b0ef8cab599.tar.xz
Merge branch 'rs/maint-grep-F' into maint
"git grep -e '$pattern'", unlike the case where the patterns are read from a file, did not treat individual lines in the given pattern argument as separate regular expressions as it should. By René Scharfe * rs/maint-grep-F: grep: stop leaking line strings with -f grep: support newline separated pattern list grep: factor out do_append_grep_pat() grep: factor out create_grep_pat()
Diffstat (limited to 'grep.c')
-rw-r--r--grep.c74
1 files changed, 57 insertions, 17 deletions
diff --git a/grep.c b/grep.c
index f8ffa4620..04e3ec6c6 100644
--- a/grep.c
+++ b/grep.c
@@ -3,18 +3,64 @@
#include "userdiff.h"
#include "xdiff-interface.h"
-void append_header_grep_pattern(struct grep_opt *opt, enum grep_header_field field, const char *pat)
+static struct grep_pat *create_grep_pat(const char *pat, size_t patlen,
+ const char *origin, int no,
+ enum grep_pat_token t,
+ enum grep_header_field field)
{
struct grep_pat *p = xcalloc(1, sizeof(*p));
- p->pattern = pat;
- p->patternlen = strlen(pat);
- p->origin = "header";
- p->no = 0;
- p->token = GREP_PATTERN_HEAD;
+ p->pattern = xmemdupz(pat, patlen);
+ p->patternlen = patlen;
+ p->origin = origin;
+ p->no = no;
+ p->token = t;
p->field = field;
- *opt->header_tail = p;
- opt->header_tail = &p->next;
+ return p;
+}
+
+static void do_append_grep_pat(struct grep_pat ***tail, struct grep_pat *p)
+{
+ **tail = p;
+ *tail = &p->next;
p->next = NULL;
+
+ switch (p->token) {
+ case GREP_PATTERN: /* atom */
+ case GREP_PATTERN_HEAD:
+ case GREP_PATTERN_BODY:
+ for (;;) {
+ struct grep_pat *new_pat;
+ size_t len = 0;
+ char *cp = p->pattern + p->patternlen, *nl = NULL;
+ while (++len <= p->patternlen) {
+ if (*(--cp) == '\n') {
+ nl = cp;
+ break;
+ }
+ }
+ if (!nl)
+ break;
+ new_pat = create_grep_pat(nl + 1, len - 1, p->origin,
+ p->no, p->token, p->field);
+ new_pat->next = p->next;
+ if (!p->next)
+ *tail = &new_pat->next;
+ p->next = new_pat;
+ *nl = '\0';
+ p->patternlen -= len;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void append_header_grep_pattern(struct grep_opt *opt,
+ enum grep_header_field field, const char *pat)
+{
+ struct grep_pat *p = create_grep_pat(pat, strlen(pat), "header", 0,
+ GREP_PATTERN_HEAD, field);
+ do_append_grep_pat(&opt->header_tail, p);
}
void append_grep_pattern(struct grep_opt *opt, const char *pat,
@@ -26,15 +72,8 @@ void append_grep_pattern(struct grep_opt *opt, const char *pat,
void append_grep_pat(struct grep_opt *opt, const char *pat, size_t patlen,
const char *origin, int no, enum grep_pat_token t)
{
- struct grep_pat *p = xcalloc(1, sizeof(*p));
- p->pattern = pat;
- p->patternlen = patlen;
- p->origin = origin;
- p->no = no;
- p->token = t;
- *opt->pattern_tail = p;
- opt->pattern_tail = &p->next;
- p->next = NULL;
+ struct grep_pat *p = create_grep_pat(pat, patlen, origin, no, t, 0);
+ do_append_grep_pat(&opt->pattern_tail, p);
}
struct grep_opt *grep_opt_dup(const struct grep_opt *opt)
@@ -430,6 +469,7 @@ void free_grep_patterns(struct grep_opt *opt)
free_pcre_regexp(p);
else
regfree(&p->regexp);
+ free(p->pattern);
break;
default:
break;