diff: fix "multiple regexp" semantics to find hunk header comment
authorJunio C Hamano <gitster@pobox.com>
Sat, 20 Sep 2008 07:52:11 +0000 (00:52 -0700)
committerJunio C Hamano <gitster@pobox.com>
Sat, 20 Sep 2008 07:52:11 +0000 (00:52 -0700)
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>
diff.c
xdiff-interface.c

diff --git a/diff.c b/diff.c
index a733010170f489cb6945a0ec4bd98727303651d6..1bcbbd5bb1e67dc238fe4f773024d49c1f8d2af7 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -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 },
index 7f1a7d3ffc62450600852059f046a482af0591ab..6c6bb19973475d9db7dfc18d5695c1bf3ec7359e 100644 (file)
@@ -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;
 }