Skip to content

Commit

Permalink
diff: fix "multiple regexp" semantics to find hunk header comment
Browse files Browse the repository at this point in the history
When multiple regular expressions are concatenated with "\n", they were
traditionally AND'ed together, and only a line that matches _all_ of them
is taken as a match.  This however is unwieldy when multiple regexp
feature is used to specify alternatives.

This fixes the semantics to take the first match.  A nagative pattern, if
matches, makes the line to fail as before.  A match with a positive
pattern will be the final match, and what it captures in $1 is used as the
hunk header comment.

We could write alternatives using "|" in ERE, but the machinery can only
use captured $1 as the hunk header comment (or $0 if there is no match in
$1), so you cannot write:

    "junk ( A | B ) | garbage ( C | D )"

and expect both "junk" and "garbage" to get stripped with the existing
code.  With this fix, you can write it as:

    "junk ( A | B ) \n garbage ( C | D )"

and the way capture works would match the user expectation more
naturally.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information
Junio C Hamano committed Sep 20, 2008
1 parent 1883a0d commit 3d8dccd
Show file tree
Hide file tree
Showing 2 changed files with 11 additions and 8 deletions.
2 changes: 1 addition & 1 deletion diff.c
Original file line number Diff line number Diff line change
Expand Up @@ -1414,7 +1414,7 @@ static const struct funcname_pattern_entry builtin_funcname_pattern[] = {
{ "pascal",
"^((procedure|function|constructor|destructor|interface|"
"implementation|initialization|finalization)[ \t]*.*)$"
"|"
"\n"
"^(.*=[ \t]*(class|record).*)$",
REG_EXTENDED },
{ "php", "^[\t ]*((function|class).*)", REG_EXTENDED },
Expand Down
17 changes: 10 additions & 7 deletions xdiff-interface.c
Original file line number Diff line number Diff line change
Expand Up @@ -194,26 +194,29 @@ static long ff_regexp(const char *line, long len,
char *line_buffer = xstrndup(line, len); /* make NUL terminated */
struct ff_regs *regs = priv;
regmatch_t pmatch[2];
int result = 0, i;
int i;
int result = -1;

for (i = 0; i < regs->nr; i++) {
struct ff_reg *reg = regs->array + i;
if (reg->negate ^ !!regexec(&reg->re,
line_buffer, 2, pmatch, 0)) {
free(line_buffer);
return -1;
if (!regexec(&reg->re, line_buffer, 2, pmatch, 0)) {
if (reg->negate)
goto fail;
break;
}
}
if (regs->nr <= i)
goto fail;
i = pmatch[1].rm_so >= 0 ? 1 : 0;
line += pmatch[i].rm_so;
result = pmatch[i].rm_eo - pmatch[i].rm_so;
if (result > buffer_size)
result = buffer_size;
else
while (result > 0 && (isspace(line[result - 1]) ||
line[result - 1] == '\n'))
while (result > 0 && (isspace(line[result - 1])))
result--;
memcpy(buffer, line, result);
fail:
free(line_buffer);
return result;
}
Expand Down

0 comments on commit 3d8dccd

Please sign in to comment.