diff options
author | Junio C Hamano <junkio@cox.net> | 2005-04-25 18:22:47 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-25 18:22:47 -0700 |
commit | 86436c28289eedd2ee9b7f9c872a0ed039866a0f (patch) | |
tree | 780ecf60c2d10084ab26758c093319d0c6c86480 /diff.c | |
parent | ab7df1874d87d3f7494397442e67e900b580a346 (diff) | |
download | git-86436c28289eedd2ee9b7f9c872a0ed039866a0f.tar.gz |
[PATCH] Split external diff command interface to a separate file.
With this patch, the non-core'ish part of show-diff command that
invokes an external "diff" comand to obtain patches is split
into a separate file. The next patch will introduce a new
command, diff-tree-helper, which uses this common diff interface
to format diff-tree and diff-cache output into a patch form.
Signed-off-by: Junio C Hamano <junkio@cox.net>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'diff.c')
-rw-r--r-- | diff.c | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/diff.c b/diff.c new file mode 100644 index 0000000000..dcefe983af --- /dev/null +++ b/diff.c @@ -0,0 +1,106 @@ +#include "cache.h" +#include "diff.h" + +static char *diff_cmd = "diff -L 'k/%s' -L 'l/%s' "; +static char *diff_opts = "-p -u"; +static char *diff_arg_forward = " - '%s'"; +static char *diff_arg_reverse = " '%s' -"; + +void prepare_diff_cmd(void) +{ + /* + * Default values above are meant to match the + * Linux kernel development style. Examples of + * alternative styles you can specify via environment + * variables are: + * + * GIT_DIFF_CMD="diff -L '%s' -L '%s'" + * GIT_DIFF_OPTS="-c"; + */ + diff_cmd = getenv("GIT_DIFF_CMD") ? : diff_cmd; + diff_opts = getenv("GIT_DIFF_OPTS") ? : diff_opts; +} + +/* Help to copy the thing properly quoted for the shell safety. + * any single quote is replaced with '\'', and the caller is + * expected to enclose the result within a single quote pair. + * + * E.g. + * original sq_expand result + * name ==> name ==> 'name' + * a b ==> a b ==> 'a b' + * a'b ==> a'\''b ==> 'a'\''b' + */ +static char *sq_expand(const char *src) +{ + static char *buf = NULL; + int cnt, c; + const char *cp; + char *bp; + + /* count bytes needed to store the quoted string. */ + for (cnt = 1, cp = src; *cp; cnt++, cp++) + if (*cp == '\'') + cnt += 3; + + if (! (buf = malloc(cnt))) + return buf; + bp = buf; + while ((c = *src++)) { + if (c != '\'') + *bp++ = c; + else { + bp = strcpy(bp, "'\\''"); + bp += 4; + } + } + *bp = 0; + return buf; +} + +void show_differences(const char *name, /* filename on the filesystem */ + const char *label, /* diff label to use */ + void *old_contents, /* contents in core */ + unsigned long long old_size, /* size in core */ + int reverse /* 0: diff core file + 1: diff file core */) +{ + FILE *f; + char *name_sq = sq_expand(name); + const char *label_sq = (name != label) ? sq_expand(label) : name_sq; + char *diff_arg = reverse ? diff_arg_reverse : diff_arg_forward; + int cmd_size = strlen(name_sq) + strlen(label_sq) * 2 + + strlen(diff_cmd) + strlen(diff_opts) + strlen(diff_arg); + char *cmd = malloc(cmd_size); + int next_at; + + fflush(stdout); + next_at = snprintf(cmd, cmd_size, diff_cmd, label_sq, label_sq); + next_at += snprintf(cmd+next_at, cmd_size-next_at, "%s", diff_opts); + next_at += snprintf(cmd+next_at, cmd_size-next_at, diff_arg, name_sq); + f = popen(cmd, "w"); + if (old_size) + fwrite(old_contents, old_size, 1, f); + pclose(f); + if (label_sq != name_sq) + free((void*)label_sq); /* constness */ + free(name_sq); + free(cmd); +} + +void show_diff_empty(const unsigned char *sha1, + const char *name, + int reverse) +{ + char *old; + unsigned long int size; + unsigned char type[20]; + + old = read_sha1_file(sha1, type, &size); + if (! old) { + error("unable to read blob object for %s (%s)", name, + sha1_to_hex(sha1)); + return; + } + show_differences("/dev/null", name, old, size, reverse); +} |