зеркало из https://github.com/microsoft/git.git
Merge branch 'rs/blame'
* rs/blame: blame: use xdi_diff_hunks(), get rid of struct patch add xdi_diff_hunks() for callers that only need hunk lengths Allow alternate "low-level" emit function from xdl_diff Always initialize xpparam_t to 0 blame: inline get_patch()
This commit is contained in:
Коммит
1e2bba92d2
207
builtin-blame.c
207
builtin-blame.c
|
@ -442,131 +442,6 @@ static struct origin *find_rename(struct scoreboard *sb,
|
|||
return porigin;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parsing of patch chunks...
|
||||
*/
|
||||
struct chunk {
|
||||
/* line number in postimage; up to but not including this
|
||||
* line is the same as preimage
|
||||
*/
|
||||
int same;
|
||||
|
||||
/* preimage line number after this chunk */
|
||||
int p_next;
|
||||
|
||||
/* postimage line number after this chunk */
|
||||
int t_next;
|
||||
};
|
||||
|
||||
struct patch {
|
||||
struct chunk *chunks;
|
||||
int num;
|
||||
};
|
||||
|
||||
struct blame_diff_state {
|
||||
struct patch *ret;
|
||||
unsigned hunk_post_context;
|
||||
unsigned hunk_in_pre_context : 1;
|
||||
};
|
||||
|
||||
static void process_u_diff(void *state_, char *line, unsigned long len)
|
||||
{
|
||||
struct blame_diff_state *state = state_;
|
||||
struct chunk *chunk;
|
||||
int off1, off2, len1, len2, num;
|
||||
|
||||
num = state->ret->num;
|
||||
if (len < 4 || line[0] != '@' || line[1] != '@') {
|
||||
if (state->hunk_in_pre_context && line[0] == ' ')
|
||||
state->ret->chunks[num - 1].same++;
|
||||
else {
|
||||
state->hunk_in_pre_context = 0;
|
||||
if (line[0] == ' ')
|
||||
state->hunk_post_context++;
|
||||
else
|
||||
state->hunk_post_context = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (num && state->hunk_post_context) {
|
||||
chunk = &state->ret->chunks[num - 1];
|
||||
chunk->p_next -= state->hunk_post_context;
|
||||
chunk->t_next -= state->hunk_post_context;
|
||||
}
|
||||
state->ret->num = ++num;
|
||||
state->ret->chunks = xrealloc(state->ret->chunks,
|
||||
sizeof(struct chunk) * num);
|
||||
chunk = &state->ret->chunks[num - 1];
|
||||
if (parse_hunk_header(line, len, &off1, &len1, &off2, &len2)) {
|
||||
state->ret->num--;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Line numbers in patch output are one based. */
|
||||
off1--;
|
||||
off2--;
|
||||
|
||||
chunk->same = len2 ? off2 : (off2 + 1);
|
||||
|
||||
chunk->p_next = off1 + (len1 ? len1 : 1);
|
||||
chunk->t_next = chunk->same + len2;
|
||||
state->hunk_in_pre_context = 1;
|
||||
state->hunk_post_context = 0;
|
||||
}
|
||||
|
||||
static struct patch *compare_buffer(mmfile_t *file_p, mmfile_t *file_o,
|
||||
int context)
|
||||
{
|
||||
struct blame_diff_state state;
|
||||
xpparam_t xpp;
|
||||
xdemitconf_t xecfg;
|
||||
xdemitcb_t ecb;
|
||||
|
||||
xpp.flags = xdl_opts;
|
||||
memset(&xecfg, 0, sizeof(xecfg));
|
||||
xecfg.ctxlen = context;
|
||||
memset(&state, 0, sizeof(state));
|
||||
state.ret = xmalloc(sizeof(struct patch));
|
||||
state.ret->chunks = NULL;
|
||||
state.ret->num = 0;
|
||||
|
||||
xdi_diff_outf(file_p, file_o, process_u_diff, &state, &xpp, &xecfg, &ecb);
|
||||
|
||||
if (state.ret->num) {
|
||||
struct chunk *chunk;
|
||||
chunk = &state.ret->chunks[state.ret->num - 1];
|
||||
chunk->p_next -= state.hunk_post_context;
|
||||
chunk->t_next -= state.hunk_post_context;
|
||||
}
|
||||
return state.ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Run diff between two origins and grab the patch output, so that
|
||||
* we can pass blame for lines origin is currently suspected for
|
||||
* to its parent.
|
||||
*/
|
||||
static struct patch *get_patch(struct origin *parent, struct origin *origin)
|
||||
{
|
||||
mmfile_t file_p, file_o;
|
||||
struct patch *patch;
|
||||
|
||||
fill_origin_blob(parent, &file_p);
|
||||
fill_origin_blob(origin, &file_o);
|
||||
if (!file_p.ptr || !file_o.ptr)
|
||||
return NULL;
|
||||
patch = compare_buffer(&file_p, &file_o, 0);
|
||||
num_get_patch++;
|
||||
return patch;
|
||||
}
|
||||
|
||||
static void free_patch(struct patch *p)
|
||||
{
|
||||
free(p->chunks);
|
||||
free(p);
|
||||
}
|
||||
|
||||
/*
|
||||
* Link in a new blame entry to the scoreboard. Entries that cover the
|
||||
* same line range have been removed from the scoreboard previously.
|
||||
|
@ -813,6 +688,22 @@ static void blame_chunk(struct scoreboard *sb,
|
|||
}
|
||||
}
|
||||
|
||||
struct blame_chunk_cb_data {
|
||||
struct scoreboard *sb;
|
||||
struct origin *target;
|
||||
struct origin *parent;
|
||||
long plno;
|
||||
long tlno;
|
||||
};
|
||||
|
||||
static void blame_chunk_cb(void *data, long same, long p_next, long t_next)
|
||||
{
|
||||
struct blame_chunk_cb_data *d = data;
|
||||
blame_chunk(d->sb, d->tlno, d->plno, same, d->target, d->parent);
|
||||
d->plno = p_next;
|
||||
d->tlno = t_next;
|
||||
}
|
||||
|
||||
/*
|
||||
* We are looking at the origin 'target' and aiming to pass blame
|
||||
* for the lines it is suspected to its parent. Run diff to find
|
||||
|
@ -822,26 +713,28 @@ static int pass_blame_to_parent(struct scoreboard *sb,
|
|||
struct origin *target,
|
||||
struct origin *parent)
|
||||
{
|
||||
int i, last_in_target, plno, tlno;
|
||||
struct patch *patch;
|
||||
int last_in_target;
|
||||
mmfile_t file_p, file_o;
|
||||
struct blame_chunk_cb_data d = { sb, target, parent, 0, 0 };
|
||||
xpparam_t xpp;
|
||||
xdemitconf_t xecfg;
|
||||
|
||||
last_in_target = find_last_in_target(sb, target);
|
||||
if (last_in_target < 0)
|
||||
return 1; /* nothing remains for this target */
|
||||
|
||||
patch = get_patch(parent, target);
|
||||
plno = tlno = 0;
|
||||
for (i = 0; i < patch->num; i++) {
|
||||
struct chunk *chunk = &patch->chunks[i];
|
||||
fill_origin_blob(parent, &file_p);
|
||||
fill_origin_blob(target, &file_o);
|
||||
num_get_patch++;
|
||||
|
||||
blame_chunk(sb, tlno, plno, chunk->same, target, parent);
|
||||
plno = chunk->p_next;
|
||||
tlno = chunk->t_next;
|
||||
}
|
||||
memset(&xpp, 0, sizeof(xpp));
|
||||
xpp.flags = xdl_opts;
|
||||
memset(&xecfg, 0, sizeof(xecfg));
|
||||
xecfg.ctxlen = 0;
|
||||
xdi_diff_hunks(&file_p, &file_o, blame_chunk_cb, &d, &xpp, &xecfg);
|
||||
/* The rest (i.e. anything after tlno) are the same as the parent */
|
||||
blame_chunk(sb, tlno, plno, last_in_target, target, parent);
|
||||
blame_chunk(sb, d.tlno, d.plno, last_in_target, target, parent);
|
||||
|
||||
free_patch(patch);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -933,6 +826,23 @@ static void handle_split(struct scoreboard *sb,
|
|||
}
|
||||
}
|
||||
|
||||
struct handle_split_cb_data {
|
||||
struct scoreboard *sb;
|
||||
struct blame_entry *ent;
|
||||
struct origin *parent;
|
||||
struct blame_entry *split;
|
||||
long plno;
|
||||
long tlno;
|
||||
};
|
||||
|
||||
static void handle_split_cb(void *data, long same, long p_next, long t_next)
|
||||
{
|
||||
struct handle_split_cb_data *d = data;
|
||||
handle_split(d->sb, d->ent, d->tlno, d->plno, same, d->parent, d->split);
|
||||
d->plno = p_next;
|
||||
d->tlno = t_next;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the lines from parent that are the same as ent so that
|
||||
* we can pass blames to it. file_p has the blob contents for
|
||||
|
@ -947,8 +857,9 @@ static void find_copy_in_blob(struct scoreboard *sb,
|
|||
const char *cp;
|
||||
int cnt;
|
||||
mmfile_t file_o;
|
||||
struct patch *patch;
|
||||
int i, plno, tlno;
|
||||
struct handle_split_cb_data d = { sb, ent, parent, split, 0, 0 };
|
||||
xpparam_t xpp;
|
||||
xdemitconf_t xecfg;
|
||||
|
||||
/*
|
||||
* Prepare mmfile that contains only the lines in ent.
|
||||
|
@ -963,24 +874,18 @@ static void find_copy_in_blob(struct scoreboard *sb,
|
|||
}
|
||||
file_o.size = cp - file_o.ptr;
|
||||
|
||||
patch = compare_buffer(file_p, &file_o, 1);
|
||||
|
||||
/*
|
||||
* file_o is a part of final image we are annotating.
|
||||
* file_p partially may match that image.
|
||||
*/
|
||||
memset(&xpp, 0, sizeof(xpp));
|
||||
xpp.flags = xdl_opts;
|
||||
memset(&xecfg, 0, sizeof(xecfg));
|
||||
xecfg.ctxlen = 1;
|
||||
memset(split, 0, sizeof(struct blame_entry [3]));
|
||||
plno = tlno = 0;
|
||||
for (i = 0; i < patch->num; i++) {
|
||||
struct chunk *chunk = &patch->chunks[i];
|
||||
|
||||
handle_split(sb, ent, tlno, plno, chunk->same, parent, split);
|
||||
plno = chunk->p_next;
|
||||
tlno = chunk->t_next;
|
||||
}
|
||||
xdi_diff_hunks(file_p, &file_o, handle_split_cb, &d, &xpp, &xecfg);
|
||||
/* remainder, if any, all match the preimage */
|
||||
handle_split(sb, ent, tlno, plno, ent->num_lines, parent, split);
|
||||
free_patch(patch);
|
||||
handle_split(sb, ent, d.tlno, d.plno, ent->num_lines, parent, split);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -98,6 +98,7 @@ static int diff_two(const char *file1, const char *label1,
|
|||
|
||||
printf("--- a/%s\n+++ b/%s\n", label1, label2);
|
||||
fflush(stdout);
|
||||
memset(&xpp, 0, sizeof(xpp));
|
||||
xpp.flags = XDF_NEED_MINIMAL;
|
||||
memset(&xecfg, 0, sizeof(xecfg));
|
||||
xecfg.ctxlen = 3;
|
||||
|
|
|
@ -213,6 +213,7 @@ static void combine_diff(const unsigned char *parent, mmfile_t *result_file,
|
|||
|
||||
parent_file.ptr = grab_blob(parent, &sz);
|
||||
parent_file.size = sz;
|
||||
memset(&xpp, 0, sizeof(xpp));
|
||||
xpp.flags = XDF_NEED_MINIMAL;
|
||||
memset(&xecfg, 0, sizeof(xecfg));
|
||||
memset(&state, 0, sizeof(state));
|
||||
|
|
5
diff.c
5
diff.c
|
@ -400,6 +400,7 @@ static void diff_words_show(struct diff_words_data *diff_words)
|
|||
mmfile_t minus, plus;
|
||||
int i;
|
||||
|
||||
memset(&xpp, 0, sizeof(xpp));
|
||||
memset(&xecfg, 0, sizeof(xecfg));
|
||||
minus.size = diff_words->minus.text.size;
|
||||
minus.ptr = xmalloc(minus.size);
|
||||
|
@ -1416,6 +1417,7 @@ static void builtin_diff(const char *name_a,
|
|||
if (!pe)
|
||||
pe = diff_funcname_pattern(two);
|
||||
|
||||
memset(&xpp, 0, sizeof(xpp));
|
||||
memset(&xecfg, 0, sizeof(xecfg));
|
||||
memset(&ecbdata, 0, sizeof(ecbdata));
|
||||
ecbdata.label_path = lbl;
|
||||
|
@ -1489,6 +1491,7 @@ static void builtin_diffstat(const char *name_a, const char *name_b,
|
|||
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,
|
||||
|
@ -1535,6 +1538,7 @@ static void builtin_checkdiff(const char *name_a, const char *name_b,
|
|||
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;
|
||||
|
@ -2958,6 +2962,7 @@ static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1)
|
|||
struct diff_filepair *p = q->queue[i];
|
||||
int len1, len2;
|
||||
|
||||
memset(&xpp, 0, sizeof(xpp));
|
||||
memset(&xecfg, 0, sizeof(xecfg));
|
||||
if (p->status == 0)
|
||||
return error("internal diff status error");
|
||||
|
|
|
@ -61,6 +61,7 @@ static int generate_common_file(mmfile_t *res, mmfile_t *f1, mmfile_t *f2)
|
|||
xdemitconf_t xecfg;
|
||||
xdemitcb_t ecb;
|
||||
|
||||
memset(&xpp, 0, sizeof(xpp));
|
||||
xpp.flags = XDF_NEED_MINIMAL;
|
||||
memset(&xecfg, 0, sizeof(xecfg));
|
||||
xecfg.ctxlen = 3;
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
#include "cache.h"
|
||||
#include "xdiff-interface.h"
|
||||
#include "strbuf.h"
|
||||
#include "xdiff/xtypes.h"
|
||||
#include "xdiff/xdiffi.h"
|
||||
#include "xdiff/xemit.h"
|
||||
#include "xdiff/xmacros.h"
|
||||
|
||||
struct xdiff_emit_state {
|
||||
xdiff_emit_consume_fn consume;
|
||||
|
@ -153,6 +156,50 @@ int xdi_diff_outf(mmfile_t *mf1, mmfile_t *mf2,
|
|||
return ret;
|
||||
}
|
||||
|
||||
struct xdiff_emit_hunk_state {
|
||||
xdiff_emit_hunk_consume_fn consume;
|
||||
void *consume_callback_data;
|
||||
};
|
||||
|
||||
static int process_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
|
||||
xdemitconf_t const *xecfg)
|
||||
{
|
||||
long s1, s2, same, p_next, t_next;
|
||||
xdchange_t *xch, *xche;
|
||||
struct xdiff_emit_hunk_state *state = ecb->priv;
|
||||
xdiff_emit_hunk_consume_fn fn = state->consume;
|
||||
void *consume_callback_data = state->consume_callback_data;
|
||||
|
||||
for (xch = xscr; xch; xch = xche->next) {
|
||||
xche = xdl_get_hunk(xch, xecfg);
|
||||
|
||||
s1 = XDL_MAX(xch->i1 - xecfg->ctxlen, 0);
|
||||
s2 = XDL_MAX(xch->i2 - xecfg->ctxlen, 0);
|
||||
same = s2 + XDL_MAX(xch->i1 - s1, 0);
|
||||
p_next = xche->i1 + xche->chg1;
|
||||
t_next = xche->i2 + xche->chg2;
|
||||
|
||||
fn(consume_callback_data, same, p_next, t_next);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xdi_diff_hunks(mmfile_t *mf1, mmfile_t *mf2,
|
||||
xdiff_emit_hunk_consume_fn fn, void *consume_callback_data,
|
||||
xpparam_t const *xpp, xdemitconf_t *xecfg)
|
||||
{
|
||||
struct xdiff_emit_hunk_state state;
|
||||
xdemitcb_t ecb;
|
||||
|
||||
memset(&state, 0, sizeof(state));
|
||||
memset(&ecb, 0, sizeof(ecb));
|
||||
state.consume = fn;
|
||||
state.consume_callback_data = consume_callback_data;
|
||||
xecfg->emit_func = (void (*)())process_diff;
|
||||
ecb.priv = &state;
|
||||
return xdi_diff(mf1, mf2, xpp, xecfg, &ecb);
|
||||
}
|
||||
|
||||
int read_mmfile(mmfile_t *ptr, const char *filename)
|
||||
{
|
||||
struct stat st;
|
||||
|
|
|
@ -4,12 +4,16 @@
|
|||
#include "xdiff/xdiff.h"
|
||||
|
||||
typedef void (*xdiff_emit_consume_fn)(void *, char *, unsigned long);
|
||||
typedef void (*xdiff_emit_hunk_consume_fn)(void *, long, long, long);
|
||||
|
||||
int xdi_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, xdemitconf_t const *xecfg, xdemitcb_t *ecb);
|
||||
int xdi_diff_outf(mmfile_t *mf1, mmfile_t *mf2,
|
||||
xdiff_emit_consume_fn fn, void *consume_callback_data,
|
||||
xpparam_t const *xpp,
|
||||
xdemitconf_t const *xecfg, xdemitcb_t *xecb);
|
||||
int xdi_diff_hunks(mmfile_t *mf1, mmfile_t *mf2,
|
||||
xdiff_emit_hunk_consume_fn fn, void *consume_callback_data,
|
||||
xpparam_t const *xpp, xdemitconf_t *xecfg);
|
||||
int parse_hunk_header(char *line, int len,
|
||||
int *ob, int *on,
|
||||
int *nb, int *nn);
|
||||
|
|
|
@ -87,6 +87,7 @@ typedef struct s_xdemitconf {
|
|||
unsigned long flags;
|
||||
find_func_t find_func;
|
||||
void *find_func_priv;
|
||||
void (*emit_func)();
|
||||
} xdemitconf_t;
|
||||
|
||||
typedef struct s_bdiffparam {
|
||||
|
|
|
@ -538,6 +538,8 @@ int xdl_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
|
|||
xdemitconf_t const *xecfg, xdemitcb_t *ecb) {
|
||||
xdchange_t *xscr;
|
||||
xdfenv_t xe;
|
||||
emit_func_t ef = xecfg->emit_func ?
|
||||
(emit_func_t)xecfg->emit_func : xdl_emit_diff;
|
||||
|
||||
if (xdl_do_diff(mf1, mf2, xpp, &xe) < 0) {
|
||||
|
||||
|
@ -551,7 +553,7 @@ int xdl_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
|
|||
return -1;
|
||||
}
|
||||
if (xscr) {
|
||||
if (xdl_emit_diff(&xe, xscr, ecb, xecfg) < 0) {
|
||||
if (ef(&xe, xscr, ecb, xecfg) < 0) {
|
||||
|
||||
xdl_free_script(xscr);
|
||||
xdl_free_env(&xe);
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
|
||||
static long xdl_get_rec(xdfile_t *xdf, long ri, char const **rec);
|
||||
static int xdl_emit_record(xdfile_t *xdf, long ri, char const *pre, xdemitcb_t *ecb);
|
||||
static xdchange_t *xdl_get_hunk(xdchange_t *xscr, xdemitconf_t const *xecfg);
|
||||
|
||||
|
||||
|
||||
|
@ -58,7 +57,7 @@ static int xdl_emit_record(xdfile_t *xdf, long ri, char const *pre, xdemitcb_t *
|
|||
* Starting at the passed change atom, find the latest change atom to be included
|
||||
* inside the differential hunk according to the specified configuration.
|
||||
*/
|
||||
static xdchange_t *xdl_get_hunk(xdchange_t *xscr, xdemitconf_t const *xecfg) {
|
||||
xdchange_t *xdl_get_hunk(xdchange_t *xscr, xdemitconf_t const *xecfg) {
|
||||
xdchange_t *xch, *xchp;
|
||||
|
||||
for (xchp = xscr, xch = xscr->next; xch; xchp = xch, xch = xch->next)
|
||||
|
|
|
@ -24,7 +24,10 @@
|
|||
#define XEMIT_H
|
||||
|
||||
|
||||
typedef int (*emit_func_t)(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
|
||||
xdemitconf_t const *xecfg);
|
||||
|
||||
xdchange_t *xdl_get_hunk(xdchange_t *xscr, xdemitconf_t const *xecfg);
|
||||
int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
|
||||
xdemitconf_t const *xecfg);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче