Merge branch 'bc/maint-diff-hunk-header-fix' into maint

* bc/maint-diff-hunk-header-fix:
  t4018-diff-funcname: test syntax of builtin xfuncname patterns
  diff hunk pattern: fix misconverted "\{" tex macro introducers
  diff: use extended regexp to find hunk headers
  diff.*.xfuncname which uses "extended" regex's for hunk header selection
  diff.c: associate a flag with each pattern and use it for compiling regex
  diff.c: return pattern entry pointer rather than just the hunk header pattern

Conflicts:
	Documentation/gitattributes.txt
This commit is contained in:
Shawn O. Pearce 2008-09-29 10:23:19 -07:00
commit edb7e82f72
5 changed files with 72 additions and 49 deletions

View File

@ -288,13 +288,13 @@ for paths.
*.tex diff=tex *.tex diff=tex
------------------------ ------------------------
Then, you would define a "diff.tex.funcname" configuration to Then, you would define a "diff.tex.xfuncname" configuration to
specify a regular expression that matches a line that you would specify a regular expression that matches a line that you would
want to appear as the hunk header "TEXT", like this: want to appear as the hunk header "TEXT", like this:
------------------------ ------------------------
[diff "tex"] [diff "tex"]
funcname = "^\\(\\\\\\(sub\\)*section{.*\\)$" xfuncname = "^(\\\\(sub)*section\\{.*)$"
------------------------ ------------------------
Note. A single level of backslashes are eaten by the Note. A single level of backslashes are eaten by the

98
diff.c
View File

