зеркало из 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
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
Look for specified patterns in the tracked files in the work tree, blobs
|
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
|
CONFIGURATION
|
||||||
|
|
|
@ -600,15 +600,12 @@ static int file_callback(const struct option *opt, const char *arg, int unset)
|
||||||
if (!patterns)
|
if (!patterns)
|
||||||
die_errno(_("cannot open '%s'"), arg);
|
die_errno(_("cannot open '%s'"), arg);
|
||||||
while (strbuf_getline(&sb, patterns, '\n') == 0) {
|
while (strbuf_getline(&sb, patterns, '\n') == 0) {
|
||||||
char *s;
|
|
||||||
size_t len;
|
|
||||||
|
|
||||||
/* ignore empty line like grep does */
|
/* ignore empty line like grep does */
|
||||||
if (sb.len == 0)
|
if (sb.len == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
s = strbuf_detach(&sb, &len);
|
append_grep_pat(grep_opt, sb.buf, sb.len, arg, ++lno,
|
||||||
append_grep_pat(grep_opt, s, len, arg, ++lno, GREP_PATTERN);
|
GREP_PATTERN);
|
||||||
}
|
}
|
||||||
if (!from_stdin)
|
if (!from_stdin)
|
||||||
fclose(patterns);
|
fclose(patterns);
|
||||||
|
|
74
grep.c
74
grep.c
|
@ -3,18 +3,64 @@
|
||||||
#include "userdiff.h"
|
#include "userdiff.h"
|
||||||
#include "xdiff-interface.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));
|
struct grep_pat *p = xcalloc(1, sizeof(*p));
|
||||||
p->pattern = pat;
|
p->pattern = xmemdupz(pat, patlen);
|
||||||
p->patternlen = strlen(pat);
|
p->patternlen = patlen;
|
||||||
p->origin = "header";
|
p->origin = origin;
|
||||||
p->no = 0;
|
p->no = no;
|
||||||
p->token = GREP_PATTERN_HEAD;
|
p->token = t;
|
||||||
p->field = field;
|
p->field = field;
|
||||||
*opt->header_tail = p;
|
return p;
|
||||||
opt->header_tail = &p->next;
|
}
|
||||||
|
|
||||||
|
static void do_append_grep_pat(struct grep_pat ***tail, struct grep_pat *p)
|
||||||
|
{
|
||||||
|
**tail = p;
|
||||||
|
*tail = &p->next;
|
||||||
p->next = NULL;
|
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,
|
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,
|
void append_grep_pat(struct grep_opt *opt, const char *pat, size_t patlen,
|
||||||
const char *origin, int no, enum grep_pat_token t)
|
const char *origin, int no, enum grep_pat_token t)
|
||||||
{
|
{
|
||||||
struct grep_pat *p = xcalloc(1, sizeof(*p));
|
struct grep_pat *p = create_grep_pat(pat, patlen, origin, no, t, 0);
|
||||||
p->pattern = pat;
|
do_append_grep_pat(&opt->pattern_tail, p);
|
||||||
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_opt *grep_opt_dup(const struct grep_opt *opt)
|
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);
|
free_pcre_regexp(p);
|
||||||
else
|
else
|
||||||
regfree(&p->regexp);
|
regfree(&p->regexp);
|
||||||
|
free(p->pattern);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
2
grep.h
2
grep.h
|
@ -38,7 +38,7 @@ struct grep_pat {
|
||||||
const char *origin;
|
const char *origin;
|
||||||
int no;
|
int no;
|
||||||
enum grep_pat_token token;
|
enum grep_pat_token token;
|
||||||
const char *pattern;
|
char *pattern;
|
||||||
size_t patternlen;
|
size_t patternlen;
|
||||||
enum grep_header_field field;
|
enum grep_header_field field;
|
||||||
regex_t regexp;
|
regex_t regexp;
|
||||||
|
|
|
@ -351,6 +351,11 @@ test_expect_success 'grep -f, multiple patterns' '
|
||||||
test_cmp expected actual
|
test_cmp expected actual
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'grep, multiple patterns' '
|
||||||
|
git grep "$(cat patterns)" >actual &&
|
||||||
|
test_cmp expected actual
|
||||||
|
'
|
||||||
|
|
||||||
cat >expected <<EOF
|
cat >expected <<EOF
|
||||||
file:foo mmap bar
|
file:foo mmap bar
|
||||||
file:foo_mmap bar
|
file:foo_mmap bar
|
||||||
|
|
Загрузка…
Ссылка в новой задаче