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
This commit is contained in:
commit
39d23dfa40
@ -110,7 +110,8 @@ static void show_diff(struct merge_list *entry)
|
||||
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);
|
||||
|
@ -41,7 +41,8 @@ static int diff_two(const char *file1, const char *label1,
|
||||
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);
|
||||
|
@ -345,38 +345,43 @@ struct combine_diff_state {
|
||||
struct sline *lost_bucket;
|
||||
};
|
||||
|
||||
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_;
|
||||
|
||||
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 (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;
|
||||
}
|
||||
if (!state->lost_bucket)
|
||||
return; /* not in any hunk yet */
|
||||
switch (line[0]) {
|
||||
@ -421,8 +426,8 @@ static void combine_diff(struct repository *r,
|
||||
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);
|
||||
|
48
diff.c
48
diff.c
@ -1912,19 +1912,17 @@ static int color_words_output_graph_prefix(struct diff_words_data *diff_words)
|
||||
}
|
||||
}
|
||||
|
||||
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 +2072,8 @@ static void diff_words_show(struct diff_words_data *diff_words)
|
||||
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);
|
||||
@ -3130,6 +3128,15 @@ static int is_conflict_marker(const char *line, int marker_size, unsigned long l
|
||||
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 +3172,6 @@ static void checkdiff_consume(void *priv, char *line, unsigned long len)
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
@ -3526,8 +3527,8 @@ static void builtin_diff(const char *name_a,
|
||||
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);
|
||||
@ -3637,8 +3638,8 @@ static void builtin_diffstat(const char *name_a, const char *name_b,
|
||||
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);
|
||||
}
|
||||
|
||||
@ -3686,7 +3687,8 @@ static void builtin_checkdiff(const char *name_a, const char *name_b,
|
||||
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);
|
||||
|
||||
@ -5666,10 +5668,6 @@ static void patch_id_consume(void *priv, char *line, unsigned long len)
|
||||
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);
|
||||
@ -5771,8 +5769,8 @@ static int diff_get_patch_id(struct diff_options *options, struct object_id *oid
|
||||
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);
|
||||
}
|
||||
|
@ -62,7 +62,8 @@ static int diff_grep(mmfile_t *one, mmfile_t *two,
|
||||
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;
|
||||
}
|
||||
|
10
range-diff.c
10
range-diff.c
@ -197,6 +197,12 @@ static void diffsize_consume(void *data, char *line, unsigned long len)
|
||||
(*(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 +216,9 @@ static int diffsize(const char *a, const char *b)
|
||||
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"));
|
||||
|
@ -9,56 +9,28 @@
|
||||
#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;
|
||||
if (priv->remainder.len)
|
||||
BUG("xdiff emitted hunk in the middle of a line");
|
||||
|
||||
priv->hunk_fn(priv->consume_callback_data,
|
||||
old_begin, old_nr, new_begin, new_nr,
|
||||
func, funclen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static void consume_one(void *priv_, char *s, unsigned long size)
|
||||
{
|
||||
struct xdiff_emit_state *priv = priv_;
|
||||
@ -67,7 +39,7 @@ static void consume_one(void *priv_, char *s, unsigned long size)
|
||||
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 @@ static int xdiff_outf(void *priv_, mmbuffer_t *mb, int nbuf)
|
||||
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 @@ int xdi_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, xdemitconf_t co
|
||||
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 @@ int xdi_diff_outf(mmfile_t *mf1, mmfile_t *mf2,
|
||||
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);
|
||||
|
@ -11,15 +11,18 @@
|
||||
*/
|
||||
#define MAX_XDIFF_SIZE (1024UL * 1024 * 1023)
|
||||
|
||||
typedef void (*xdiff_emit_consume_fn)(void *, char *, unsigned long);
|
||||
typedef void (*xdiff_emit_line_fn)(void *, char *, unsigned long);
|
||||
typedef void (*xdiff_emit_hunk_fn)(void *data,
|
||||
long old_begin, long old_nr,
|
||||
long new_begin, long new_nr,
|
||||
const char *func, long funclen);
|
||||
|
||||
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,
|
||||
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 parse_hunk_header(char *line, int len,
|
||||
int *ob, int *on,
|
||||
int *nb, int *nn);
|
||||
int read_mmfile(mmfile_t *ptr, const char *filename);
|
||||
void read_mmblob(mmfile_t *ptr, const struct object_id *oid);
|
||||
int buffer_is_binary(const char *ptr, unsigned long size);
|
||||
@ -29,6 +32,14 @@ extern void xdiff_clear_find_func(xdemitconf_t *xecfg);
|
||||
extern int git_xmerge_config(const char *var, const char *value, void *cb);
|
||||
extern int git_xmerge_style;
|
||||
|
||||
/*
|
||||
* Can be used as a no-op hunk_fn for xdi_diff_outf(), since a NULL
|
||||
* one just sends the hunk line to the line_fn callback).
|
||||
*/
|
||||
void discard_hunk_line(void *priv,
|
||||
long ob, long on, long nb, long nn,
|
||||
const char *func, long funclen);
|
||||
|
||||
/*
|
||||
* Compare the strings l1 with l2 which are of size s1 and s2 respectively.
|
||||
* Returns 1 if the strings are deemed equal, 0 otherwise.
|
||||
|
@ -86,7 +86,11 @@ typedef struct s_xpparam {
|
||||
|
||||
typedef struct s_xdemitcb {
|
||||
void *priv;
|
||||
int (*outf)(void *, mmbuffer_t *, int);
|
||||
int (*out_hunk)(void *,
|
||||
long old_begin, long old_nr,
|
||||
long new_begin, long new_nr,
|
||||
const char *func, long funclen);
|
||||
int (*out_line)(void *, mmbuffer_t *, int);
|
||||
} xdemitcb_t;
|
||||
|
||||
typedef long (*find_func_t)(const char *line, long line_len, char *buffer, long buffer_size, void *priv);
|
||||
|
@ -54,7 +54,7 @@ int xdl_emit_diffrec(char const *rec, long size, char const *pre, long psize,
|
||||
mb[2].size = strlen(mb[2].ptr);
|
||||
i++;
|
||||
}
|
||||
if (ecb->outf(ecb->priv, mb, i) < 0) {
|
||||
if (ecb->out_line(ecb->priv, mb, i) < 0) {
|
||||
|
||||
return -1;
|
||||
}
|
||||
@ -344,8 +344,9 @@ int xdl_num_out(char *out, long val) {
|
||||
return str - out;
|
||||
}
|
||||
|
||||
int xdl_emit_hunk_hdr(long s1, long c1, long s2, long c2,
|
||||
const char *func, long funclen, xdemitcb_t *ecb) {
|
||||
static int xdl_format_hunk_hdr(long s1, long c1, long s2, long c2,
|
||||
const char *func, long funclen,
|
||||
xdemitcb_t *ecb) {
|
||||
int nb = 0;
|
||||
mmbuffer_t mb;
|
||||
char buf[128];
|
||||
@ -387,9 +388,21 @@ int xdl_emit_hunk_hdr(long s1, long c1, long s2, long c2,
|
||||
|
||||
mb.ptr = buf;
|
||||
mb.size = nb;
|
||||
if (ecb->outf(ecb->priv, &mb, 1) < 0)
|
||||
if (ecb->out_line(ecb->priv, &mb, 1) < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xdl_emit_hunk_hdr(long s1, long c1, long s2, long c2,
|
||||
const char *func, long funclen,
|
||||
xdemitcb_t *ecb) {
|
||||
if (!ecb->out_hunk)
|
||||
return xdl_format_hunk_hdr(s1, c1, s2, c2, func, funclen, ecb);
|
||||
if (ecb->out_hunk(ecb->priv,
|
||||
c1 ? s1 : s1 - 1, c1,
|
||||
c2 ? s2 : s2 - 1, c2,
|
||||
func, funclen) < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user