X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=diff.c;h=4a350e365e5f4d0c61977546e620bf6b79679dd5;hb=9ca5df90615aa3c6b60e1bc8f03db6cae98e816c;hp=dfdfa1a813c345b7653b1743afa75ff15d8c379f;hpb=954f7cfdac48b8d9fe91c29ecfa44ac0c639867c;p=git.git diff --git a/diff.c b/diff.c index dfdfa1a81..4a350e365 100644 --- a/diff.c +++ b/diff.c @@ -14,6 +14,7 @@ #include "userdiff.h" #include "sigchain.h" #include "submodule.h" +#include "ll-merge.h" #ifdef NO_FAST_WORKING_DIRECTORY #define FAST_WORKING_DIRECTORY 0 @@ -550,6 +551,10 @@ static void emit_rewrite_diff(const char *name_a, emit_rewrite_lines(&ecbdata, '-', data_one, size_one); if (lc_b) emit_rewrite_lines(&ecbdata, '+', data_two, size_two); + if (textconv_one) + free((char *)data_one); + if (textconv_two) + free((char *)data_two); } struct diff_words_buffer { @@ -695,7 +700,6 @@ static void diff_words_show(struct diff_words_data *diff_words) { xpparam_t xpp; xdemitconf_t xecfg; - xdemitcb_t ecb; mmfile_t minus, plus; /* special case: only removal */ @@ -717,7 +721,7 @@ static void diff_words_show(struct diff_words_data *diff_words) /* as only the hunk header will be parsed, we need a 0-context */ xecfg.ctxlen = 0; xdi_diff_outf(&minus, &plus, fn_out_diff_words_aux, diff_words, - &xpp, &xecfg, &ecb); + &xpp, &xecfg); free(minus.ptr); free(plus.ptr); if (diff_words->current_plus != diff_words->plus.text.ptr + @@ -948,7 +952,7 @@ struct diffstat_t { unsigned is_unmerged:1; unsigned is_binary:1; unsigned is_renamed:1; - unsigned int added, deleted; + uintmax_t added, deleted; } **files; }; @@ -1040,7 +1044,7 @@ static void fill_print_name(struct diffstat_file *file) static void show_stats(struct diffstat_t *data, struct diff_options *options) { int i, len, add, del, adds = 0, dels = 0; - int max_change = 0, max_len = 0; + uintmax_t max_change = 0, max_len = 0; int total_files = data->nr; int width, name_width; const char *reset, *set, *add_c, *del_c; @@ -1069,7 +1073,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options) for (i = 0; i < data->nr; i++) { struct diffstat_file *file = data->files[i]; - int change = file->added + file->deleted; + uintmax_t change = file->added + file->deleted; fill_print_name(file); len = strlen(file->print_name); if (max_len < len) @@ -1097,8 +1101,8 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options) for (i = 0; i < data->nr; i++) { const char *prefix = ""; char *name = data->files[i]->print_name; - int added = data->files[i]->added; - int deleted = data->files[i]->deleted; + uintmax_t added = data->files[i]->added; + uintmax_t deleted = data->files[i]->deleted; int name_len; /* @@ -1119,9 +1123,11 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options) if (data->files[i]->is_binary) { show_name(options->file, prefix, name, len); fprintf(options->file, " Bin "); - fprintf(options->file, "%s%d%s", del_c, deleted, reset); + fprintf(options->file, "%s%"PRIuMAX"%s", + del_c, deleted, reset); fprintf(options->file, " -> "); - fprintf(options->file, "%s%d%s", add_c, added, reset); + fprintf(options->file, "%s%"PRIuMAX"%s", + add_c, added, reset); fprintf(options->file, " bytes"); fprintf(options->file, "\n"); continue; @@ -1150,7 +1156,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options) del = scale_linear(del, width, max_change); } show_name(options->file, prefix, name, len); - fprintf(options->file, "%5d%s", added + deleted, + fprintf(options->file, "%5"PRIuMAX"%s", added + deleted, added + deleted ? " " : ""); show_graph(options->file, '+', add, add_c, reset); show_graph(options->file, '-', del, del_c, reset); @@ -1200,7 +1206,8 @@ static void show_numstat(struct diffstat_t *data, struct diff_options *options) fprintf(options->file, "-\t-\t"); else fprintf(options->file, - "%d\t%d\t", file->added, file->deleted); + "%"PRIuMAX"\t%"PRIuMAX"\t", + file->added, file->deleted); if (options->line_termination) { fill_print_name(file); if (!file->is_renamed) @@ -1370,37 +1377,32 @@ static void free_diffstat_info(struct diffstat_t *diffstat) struct checkdiff_t { const char *filename; int lineno; + int conflict_marker_size; struct diff_options *o; unsigned ws_rule; unsigned status; }; -static int is_conflict_marker(const char *line, unsigned long len) +static int is_conflict_marker(const char *line, int marker_size, unsigned long len) { char firstchar; int cnt; - if (len < 8) + if (len < marker_size + 1) return 0; firstchar = line[0]; switch (firstchar) { - case '=': case '>': case '<': + case '=': case '>': case '<': case '|': break; default: return 0; } - for (cnt = 1; cnt < 7; cnt++) + for (cnt = 1; cnt < marker_size; cnt++) if (line[cnt] != firstchar) return 0; - /* line[0] thru line[6] are same as firstchar */ - if (firstchar == '=') { - /* divider between ours and theirs? */ - if (len != 8 || line[7] != '\n') - return 0; - } else if (len < 8 || !isspace(line[7])) { - /* not divider before ours nor after theirs */ + /* line[1] thru line[marker_size-1] are same as firstchar */ + if (len < marker_size + 1 || !isspace(line[marker_size])) return 0; - } return 1; } @@ -1408,6 +1410,7 @@ static void checkdiff_consume(void *priv, char *line, unsigned long len) { struct checkdiff_t *data = priv; int color_diff = DIFF_OPT_TST(data->o, COLOR_DIFF); + int marker_size = data->conflict_marker_size; const char *ws = diff_get_color(color_diff, DIFF_WHITESPACE); const char *reset = diff_get_color(color_diff, DIFF_RESET); const char *set = diff_get_color(color_diff, DIFF_FILE_NEW); @@ -1416,7 +1419,7 @@ static void checkdiff_consume(void *priv, char *line, unsigned long len) if (line[0] == '+') { unsigned bad; data->lineno++; - if (is_conflict_marker(line + 1, len - 1)) { + if (is_conflict_marker(line + 1, marker_size, len - 1)) { data->status |= 1; fprintf(data->o->file, "%s:%d: leftover conflict marker\n", @@ -1704,7 +1707,6 @@ static void builtin_diff(const char *name_a, const char *diffopts = getenv("GIT_DIFF_OPTS"); xpparam_t xpp; xdemitconf_t xecfg; - xdemitcb_t ecb; struct emit_callback ecbdata; const struct userdiff_funcname *pe; @@ -1776,7 +1778,7 @@ static void builtin_diff(const char *name_a, } } xdi_diff_outf(&mf1, &mf2, fn_out_consume, &ecbdata, - &xpp, &xecfg, &ecb); + &xpp, &xecfg); if (DIFF_OPT_TST(o, COLOR_DIFF_WORDS)) free_diff_words_data(&ecbdata); if (textconv_one) @@ -1829,13 +1831,12 @@ static void builtin_diffstat(const char *name_a, const char *name_b, /* Crazy xdl interfaces.. */ xpparam_t xpp; xdemitconf_t xecfg; - xdemitcb_t ecb; memset(&xpp, 0, sizeof(xpp)); memset(&xecfg, 0, sizeof(xecfg)); xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts; xdi_diff_outf(&mf1, &mf2, diffstat_consume, diffstat, - &xpp, &xecfg, &ecb); + &xpp, &xecfg); } free_and_return: @@ -1860,6 +1861,7 @@ static void builtin_checkdiff(const char *name_a, const char *name_b, data.lineno = 0; data.o = o; data.ws_rule = whitespace_rule(attr_path); + data.conflict_marker_size = ll_merge_marker_size(attr_path); if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0) die("unable to read files to diff"); @@ -1876,14 +1878,13 @@ static void builtin_checkdiff(const char *name_a, const char *name_b, /* Crazy xdl interfaces.. */ xpparam_t xpp; xdemitconf_t xecfg; - xdemitcb_t ecb; memset(&xpp, 0, sizeof(xpp)); memset(&xecfg, 0, sizeof(xecfg)); xecfg.ctxlen = 1; /* at least one context line */ xpp.flags = XDF_NEED_MINIMAL; xdi_diff_outf(&mf1, &mf2, checkdiff_consume, &data, - &xpp, &xecfg, &ecb); + &xpp, &xecfg); if (data.ws_rule & WS_BLANK_AT_EOF) { struct emit_callback ecbdata; @@ -2032,7 +2033,7 @@ static int diff_populate_gitlink(struct diff_filespec *s, int size_only) char *data = xmalloc(100), *dirty = ""; /* Are we looking at the work tree? */ - if (!s->sha1_valid && s->dirty_submodule) + if (s->dirty_submodule) dirty = "-dirty"; len = snprintf(data, 100, @@ -2539,6 +2540,7 @@ static void run_checkdiff(struct diff_filepair *p, struct diff_options *o) void diff_setup(struct diff_options *options) { memset(options, 0, sizeof(*options)); + memset(&diff_queued_diff, 0, sizeof(diff_queued_diff)); options->file = stdout; @@ -2628,6 +2630,12 @@ int diff_setup_done(struct diff_options *options) */ if (options->pickaxe) DIFF_OPT_SET(options, RECURSIVE); + /* + * When patches are generated, submodules diffed against the work tree + * must be checked for dirtiness too so it can be shown in the output + */ + if (options->output_format & DIFF_FORMAT_PATCH) + DIFF_OPT_SET(options, DIRTY_SUBMODULES); if (options->detect_rename && options->rename_limit < 0) options->rename_limit = diff_rename_limit_default; @@ -3086,7 +3094,8 @@ int diff_unmodified_pair(struct diff_filepair *p) * dealing with a change. */ if (one->sha1_valid && two->sha1_valid && - !hashcmp(one->sha1, two->sha1)) + !hashcmp(one->sha1, two->sha1) && + !one->dirty_submodule && !two->dirty_submodule) return 1; /* no change */ if (!one->sha1_valid && !two->sha1_valid) return 1; /* both look at the same file on the filesystem. */ @@ -3221,6 +3230,8 @@ static void diff_resolve_rename_copy(void) } else if (hashcmp(p->one->sha1, p->two->sha1) || p->one->mode != p->two->mode || + p->one->dirty_submodule || + p->two->dirty_submodule || is_null_sha1(p->one->sha1)) p->status = DIFF_STATUS_MODIFIED; else { @@ -3369,7 +3380,6 @@ static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1) for (i = 0; i < q->nr; i++) { xpparam_t xpp; xdemitconf_t xecfg; - xdemitcb_t ecb; mmfile_t mf1, mf2; struct diff_filepair *p = q->queue[i]; int len1, len2; @@ -3431,7 +3441,7 @@ static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1) xecfg.ctxlen = 3; xecfg.flags = XDL_EMIT_FUNCNAMES; xdi_diff_outf(&mf1, &mf2, patch_id_consume, &data, - &xpp, &xecfg, &ecb); + &xpp, &xecfg); } git_SHA1_Final(sha1, &ctx); @@ -3448,8 +3458,7 @@ int diff_flush_patch_id(struct diff_options *options, unsigned char *sha1) diff_free_filepair(q->queue[i]); free(q->queue); - q->queue = NULL; - q->nr = q->alloc = 0; + DIFF_QUEUE_CLEAR(q); return result; } @@ -3577,8 +3586,7 @@ void diff_flush(struct diff_options *options) diff_free_filepair(q->queue[i]); free_queue: free(q->queue); - q->queue = NULL; - q->nr = q->alloc = 0; + DIFF_QUEUE_CLEAR(q); if (options->close_file) fclose(options->file); @@ -3600,8 +3608,7 @@ static void diffcore_apply_filter(const char *filter) int i; struct diff_queue_struct *q = &diff_queued_diff; struct diff_queue_struct outq; - outq.queue = NULL; - outq.nr = outq.alloc = 0; + DIFF_QUEUE_CLEAR(&outq); if (!filter) return; @@ -3669,8 +3676,7 @@ static void diffcore_skip_stat_unmatch(struct diff_options *diffopt) int i; struct diff_queue_struct *q = &diff_queued_diff; struct diff_queue_struct outq; - outq.queue = NULL; - outq.nr = outq.alloc = 0; + DIFF_QUEUE_CLEAR(&outq); for (i = 0; i < q->nr; i++) { struct diff_filepair *p = q->queue[i]; @@ -3874,6 +3880,7 @@ static char *run_textconv(const char *pgm, struct diff_filespec *spec, const char **arg = argv; struct child_process child; struct strbuf buf = STRBUF_INIT; + int err = 0; temp = prepare_temp_file(spec->path, spec); *arg++ = pgm; @@ -3884,16 +3891,20 @@ static char *run_textconv(const char *pgm, struct diff_filespec *spec, child.use_shell = 1; child.argv = argv; child.out = -1; - if (start_command(&child) != 0 || - strbuf_read(&buf, child.out, 0) < 0 || - finish_command(&child) != 0) { - close(child.out); - strbuf_release(&buf); + if (start_command(&child)) { remove_tempfile(); - error("error running textconv command '%s'", pgm); return NULL; } + + if (strbuf_read(&buf, child.out, 0) < 0) + err = error("error reading from textconv command '%s'", pgm); close(child.out); + + if (finish_command(&child) || err) { + strbuf_release(&buf); + remove_tempfile(); + return NULL; + } remove_tempfile(); return strbuf_detach(&buf, outsize);