зеркало из https://github.com/microsoft/git.git
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()
This commit is contained in:
Коммит
2147cb2762
|
@ -31,7 +31,9 @@ SYNOPSIS
|
|||
DESCRIPTION
|
||||
-----------
|
||||
Look for specified patterns in the tracked files in the work tree, blobs
|
||||
registered in the index file, or blobs in given tree objects.
|
||||
registered in the index file, or blobs in given tree objects. Patterns
|
||||
are lists of one or more search expressions separated by newline
|
||||
characters. An empty string as search expression matches all lines.
|
||||
|
||||
|
||||
CONFIGURATION
|
||||
|
|
|
@ -600,15 +600,12 @@ static int file_callback(const struct option *opt, const char *arg, int unset)
|
|||
if (!patterns)
|
||||
die_errno(_("cannot open '%s'"), arg);
|
||||
while (strbuf_getline(&sb, patterns, '\n') == 0) {
|
||||
char *s;
|
||||
size_t len;
|
||||
|
||||
/* ignore empty line like grep does */
|
||||
if (sb.len == 0)
|
||||
continue;
|
||||
|
||||
s = strbuf_detach(&sb, &len);
|
||||
append_grep_pat(grep_opt, s, len, arg, ++lno, GREP_PATTERN);
|
||||
append_grep_pat(grep_opt, sb.buf, sb.len, arg, ++lno,
|
||||
GREP_PATTERN);
|
||||
}
|
||||
if (!from_stdin)
|
||||
fclose(patterns);
|
||||
|
|
74
grep.c
74
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;
|
||||
|
|
2
grep.h
2
grep.h
|
@ -38,7 +38,7 @@ struct grep_pat {
|
|||
const char *origin;
|
||||
int no;
|
||||
enum grep_pat_token token;
|
||||
const char *pattern;
|
||||
char *pattern;
|
||||
size_t patternlen;
|
||||
enum grep_header_field field;
|
||||
regex_t regexp;
|
||||
|
|
|
@ -351,6 +351,11 @@ test_expect_success 'grep -f, multiple patterns' '
|
|||
test_cmp expected actual
|
||||
'
|
||||
|
||||
test_expect_success 'grep, multiple patterns' '
|
||||
git grep "$(cat patterns)" >actual &&
|
||||
test_cmp expected actual
|
||||
'
|
||||
|
||||
cat >expected <<EOF
|
||||
file:foo mmap bar
|
||||
file:foo_mmap bar
|
||||
|
|
Загрузка…
Ссылка в новой задаче