Skip to content

Commit 526a858

Browse files
René Scharfegitster
authored andcommitted
grep: support newline separated pattern list
Currently, patterns that contain newline characters don't match anything when given to git grep. Regular grep(1) interprets patterns as lists of newline separated search strings instead. Implement this functionality by creating and inserting extra grep_pat structures for patterns consisting of multiple lines when appending to the pattern lists. For simplicity, all pattern strings are duplicated. The original pattern is truncated in place to make it contain only the first line. Requested-by: Torne (Richard Coles) <[email protected]> Signed-off-by: Rene Scharfe <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 2b3873f commit 526a858

File tree

4 files changed

+41
-3
lines changed

4 files changed

+41
-3
lines changed

Documentation/git-grep.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@ SYNOPSIS
2929
DESCRIPTION
3030
-----------
3131
Look for specified patterns in the tracked files in the work tree, blobs
32-
registered in the index file, or blobs in given tree objects.
32+
registered in the index file, or blobs in given tree objects. Patterns
33+
are lists of one or more search expressions separated by newline
34+
characters. An empty string as search expression matches all lines.
3335

3436

3537
CONFIGURATION

grep.c

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ static struct grep_pat *create_grep_pat(const char *pat, size_t patlen,
99
enum grep_header_field field)
1010
{
1111
struct grep_pat *p = xcalloc(1, sizeof(*p));
12-
p->pattern = pat;
12+
p->pattern = xmemdupz(pat, patlen);
1313
p->patternlen = patlen;
1414
p->origin = origin;
1515
p->no = no;
@@ -23,6 +23,36 @@ static void do_append_grep_pat(struct grep_pat ***tail, struct grep_pat *p)
2323
**tail = p;
2424
*tail = &p->next;
2525
p->next = NULL;
26+
27+
switch (p->token) {
28+
case GREP_PATTERN: /* atom */
29+
case GREP_PATTERN_HEAD:
30+
case GREP_PATTERN_BODY:
31+
for (;;) {
32+
struct grep_pat *new_pat;
33+
size_t len = 0;
34+
char *cp = p->pattern + p->patternlen, *nl = NULL;
35+
while (++len <= p->patternlen) {
36+
if (*(--cp) == '\n') {
37+
nl = cp;
38+
break;
39+
}
40+
}
41+
if (!nl)
42+
break;
43+
new_pat = create_grep_pat(nl + 1, len - 1, p->origin,
44+
p->no, p->token, p->field);
45+
new_pat->next = p->next;
46+
if (!p->next)
47+
*tail = &new_pat->next;
48+
p->next = new_pat;
49+
*nl = '\0';
50+
p->patternlen -= len;
51+
}
52+
break;
53+
default:
54+
break;
55+
}
2656
}
2757

2858
void append_header_grep_pattern(struct grep_opt *opt,
@@ -408,6 +438,7 @@ void free_grep_patterns(struct grep_opt *opt)
408438
free_pcre_regexp(p);
409439
else
410440
regfree(&p->regexp);
441+
free(p->pattern);
411442
break;
412443
default:
413444
break;

grep.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ struct grep_pat {
3535
const char *origin;
3636
int no;
3737
enum grep_pat_token token;
38-
const char *pattern;
38+
char *pattern;
3939
size_t patternlen;
4040
enum grep_header_field field;
4141
regex_t regexp;

t/t7810-grep.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,11 @@ test_expect_success 'grep -f, multiple patterns' '
322322
test_cmp expected actual
323323
'
324324

325+
test_expect_success 'grep, multiple patterns' '
326+
git grep "$(cat patterns)" >actual &&
327+
test_cmp expected actual
328+
'
329+
325330
cat >expected <<EOF
326331
file:foo mmap bar
327332
file:foo_mmap bar

0 commit comments

Comments
 (0)