diff: introduce diff.<driver>.binary
authorJeff King <peff@peff.net>
Sun, 5 Oct 2008 21:43:36 +0000 (17:43 -0400)
committerJunio C Hamano <gitster@pobox.com>
Sat, 18 Oct 2008 15:02:26 +0000 (08:02 -0700)
The "diff" gitattribute is somewhat overloaded right now. It
can say one of three things:

  1. this file is definitely binary, or definitely not
     (i.e., diff or !diff)
  2. this file should use an external diff engine (i.e.,
     diff=foo, diff.foo.command = custom-script)
  3. this file should use particular funcname patterns
     (i.e., diff=foo, diff.foo.(x?)funcname = some-regex)

Most of the time, there is no conflict between these uses,
since using one implies that the other is irrelevant (e.g.,
an external diff engine will decide for itself whether the
file is binary).

However, there is at least one conflicting situation: there
is no way to say "use the regular rules to determine whether
this file is binary, but if we do diff it textually, use
this funcname pattern." That is, currently setting diff=foo
indicates that the file is definitely text.

This patch introduces a "binary" config option for a diff
driver, so that one can explicitly set diff.foo.binary. We
default this value to "don't know". That is, setting a diff
attribute to "foo" and using "diff.foo.funcname" will have
no effect on the binaryness of a file. To get the current
behavior, one can set diff.foo.binary to true.

This patch also has one additional advantage: it cleans up
the interface to the userdiff code a bit. Before, calling
code had to know more about whether attributes were false,
true, or unset to determine binaryness. Now that binaryness
is a property of a driver, we can represent these situations
just by passing back a driver struct.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
diff.c
diffcore.h
userdiff.c
userdiff.h

diff --git a/diff.c b/diff.c
index d50355e842b025fe98808a3800d9b0863f5c1a91..dabd7f50ec28ed804cf5cace06cf72753be562ae 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -1268,46 +1268,37 @@ static void emit_binary_diff(FILE *file, mmfile_t *one, mmfile_t *two)
        emit_binary_diff_body(file, two, one);
 }
 
-static void diff_filespec_check_attr(struct diff_filespec *one)
+void diff_filespec_load_driver(struct diff_filespec *one)
 {
-       struct userdiff_driver *drv;
-       int check_from_data = 0;
-
-       if (one->checked_attr)
-               return;
-
-       drv = userdiff_find_by_path(one->path);
-       one->is_binary = 0;
-
-       /* binaryness */
-       if (drv == USERDIFF_ATTR_TRUE)
-               ;
-       else if (drv == USERDIFF_ATTR_FALSE)
-               one->is_binary = 1;
-       else
-               check_from_data = 1;
-
-       if (check_from_data) {
-               if (!one->data && DIFF_FILE_VALID(one))
-                       diff_populate_filespec(one, 0);
-
-               if (one->data)
-                       one->is_binary = buffer_is_binary(one->data, one->size);
-       }
+       if (!one->driver)
+               one->driver = userdiff_find_by_path(one->path);
+       if (!one->driver)
+               one->driver = userdiff_find_by_name("default");
 }
 
 int diff_filespec_is_binary(struct diff_filespec *one)
 {
-       diff_filespec_check_attr(one);
+       if (one->is_binary == -1) {
+               diff_filespec_load_driver(one);
+               if (one->driver->binary != -1)
+                       one->is_binary = one->driver->binary;
+               else {
+                       if (!one->data && DIFF_FILE_VALID(one))
+                               diff_populate_filespec(one, 0);
+                       if (one->data)
+                               one->is_binary = buffer_is_binary(one->data,
+                                               one->size);
+                       if (one->is_binary == -1)
+                               one->is_binary = 0;
+               }
+       }
        return one->is_binary;
 }
 
 static const struct userdiff_funcname *diff_funcname_pattern(struct diff_filespec *one)
 {
-       struct userdiff_driver *drv = userdiff_find_by_path(one->path);
-       if (!drv)
-               drv = userdiff_find_by_name("default");
-       return drv && drv->funcname.pattern ? &drv->funcname : NULL;
+       diff_filespec_load_driver(one);
+       return one->driver->funcname.pattern ? &one->driver->funcname : NULL;
 }
 
 void diff_set_mnemonic_prefix(struct diff_options *options, const char *a, const char *b)
@@ -1559,6 +1550,7 @@ struct diff_filespec *alloc_filespec(const char *path)
        spec->path = (char *)(spec + 1);
        memcpy(spec->path, path, namelen+1);
        spec->count = 1;
+       spec->is_binary = -1;
        return spec;
 }
 