@ -94,32 +94,37 @@ static int parse_lldiff_command(const char *var, const char *ep, const char *val
* to define a customized regexp to find the beginning of a function to * to define a customized regexp to find the beginning of a function to
* be used for hunk header lines of "diff -p" style output. * be used for hunk header lines of "diff -p" style output.
*/ */
static struct funcname_pattern { struct funcname_pattern_entry {
char *name; char *name;
char *pattern; char *pattern;
struct funcname_pattern *next; int cflags;
};
static struct funcname_pattern_list {
struct funcname_pattern_list *next;
struct funcname_pattern_entry e;
} *funcname_pattern_list; } *funcname_pattern_list;
static int parse_funcname_pattern(const char *var, const char *ep, const char *value) static int parse_funcname_pattern(const char *var, const char *ep, const char *value, int cflags)
{ {
const char *name; const char *name;
int namelen; int namelen;
struct funcname_pattern *pp; struct funcname_pattern_list *pp;
name = var + 5; /* "diff." */ name = var + 5; /* "diff." */
namelen = ep - name; namelen = ep - name;
for (pp = funcname_pattern_list; pp; pp = pp->next) for (pp = funcname_pattern_list; pp; pp = pp->next)
if (!strncmp(pp->name, name, namelen) && !pp->name[namelen]) if (!strncmp(pp->e.name, name, namelen) && !pp->e.name[namelen])
break; break;
if (!pp) { if (!pp) {
pp = xcalloc(1, sizeof(*pp)); pp = xcalloc(1, sizeof(*pp));
pp->name = xmemdupz(name, namelen); pp->e.name = xmemdupz(name, namelen);
pp->next = funcname_pattern_list; pp->next = funcname_pattern_list;
funcname_pattern_list = pp; funcname_pattern_list = pp;
} }
free(pp->pattern); free(pp->e.pattern);
pp->pattern = xstrdup(value); pp->e.pattern = xstrdup(value);
pp->e.cflags = cflags;
return 0; return 0;
} }
@ -182,7 +187,13 @@ int git_diff_basic_config(const char *var, const char *value, void *cb)
if (!strcmp(ep, ".funcname")) { if (!strcmp(ep, ".funcname")) {
if (!value) if (!value)
return config_error_nonbool(var); return config_error_nonbool(var);
return parse_funcname_pattern(var, ep, value); return parse_funcname_pattern(var, ep, value,
0);
} else if (!strcmp(ep, ".xfuncname")) {
if (!value)
return config_error_nonbool(var);
return parse_funcname_pattern(var, ep, value,
REG_EXTENDED);
} }
} }
} }
@ -1377,39 +1388,40 @@ int diff_filespec_is_binary(struct diff_filespec *one)
return one->is_binary; return one->is_binary;
} }
static const char *funcname_pattern(const char *ident) static const struct funcname_pattern_entry *funcname_pattern(const char *ident)
{ {
struct funcname_pattern *pp; struct funcname_pattern_list *pp;
for (pp = funcname_pattern_list; pp; pp = pp->next) for (pp = funcname_pattern_list; pp; pp = pp->next)
if (!strcmp(ident, pp->name)) if (!strcmp(ident, pp->e.name))
return pp->pattern; return &pp->e;
return NULL; return NULL;
} }
static struct builtin_funcname_pattern { static const struct funcname_pattern_entry builtin_funcname_pattern[] = {
const char *name; { "java",
const char *pattern; "!^[ \t]*(catch|do|for|if|instanceof|new|return|switch|throw|while)\n"
} builtin_funcname_pattern[] = { "^[ \t]*(([ \t]*[A-Za-z_][A-Za-z_0-9]*){2,}[ \t]*\\([^;]*)$",
{ "java", "!^[ ]*\\(catch\\|do\\|for\\|if\\|instanceof\\|" REG_EXTENDED },
"new\\|return\\|switch\\|throw\\|while\\)\n" { "pascal",
"^[ ]*\\(\\([ ]*" "^((procedure|function|constructor|destructor|interface|"
"[A-Za-z_][A-Za-z_0-9]*\\)\\{2,\\}" "implementation|initialization|finalization)[ \t]*.*)$"
"[ ]*([^;]*\\)$" }, "|"
{ "pascal", "^\\(\\(procedure\\|function\\|constructor\\|" "^(.*=[ \t]*(class|record).*)$",
"destructor\\|interface\\|implementation\\|" REG_EXTENDED },
"initialization\\|finalization\\)[ \t]*.*\\)$" { "bibtex", "(@[a-zA-Z]{1,}[ \t]*\\{{0,1}[ \t]*[^ \t\"@',\\#}{~%]*).*$",
"\\|" REG_EXTENDED },
"^\\(.*=[ \t]*\\(class\\|record\\).*\\)$" { "tex",
}, "^(\\\\((sub)*section|chapter|part)\\*{0,1}\\{.*)$",
{ "bibtex", "\\(@[a-zA-Z]\\{1,\\}[ \t]*{\\{0,1\\}[ \t]*[^ \t\"@',\\#}{~%]*\\).*$" }, REG_EXTENDED },
{ "tex", "^\\(\\\\\\(\\(sub\\)*section\\|chapter\\|part\\)\\*\\{0,1\\}{.*\\)$" }, { "ruby", "^[ \t]*((class|module|def)[ \t].*)$",
{ "ruby", "^\\s*\\(\\(class\\|module\\|def\\)\\s.*\\)$" }, REG_EXTENDED },
}; };
static const char *diff_funcname_pattern(struct diff_filespec *one) static const struct funcname_pattern_entry *diff_funcname_pattern(struct diff_filespec *one)
{ {
const char *ident, *pattern; const char *ident;
const struct funcname_pattern_entry *pe;
int i; int i;
diff_filespec_check_attr(one); diff_filespec_check_attr(one);
@ -1424,9 +1436,9 @@ static const char *diff_funcname_pattern(struct diff_filespec *one)
return funcname_pattern("default"); return funcname_pattern("default");
/* Look up custom "funcname.$ident" regexp from config. */ /* Look up custom "funcname.$ident" regexp from config. */
pattern = funcname_pattern(ident); pe = funcname_pattern(ident);
if (pattern) if (pe)
return pattern; return pe;
/* /*
* And define built-in fallback patterns here. Note that * And define built-in fallback patterns here. Note that
@ -1434,7 +1446,7 @@ static const char *diff_funcname_pattern(struct diff_filespec *one)
*/ */
for (i = 0; i < ARRAY_SIZE(builtin_funcname_pattern); i++) for (i = 0; i < ARRAY_SIZE(builtin_funcname_pattern); i++)
if (!strcmp(ident, builtin_funcname_pattern[i].name)) if (!strcmp(ident, builtin_funcname_pattern[i].name))
return builtin_funcname_pattern[i].pattern; return &builtin_funcname_pattern[i];
return NULL; return NULL;
} }
@ -1512,11 +1524,11 @@ static void builtin_diff(const char *name_a,
xdemitconf_t xecfg; xdemitconf_t xecfg;
xdemitcb_t ecb; xdemitcb_t ecb;
struct emit_callback ecbdata; struct emit_callback ecbdata;
const char *funcname_pattern; const struct funcname_pattern_entry *pe;
funcname_pattern = diff_funcname_pattern(one); pe = diff_funcname_pattern(one);
if (!funcname_pattern) if (!pe)
funcname_pattern = diff_funcname_pattern(two); pe = diff_funcname_pattern(two);
memset(&xecfg, 0, sizeof(xecfg)); memset(&xecfg, 0, sizeof(xecfg));
memset(&ecbdata, 0, sizeof(ecbdata)); memset(&ecbdata, 0, sizeof(ecbdata));
@ -1528,8 +1540,8 @@ static void builtin_diff(const char *name_a,
xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts; xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts;
xecfg.ctxlen = o->context; xecfg.ctxlen = o->context;
xecfg.flags = XDL_EMIT_FUNCNAMES; xecfg.flags = XDL_EMIT_FUNCNAMES;
if (funcname_pattern) if (pe)
xdiff_set_find_func(&xecfg, funcname_pattern); xdiff_set_find_func(&xecfg, pe->pattern, pe->cflags);
if (!diffopts) if (!diffopts)
; ;
else if (!prefixcmp(diffopts, "--unified=")) else if (!prefixcmp(diffopts, "--unified="))

View File

@ -32,7 +32,18 @@ EOF
sed 's/beer\\/beer,\\/' < Beer.java > Beer-correct.java sed 's/beer\\/beer,\\/' < Beer.java > Beer-correct.java
builtin_patterns="bibtex java pascal ruby tex"
for p in $builtin_patterns
do
test_expect_success "builtin $p pattern compiles" '
echo "*.java diff=$p" > .gitattributes &&
! ( git diff --no-index Beer.java Beer-correct.java 2>&1 |
grep "fatal" > /dev/null )
'
done
test_expect_success 'default behaviour' ' test_expect_success 'default behaviour' '
rm -f .gitattributes &&
git diff --no-index Beer.java Beer-correct.java | git diff --no-index Beer.java Beer-correct.java |
grep "^@@.*@@ public class Beer" grep "^@@.*@@ public class Beer"
' '
@ -58,7 +69,7 @@ test_expect_success 'last regexp must not be negated' '
' '
test_expect_success 'alternation in pattern' ' test_expect_success 'alternation in pattern' '
git config diff.java.funcname "^[ ]*\\(\\(public\\|static\\).*\\)$" git config diff.java.xfuncname "^[ ]*((public|static).*)$" &&
git diff --no-index Beer.java Beer-correct.java | git diff --no-index Beer.java Beer-correct.java |
grep "^@@.*@@ public static void main(" grep "^@@.*@@ public static void main("
' '

View File

@ -206,7 +206,7 @@ static long ff_regexp(const char *line, long len,
return result; return result;
} }
void xdiff_set_find_func(xdemitconf_t *xecfg, const char *value) void xdiff_set_find_func(xdemitconf_t *xecfg, const char *value, int cflags)
{ {
int i; int i;
struct ff_regs *regs; struct ff_regs *regs;
@ -231,7 +231,7 @@ void xdiff_set_find_func(xdemitconf_t *xecfg, const char *value)
expression = buffer = xstrndup(value, ep - value); expression = buffer = xstrndup(value, ep - value);
else else
expression = value; expression = value;
if (regcomp(&reg->re, expression, 0)) if (regcomp(&reg->re, expression, cflags))
die("Invalid regexp to look for hunk header: %s", expression); die("Invalid regexp to look for hunk header: %s", expression);
free(buffer); free(buffer);
value = ep + 1; value = ep + 1;

View File

@ -21,6 +21,6 @@ int parse_hunk_header(char *line, int len,
int read_mmfile(mmfile_t *ptr, const char *filename); int read_mmfile(mmfile_t *ptr, const char *filename);
int buffer_is_binary(const char *ptr, unsigned long size); int buffer_is_binary(const char *ptr, unsigned long size);
extern void xdiff_set_find_func(xdemitconf_t *xecfg, const char *line); extern void xdiff_set_find_func(xdemitconf_t *xecfg, const char *line, int cflags);
#endif #endif