diff options
Diffstat (limited to 'xdiff')
-rw-r--r-- | xdiff/xdiff.h | 2 | ||||
-rw-r--r-- | xdiff/xdiffi.c | 40 | ||||
-rw-r--r-- | xdiff/xemit.c | 65 | ||||
-rw-r--r-- | xdiff/xpatience.c | 2 | ||||
-rw-r--r-- | xdiff/xprepare.c | 3 | ||||
-rw-r--r-- | xdiff/xutils.c | 6 |
6 files changed, 102 insertions, 16 deletions
diff --git a/xdiff/xdiff.h b/xdiff/xdiff.h index 4fb7e79410..7423f77fc8 100644 --- a/xdiff/xdiff.h +++ b/xdiff/xdiff.h @@ -41,6 +41,8 @@ extern "C" { #define XDF_IGNORE_BLANK_LINES (1 << 7) +#define XDF_COMPACTION_HEURISTIC (1 << 8) + #define XDL_EMIT_FUNCNAMES (1 << 0) #define XDL_EMIT_FUNCCONTEXT (1 << 2) diff --git a/xdiff/xdiffi.c b/xdiff/xdiffi.c index 2358a2d632..b3c6848875 100644 --- a/xdiff/xdiffi.c +++ b/xdiff/xdiffi.c @@ -400,9 +400,23 @@ static xdchange_t *xdl_add_change(xdchange_t *xscr, long i1, long i2, long chg1, } +static int is_blank_line(xrecord_t **recs, long ix, long flags) +{ + return xdl_blankline(recs[ix]->ptr, recs[ix]->size, flags); +} + +static int recs_match(xrecord_t **recs, long ixs, long ix, long flags) +{ + return (recs[ixs]->ha == recs[ix]->ha && + xdl_recmatch(recs[ixs]->ptr, recs[ixs]->size, + recs[ix]->ptr, recs[ix]->size, + flags)); +} + int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) { long ix, ixo, ixs, ixref, grpsiz, nrec = xdf->nrec; char *rchg = xdf->rchg, *rchgo = xdfo->rchg; + unsigned int blank_lines; xrecord_t **recs = xdf->recs; /* @@ -436,14 +450,14 @@ int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) { do { grpsiz = ix - ixs; + blank_lines = 0; /* * If the line before the current change group, is equal to * the last line of the current change group, shift backward * the group. */ - while (ixs > 0 && recs[ixs - 1]->ha == recs[ix - 1]->ha && - xdl_recmatch(recs[ixs - 1]->ptr, recs[ixs - 1]->size, recs[ix - 1]->ptr, recs[ix - 1]->size, flags)) { + while (ixs > 0 && recs_match(recs, ixs - 1, ix - 1, flags)) { rchg[--ixs] = 1; rchg[--ix] = 0; @@ -470,8 +484,9 @@ int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) { * the line next of the current change group, shift forward * the group. */ - while (ix < nrec && recs[ixs]->ha == recs[ix]->ha && - xdl_recmatch(recs[ixs]->ptr, recs[ixs]->size, recs[ix]->ptr, recs[ix]->size, flags)) { + while (ix < nrec && recs_match(recs, ixs, ix, flags)) { + blank_lines += is_blank_line(recs, ix, flags); + rchg[ixs++] = 0; rchg[ix++] = 1; @@ -498,6 +513,23 @@ int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) { rchg[--ix] = 0; while (rchgo[--ixo]); } + + /* + * If a group can be moved back and forth, see if there is a + * blank line in the moving space. If there is a blank line, + * make sure the last blank line is the end of the group. + * + * As we already shifted the group forward as far as possible + * in the earlier loop, we need to shift it back only if at all. + */ + if ((flags & XDF_COMPACTION_HEURISTIC) && blank_lines) { + while (ixs > 0 && + !is_blank_line(recs, ix - 1, flags) && + recs_match(recs, ixs - 1, ix - 1, flags)) { + rchg[--ixs] = 1; + rchg[--ix] = 0; + } + } } return 0; diff --git a/xdiff/xemit.c b/xdiff/xemit.c index 993724b11c..49aa16ff78 100644 --- a/xdiff/xemit.c +++ b/xdiff/xemit.c @@ -120,6 +120,16 @@ static long def_ff(const char *rec, long len, char *buf, long sz, void *priv) return -1; } +static long match_func_rec(xdfile_t *xdf, xdemitconf_t const *xecfg, long ri, + char *buf, long sz) +{ + const char *rec; + long len = xdl_get_rec(xdf, ri, &rec); + if (!xecfg->find_func) + return def_ff(rec, len, buf, sz, xecfg->find_func_priv); + return xecfg->find_func(rec, len, buf, sz, xecfg->find_func_priv); +} + struct func_line { long len; char buf[80]; @@ -128,7 +138,6 @@ struct func_line { static long get_func_line(xdfenv_t *xe, xdemitconf_t const *xecfg, struct func_line *func_line, long start, long limit) { - find_func_t ff = xecfg->find_func ? xecfg->find_func : def_ff; long l, size, step = (start > limit) ? -1 : 1; char *buf, dummy[1]; @@ -136,9 +145,7 @@ static long get_func_line(xdfenv_t *xe, xdemitconf_t const *xecfg, size = func_line ? sizeof(func_line->buf) : sizeof(dummy); for (l = start; l != limit && 0 <= l && l < xe->xdf1.nrec; l += step) { - const char *rec; - long reclen = xdl_get_rec(&xe->xdf1, l, &rec); - long len = ff(rec, reclen, buf, size, xecfg->find_func_priv); + long len = match_func_rec(&xe->xdf1, xecfg, l, buf, size); if (len >= 0) { if (func_line) func_line->len = len; @@ -148,6 +155,18 @@ static long get_func_line(xdfenv_t *xe, xdemitconf_t const *xecfg, return -1; } +static int is_empty_rec(xdfile_t *xdf, long ri) +{ + const char *rec; + long len = xdl_get_rec(xdf, ri, &rec); + + while (len > 0 && XDL_ISSPACE(*rec)) { + rec++; + len--; + } + return !len; +} + int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, xdemitconf_t const *xecfg) { long s1, s2, e1, e2, lctx; @@ -164,7 +183,34 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, s2 = XDL_MAX(xch->i2 - xecfg->ctxlen, 0); if (xecfg->flags & XDL_EMIT_FUNCCONTEXT) { - long fs1 = get_func_line(xe, xecfg, NULL, xch->i1, -1); + long fs1, i1 = xch->i1; + + /* Appended chunk? */ + if (i1 >= xe->xdf1.nrec) { + char dummy[1]; + long i2 = xch->i2; + + /* + * We don't need additional context if + * a whole function was added, possibly + * starting with empty lines. + */ + while (i2 < xe->xdf2.nrec && + is_empty_rec(&xe->xdf2, i2)) + i2++; + if (i2 < xe->xdf2.nrec && + match_func_rec(&xe->xdf2, xecfg, i2, + dummy, sizeof(dummy)) >= 0) + goto post_context_calculation; + + /* + * Otherwise get more context from the + * pre-image. + */ + i1 = xe->xdf1.nrec - 1; + } + + fs1 = get_func_line(xe, xecfg, NULL, i1, -1); if (fs1 < 0) fs1 = 0; if (fs1 < s1) { @@ -173,7 +219,7 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, } } - again: + post_context_calculation: lctx = xecfg->ctxlen; lctx = XDL_MIN(lctx, xe->xdf1.nrec - (xche->i1 + xche->chg1)); lctx = XDL_MIN(lctx, xe->xdf2.nrec - (xche->i2 + xche->chg2)); @@ -185,6 +231,8 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, long fe1 = get_func_line(xe, xecfg, NULL, xche->i1 + xche->chg1, xe->xdf1.nrec); + while (fe1 > 0 && is_empty_rec(&xe->xdf1, fe1 - 1)) + fe1--; if (fe1 < 0) fe1 = xe->xdf1.nrec; if (fe1 > e1) { @@ -198,11 +246,12 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, * its new end. */ if (xche->next) { - long l = xche->next->i1; + long l = XDL_MIN(xche->next->i1, + xe->xdf1.nrec - 1); if (l <= e1 || get_func_line(xe, xecfg, NULL, l, e1) < 0) { xche = xche->next; - goto again; + goto post_context_calculation; } } } diff --git a/xdiff/xpatience.c b/xdiff/xpatience.c index 04e1a1ab2a..a613efc703 100644 --- a/xdiff/xpatience.c +++ b/xdiff/xpatience.c @@ -1,6 +1,6 @@ /* * LibXDiff by Davide Libenzi ( File Differential Library ) - * Copyright (C) 2003-2009 Davide Libenzi, Johannes E. Schindelin + * Copyright (C) 2003-2016 Davide Libenzi, Johannes E. Schindelin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public diff --git a/xdiff/xprepare.c b/xdiff/xprepare.c index 63a22c630e..13b55aba74 100644 --- a/xdiff/xprepare.c +++ b/xdiff/xprepare.c @@ -301,10 +301,11 @@ int xdl_prepare_env(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, xdl_free_ctx(&xe->xdf2); xdl_free_ctx(&xe->xdf1); + xdl_free_classifier(&cf); return -1; } - if (!(xpp->flags & XDF_HISTOGRAM_DIFF)) + if (XDF_DIFF_ALG(xpp->flags) != XDF_HISTOGRAM_DIFF) xdl_free_classifier(&cf); return 0; diff --git a/xdiff/xutils.c b/xdiff/xutils.c index 62cb23dfd3..027192a1c7 100644 --- a/xdiff/xutils.c +++ b/xdiff/xutils.c @@ -200,8 +200,10 @@ int xdl_recmatch(const char *l1, long s1, const char *l2, long s2, long flags) return 0; } } else if (flags & XDF_IGNORE_WHITESPACE_AT_EOL) { - while (i1 < s1 && i2 < s2 && l1[i1++] == l2[i2++]) - ; /* keep going */ + while (i1 < s1 && i2 < s2 && l1[i1] == l2[i2]) { + i1++; + i2++; + } } /* |