index 8ae35785fd4439f466620ab9186838e7cb20fa36..713cca785c4b986b5f667086ad43c324f248929c 100644 (file)
@@ -22,6 +22,8 @@
 
 #define MINIMUM_BREAK_SIZE     400 /* do not break a file smaller than this */
 
+struct userdiff_driver;
+
 struct diff_filespec {
        unsigned char sha1[20];
        char *path;
@@ -40,8 +42,10 @@ struct diff_filespec {
 #define DIFF_FILE_VALID(spec) (((spec)->mode) != 0)
        unsigned should_free : 1; /* data should be free()'ed */
        unsigned should_munmap : 1; /* data should be munmap()'ed */
-       unsigned checked_attr : 1;
-       unsigned is_binary : 1; /* data should be considered "binary" */
+
+       struct userdiff_driver *driver;
+       /* data should be considered "binary"; -1 means "don't know yet" */
+       int is_binary;
 };
 
 extern struct diff_filespec *alloc_filespec(const char *);
index 80e2857abb8d6854276261cc99424984217a9029..58478a6912200b6c5784e443072c4427bb8386f5 100644 (file)
@@ -7,7 +7,7 @@ static int ndrivers;
 static int drivers_alloc;
 
 #define FUNCNAME(name, pattern) \
-       { name, NULL, { pattern, REG_EXTENDED } }
+       { name, NULL, -1, { pattern, REG_EXTENDED } }
 static struct userdiff_driver builtin_drivers[] = {
 FUNCNAME("html", "^[ \t]*(<[Hh][1-6][ \t].*>.*)$"),
 FUNCNAME("java",
@@ -32,22 +32,23 @@ FUNCNAME("python", "^[ \t]*((class|def)[ \t].*)$"),
 FUNCNAME("ruby", "^[ \t]*((class|module|def)[ \t].*)$"),
 FUNCNAME("bibtex", "(@[a-zA-Z]{1,}[ \t]*\\{{0,1}[ \t]*[^ \t\"@',\\#}{~%]*).*$"),
 FUNCNAME("tex", "^(\\\\((sub)*section|chapter|part)\\*{0,1}\\{.*)$"),
+{ "default", NULL, -1, { NULL, 0 } },
 };
 #undef FUNCNAME
 
 static struct userdiff_driver driver_true = {
        "diff=true",
        NULL,
+       0,
        { NULL, 0 }
 };
-struct userdiff_driver *USERDIFF_ATTR_TRUE = &driver_true;
 
 static struct userdiff_driver driver_false = {
        "!diff",
        NULL,
+       1,
        { NULL, 0 }
 };
-struct userdiff_driver *USERDIFF_ATTR_FALSE = &driver_false;
 
 static struct userdiff_driver *userdiff_find_by_namelen(const char *k, int len)
 {
@@ -89,6 +90,7 @@ static struct userdiff_driver *parse_driver(const char *var,
                drv = &drivers[ndrivers++];
                memset(drv, 0, sizeof(*drv));
                drv->name = xmemdupz(name, namelen);
+               drv->binary = -1;
        }
        return drv;
 }
@@ -109,6 +111,15 @@ static int parse_string(const char **d, const char *k, const char *v)
        return 1;
 }
 
+static int parse_tristate(int *b, const char *k, const char *v)
+{
+       if (v && !strcasecmp(v, "auto"))
+               *b = -1;
+       else
+               *b = git_config_bool(k, v);
+       return 1;
+}
+
 int userdiff_config_basic(const char *k, const char *v)
 {
        struct userdiff_driver *drv;
@@ -117,6 +128,8 @@ int userdiff_config_basic(const char *k, const char *v)
                return parse_funcname(&drv->funcname, k, v, 0);
        if ((drv = parse_driver(k, v, "xfuncname")))
                return parse_funcname(&drv->funcname, k, v, REG_EXTENDED);
+       if ((drv = parse_driver(k, v, "binary")))
+               return parse_tristate(&drv->binary, k, v);
 
        return 0;
 }
index c64c5f56697cc45beadf18d8e645c7096b42c82c..1c1eb042b44fc9e5085c34ffbd06e7e55043580b 100644 (file)
@@ -9,12 +9,10 @@ struct userdiff_funcname {
 struct userdiff_driver {
        const char *name;
        const char *external;
+       int binary;
        struct userdiff_funcname funcname;
 };
 
-extern struct userdiff_driver *USERDIFF_ATTR_TRUE;
-extern struct userdiff_driver *USERDIFF_ATTR_FALSE;
-
 int userdiff_config_basic(const char *k, const char *v);
 int userdiff_config_porcelain(const char *k, const char *v);
 struct userdiff_driver *userdiff_find_by_name(const char *name);