Merge branch 'jk/xdiff-interface'
authorJunio C Hamano <gitster@pobox.com>
Tue, 13 Nov 2018 13:37:27 +0000 (22:37 +0900)
committerJunio C Hamano <gitster@pobox.com>
Tue, 13 Nov 2018 13:37:27 +0000 (22:37 +0900)
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

builtin/merge-tree.c
builtin/rerere.c
combine-diff.c
diff.c
diffcore-pickaxe.c
range-diff.c
xdiff-interface.c
xdiff-interface.h
xdiff/xdiff.h
xdiff/xutils.c
index 8fc108d305a33c4ba615837b60bda8175f2fb882..70f6fc916765c5a5ca67c2dfe72e0480128182e3 100644 (file)
@@ -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);
index e89ccbc524a62d5a8760311a2797dfa49fe8525d..d78eeaed329e5c647e5474b6a4205194b539f4b4 100644 (file)
@@ -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);
index 10155e0ec8b18fa80ea96f90a508250bdc5bb9f0..ad7752ea6b7e3173066e346b7dd314e7707f7d8c 100644 (file)
@@ -345,38 +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]) {
@@ -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);
diff --git a/diff.c b/diff.c
index 8647db3d307c297448c91b328b1dabf19635fb94..e38d1ecaf45d1b79eeab093ba86e34fe3bbd931a 100644 (file)
--- a/diff.c
+++ b/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);
        }
index d2361e06a1e45a1bdb94d6f5d6d2c003ac587e30..69fc55ea1e34af69b7ed4d57e521cb4825f99fd2 100644 (file)
@@ -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;
 }
index bd8083f2d10cea9a464ebfd1490295d13267421a..3958720f004ebe9ba027cd6097a7cd3ce41e3d73 100644 (file)
@@ -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"));
index e7af95db8654a88359b9abd31bc018fb1cb66b5f..80f060d2782e227ce7637a41d05742729c48f6ac 100644 (file)
@@ -9,54 +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 @@ 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);
index 135fc05d72e8f066a63902785d12485a656efa97..2d41fffd4c618b5d7b816146d9df684b195535e3 100644 (file)
  */
 #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.
index 2356da5f784fbe5670b3f9e8bbc6d6419b4fa9d3..b1583690208096f7bb75e0aa67cacc3179da1185 100644 (file)
@@ -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);
index 88e5995535467475216de82b1eeb744e744f3b4d..963e1c58b9049f1b9ee94537171bd3c6cd21680f 100644 (file)
@@ -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;
 }