X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=diff.c;h=a14e6644ca9a39d0a0e1702ccefadf7a5bb64081;hb=2283645b85dc91ca958b05066511083255a8612a;hp=4440465b4781cb62bdd6a0ea3d04617287cc5ca1;hpb=dad7230a1c9e6d4be2cbc1596406819975588233;p=git.git diff --git a/diff.c b/diff.c index 4440465b..a14e6644 100644 --- a/diff.c +++ b/diff.c @@ -10,8 +10,6 @@ #include "diffcore.h" #include "xdiff/xdiff.h" -static const char *diff_opts = "-pu"; - static int use_size_cache; int diff_rename_limit_default = -1; @@ -70,25 +68,10 @@ static const char *external_diff(void) { static const char *external_diff_cmd = NULL; static int done_preparing = 0; - const char *env_diff_opts; if (done_preparing) return external_diff_cmd; - - /* - * 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_OPTS="-c"; - */ external_diff_cmd = getenv("GIT_EXTERNAL_DIFF"); - - /* In case external diff fails... */ - env_diff_opts = getenv("GIT_DIFF_OPTS"); - if (env_diff_opts) diff_opts = env_diff_opts; - done_preparing = 1; return external_diff_cmd; } @@ -102,13 +85,12 @@ static struct diff_tempfile { char tmp_path[TEMPFILE_PATH_LEN]; } diff_temp[2]; -static int count_lines(const char *filename) +static int count_lines(const char *data, int size) { - FILE *in; int count, ch, completely_empty = 1, nl_just_seen = 0; - in = fopen(filename, "r"); count = 0; - while ((ch = fgetc(in)) != EOF) + while (0 < size--) { + ch = *data++; if (ch == '\n') { count++; nl_just_seen = 1; @@ -118,7 +100,7 @@ static int count_lines(const char *filename) nl_just_seen = 0; completely_empty = 0; } - fclose(in); + } if (completely_empty) return 0; if (!nl_just_seen) @@ -141,12 +123,11 @@ static void print_line_count(int count) } } -static void copy_file(int prefix, const char *filename) +static void copy_file(int prefix, const char *data, int size) { - FILE *in; int ch, nl_just_seen = 1; - in = fopen(filename, "r"); - while ((ch = fgetc(in)) != EOF) { + while (0 < size--) { + ch = *data++; if (nl_just_seen) putchar(prefix); putchar(ch); @@ -155,60 +136,42 @@ static void copy_file(int prefix, const char *filename) else nl_just_seen = 0; } - fclose(in); if (!nl_just_seen) printf("\n\\ No newline at end of file\n"); } static void emit_rewrite_diff(const char *name_a, const char *name_b, - struct diff_tempfile *temp) + struct diff_filespec *one, + struct diff_filespec *two) { - /* Use temp[i].name as input, name_a and name_b as labels */ int lc_a, lc_b; - lc_a = count_lines(temp[0].name); - lc_b = count_lines(temp[1].name); + diff_populate_filespec(one, 0); + diff_populate_filespec(two, 0); + lc_a = count_lines(one->data, one->size); + lc_b = count_lines(two->data, two->size); printf("--- %s\n+++ %s\n@@ -", name_a, name_b); print_line_count(lc_a); printf(" +"); print_line_count(lc_b); printf(" @@\n"); if (lc_a) - copy_file('-', temp[0].name); + copy_file('-', one->data, one->size); if (lc_b) - copy_file('+', temp[1].name); + copy_file('+', two->data, two->size); } -static int fill_mmfile(mmfile_t *mf, const char *file) +static int fill_mmfile(mmfile_t *mf, struct diff_filespec *one) { - int fd = open(file, O_RDONLY); - struct stat st; - char *buf; - unsigned long size; - - mf->ptr = NULL; - mf->size = 0; - if (fd < 0) + if (!DIFF_FILE_VALID(one)) { + mf->ptr = ""; /* does not matter */ + mf->size = 0; return 0; - fstat(fd, &st); - size = st.st_size; - buf = xmalloc(size); - mf->ptr = buf; - mf->size = size; - while (size) { - int retval = read(fd, buf, size); - if (retval < 0) { - if (errno == EINTR || errno == EAGAIN) - continue; - break; - } - if (!retval) - break; - buf += retval; - size -= retval; } - mf->size -= size; - close(fd); + else if (diff_populate_filespec(one, 0)) + return -1; + mf->ptr = one->data; + mf->size = one->size; return 0; } @@ -243,69 +206,37 @@ static int mmfile_is_binary(mmfile_t *mf) return 0; } -static const char *builtin_diff(const char *name_a, +static void builtin_diff(const char *name_a, const char *name_b, - struct diff_tempfile *temp, + struct diff_filespec *one, + struct diff_filespec *two, const char *xfrm_msg, - int complete_rewrite, - const char **args) + int complete_rewrite) { - int i, next_at, cmd_size; mmfile_t mf1, mf2; - const char *const diff_cmd = "diff -L%s -L%s"; - const char *const diff_arg = "-- %s %s||:"; /* "||:" is to return 0 */ - const char *input_name_sq[2]; - const char *label_path[2]; - char *cmd; - - /* diff_cmd and diff_arg have 4 %s in total which makes - * the sum of these strings 8 bytes larger than required. - * we use 2 spaces around diff-opts, and we need to count - * terminating NUL; we used to subtract 5 here, but we do not - * care about small leaks in this subprocess that is about - * to exec "diff" anymore. - */ - cmd_size = (strlen(diff_cmd) + strlen(diff_opts) + strlen(diff_arg) - + 128); - - for (i = 0; i < 2; i++) { - input_name_sq[i] = sq_quote(temp[i].name); - if (!strcmp(temp[i].name, "/dev/null")) - label_path[i] = "/dev/null"; - else if (!i) - label_path[i] = sq_quote(quote_two("a/", name_a)); - else - label_path[i] = sq_quote(quote_two("b/", name_b)); - cmd_size += (strlen(label_path[i]) + strlen(input_name_sq[i])); - } - - cmd = xmalloc(cmd_size); - - next_at = 0; - next_at += snprintf(cmd+next_at, cmd_size-next_at, - diff_cmd, label_path[0], label_path[1]); - 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, input_name_sq[0], input_name_sq[1]); - - printf("diff --git %s %s\n", - quote_two("a/", name_a), quote_two("b/", name_b)); - if (label_path[0][0] == '/') { - /* dev/null */ - printf("new file mode %s\n", temp[1].mode); + const char *lbl[2]; + char *a_one, *b_two; + + a_one = quote_two("a/", name_a); + b_two = quote_two("b/", name_b); + lbl[0] = DIFF_FILE_VALID(one) ? a_one : "/dev/null"; + lbl[1] = DIFF_FILE_VALID(two) ? b_two : "/dev/null"; + printf("diff --git %s %s\n", a_one, b_two); + if (lbl[0][0] == '/') { + /* /dev/null */ + printf("new file mode %06o\n", two->mode); if (xfrm_msg && xfrm_msg[0]) puts(xfrm_msg); } - else if (label_path[1][0] == '/') { - printf("deleted file mode %s\n", temp[0].mode); + else if (lbl[1][0] == '/') { + printf("deleted file mode %06o\n", one->mode); if (xfrm_msg && xfrm_msg[0]) puts(xfrm_msg); } else { - if (strcmp(temp[0].mode, temp[1].mode)) { - printf("old mode %s\n", temp[0].mode); - printf("new mode %s\n", temp[1].mode); + if (one->mode != two->mode) { + printf("old mode %06o\n", one->mode); + printf("new mode %06o\n", two->mode); } if (xfrm_msg && xfrm_msg[0]) puts(xfrm_msg); @@ -313,27 +244,19 @@ static const char *builtin_diff(const char *name_a, * we do not run diff between different kind * of objects. */ - if (strncmp(temp[0].mode, temp[1].mode, 3)) - return NULL; + if ((one->mode ^ two->mode) & S_IFMT) + goto free_ab_and_return; if (complete_rewrite) { - emit_rewrite_diff(name_a, name_b, temp); - return NULL; + emit_rewrite_diff(name_a, name_b, one, two); + goto free_ab_and_return; } } - /* Un-quote the paths */ - if (label_path[0][0] != '/') - label_path[0] = quote_two("a/", name_a); - if (label_path[1][0] != '/') - label_path[1] = quote_two("b/", name_b); - - if (fill_mmfile(&mf1, temp[0].name) < 0 || - fill_mmfile(&mf2, temp[1].name) < 0) + if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0) die("unable to read files to diff"); if (mmfile_is_binary(&mf1) || mmfile_is_binary(&mf2)) - printf("Binary files %s and %s differ\n", - label_path[0], label_path[1]); + printf("Binary files %s and %s differ\n", lbl[0], lbl[1]); else { /* Crazy xdl interfaces.. */ const char *diffopts = getenv("GIT_DIFF_OPTS"); @@ -342,9 +265,10 @@ static const char *builtin_diff(const char *name_a, xdemitcb_t ecb; struct emit_callback ecbdata; - ecbdata.label_path = label_path; + ecbdata.label_path = lbl; xpp.flags = XDF_NEED_MINIMAL; xecfg.ctxlen = 3; + xecfg.flags = XDL_EMIT_FUNCNAMES; if (!diffopts) ; else if (!strncmp(diffopts, "--unified=", 10)) @@ -356,9 +280,10 @@ static const char *builtin_diff(const char *name_a, xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb); } - free(mf1.ptr); - free(mf2.ptr); - return NULL; + free_ab_and_return: + free(a_one); + free(b_two); + return; } struct diff_filespec *alloc_filespec(const char *path) @@ -376,7 +301,7 @@ void fill_filespec(struct diff_filespec *spec, const unsigned char *sha1, unsigned short mode) { if (mode) { - spec->mode = DIFF_FILE_CANON_MODE(mode); + spec->mode = canon_mode(mode); memcpy(spec->sha1, sha1, 20); spec->sha1_valid = !!memcmp(sha1, null_sha1, 20); } @@ -718,6 +643,7 @@ static void run_external_diff(const char *pgm, int retval; static int atexit_asked = 0; const char *othername; + const char **arg = &spawn_arg[0]; othername = (other? other : name); if (one && two) { @@ -732,36 +658,25 @@ static void run_external_diff(const char *pgm, signal(SIGINT, remove_tempfile_on_signal); } - if (pgm) { - const char **arg = &spawn_arg[0]; - if (one && two) { - *arg++ = pgm; - *arg++ = name; - *arg++ = temp[0].name; - *arg++ = temp[0].hex; - *arg++ = temp[0].mode; - *arg++ = temp[1].name; - *arg++ = temp[1].hex; - *arg++ = temp[1].mode; - if (other) { - *arg++ = other; - *arg++ = xfrm_msg; - } - } else { - *arg++ = pgm; - *arg++ = name; + if (one && two) { + *arg++ = pgm; + *arg++ = name; + *arg++ = temp[0].name; + *arg++ = temp[0].hex; + *arg++ = temp[0].mode; + *arg++ = temp[1].name; + *arg++ = temp[1].hex; + *arg++ = temp[1].mode; + if (other) { + *arg++ = other; + *arg++ = xfrm_msg; } - *arg = NULL; } else { - if (one && two) { - pgm = builtin_diff(name, othername, temp, xfrm_msg, complete_rewrite, spawn_arg); - } else - printf("* Unmerged path %s\n", name); + *arg++ = pgm; + *arg++ = name; } - - retval = 0; - if (pgm) - retval = spawn_prog(pgm, spawn_arg); + *arg = NULL; + retval = spawn_prog(pgm, spawn_arg); remove_tempfile(); if (retval) { fprintf(stderr, "external diff died, stopping at %s.\n", name); @@ -769,6 +684,26 @@ static void run_external_diff(const char *pgm, } } +static void run_diff_cmd(const char *pgm, + const char *name, + const char *other, + struct diff_filespec *one, + struct diff_filespec *two, + const char *xfrm_msg, + int complete_rewrite) +{ + if (pgm) { + run_external_diff(pgm, name, other, one, two, xfrm_msg, + complete_rewrite); + return; + } + if (one && two) + builtin_diff(name, other ? other : name, + one, two, xfrm_msg, complete_rewrite); + else + printf("* Unmerged path %s\n", name); +} + static void diff_fill_sha1_info(struct diff_filespec *one) { if (DIFF_FILE_VALID(one)) { @@ -798,8 +733,7 @@ static void run_diff(struct diff_filepair *p, struct diff_options *o) if (DIFF_PAIR_UNMERGED(p)) { /* unmerged */ - run_external_diff(pgm, p->one->path, NULL, NULL, NULL, NULL, - 0); + run_diff_cmd(pgm, p->one->path, NULL, NULL, NULL, NULL, 0); return; } @@ -871,15 +805,15 @@ static void run_diff(struct diff_filepair *p, struct diff_options *o) * needs to be split into deletion and creation. */ struct diff_filespec *null = alloc_filespec(two->path); - run_external_diff(NULL, name, other, one, null, xfrm_msg, 0); + run_diff_cmd(NULL, name, other, one, null, xfrm_msg, 0); free(null); null = alloc_filespec(one->path); - run_external_diff(NULL, name, other, null, two, xfrm_msg, 0); + run_diff_cmd(NULL, name, other, null, two, xfrm_msg, 0); free(null); } else - run_external_diff(pgm, name, other, one, two, xfrm_msg, - complete_rewrite); + run_diff_cmd(pgm, name, other, one, two, xfrm_msg, + complete_rewrite); free(name_munged); free(other_munged); @@ -928,6 +862,10 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) const char *arg = av[0]; if (!strcmp(arg, "-p") || !strcmp(arg, "-u")) options->output_format = DIFF_FORMAT_PATCH; + else if (!strcmp(arg, "--patch-with-raw")) { + options->output_format = DIFF_FORMAT_PATCH; + options->with_raw = 1; + } else if (!strcmp(arg, "-z")) options->line_termination = 0; else if (!strncmp(arg, "-l", 2)) @@ -950,6 +888,8 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) options->filter = arg + 14; else if (!strcmp(arg, "--pickaxe-all")) options->pickaxe_opts = DIFF_PICKAXE_ALL; + else if (!strcmp(arg, "--pickaxe-regex")) + options->pickaxe_opts = DIFF_PICKAXE_REGEX; else if (!strncmp(arg, "-B", 2)) { if ((options->break_opt = diff_scoreopt_parse(arg)) == -1) @@ -1112,13 +1052,13 @@ const char *diff_unique_abbrev(const unsigned char *sha1, int len) static void diff_flush_raw(struct diff_filepair *p, int line_termination, int inter_name_termination, - struct diff_options *options) + struct diff_options *options, + int output_format) { int two_paths; char status[10]; int abbrev = options->abbrev; const char *path_one, *path_two; - int output_format = options->output_format; path_one = p->one->path; path_two = p->two->path; @@ -1334,24 +1274,22 @@ static void diff_resolve_rename_copy(void) diff_debug_queue("resolve-rename-copy done", q); } -void diff_flush(struct diff_options *options) +static void flush_one_pair(struct diff_filepair *p, + int diff_output_format, + struct diff_options *options) { - struct diff_queue_struct *q = &diff_queued_diff; - int i; int inter_name_termination = '\t'; - int diff_output_format = options->output_format; int line_termination = options->line_termination; - if (!line_termination) inter_name_termination = 0; - for (i = 0; i < q->nr; i++) { - struct diff_filepair *p = q->queue[i]; - if ((diff_output_format == DIFF_FORMAT_NO_OUTPUT) || - (p->status == DIFF_STATUS_UNKNOWN)) - continue; - if (p->status == 0) - die("internal error in diff-resolve-rename-copy"); + switch (p->status) { + case DIFF_STATUS_UNKNOWN: + break; + case 0: + die("internal error in diff-resolve-rename-copy"); + break; + default: switch (diff_output_format) { case DIFF_FORMAT_PATCH: diff_flush_patch(p, options); @@ -1360,15 +1298,36 @@ void diff_flush(struct diff_options *options) case DIFF_FORMAT_NAME_STATUS: diff_flush_raw(p, line_termination, inter_name_termination, - options); + options, diff_output_format); break; case DIFF_FORMAT_NAME: diff_flush_name(p, inter_name_termination, line_termination); break; + case DIFF_FORMAT_NO_OUTPUT: + break; + } + } +} + +void diff_flush(struct diff_options *options) +{ + struct diff_queue_struct *q = &diff_queued_diff; + int i; + int diff_output_format = options->output_format; + + if (options->with_raw) { + for (i = 0; i < q->nr; i++) { + struct diff_filepair *p = q->queue[i]; + flush_one_pair(p, DIFF_FORMAT_RAW, options); } - diff_free_filepair(q->queue[i]); + putchar(options->line_termination); + } + for (i = 0; i < q->nr; i++) { + struct diff_filepair *p = q->queue[i]; + flush_one_pair(p, diff_output_format, options); + diff_free_filepair(p); } free(q->queue); q->queue = NULL; @@ -1433,8 +1392,6 @@ static void diffcore_apply_filter(const char *filter) void diffcore_std(struct diff_options *options) { - if (options->paths && options->paths[0]) - diffcore_pathspec(options->paths); if (options->break_opt != -1) diffcore_break(options->break_opt); if (options->detect_rename)