From: Junio C Hamano Date: Tue, 13 Nov 2018 13:37:27 +0000 (+0900) Subject: Merge branch 'jk/xdiff-interface' X-Git-Tag: v2.20.0-rc0~33 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/39d23dfa409e51844ddda99599927092c8300f12?ds=inline;hp=-c Merge branch 'jk/xdiff-interface' The interface into "xdiff" library used to discover the offset and size of a generated patch hunk by first formatting it into the textual hunk header "@@ -n,m +k,l @@" and then parsing the numbers out. A new interface has been introduced to allow callers a more direct access to them. * jk/xdiff-interface: xdiff-interface: drop parse_hunk_header() range-diff: use a hunk callback diff: convert --check to use a hunk callback combine-diff: use an xdiff hunk callback diff: use hunk callback for word-diff diff: discard hunk headers for patch-ids earlier diff: avoid generating unused hunk header lines xdiff-interface: provide a separate consume callback for hunks xdiff: provide a separate emit callback for hunks --- 39d23dfa409e51844ddda99599927092c8300f12 diff --combined builtin/merge-tree.c index 8fc108d305,e7771a1012..70f6fc9167 --- a/builtin/merge-tree.c +++ b/builtin/merge-tree.c @@@ -76,7 -76,7 +76,7 @@@ static void *result(struct merge_list * their = NULL; if (entry) their = entry->blob; - return merge_blobs(path, base, our, their, size); + return merge_blobs(&the_index, path, base, our, their, size); } static void *origin(struct merge_list *entry, unsigned long *size) @@@ -110,7 -110,8 +110,8 @@@ static void show_diff(struct merge_lis xpp.flags = 0; memset(&xecfg, 0, sizeof(xecfg)); xecfg.ctxlen = 3; - ecb.outf = show_outf; + ecb.out_hunk = NULL; + ecb.out_line = show_outf; ecb.priv = NULL; src.ptr = origin(entry, &size); @@@ -155,7 -156,7 +156,7 @@@ static int same_entry(struct name_entr { return a->oid && b->oid && - !oidcmp(a->oid, b->oid) && + oideq(a->oid, b->oid) && a->mode == b->mode; } diff --combined builtin/rerere.c index e89ccbc524,ea409e80cb..d78eeaed32 --- a/builtin/rerere.c +++ b/builtin/rerere.c @@@ -41,7 -41,8 +41,8 @@@ static int diff_two(const char *file1, xpp.flags = 0; memset(&xecfg, 0, sizeof(xecfg)); xecfg.ctxlen = 3; - ecb.outf = outf; + ecb.out_hunk = NULL; + ecb.out_line = outf; ret = xdi_diff(&minus, &plus, &xpp, &xecfg, &ecb); free(minus.ptr); @@@ -70,15 -71,15 +71,15 @@@ int cmd_rerere(int argc, const char **a flags = RERERE_NOAUTOUPDATE; if (argc < 1) - return rerere(flags); + return repo_rerere(the_repository, flags); if (!strcmp(argv[0], "forget")) { struct pathspec pathspec; if (argc < 2) - warning("'git rerere forget' without paths is deprecated"); + warning(_("'git rerere forget' without paths is deprecated")); parse_pathspec(&pathspec, 0, PATHSPEC_PREFER_CWD, prefix, argv + 1); - return rerere_forget(&pathspec); + return rerere_forget(the_repository, &pathspec); } if (!strcmp(argv[0], "clear")) { @@@ -91,7 -92,7 +92,7 @@@ for (i = 0; i < merge_rr.nr; i++) printf("%s\n", merge_rr.items[i].string); } else if (!strcmp(argv[0], "remaining")) { - rerere_remaining(&merge_rr); + rerere_remaining(the_repository, &merge_rr); for (i = 0; i < merge_rr.nr; i++) { if (merge_rr.items[i].util != RERERE_RESOLVED) printf("%s\n", merge_rr.items[i].string); @@@ -107,7 -108,7 +108,7 @@@ const char *path = merge_rr.items[i].string; const struct rerere_id *id = merge_rr.items[i].util; if (diff_two(rerere_path(id, "preimage"), path, path, path)) - die("unable to generate diff for %s", rerere_path(id, NULL)); + die(_("unable to generate diff for '%s'"), rerere_path(id, NULL)); } } else usage_with_options(rerere_usage, options); diff --combined combine-diff.c index 10155e0ec8,e585683ea9..ad7752ea6b --- a/combine-diff.c +++ b/combine-diff.c @@@ -285,8 -285,7 +285,8 @@@ static struct lline *coalesce_lines(str return base; } -static char *grab_blob(const struct object_id *oid, unsigned int mode, +static char *grab_blob(struct repository *r, + const struct object_id *oid, unsigned int mode, unsigned long *size, struct userdiff_driver *textconv, const char *path) { @@@ -305,7 -304,7 +305,7 @@@ } else if (textconv) { struct diff_filespec *df = alloc_filespec(path); fill_filespec(df, oid, 1, mode); - *size = fill_textconv(textconv, df, &blob); + *size = fill_textconv(r, textconv, df, &blob); free_filespec(df); } else { blob = read_object_file(oid, &type, size); @@@ -345,38 -344,43 +345,43 @@@ struct combine_diff_state struct sline *lost_bucket; }; - static void consume_line(void *state_, char *line, unsigned long len) + static void consume_hunk(void *state_, + long ob, long on, + long nb, long nn, + const char *funcline, long funclen) { struct combine_diff_state *state = state_; - if (5 < len && !memcmp("@@ -", line, 4)) { - if (parse_hunk_header(line, len, - &state->ob, &state->on, - &state->nb, &state->nn)) - return; - state->lno = state->nb; - if (state->nn == 0) { - /* @@ -X,Y +N,0 @@ removed Y lines - * that would have come *after* line N - * in the result. Our lost buckets hang - * to the line after the removed lines, - * - * Note that this is correct even when N == 0, - * in which case the hunk removes the first - * line in the file. - */ - state->lost_bucket = &state->sline[state->nb]; - if (!state->nb) - state->nb = 1; - } else { - state->lost_bucket = &state->sline[state->nb-1]; - } - if (!state->sline[state->nb-1].p_lno) - state->sline[state->nb-1].p_lno = - xcalloc(state->num_parent, - sizeof(unsigned long)); - state->sline[state->nb-1].p_lno[state->n] = state->ob; - return; + + state->ob = ob; + state->on = on; + state->nb = nb; + state->nn = nn; + state->lno = state->nb; + if (state->nn == 0) { + /* @@ -X,Y +N,0 @@ removed Y lines + * that would have come *after* line N + * in the result. Our lost buckets hang + * to the line after the removed lines, + * + * Note that this is correct even when N == 0, + * in which case the hunk removes the first + * line in the file. + */ + state->lost_bucket = &state->sline[state->nb]; + if (!state->nb) + state->nb = 1; + } else { + state->lost_bucket = &state->sline[state->nb-1]; } + if (!state->sline[state->nb-1].p_lno) + state->sline[state->nb-1].p_lno = + xcalloc(state->num_parent, sizeof(unsigned long)); + state->sline[state->nb-1].p_lno[state->n] = state->ob; + } + + static void consume_line(void *state_, char *line, unsigned long len) + { + struct combine_diff_state *state = state_; if (!state->lost_bucket) return; /* not in any hunk yet */ switch (line[0]) { @@@ -390,8 -394,7 +395,8 @@@ } } -static void combine_diff(const struct object_id *parent, unsigned int mode, +static void combine_diff(struct repository *r, + const struct object_id *parent, unsigned int mode, mmfile_t *result_file, struct sline *sline, unsigned int cnt, int n, int num_parent, int result_deleted, @@@ -409,7 -412,7 +414,7 @@@ if (result_deleted) return; /* result deleted */ - parent_file.ptr = grab_blob(parent, mode, &sz, textconv, path); + parent_file.ptr = grab_blob(r, parent, mode, &sz, textconv, path); parent_file.size = sz; memset(&xpp, 0, sizeof(xpp)); xpp.flags = flags; @@@ -421,8 -424,8 +426,8 @@@ state.num_parent = num_parent; state.n = n; - if (xdi_diff_outf(&parent_file, result_file, consume_line, &state, - &xpp, &xecfg)) + if (xdi_diff_outf(&parent_file, result_file, consume_hunk, + consume_line, &state, &xpp, &xecfg)) die("unable to generate combined diff for %s", oid_to_hex(parent)); free(parent_file.ptr); @@@ -987,7 -990,7 +992,7 @@@ static void show_patch_diff(struct comb const char *line_prefix = diff_line_prefix(opt); context = opt->context; - userdiff = userdiff_find_by_path(elem->path); + userdiff = userdiff_find_by_path(opt->repo->index, elem->path); if (!userdiff) userdiff = userdiff_find_by_name("default"); if (opt->flags.allow_textconv) @@@ -995,7 -998,7 +1000,7 @@@ /* Read the result of merge first */ if (!working_tree_file) - result = grab_blob(&elem->oid, elem->mode, &result_size, + result = grab_blob(opt->repo, &elem->oid, elem->mode, &result_size, textconv, elem->path); else { /* Used by diff-tree to read from the working tree */ @@@ -1018,16 -1021,15 +1023,16 @@@ } else if (S_ISDIR(st.st_mode)) { struct object_id oid; if (resolve_gitlink_ref(elem->path, "HEAD", &oid) < 0) - result = grab_blob(&elem->oid, elem->mode, - &result_size, NULL, NULL); + result = grab_blob(opt->repo, &elem->oid, + elem->mode, &result_size, + NULL, NULL); else - result = grab_blob(&oid, elem->mode, + result = grab_blob(opt->repo, &oid, elem->mode, &result_size, NULL, NULL); } else if (textconv) { struct diff_filespec *df = alloc_filespec(elem->path); fill_filespec(df, &null_oid, 0, st.st_mode); - result_size = fill_textconv(textconv, df, &result); + result_size = fill_textconv(opt->repo, textconv, df, &result); free_filespec(df); } else if (0 <= (fd = open(elem->path, O_RDONLY))) { size_t len = xsize_t(st.st_size); @@@ -1057,8 -1059,7 +1062,8 @@@ if (is_file) { struct strbuf buf = STRBUF_INIT; - if (convert_to_git(&the_index, elem->path, result, len, &buf, global_conv_flags_eol)) { + if (convert_to_git(rev->diffopt.repo->index, + elem->path, result, len, &buf, global_conv_flags_eol)) { free(result); result = strbuf_detach(&buf, &len); result_size = len; @@@ -1093,8 -1094,7 +1098,8 @@@ for (i = 0; !is_binary && i < num_parent; i++) { char *buf; unsigned long size; - buf = grab_blob(&elem->parent[i].oid, + buf = grab_blob(opt->repo, + &elem->parent[i].oid, elem->parent[i].mode, &size, NULL, NULL); if (buffer_is_binary(buf, size)) @@@ -1143,15 -1143,14 +1148,15 @@@ for (i = 0; i < num_parent; i++) { int j; for (j = 0; j < i; j++) { - if (!oidcmp(&elem->parent[i].oid, - &elem->parent[j].oid)) { + if (oideq(&elem->parent[i].oid, + &elem->parent[j].oid)) { reuse_combine_diff(sline, cnt, i, j); break; } } if (i <= j) - combine_diff(&elem->parent[i].oid, + combine_diff(opt->repo, + &elem->parent[i].oid, elem->parent[i].mode, &result_file, sline, cnt, i, num_parent, result_deleted, diff --combined diff.c index 8647db3d30,6a34bbeeeb..e38d1ecaf4 --- a/diff.c +++ b/diff.c @@@ -554,15 -554,14 +554,15 @@@ static int count_lines(const char *data return count; } -static int fill_mmfile(mmfile_t *mf, struct diff_filespec *one) +static int fill_mmfile(struct repository *r, mmfile_t *mf, + struct diff_filespec *one) { if (!DIFF_FILE_VALID(one)) { mf->ptr = (char *)""; /* does not matter */ mf->size = 0; return 0; } - else if (diff_populate_filespec(one, 0)) + else if (diff_populate_filespec(r, one, 0)) return -1; mf->ptr = one->data; @@@ -571,12 -570,11 +571,12 @@@ } /* like fill_mmfile, but only for size, so we can avoid retrieving blob */ -static unsigned long diff_filespec_size(struct diff_filespec *one) +static unsigned long diff_filespec_size(struct repository *r, + struct diff_filespec *one) { if (!DIFF_FILE_VALID(one)) return 0; - diff_populate_filespec(one, CHECK_SIZE_ONLY); + diff_populate_filespec(r, one, CHECK_SIZE_ONLY); return one->size; } @@@ -626,54 -624,42 +626,54 @@@ static void check_blank_at_eof(mmfile_ } static void emit_line_0(struct diff_options *o, - const char *set, unsigned reverse, const char *reset, + const char *set_sign, const char *set, unsigned reverse, const char *reset, int first, const char *line, int len) { int has_trailing_newline, has_trailing_carriage_return; - int nofirst; + int needs_reset = 0; /* at the end of the line */ FILE *file = o->file; - if (first) - fputs(diff_line_prefix(o), file); - else if (!len) - return; + fputs(diff_line_prefix(o), file); - if (len == 0) { - has_trailing_newline = (first == '\n'); - has_trailing_carriage_return = (!has_trailing_newline && - (first == '\r')); - nofirst = has_trailing_newline || has_trailing_carriage_return; - } else { - has_trailing_newline = (len > 0 && line[len-1] == '\n'); - if (has_trailing_newline) - len--; - has_trailing_carriage_return = (len > 0 && line[len-1] == '\r'); - if (has_trailing_carriage_return) - len--; - nofirst = 0; + has_trailing_newline = (len > 0 && line[len-1] == '\n'); + if (has_trailing_newline) + len--; + + has_trailing_carriage_return = (len > 0 && line[len-1] == '\r'); + if (has_trailing_carriage_return) + len--; + + if (!len && !first) + goto end_of_line; + + if (reverse && want_color(o->use_color)) { + fputs(GIT_COLOR_REVERSE, file); + needs_reset = 1; } - if (len || !nofirst) { - if (reverse && want_color(o->use_color)) - fputs(GIT_COLOR_REVERSE, file); + if (set_sign) { + fputs(set_sign, file); + needs_reset = 1; + } + + if (first) + fputc(first, file); + + if (!len) + goto end_of_line; + + if (set) { + if (set_sign && set != set_sign) + fputs(reset, file); fputs(set, file); - if (first && !nofirst) - fputc(first, file); - fwrite(line, len, 1, file); - fputs(reset, file); + needs_reset = 1; } + fwrite(line, len, 1, file); + needs_reset = 1; /* 'line' may contain color codes. */ + +end_of_line: + if (needs_reset) + fputs(reset, file); if (has_trailing_carriage_return) fputc('\r', file); if (has_trailing_newline) @@@ -683,7 -669,7 +683,7 @@@ static void emit_line(struct diff_options *o, const char *set, const char *reset, const char *line, int len) { - emit_line_0(o, set, 0, reset, line[0], line+1, len-1); + emit_line_0(o, set, NULL, 0, reset, 0, line, len); } enum diff_symbol { @@@ -778,6 -764,7 +778,6 @@@ struct moved_entry struct hashmap_entry ent; const struct emitted_diff_symbol *es; struct moved_entry *next_line; - struct ws_delta *wsd; }; /** @@@ -794,17 -781,6 +794,17 @@@ struct ws_delta }; #define WS_DELTA_INIT { NULL, 0 } +struct moved_block { + struct moved_entry *match; + struct ws_delta wsd; +}; + +static void moved_block_clear(struct moved_block *b) +{ + FREE_AND_NULL(b->wsd.string); + b->match = NULL; +} + static int compute_ws_delta(const struct emitted_diff_symbol *a, const struct emitted_diff_symbol *b, struct ws_delta *out) @@@ -813,19 -789,16 +813,19 @@@ const struct emitted_diff_symbol *shorter = a->len > b->len ? b : a; int d = longer->len - shorter->len; + if (strncmp(longer->line + d, shorter->line, shorter->len)) + return 0; + out->string = xmemdupz(longer->line, d); out->current_longer = (a == longer); - return !strncmp(longer->line + d, shorter->line, shorter->len); + return 1; } static int cmp_in_block_with_wsd(const struct diff_options *o, const struct moved_entry *cur, const struct moved_entry *match, - struct moved_entry *pmb, + struct moved_block *pmb, int n) { struct emitted_diff_symbol *l = &o->emitted_symbols->buf[n]; @@@ -845,15 -818,16 +845,15 @@@ if (strcmp(a, b)) return 1; - if (!pmb->wsd) + if (!pmb->wsd.string) /* - * No white space delta was carried forward? This can happen - * when we exit early in this function and do not carry - * forward ws. + * The white space delta is not active? This can happen + * when we exit early in this function. */ return 1; /* - * The indent changes of the block are known and carried forward in + * The indent changes of the block are known and stored in * pmb->wsd; however we need to check if the indent changes of the * current line are still the same as before. * @@@ -861,8 -835,8 +861,8 @@@ * one of them for the white spaces, depending which was longer. */ - wslen = strlen(pmb->wsd->string); - if (pmb->wsd->current_longer) { + wslen = strlen(pmb->wsd.string); + if (pmb->wsd.current_longer) { c += wslen; cl -= wslen; } else { @@@ -870,7 -844,7 +870,7 @@@ al -= wslen; } - if (strcmp(a, c)) + if (al != cl || memcmp(a, c, al)) return 1; return 0; @@@ -912,6 -886,7 +912,6 @@@ static struct moved_entry *prepare_entr ret->ent.hash = xdiff_hash_string(l->line, l->len, flags); ret->es = l; ret->next_line = NULL; - ret->wsd = NULL; return ret; } @@@ -951,18 -926,18 +951,18 @@@ static void add_lines_to_move_detection static void pmb_advance_or_null(struct diff_options *o, struct moved_entry *match, struct hashmap *hm, - struct moved_entry **pmb, + struct moved_block *pmb, int pmb_nr) { int i; for (i = 0; i < pmb_nr; i++) { - struct moved_entry *prev = pmb[i]; + struct moved_entry *prev = pmb[i].match; struct moved_entry *cur = (prev && prev->next_line) ? prev->next_line : NULL; if (cur && !hm->cmpfn(o, cur, match, NULL)) { - pmb[i] = cur; + pmb[i].match = cur; } else { - pmb[i] = NULL; + pmb[i].match = NULL; } } } @@@ -970,7 -945,7 +970,7 @@@ static void pmb_advance_or_null_multi_match(struct diff_options *o, struct moved_entry *match, struct hashmap *hm, - struct moved_entry **pmb, + struct moved_block *pmb, int pmb_nr, int n) { int i; @@@ -978,47 -953,48 +978,47 @@@ for (; match; match = hashmap_get_next(hm, match)) { for (i = 0; i < pmb_nr; i++) { - struct moved_entry *prev = pmb[i]; + struct moved_entry *prev = pmb[i].match; struct moved_entry *cur = (prev && prev->next_line) ? prev->next_line : NULL; if (!cur) continue; - if (!cmp_in_block_with_wsd(o, cur, match, pmb[i], n)) + if (!cmp_in_block_with_wsd(o, cur, match, &pmb[i], n)) got_match[i] |= 1; } } for (i = 0; i < pmb_nr; i++) { if (got_match[i]) { - /* Carry the white space delta forward */ - pmb[i]->next_line->wsd = pmb[i]->wsd; - pmb[i] = pmb[i]->next_line; - } else - pmb[i] = NULL; + /* Advance to the next line */ + pmb[i].match = pmb[i].match->next_line; + } else { + moved_block_clear(&pmb[i]); + } } + + free(got_match); } -static int shrink_potential_moved_blocks(struct moved_entry **pmb, +static int shrink_potential_moved_blocks(struct moved_block *pmb, int pmb_nr) { int lp, rp; /* Shrink the set of potential block to the remaining running */ for (lp = 0, rp = pmb_nr - 1; lp <= rp;) { - while (lp < pmb_nr && pmb[lp]) + while (lp < pmb_nr && pmb[lp].match) lp++; /* lp points at the first NULL now */ - while (rp > -1 && !pmb[rp]) + while (rp > -1 && !pmb[rp].match) rp--; /* rp points at the last non-NULL */ if (lp < pmb_nr && rp > -1 && lp < rp) { pmb[lp] = pmb[rp]; - if (pmb[rp]->wsd) { - free(pmb[rp]->wsd->string); - FREE_AND_NULL(pmb[rp]->wsd); - } - pmb[rp] = NULL; + pmb[rp].match = NULL; + pmb[rp].wsd.string = NULL; rp--; lp++; } @@@ -1065,7 -1041,7 +1065,7 @@@ static void mark_color_as_moved(struct struct hashmap *add_lines, struct hashmap *del_lines) { - struct moved_entry **pmb = NULL; /* potentially moved blocks */ + struct moved_block *pmb = NULL; /* potentially moved blocks */ int pmb_nr = 0, pmb_alloc = 0; int n, flipped_block = 1, block_length = 0; @@@ -1094,11 -1070,7 +1094,11 @@@ } if (!match) { + int i; + adjust_last_block(o, n, block_length); + for(i = 0; i < pmb_nr; i++) + moved_block_clear(&pmb[i]); pmb_nr = 0; block_length = 0; continue; @@@ -1126,12 -1098,14 +1126,12 @@@ ALLOC_GROW(pmb, pmb_nr + 1, pmb_alloc); if (o->color_moved_ws_handling & COLOR_MOVED_WS_ALLOW_INDENTATION_CHANGE) { - struct ws_delta *wsd = xmalloc(sizeof(*match->wsd)); - if (compute_ws_delta(l, match->es, wsd)) { - match->wsd = wsd; - pmb[pmb_nr++] = match; - } else - free(wsd); + if (compute_ws_delta(l, match->es, + &pmb[pmb_nr].wsd)) + pmb[pmb_nr++].match = match; } else { - pmb[pmb_nr++] = match; + pmb[pmb_nr].wsd.string = NULL; + pmb[pmb_nr++].match = match; } } @@@ -1148,8 -1122,6 +1148,8 @@@ } adjust_last_block(o, n, block_length); + for(n = 0; n < pmb_nr; n++) + moved_block_clear(&pmb[n]); free(pmb); } @@@ -1215,13 -1187,12 +1215,13 @@@ static void dim_moved_lines(struct diff } static void emit_line_ws_markup(struct diff_options *o, - const char *set, const char *reset, - const char *line, int len, - const char *set_sign, char sign, + const char *set_sign, const char *set, + const char *reset, + int sign_index, const char *line, int len, unsigned ws_rule, int blank_at_eof) { const char *ws = NULL; + int sign = o->output_indicators[sign_index]; if (o->ws_error_highlight & ws_rule) { ws = diff_get_color_opt(o, DIFF_WHITESPACE); @@@ -1230,15 -1201,18 +1230,15 @@@ } if (!ws && !set_sign) - emit_line_0(o, set, 0, reset, sign, line, len); + emit_line_0(o, set, NULL, 0, reset, sign, line, len); else if (!ws) { - /* Emit just the prefix, then the rest. */ - emit_line_0(o, set_sign ? set_sign : set, !!set_sign, reset, - sign, "", 0); - emit_line_0(o, set, 0, reset, 0, line, len); + emit_line_0(o, set_sign, set, !!set_sign, reset, sign, line, len); } else if (blank_at_eof) /* Blank line at EOF - paint '+' as well */ - emit_line_0(o, ws, 0, reset, sign, line, len); + emit_line_0(o, ws, NULL, 0, reset, sign, line, len); else { /* Emit just the prefix, then the rest. */ - emit_line_0(o, set_sign ? set_sign : set, !!set_sign, reset, + emit_line_0(o, set_sign ? set_sign : set, NULL, !!set_sign, reset, sign, "", 0); ws_check_emit(line, len, ws_rule, o->file, set, reset, ws); @@@ -1262,7 -1236,7 +1262,7 @@@ static void emit_diff_symbol_from_struc context = diff_get_color_opt(o, DIFF_CONTEXT); reset = diff_get_color_opt(o, DIFF_RESET); putc('\n', o->file); - emit_line_0(o, context, 0, reset, '\\', + emit_line_0(o, context, NULL, 0, reset, '\\', nneof, strlen(nneof)); break; case DIFF_SYMBOL_SUBMODULE_HEADER: @@@ -1300,8 -1274,7 +1300,8 @@@ else if (c == '-') set = diff_get_color_opt(o, DIFF_FILE_OLD); } - emit_line_ws_markup(o, set, reset, line, len, set_sign, ' ', + emit_line_ws_markup(o, set_sign, set, reset, + OUTPUT_INDICATOR_CONTEXT, line, len, flags & (DIFF_SYMBOL_CONTENT_WS_MASK), 0); break; case DIFF_SYMBOL_PLUS: @@@ -1344,8 -1317,7 +1344,8 @@@ set = diff_get_color_opt(o, DIFF_CONTEXT_BOLD); flags &= ~DIFF_SYMBOL_CONTENT_WS_MASK; } - emit_line_ws_markup(o, set, reset, line, len, set_sign, '+', + emit_line_ws_markup(o, set_sign, set, reset, + OUTPUT_INDICATOR_NEW, line, len, flags & DIFF_SYMBOL_CONTENT_WS_MASK, flags & DIFF_SYMBOL_CONTENT_BLANK_LINE_EOF); break; @@@ -1388,8 -1360,7 +1388,8 @@@ else set = diff_get_color_opt(o, DIFF_CONTEXT_DIM); } - emit_line_ws_markup(o, set, reset, line, len, set_sign, '-', + emit_line_ws_markup(o, set_sign, set, reset, + OUTPUT_INDICATOR_OLD, line, len, flags & DIFF_SYMBOL_CONTENT_WS_MASK, 0); break; case DIFF_SYMBOL_WORDS_PORCELAIN: @@@ -1727,12 -1698,12 +1727,12 @@@ static void emit_rewrite_diff(const cha quote_two_c_style(&a_name, a_prefix, name_a, 0); quote_two_c_style(&b_name, b_prefix, name_b, 0); - size_one = fill_textconv(textconv_one, one, &data_one); - size_two = fill_textconv(textconv_two, two, &data_two); + size_one = fill_textconv(o->repo, textconv_one, one, &data_one); + size_two = fill_textconv(o->repo, textconv_two, two, &data_two); memset(&ecbdata, 0, sizeof(ecbdata)); ecbdata.color_diff = want_color(o->use_color); - ecbdata.ws_rule = whitespace_rule(name_b); + ecbdata.ws_rule = whitespace_rule(o->repo->index, name_b); ecbdata.opt = o; if (ecbdata.ws_rule & WS_BLANK_AT_EOF) { mmfile_t mf1, mf2; @@@ -1912,19 -1883,17 +1912,17 @@@ static int color_words_output_graph_pre } } - static void fn_out_diff_words_aux(void *priv, char *line, unsigned long len) + static void fn_out_diff_words_aux(void *priv, + long minus_first, long minus_len, + long plus_first, long plus_len, + const char *func, long funclen) { struct diff_words_data *diff_words = priv; struct diff_words_style *style = diff_words->style; - int minus_first, minus_len, plus_first, plus_len; const char *minus_begin, *minus_end, *plus_begin, *plus_end; struct diff_options *opt = diff_words->opt; const char *line_prefix; - if (line[0] != '@' || parse_hunk_header(line, len, - &minus_first, &minus_len, &plus_first, &plus_len)) - return; - assert(opt); line_prefix = diff_line_prefix(opt); @@@ -2074,8 -2043,8 +2072,8 @@@ static void diff_words_show(struct diff xpp.flags = 0; /* as only the hunk header will be parsed, we need a 0-context */ xecfg.ctxlen = 0; - if (xdi_diff_outf(&minus, &plus, fn_out_diff_words_aux, diff_words, - &xpp, &xecfg)) + if (xdi_diff_outf(&minus, &plus, fn_out_diff_words_aux, NULL, + diff_words, &xpp, &xecfg)) die("unable to generate word diff"); free(minus.ptr); free(plus.ptr); @@@ -2120,25 -2089,23 +2118,25 @@@ static void diff_words_flush(struct emi } } -static void diff_filespec_load_driver(struct diff_filespec *one) +static void diff_filespec_load_driver(struct diff_filespec *one, + struct index_state *istate) { /* Use already-loaded driver */ if (one->driver) return; if (S_ISREG(one->mode)) - one->driver = userdiff_find_by_path(one->path); + one->driver = userdiff_find_by_path(istate, one->path); /* Fallback to default settings */ if (!one->driver) one->driver = userdiff_find_by_name("default"); } -static const char *userdiff_word_regex(struct diff_filespec *one) +static const char *userdiff_word_regex(struct diff_filespec *one, + struct index_state *istate) { - diff_filespec_load_driver(one); + diff_filespec_load_driver(one, istate); return one->driver->word_regex; } @@@ -2161,9 -2128,9 +2159,9 @@@ static void init_diff_words_data(struc xcalloc(1, sizeof(struct emitted_diff_symbols)); if (!o->word_regex) - o->word_regex = userdiff_word_regex(one); + o->word_regex = userdiff_word_regex(one, o->repo->index); if (!o->word_regex) - o->word_regex = userdiff_word_regex(two); + o->word_regex = userdiff_word_regex(two, o->repo->index); if (!o->word_regex) o->word_regex = diff_word_regex_cfg; if (o->word_regex) { @@@ -2964,11 -2931,16 +2962,11 @@@ static void show_dirstat(struct diff_op struct diff_filepair *p = q->queue[i]; const char *name; unsigned long copied, added, damage; - int content_changed; name = p->two->path ? p->two->path : p->one->path; - if (p->one->oid_valid && p->two->oid_valid) - content_changed = oidcmp(&p->one->oid, &p->two->oid); - else - content_changed = 1; - - if (!content_changed) { + if (p->one->oid_valid && p->two->oid_valid && + oideq(&p->one->oid, &p->two->oid)) { /* * The SHA1 has not changed, so pre-/post-content is * identical. We can therefore skip looking at the @@@ -2991,19 -2963,18 +2989,19 @@@ } if (DIFF_FILE_VALID(p->one) && DIFF_FILE_VALID(p->two)) { - diff_populate_filespec(p->one, 0); - diff_populate_filespec(p->two, 0); - diffcore_count_changes(p->one, p->two, NULL, NULL, + diff_populate_filespec(options->repo, p->one, 0); + diff_populate_filespec(options->repo, p->two, 0); + diffcore_count_changes(options->repo, + p->one, p->two, NULL, NULL, &copied, &added); diff_free_filespec_data(p->one); diff_free_filespec_data(p->two); } else if (DIFF_FILE_VALID(p->one)) { - diff_populate_filespec(p->one, CHECK_SIZE_ONLY); + diff_populate_filespec(options->repo, p->one, CHECK_SIZE_ONLY); copied = added = 0; diff_free_filespec_data(p->one); } else if (DIFF_FILE_VALID(p->two)) { - diff_populate_filespec(p->two, CHECK_SIZE_ONLY); + diff_populate_filespec(options->repo, p->two, CHECK_SIZE_ONLY); copied = 0; added = p->two->size; diff_free_filespec_data(p->two); @@@ -3016,7 -2987,7 +3014,7 @@@ * made to the preimage. * If the resulting damage is zero, we know that * diffcore_count_changes() considers the two entries to - * be identical, but since content_changed is true, we + * be identical, but since the oid changed, we * know that there must have been _some_ kind of change, * so we force all entries to have damage > 0. */ @@@ -3130,6 -3101,15 +3128,15 @@@ static int is_conflict_marker(const cha return 1; } + static void checkdiff_consume_hunk(void *priv, + long ob, long on, long nb, long nn, + const char *func, long funclen) + + { + struct checkdiff_t *data = priv; + data->lineno = nb - 1; + } + static void checkdiff_consume(void *priv, char *line, unsigned long len) { struct checkdiff_t *data = priv; @@@ -3165,12 -3145,6 +3172,6 @@@ data->o->file, set, reset, ws); } else if (line[0] == ' ') { data->lineno++; - } else if (line[0] == '@') { - char *plus = strchr(line, '+'); - if (plus) - data->lineno = strtol(plus, NULL, 10) - 1; - else - die("invalid diff"); } } @@@ -3277,16 -3251,15 +3278,16 @@@ static void emit_binary_diff(struct dif emit_binary_diff_body(o, two, one); } -int diff_filespec_is_binary(struct diff_filespec *one) +int diff_filespec_is_binary(struct repository *r, + struct diff_filespec *one) { if (one->is_binary == -1) { - diff_filespec_load_driver(one); + diff_filespec_load_driver(one, r->index); if (one->driver->binary != -1) one->is_binary = one->driver->binary; else { if (!one->data && DIFF_FILE_VALID(one)) - diff_populate_filespec(one, CHECK_BINARY); + diff_populate_filespec(r, one, CHECK_BINARY); if (one->is_binary == -1 && one->data) one->is_binary = buffer_is_binary(one->data, one->size); @@@ -3297,10 -3270,9 +3298,10 @@@ return one->is_binary; } -static const struct userdiff_funcname *diff_funcname_pattern(struct diff_filespec *one) +static const struct userdiff_funcname * +diff_funcname_pattern(struct diff_options *o, struct diff_filespec *one) { - diff_filespec_load_driver(one); + diff_filespec_load_driver(one, o->repo->index); return one->driver->funcname.pattern ? &one->driver->funcname : NULL; } @@@ -3312,13 -3284,12 +3313,13 @@@ void diff_set_mnemonic_prefix(struct di options->b_prefix = b; } -struct userdiff_driver *get_textconv(struct diff_filespec *one) +struct userdiff_driver *get_textconv(struct index_state *istate, + struct diff_filespec *one) { if (!DIFF_FILE_VALID(one)) return NULL; - diff_filespec_load_driver(one); + diff_filespec_load_driver(one, istate); return userdiff_get_textconv(one->driver); } @@@ -3368,8 -3339,8 +3369,8 @@@ static void builtin_diff(const char *na } if (o->flags.allow_textconv) { - textconv_one = get_textconv(one); - textconv_two = get_textconv(two); + textconv_one = get_textconv(o->repo->index, one); + textconv_two = get_textconv(o->repo->index, two); } /* Never use a non-valid filename anywhere if at all possible */ @@@ -3410,13 -3381,13 +3411,13 @@@ if ((one->mode ^ two->mode) & S_IFMT) goto free_ab_and_return; if (complete_rewrite && - (textconv_one || !diff_filespec_is_binary(one)) && - (textconv_two || !diff_filespec_is_binary(two))) { + (textconv_one || !diff_filespec_is_binary(o->repo, one)) && + (textconv_two || !diff_filespec_is_binary(o->repo, two))) { emit_diff_symbol(o, DIFF_SYMBOL_HEADER, header.buf, header.len, 0); strbuf_reset(&header); emit_rewrite_diff(name_a, name_b, one, two, - textconv_one, textconv_two, o); + textconv_one, textconv_two, o); o->found_changes = 1; goto free_ab_and_return; } @@@ -3428,13 -3399,13 +3429,13 @@@ strbuf_reset(&header); goto free_ab_and_return; } else if (!o->flags.text && - ( (!textconv_one && diff_filespec_is_binary(one)) || - (!textconv_two && diff_filespec_is_binary(two)) )) { + ( (!textconv_one && diff_filespec_is_binary(o->repo, one)) || + (!textconv_two && diff_filespec_is_binary(o->repo, two)) )) { struct strbuf sb = STRBUF_INIT; if (!one->data && !two->data && S_ISREG(one->mode) && S_ISREG(two->mode) && !o->flags.binary) { - if (!oidcmp(&one->oid, &two->oid)) { + if (oideq(&one->oid, &two->oid)) { if (must_show_header) emit_diff_symbol(o, DIFF_SYMBOL_HEADER, header.buf, header.len, @@@ -3450,8 -3421,7 +3451,8 @@@ strbuf_release(&sb); goto free_ab_and_return; } - if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0) + if (fill_mmfile(o->repo, &mf1, one) < 0 || + fill_mmfile(o->repo, &mf2, two) < 0) die("unable to read files to diff"); /* Quite common confusing case */ if (mf1.size == mf2.size && @@@ -3488,12 -3458,12 +3489,12 @@@ strbuf_reset(&header); } - mf1.size = fill_textconv(textconv_one, one, &mf1.ptr); - mf2.size = fill_textconv(textconv_two, two, &mf2.ptr); + mf1.size = fill_textconv(o->repo, textconv_one, one, &mf1.ptr); + mf2.size = fill_textconv(o->repo, textconv_two, two, &mf2.ptr); - pe = diff_funcname_pattern(one); + pe = diff_funcname_pattern(o, one); if (!pe) - pe = diff_funcname_pattern(two); + pe = diff_funcname_pattern(o, two); memset(&xpp, 0, sizeof(xpp)); memset(&xecfg, 0, sizeof(xecfg)); @@@ -3502,7 -3472,7 +3503,7 @@@ lbl[0] = NULL; ecbdata.label_path = lbl; ecbdata.color_diff = want_color(o->use_color); - ecbdata.ws_rule = whitespace_rule(name_b); + ecbdata.ws_rule = whitespace_rule(o->repo->index, name_b); if (ecbdata.ws_rule & WS_BLANK_AT_EOF) check_blank_at_eof(&mf1, &mf2, &ecbdata); ecbdata.opt = o; @@@ -3526,8 -3496,8 +3527,8 @@@ xecfg.ctxlen = strtoul(v, NULL, 10); if (o->word_diff) init_diff_words_data(&ecbdata, o, one, two); - if (xdi_diff_outf(&mf1, &mf2, fn_out_consume, &ecbdata, - &xpp, &xecfg)) + if (xdi_diff_outf(&mf1, &mf2, NULL, fn_out_consume, + &ecbdata, &xpp, &xecfg)) die("unable to generate diff for %s", one->path); if (o->word_diff) free_diff_words_data(&ecbdata); @@@ -3600,23 -3570,22 +3601,23 @@@ static void builtin_diffstat(const cha return; } - same_contents = !oidcmp(&one->oid, &two->oid); + same_contents = oideq(&one->oid, &two->oid); - if (diff_filespec_is_binary(one) || diff_filespec_is_binary(two)) { + if (diff_filespec_is_binary(o->repo, one) || + diff_filespec_is_binary(o->repo, two)) { data->is_binary = 1; if (same_contents) { data->added = 0; data->deleted = 0; } else { - data->added = diff_filespec_size(two); - data->deleted = diff_filespec_size(one); + data->added = diff_filespec_size(o->repo, two); + data->deleted = diff_filespec_size(o->repo, one); } } else if (complete_rewrite) { - diff_populate_filespec(one, 0); - diff_populate_filespec(two, 0); + diff_populate_filespec(o->repo, one, 0); + diff_populate_filespec(o->repo, two, 0); data->deleted = count_lines(one->data, one->size); data->added = count_lines(two->data, two->size); } @@@ -3626,8 -3595,7 +3627,8 @@@ xpparam_t xpp; xdemitconf_t xecfg; - if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0) + if (fill_mmfile(o->repo, &mf1, one) < 0 || + fill_mmfile(o->repo, &mf2, two) < 0) die("unable to read files to diff"); memset(&xpp, 0, sizeof(xpp)); @@@ -3637,8 -3605,8 +3638,8 @@@ xpp.anchors_nr = o->anchors_nr; xecfg.ctxlen = o->context; xecfg.interhunkctxlen = o->interhunkcontext; - if (xdi_diff_outf(&mf1, &mf2, diffstat_consume, diffstat, - &xpp, &xecfg)) + if (xdi_diff_outf(&mf1, &mf2, discard_hunk_line, + diffstat_consume, diffstat, &xpp, &xecfg)) die("unable to generate diffstat for %s", one->path); } @@@ -3662,11 -3630,10 +3663,11 @@@ static void builtin_checkdiff(const cha data.filename = name_b ? name_b : name_a; data.lineno = 0; data.o = o; - data.ws_rule = whitespace_rule(attr_path); - data.conflict_marker_size = ll_merge_marker_size(attr_path); + data.ws_rule = whitespace_rule(o->repo->index, attr_path); + data.conflict_marker_size = ll_merge_marker_size(o->repo->index, attr_path); - if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0) + if (fill_mmfile(o->repo, &mf1, one) < 0 || + fill_mmfile(o->repo, &mf2, two) < 0) die("unable to read files to diff"); /* @@@ -3675,7 -3642,7 +3676,7 @@@ * introduced changes, and as long as the "new" side is text, we * can and should check what it introduces. */ - if (diff_filespec_is_binary(two)) + if (diff_filespec_is_binary(o->repo, two)) goto free_and_return; else { /* Crazy xdl interfaces.. */ @@@ -3686,7 -3653,8 +3687,8 @@@ memset(&xecfg, 0, sizeof(xecfg)); xecfg.ctxlen = 1; /* at least one context line */ xpp.flags = 0; - if (xdi_diff_outf(&mf1, &mf2, checkdiff_consume, &data, + if (xdi_diff_outf(&mf1, &mf2, checkdiff_consume_hunk, + checkdiff_consume, &data, &xpp, &xecfg)) die("unable to generate checkdiff for %s", one->path); @@@ -3748,10 -3716,7 +3750,10 @@@ void fill_filespec(struct diff_filespe * the work tree has that object contents, return true, so that * prepare_temp_file() does not have to inflate and extract. */ -static int reuse_worktree_file(const char *name, const struct object_id *oid, int want_file) +static int reuse_worktree_file(struct index_state *istate, + const char *name, + const struct object_id *oid, + int want_file) { const struct cache_entry *ce; struct stat st; @@@ -3770,7 -3735,7 +3772,7 @@@ * by diff-cache --cached, which does read the cache before * calling us. */ - if (!active_cache) + if (!istate->cache) return 0; /* We want to avoid the working directory if our caller @@@ -3789,20 -3754,20 +3791,20 @@@ * Similarly, if we'd have to convert the file contents anyway, that * makes the optimization not worthwhile. */ - if (!want_file && would_convert_to_git(&the_index, name)) + if (!want_file && would_convert_to_git(istate, name)) return 0; len = strlen(name); - pos = cache_name_pos(name, len); + pos = index_name_pos(istate, name, len); if (pos < 0) return 0; - ce = active_cache[pos]; + ce = istate->cache[pos]; /* * This is not the sha1 we are looking for, or * unreusable because it is not a regular file. */ - if (oidcmp(oid, &ce->oid) || !S_ISREG(ce->ce_mode)) + if (!oideq(oid, &ce->oid) || !S_ISREG(ce->ce_mode)) return 0; /* @@@ -3816,7 -3781,7 +3818,7 @@@ * If ce matches the file in the work tree, we can reuse it. */ if (ce_uptodate(ce) || - (!lstat(name, &st) && !ce_match_stat(ce, &st, 0))) + (!lstat(name, &st) && !ie_match_stat(istate, ce, &st, 0))) return 1; return 0; @@@ -3849,9 -3814,7 +3851,9 @@@ static int diff_populate_gitlink(struc * grab the data for the blob (or file) for our own in-core comparison. * diff_filespec has data and size fields for this purpose. */ -int diff_populate_filespec(struct diff_filespec *s, unsigned int flags) +int diff_populate_filespec(struct repository *r, + struct diff_filespec *s, + unsigned int flags) { int size_only = flags & CHECK_SIZE_ONLY; int err = 0; @@@ -3878,7 -3841,7 +3880,7 @@@ return diff_populate_gitlink(s, size_only); if (!s->oid_valid || - reuse_worktree_file(s->path, &s->oid, 0)) { + reuse_worktree_file(r->index, s->path, &s->oid, 0)) { struct strbuf buf = STRBUF_INIT; struct stat st; int fd; @@@ -3911,7 -3874,7 +3913,7 @@@ * point if the path requires us to run the content * conversion. */ - if (size_only && !would_convert_to_git(&the_index, s->path)) + if (size_only && !would_convert_to_git(r->index, s->path)) return 0; /* @@@ -3938,7 -3901,7 +3940,7 @@@ /* * Convert from working tree format to canonical git format */ - if (convert_to_git(&the_index, s->path, s->data, s->size, &buf, conv_flags)) { + if (convert_to_git(r->index, s->path, s->data, s->size, &buf, conv_flags)) { size_t size = 0; munmap(s->data, s->size); s->should_munmap = 0; @@@ -3950,7 -3913,8 +3952,7 @@@ else { enum object_type type; if (size_only || (flags & CHECK_BINARY)) { - type = oid_object_info(the_repository, &s->oid, - &s->size); + type = oid_object_info(r, &s->oid, &s->size); if (type < 0) die("unable to read %s", oid_to_hex(&s->oid)); @@@ -3988,8 -3952,7 +3990,8 @@@ void diff_free_filespec_data(struct dif FREE_AND_NULL(s->cnt_data); } -static void prep_temp_blob(const char *path, struct diff_tempfile *temp, +static void prep_temp_blob(struct index_state *istate, + const char *path, struct diff_tempfile *temp, void *blob, unsigned long size, const struct object_id *oid, @@@ -4007,7 -3970,7 +4009,7 @@@ temp->tempfile = mks_tempfile_ts(tempfile.buf, strlen(base) + 1); if (!temp->tempfile) die_errno("unable to create temp-file"); - if (convert_to_working_tree(&the_index, path, + if (convert_to_working_tree(istate, path, (const char *)blob, (size_t)size, &buf)) { blob = buf.buf; size = buf.len; @@@ -4023,9 -3986,8 +4025,9 @@@ free(path_dup); } -static struct diff_tempfile *prepare_temp_file(const char *name, - struct diff_filespec *one) +static struct diff_tempfile *prepare_temp_file(struct repository *r, + const char *name, + struct diff_filespec *one) { struct diff_tempfile *temp = claim_diff_tempfile(); @@@ -4042,7 -4004,7 +4044,7 @@@ if (!S_ISGITLINK(one->mode) && (!one->oid_valid || - reuse_worktree_file(name, &one->oid, 1))) { + reuse_worktree_file(r->index, name, &one->oid, 1))) { struct stat st; if (lstat(name, &st) < 0) { if (errno == ENOENT) @@@ -4053,7 -4015,7 +4055,7 @@@ struct strbuf sb = STRBUF_INIT; if (strbuf_readlink(&sb, name, st.st_size) < 0) die_errno("readlink(%s)", name); - prep_temp_blob(name, temp, sb.buf, sb.len, + prep_temp_blob(r->index, name, temp, sb.buf, sb.len, (one->oid_valid ? &one->oid : &null_oid), (one->oid_valid ? @@@ -4078,21 -4040,19 +4080,21 @@@ return temp; } else { - if (diff_populate_filespec(one, 0)) + if (diff_populate_filespec(r, one, 0)) die("cannot read data blob for %s", one->path); - prep_temp_blob(name, temp, one->data, one->size, + prep_temp_blob(r->index, name, temp, + one->data, one->size, &one->oid, one->mode); } return temp; } -static void add_external_diff_name(struct argv_array *argv, +static void add_external_diff_name(struct repository *r, + struct argv_array *argv, const char *name, struct diff_filespec *df) { - struct diff_tempfile *temp = prepare_temp_file(name, df); + struct diff_tempfile *temp = prepare_temp_file(r, name, df); argv_array_push(argv, temp->name); argv_array_push(argv, temp->hex); argv_array_push(argv, temp->mode); @@@ -4121,11 -4081,11 +4123,11 @@@ static void run_external_diff(const cha argv_array_push(&argv, name); if (one && two) { - add_external_diff_name(&argv, name, one); + add_external_diff_name(o->repo, &argv, name, one); if (!other) - add_external_diff_name(&argv, name, two); + add_external_diff_name(o->repo, &argv, name, two); else { - add_external_diff_name(&argv, other, two); + add_external_diff_name(o->repo, &argv, other, two); argv_array_push(&argv, other); argv_array_push(&argv, xfrm_msg); } @@@ -4212,16 -4172,14 +4214,16 @@@ static void fill_metainfo(struct strbu default: *must_show_header = 0; } - if (one && two && oidcmp(&one->oid, &two->oid)) { + if (one && two && !oideq(&one->oid, &two->oid)) { const unsigned hexsz = the_hash_algo->hexsz; int abbrev = o->flags.full_index ? hexsz : DEFAULT_ABBREV; if (o->flags.binary) { mmfile_t mf; - if ((!fill_mmfile(&mf, one) && diff_filespec_is_binary(one)) || - (!fill_mmfile(&mf, two) && diff_filespec_is_binary(two))) + if ((!fill_mmfile(o->repo, &mf, one) && + diff_filespec_is_binary(o->repo, one)) || + (!fill_mmfile(o->repo, &mf, two) && + diff_filespec_is_binary(o->repo, two))) abbrev = hexsz; } strbuf_addf(msg, "%s%sindex %s..%s", line_prefix, set, @@@ -4249,9 -4207,7 +4251,9 @@@ static void run_diff_cmd(const char *pg if (o->flags.allow_external) { - struct userdiff_driver *drv = userdiff_find_by_path(attr_path); + struct userdiff_driver *drv; + + drv = userdiff_find_by_path(o->repo->index, attr_path); if (drv && drv->external) pgm = drv->external; } @@@ -4280,7 -4236,7 +4282,7 @@@ fprintf(o->file, "* Unmerged path %s\n", name); } -static void diff_fill_oid_info(struct diff_filespec *one) +static void diff_fill_oid_info(struct diff_filespec *one, struct index_state *istate) { if (DIFF_FILE_VALID(one)) { if (!one->oid_valid) { @@@ -4291,7 -4247,7 +4293,7 @@@ } if (lstat(one->path, &st) < 0) die_errno("stat '%s'", one->path); - if (index_path(&one->oid, one->path, &st, 0)) + if (index_path(istate, &one->oid, one->path, &st, 0)) die("cannot hash %s", one->path); } } @@@ -4302,12 -4258,12 +4304,12 @@@ static void strip_prefix(int prefix_length, const char **namep, const char **otherp) { /* Strip the prefix but do not molest /dev/null and absolute paths */ - if (*namep && **namep != '/') { + if (*namep && !is_absolute_path(*namep)) { *namep += prefix_length; if (**namep == '/') ++*namep; } - if (*otherp && **otherp != '/') { + if (*otherp && !is_absolute_path(*otherp)) { *otherp += prefix_length; if (**otherp == '/') ++*otherp; @@@ -4339,8 -4295,8 +4341,8 @@@ static void run_diff(struct diff_filepa return; } - diff_fill_oid_info(one); - diff_fill_oid_info(two); + diff_fill_oid_info(one, o->repo->index); + diff_fill_oid_info(two, o->repo->index); if (!pgm && DIFF_FILE_VALID(one) && DIFF_FILE_VALID(two) && @@@ -4351,8 -4307,7 +4353,8 @@@ */ struct diff_filespec *null = alloc_filespec(two->path); run_diff_cmd(NULL, name, other, attr_path, - one, null, &msg, o, p); + one, null, &msg, + o, p); free(null); strbuf_release(&msg); @@@ -4376,8 -4331,7 +4378,8 @@@ static void run_diffstat(struct diff_fi if (DIFF_PAIR_UNMERGED(p)) { /* unmerged */ - builtin_diffstat(p->one->path, NULL, NULL, NULL, diffstat, o, p); + builtin_diffstat(p->one->path, NULL, NULL, NULL, + diffstat, o, p); return; } @@@ -4387,11 -4341,10 +4389,11 @@@ if (o->prefix_length) strip_prefix(o->prefix_length, &name, &other); - diff_fill_oid_info(p->one); - diff_fill_oid_info(p->two); + diff_fill_oid_info(p->one, o->repo->index); + diff_fill_oid_info(p->two, o->repo->index); - builtin_diffstat(name, other, p->one, p->two, diffstat, o, p); + builtin_diffstat(name, other, p->one, p->two, + diffstat, o, p); } static void run_checkdiff(struct diff_filepair *p, struct diff_options *o) @@@ -4412,22 -4365,18 +4414,22 @@@ if (o->prefix_length) strip_prefix(o->prefix_length, &name, &other); - diff_fill_oid_info(p->one); - diff_fill_oid_info(p->two); + diff_fill_oid_info(p->one, o->repo->index); + diff_fill_oid_info(p->two, o->repo->index); builtin_checkdiff(name, other, attr_path, p->one, p->two, o); } -void diff_setup(struct diff_options *options) +void repo_diff_setup(struct repository *r, struct diff_options *options) { memcpy(options, &default_diff_options, sizeof(*options)); options->file = stdout; + options->repo = r; + options->output_indicators[OUTPUT_INDICATOR_NEW] = '+'; + options->output_indicators[OUTPUT_INDICATOR_OLD] = '-'; + options->output_indicators[OUTPUT_INDICATOR_CONTEXT] = ' '; options->abbrev = DEFAULT_ABBREV; options->line_termination = '\n'; options->break_opt = -1; @@@ -4905,12 -4854,6 +4907,12 @@@ int diff_opt_parse(struct diff_options options->output_format |= DIFF_FORMAT_DIFFSTAT; } else if (!strcmp(arg, "--no-compact-summary")) options->flags.stat_with_summary = 0; + else if (skip_prefix(arg, "--output-indicator-new=", &arg)) + options->output_indicators[OUTPUT_INDICATOR_NEW] = arg[0]; + else if (skip_prefix(arg, "--output-indicator-old=", &arg)) + options->output_indicators[OUTPUT_INDICATOR_OLD] = arg[0]; + else if (skip_prefix(arg, "--output-indicator-context=", &arg)) + options->output_indicators[OUTPUT_INDICATOR_CONTEXT] = arg[0]; /* renames options */ else if (starts_with(arg, "-B") || @@@ -5382,7 -5325,7 +5384,7 @@@ int diff_unmodified_pair(struct diff_fi * dealing with a change. */ if (one->oid_valid && two->oid_valid && - !oidcmp(&one->oid, &two->oid) && + oideq(&one->oid, &two->oid) && !one->dirty_submodule && !two->dirty_submodule) return 1; /* no change */ if (!one->oid_valid && !two->oid_valid) @@@ -5516,7 -5459,7 +5518,7 @@@ static void diff_resolve_rename_copy(vo else p->status = DIFF_STATUS_RENAMED; } - else if (oidcmp(&p->one->oid, &p->two->oid) || + else if (!oideq(&p->one->oid, &p->two->oid) || p->one->mode != p->two->mode || p->one->dirty_submodule || p->two->dirty_submodule || @@@ -5666,10 -5609,6 +5668,6 @@@ static void patch_id_consume(void *priv struct patch_id_t *data = priv; int new_len; - /* Ignore line numbers when computing the SHA1 of the patch */ - if (starts_with(line, "@@ -")) - return; - new_len = remove_space(line, len); git_SHA1_Update(data->ctx, line, new_len); @@@ -5722,8 -5661,8 +5720,8 @@@ static int diff_get_patch_id(struct dif if (DIFF_PAIR_UNMERGED(p)) continue; - diff_fill_oid_info(p->one); - diff_fill_oid_info(p->two); + diff_fill_oid_info(p->one, options->repo->index); + diff_fill_oid_info(p->two, options->repo->index); len1 = remove_space(p->one->path, strlen(p->one->path)); len2 = remove_space(p->two->path, strlen(p->two->path)); @@@ -5755,12 -5694,12 +5753,12 @@@ if (diff_header_only) continue; - if (fill_mmfile(&mf1, p->one) < 0 || - fill_mmfile(&mf2, p->two) < 0) + if (fill_mmfile(options->repo, &mf1, p->one) < 0 || + fill_mmfile(options->repo, &mf2, p->two) < 0) return error("unable to read files to diff"); - if (diff_filespec_is_binary(p->one) || - diff_filespec_is_binary(p->two)) { + if (diff_filespec_is_binary(options->repo, p->one) || + diff_filespec_is_binary(options->repo, p->two)) { git_SHA1_Update(&ctx, oid_to_hex(&p->one->oid), GIT_SHA1_HEXSZ); git_SHA1_Update(&ctx, oid_to_hex(&p->two->oid), @@@ -5771,8 -5710,8 +5769,8 @@@ xpp.flags = 0; xecfg.ctxlen = 3; xecfg.flags = 0; - if (xdi_diff_outf(&mf1, &mf2, patch_id_consume, &data, - &xpp, &xecfg)) + if (xdi_diff_outf(&mf1, &mf2, discard_hunk_line, + patch_id_consume, &data, &xpp, &xecfg)) return error("unable to generate patch-id diff for %s", p->one->path); } @@@ -5878,8 -5817,8 +5876,8 @@@ static void diff_flush_patch_all_file_p if (o->color_moved == COLOR_MOVED_ZEBRA_DIM) dim_moved_lines(o); - hashmap_free(&add_lines, 0); - hashmap_free(&del_lines, 0); + hashmap_free(&add_lines, 1); + hashmap_free(&del_lines, 1); } for (i = 0; i < esm.nr; i++) @@@ -6063,21 -6002,19 +6061,21 @@@ static void diffcore_apply_filter(struc } /* Check whether two filespecs with the same mode and size are identical */ -static int diff_filespec_is_identical(struct diff_filespec *one, +static int diff_filespec_is_identical(struct repository *r, + struct diff_filespec *one, struct diff_filespec *two) { if (S_ISGITLINK(one->mode)) return 0; - if (diff_populate_filespec(one, 0)) + if (diff_populate_filespec(r, one, 0)) return 0; - if (diff_populate_filespec(two, 0)) + if (diff_populate_filespec(r, two, 0)) return 0; return !memcmp(one->data, two->data, one->size); } -static int diff_filespec_check_stat_unmatch(struct diff_filepair *p) +static int diff_filespec_check_stat_unmatch(struct repository *r, + struct diff_filepair *p) { if (p->done_skip_stat_unmatch) return p->skip_stat_unmatch_result; @@@ -6101,10 -6038,10 +6099,10 @@@ !DIFF_FILE_VALID(p->two) || (p->one->oid_valid && p->two->oid_valid) || (p->one->mode != p->two->mode) || - diff_populate_filespec(p->one, CHECK_SIZE_ONLY) || - diff_populate_filespec(p->two, CHECK_SIZE_ONLY) || + diff_populate_filespec(r, p->one, CHECK_SIZE_ONLY) || + diff_populate_filespec(r, p->two, CHECK_SIZE_ONLY) || (p->one->size != p->two->size) || - !diff_filespec_is_identical(p->one, p->two)) /* (2) */ + !diff_filespec_is_identical(r, p->one, p->two)) /* (2) */ p->skip_stat_unmatch_result = 1; return p->skip_stat_unmatch_result; } @@@ -6119,7 -6056,7 +6117,7 @@@ static void diffcore_skip_stat_unmatch( for (i = 0; i < q->nr; i++) { struct diff_filepair *p = q->queue[i]; - if (diff_filespec_check_stat_unmatch(p)) + if (diff_filespec_check_stat_unmatch(diffopt->repo, p)) diff_q(&outq, p); else { /* @@@ -6161,8 -6098,7 +6159,8 @@@ void diffcore_std(struct diff_options * if (!options->found_follow) { /* See try_to_follow_renames() in tree-diff.c */ if (options->break_opt != -1) - diffcore_break(options->break_opt); + diffcore_break(options->repo, + options->break_opt); if (options->detect_rename) diffcore_rename(options); if (options->break_opt != -1) @@@ -6313,7 -6249,7 +6311,7 @@@ void diff_change(struct diff_options *o return; if (options->flags.quick && options->skip_stat_unmatch && - !diff_filespec_check_stat_unmatch(p)) + !diff_filespec_check_stat_unmatch(options->repo, p)) return; options->flags.has_changes = 1; @@@ -6335,10 -6271,8 +6333,10 @@@ struct diff_filepair *diff_unmerge(stru return pair; } -static char *run_textconv(const char *pgm, struct diff_filespec *spec, - size_t *outsize) +static char *run_textconv(struct repository *r, + const char *pgm, + struct diff_filespec *spec, + size_t *outsize) { struct diff_tempfile *temp; const char *argv[3]; @@@ -6347,7 -6281,7 +6345,7 @@@ struct strbuf buf = STRBUF_INIT; int err = 0; - temp = prepare_temp_file(spec->path, spec); + temp = prepare_temp_file(r, spec->path, spec); *arg++ = pgm; *arg++ = temp->name; *arg = NULL; @@@ -6374,8 -6308,7 +6372,8 @@@ return strbuf_detach(&buf, outsize); } -size_t fill_textconv(struct userdiff_driver *driver, +size_t fill_textconv(struct repository *r, + struct userdiff_driver *driver, struct diff_filespec *df, char **outbuf) { @@@ -6386,7 -6319,7 +6384,7 @@@ *outbuf = ""; return 0; } - if (diff_populate_filespec(df, 0)) + if (diff_populate_filespec(r, df, 0)) die("unable to read files to diff"); *outbuf = df->data; return df->size; @@@ -6403,7 -6336,7 +6401,7 @@@ return size; } - *outbuf = run_textconv(driver->textconv, df, &size); + *outbuf = run_textconv(r, driver->textconv, df, &size); if (!*outbuf) die("unable to read files to diff"); @@@ -6423,8 -6356,7 +6421,8 @@@ return size; } -int textconv_object(const char *path, +int textconv_object(struct repository *r, + const char *path, unsigned mode, const struct object_id *oid, int oid_valid, @@@ -6436,13 -6368,13 +6434,13 @@@ df = alloc_filespec(path); fill_filespec(df, oid, oid_valid, mode); - textconv = get_textconv(df); + textconv = get_textconv(r->index, df); if (!textconv) { free_filespec(df); return 0; } - *buf_size = fill_textconv(textconv, df, buf); + *buf_size = fill_textconv(r, textconv, df, buf); free_filespec(df); return 1; } diff --combined diffcore-pickaxe.c index d2361e06a1,25e12148e4..69fc55ea1e --- a/diffcore-pickaxe.c +++ b/diffcore-pickaxe.c @@@ -62,7 -62,8 +62,8 @@@ static int diff_grep(mmfile_t *one, mmf ecbdata.hit = 0; xecfg.ctxlen = o->context; xecfg.interhunkctxlen = o->interhunkcontext; - if (xdi_diff_outf(one, two, diffgrep_consume, &ecbdata, &xpp, &xecfg)) + if (xdi_diff_outf(one, two, discard_hunk_line, diffgrep_consume, + &ecbdata, &xpp, &xecfg)) return 0; return ecbdata.hit; } @@@ -139,8 -140,8 +140,8 @@@ static int pickaxe_match(struct diff_fi return 0; if (o->flags.allow_textconv) { - textconv_one = get_textconv(p->one); - textconv_two = get_textconv(p->two); + textconv_one = get_textconv(o->repo->index, p->one); + textconv_two = get_textconv(o->repo->index, p->two); } /* @@@ -153,8 -154,8 +154,8 @@@ if (textconv_one == textconv_two && diff_unmodified_pair(p)) return 0; - mf1.size = fill_textconv(textconv_one, p->one, &mf1.ptr); - mf2.size = fill_textconv(textconv_two, p->two, &mf2.ptr); + mf1.size = fill_textconv(o->repo, textconv_one, p->one, &mf1.ptr); + mf2.size = fill_textconv(o->repo, textconv_two, p->two, &mf2.ptr); ret = fn(DIFF_FILE_VALID(p->one) ? &mf1 : NULL, DIFF_FILE_VALID(p->two) ? &mf2 : NULL, diff --combined range-diff.c index bd8083f2d1,2ef372bbac..3958720f00 --- a/range-diff.c +++ b/range-diff.c @@@ -38,14 -38,6 +38,14 @@@ static int read_patches(const char *ran argv_array_pushl(&cp.args, "log", "--no-color", "-p", "--no-merges", "--reverse", "--date-order", "--decorate=no", + /* + * Choose indicators that are not used anywhere + * else in diffs, but still look reasonable + * (e.g. will not be confusing when debugging) + */ + "--output-indicator-new=>", + "--output-indicator-old=<", + "--output-indicator-context=#", "--no-abbrev-commit", range, NULL); cp.out = -1; @@@ -90,7 -82,6 +90,7 @@@ strbuf_addch(&buf, '\n'); if (!util->diff_offset) util->diff_offset = buf.len; + strbuf_addch(&buf, ' '); strbuf_addbuf(&buf, &line); } else if (in_header) { if (starts_with(line.buf, "Author: ")) { @@@ -117,19 -108,8 +117,19 @@@ * we are not interested. */ continue; - else + else if (line.buf[0] == '>') { + strbuf_addch(&buf, '+'); + strbuf_add(&buf, line.buf + 1, line.len - 1); + } else if (line.buf[0] == '<') { + strbuf_addch(&buf, '-'); + strbuf_add(&buf, line.buf + 1, line.len - 1); + } else if (line.buf[0] == '#') { + strbuf_addch(&buf, ' '); + strbuf_add(&buf, line.buf + 1, line.len - 1); + } else { + strbuf_addch(&buf, ' '); strbuf_addbuf(&buf, &line); + } strbuf_addch(&buf, '\n'); util->diffsize++; @@@ -197,6 -177,12 +197,12 @@@ static void diffsize_consume(void *data (*(int *)data)++; } + static void diffsize_hunk(void *data, long ob, long on, long nb, long nn, + const char *funcline, long funclen) + { + diffsize_consume(data, NULL, 0); + } + static int diffsize(const char *a, const char *b) { xpparam_t pp = { 0 }; @@@ -210,7 -196,9 +216,9 @@@ mf2.size = strlen(b); cfg.ctxlen = 3; - if (!xdi_diff_outf(&mf1, &mf2, diffsize_consume, &count, &pp, &cfg)) + if (!xdi_diff_outf(&mf1, &mf2, + diffsize_hunk, diffsize_consume, &count, + &pp, &cfg)) return count; error(_("failed to generate diff")); @@@ -343,7 -331,7 +351,7 @@@ static void output_pair_header(struct d } strbuf_addf(buf, "%s\n", color_reset); - fwrite(buf->buf, buf->len, 1, stdout); + fwrite(buf->buf, buf->len, 1, diffopt->file); } static struct userdiff_driver no_func_name = { @@@ -354,7 -342,7 +362,7 @@@ static struct diff_filespec *get_filesp { struct diff_filespec *spec = alloc_filespec(name); - fill_filespec(spec, &null_oid, 0, 0644); + fill_filespec(spec, &null_oid, 0, 0100644); spec->data = (char *)p; spec->size = strlen(p); spec->should_munmap = 0; @@@ -429,14 -417,8 +437,14 @@@ static void output(struct string_list * strbuf_release(&dashes); } +static struct strbuf *output_prefix_cb(struct diff_options *opt, void *data) +{ + return data; +} + int show_range_diff(const char *range1, const char *range2, - int creation_factor, struct diff_options *diffopt) + int creation_factor, int dual_color, + struct diff_options *diffopt) { int res = 0; @@@ -449,23 -431,9 +457,23 @@@ res = error(_("could not parse log for '%s'"), range2); if (!res) { + struct diff_options opts; + struct strbuf indent = STRBUF_INIT; + + memcpy(&opts, diffopt, sizeof(opts)); + opts.output_format = DIFF_FORMAT_PATCH; + opts.flags.suppress_diff_headers = 1; + opts.flags.dual_color_diffed_diffs = dual_color; + opts.output_prefix = output_prefix_cb; + strbuf_addstr(&indent, " "); + opts.output_prefix_data = &indent; + diff_setup_done(&opts); + find_exact_matches(&branch1, &branch2); get_correspondences(&branch1, &branch2, creation_factor); - output(&branch1, &branch2, diffopt); + output(&branch1, &branch2, &opts); + + strbuf_release(&indent); } string_list_clear(&branch1, 1); diff --combined xdiff-interface.c index e7af95db86,de9c524d2f..80f060d278 --- a/xdiff-interface.c +++ b/xdiff-interface.c @@@ -9,54 -9,26 +9,26 @@@ #include "xdiff/xutils.h" struct xdiff_emit_state { - xdiff_emit_consume_fn consume; + xdiff_emit_hunk_fn hunk_fn; + xdiff_emit_line_fn line_fn; void *consume_callback_data; struct strbuf remainder; }; - static int parse_num(char **cp_p, int *num_p) + static int xdiff_out_hunk(void *priv_, + long old_begin, long old_nr, + long new_begin, long new_nr, + const char *func, long funclen) { - char *cp = *cp_p; - int num = 0; + struct xdiff_emit_state *priv = priv_; - while ('0' <= *cp && *cp <= '9') - num = num * 10 + *cp++ - '0'; - if (!(cp - *cp_p)) - return -1; - *cp_p = cp; - *num_p = num; - return 0; - } + if (priv->remainder.len) + BUG("xdiff emitted hunk in the middle of a line"); - int parse_hunk_header(char *line, int len, - int *ob, int *on, - int *nb, int *nn) - { - char *cp; - cp = line + 4; - if (parse_num(&cp, ob)) { - bad_line: - return error("malformed diff output: %s", line); - } - if (*cp == ',') { - cp++; - if (parse_num(&cp, on)) - goto bad_line; - } - else - *on = 1; - if (*cp++ != ' ' || *cp++ != '+') - goto bad_line; - if (parse_num(&cp, nb)) - goto bad_line; - if (*cp == ',') { - cp++; - if (parse_num(&cp, nn)) - goto bad_line; - } - else - *nn = 1; - return -!!memcmp(cp, " @@", 3); + priv->hunk_fn(priv->consume_callback_data, + old_begin, old_nr, new_begin, new_nr, + func, funclen); + return 0; } static void consume_one(void *priv_, char *s, unsigned long size) @@@ -67,7 -39,7 +39,7 @@@ unsigned long this_size; ep = memchr(s, '\n', size); this_size = (ep == NULL) ? size : (ep - s + 1); - priv->consume(priv->consume_callback_data, s, this_size); + priv->line_fn(priv->consume_callback_data, s, this_size); size -= this_size; s += this_size; } @@@ -78,6 -50,9 +50,9 @@@ static int xdiff_outf(void *priv_, mmbu struct xdiff_emit_state *priv = priv_; int i; + if (!priv->line_fn) + return 0; + for (i = 0; i < nbuf; i++) { if (mb[i].ptr[mb[i].size-1] != '\n') { /* Incomplete line */ @@@ -140,8 -115,16 +115,16 @@@ int xdi_diff(mmfile_t *mf1, mmfile_t *m return xdl_diff(&a, &b, xpp, xecfg, xecb); } + void discard_hunk_line(void *priv, + long ob, long on, long nb, long nn, + const char *func, long funclen) + { + } + int xdi_diff_outf(mmfile_t *mf1, mmfile_t *mf2, - xdiff_emit_consume_fn fn, void *consume_callback_data, + xdiff_emit_hunk_fn hunk_fn, + xdiff_emit_line_fn line_fn, + void *consume_callback_data, xpparam_t const *xpp, xdemitconf_t const *xecfg) { int ret; @@@ -149,10 -132,13 +132,13 @@@ xdemitcb_t ecb; memset(&state, 0, sizeof(state)); - state.consume = fn; + state.hunk_fn = hunk_fn; + state.line_fn = line_fn; state.consume_callback_data = consume_callback_data; memset(&ecb, 0, sizeof(ecb)); - ecb.outf = xdiff_outf; + if (hunk_fn) + ecb.out_hunk = xdiff_out_hunk; + ecb.out_line = xdiff_outf; ecb.priv = &state; strbuf_init(&state.remainder, 0); ret = xdi_diff(mf1, mf2, xpp, xecfg, &ecb); @@@ -186,7 -172,7 +172,7 @@@ void read_mmblob(mmfile_t *ptr, const s unsigned long size; enum object_type type; - if (!oidcmp(oid, &null_oid)) { + if (oideq(oid, &null_oid)) { ptr->ptr = xstrdup(""); ptr->size = 0; return;