That feature is similar to the custom diff driver, but the user only has to provide a text filter (a command to convert a file into a plain-text representation). Git takes care of diffing, mode change, ... For example, with [textconv "odt2txt"] command=odt2txt *.ods textconv=odt2txt *.odp textconv=odt2txt *.odt textconv=odt2txt One can use "git diff" on OpenOffice files (including "git diff --color" and friends). This could be extended so that "git blame" can use it also. --- diff.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 68 insertions(+), 0 deletions(-) diff --git a/diff.c b/diff.c index 6917981..7cbc42b 100644 --- a/diff.c +++ b/diff.c @@ -181,6 +181,12 @@ int git_diff_ui_config(const char *var, const char *value, void *cb) if (ep != var + 4 && !strcmp(ep, ".command")) return parse_ll_command(var, var + 5, ep, value, DIFF_DRIVER); } + if (!prefixcmp(var, "textconv.")) { + const char *ep = strrchr(var, '.'); + + if (ep != var + 8 && !strcmp(ep, ".command")) + return parse_ll_command(var, var + 9, ep, value, TEXTCONV_DRIVER); + } return git_diff_basic_config(var, value, cb); } @@ -262,6 +268,10 @@ static struct diff_tempfile { /* Forward declarations */ static int run_command_to_buf(const char **argv, char **buf, size_t * size); +static const char *external_cmd_attr(const char *name, int driver_index); +static void prepare_temp_file(const char *name, + struct diff_tempfile *temp, + struct diff_filespec *one); /* End forward declarations */ static int count_lines(const char *data, int size) @@ -1511,6 +1521,52 @@ static int run_command_to_buf(const char **argv, char **buf, size_t * size) return 0; } +static int textconv_two_files(const char *textconv, + const char *name_a, + const char *name_b, + mmfile_t *mf1, + mmfile_t *mf2, + struct diff_filespec *one, + struct diff_filespec *two) +{ + const char *spawn_arg[3]; + const char **arg = &spawn_arg[0]; + struct diff_tempfile *temp = diff_temp; + char *buf_a, *buf_b; + size_t size_a, size_b; + prepare_temp_file(name_a, &temp[0], one); + *arg++ = textconv; + *arg++ = temp[0].name; + *arg++ = NULL; + /* + * Run both commands before touching arguments to make sure we + * do all or nothing. + */ + if(run_command_to_buf(spawn_arg, &buf_a, &size_a)) + return -1; + + prepare_temp_file(name_b, &temp[1], two); + spawn_arg[1] = temp[1].name; + if(run_command_to_buf(spawn_arg, &buf_b, &size_b)) + return -1; + + mf1->ptr = buf_a; + mf1->size = (long)size_a; + one->data = mf1->ptr; + one->size = mf1->size; + one->should_free = 1; + one->should_munmap = 1; + + mf2->ptr = buf_b; + mf2->size = (long)size_b; + two->data = mf2->ptr; + two->size = mf2->size; + two->should_free = 1; + two->should_munmap = 1; + return 0; +} + + static void builtin_diff(const char *name_a, const char *name_b, struct diff_filespec *one, @@ -1574,6 +1630,18 @@ static void builtin_diff(const char *name_a, if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0) die("unable to read files to diff"); + const char * textconv = external_cmd_attr(name_a, TEXTCONV_DRIVER); + const char * textconvb = external_cmd_attr(name_b, TEXTCONV_DRIVER); + + /* + * Only use the textconv driver if it is set, and is the same + * for source and destination file. + */ + if (textconv && textconvb && !strcmp(textconv, textconvb)) + if(textconv_two_files(textconv, name_a, name_b, &mf1, &mf2, one, two)) + fprintf(stderr, "warning: textconv filter failed, " + "falling back to plain diff\n"); + if (!DIFF_OPT_TST(o, TEXT) && (diff_filespec_is_binary(one) || diff_filespec_is_binary(two))) { /* Quite common confusing case */ -- 1.6.0.2.312.g1ef81a -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html