diff --git a/mercurial/thirdparty/xdiff/xdiffi.c b/mercurial/thirdparty/xdiff/xdiffi.c --- a/mercurial/thirdparty/xdiff/xdiffi.c +++ b/mercurial/thirdparty/xdiff/xdiffi.c @@ -1062,6 +1062,7 @@ static int xdl_call_hunk_func(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, xdemitconf_t const *xecfg) { + long p = xe->nprefix, s = xe->nsuffix; xdchange_t *xch, *xche; if (!xecfg->hunk_func) @@ -1073,6 +1074,10 @@ xche = xdl_get_hunk(&xch, xecfg); if (!xch) break; + if (xch != xche) + xdl_bug("xch != xche"); + xch->i1 += p; + xch->i2 += p; if (xch->i1 > i1 || xch->i2 > i2) { if (xecfg->hunk_func(i1, xch->i1, i2, xch->i2, ecb->priv) < 0) return -1; @@ -1080,16 +1085,18 @@ i1 = xche->i1 + xche->chg1; i2 = xche->i2 + xche->chg2; } - if (xecfg->hunk_func(i1, n1, i2, n2, ecb->priv) < 0) + if (xecfg->hunk_func(i1, n1 + p + s, i2, n2 + p + s, + ecb->priv) < 0) return -1; } else { for (xch = xscr; xch; xch = xche->next) { xche = xdl_get_hunk(&xch, xecfg); if (!xch) break; - if (xecfg->hunk_func( - xch->i1, xche->i1 + xche->chg1 - xch->i1, - xch->i2, xche->i2 + xche->chg2 - xch->i2, + if (xecfg->hunk_func(xch->i1 + p, + xche->i1 + xche->chg1 - xch->i1, + xch->i2 + p, + xche->i2 + xche->chg2 - xch->i2, ecb->priv) < 0) return -1; } diff --git a/mercurial/thirdparty/xdiff/xprepare.c b/mercurial/thirdparty/xdiff/xprepare.c --- a/mercurial/thirdparty/xdiff/xprepare.c +++ b/mercurial/thirdparty/xdiff/xprepare.c @@ -156,6 +156,78 @@ } +/* + * Trim common prefix from files. + * + * Note: trimming could have side effects on hunk shifting, but the performance + * benefit outweighs the possible shifting change. + */ +static void xdl_trim_files(mmfile_t *mf1, mmfile_t *mf2, long reserved, + xdfenv_t *xe, mmfile_t *out_mf1, mmfile_t *out_mf2) { + mmfile_t msmall, mlarge; + long plines = 0, pbytes = 0, slines = 0, sbytes = 0, i; + const char *pp1, *pp2, *ps1, *ps2; + + /* reserved must >= 0 for the line boundary adjustment to work */ + if (reserved < 0) + reserved = 0; + + if (mf1->size < mf2->size) { + memcpy(&msmall, mf1, sizeof(mmfile_t)); + memcpy(&mlarge, mf2, sizeof(mmfile_t)); + } else { + memcpy(&msmall, mf2, sizeof(mmfile_t)); + memcpy(&mlarge, mf1, sizeof(mmfile_t)); + } + + pp1 = msmall.ptr, pp2 = mlarge.ptr; + for (i = 0; i < msmall.size && *pp1 == *pp2; ++i) { + plines += (*pp1 == '\n'); + pp1++, pp2++; + } + + ps1 = msmall.ptr + msmall.size - 1, ps2 = mlarge.ptr + mlarge.size - 1; + for (; ps1 > pp1 && *ps1 == *ps2; ++i) { + slines += (*ps1 == '\n'); + ps1--, ps2--; + } + + /* Retract common prefix and suffix boundaries for reserved lines */ + if (plines <= reserved + 1) { + plines = 0; + } else { + for (i = 0; i <= reserved;) { + pp1--; + i += (*pp1 == '\n'); + } + /* The new mmfile starts at the next char just after '\n' */ + pbytes = pp1 - msmall.ptr + 1; + plines -= reserved; + } + + if (slines <= reserved + 1) { + slines = 0; + } else { + for (i = 0; i <= reserved;) { + ps1++; + i += (*ps1 == '\n'); + } + /* The new mmfile includes this '\n' */ + sbytes = msmall.ptr + msmall.size - ps1 - 1; + slines -= reserved; + if (msmall.ptr[msmall.size - 1] == '\n') + slines -= 1; + } + + xe->nprefix = plines; + xe->nsuffix = slines; + out_mf1->ptr = mf1->ptr + pbytes; + out_mf1->size = mf1->size - pbytes - sbytes; + out_mf2->ptr = mf2->ptr + pbytes; + out_mf2->size = mf2->size - pbytes - sbytes; +} + + static int xdl_prepare_ctx(unsigned int pass, mmfile_t *mf, long narec, xpparam_t const *xpp, xdlclassifier_t *cf, xdfile_t *xdf) { unsigned int hbits; @@ -254,10 +326,13 @@ xdl_cha_free(&xdf->rcha); } +/* Reserved lines for trimming, to leave room for shifting */ +#define TRIM_RESERVED_LINES 100 int xdl_prepare_env(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, xdfenv_t *xe) { long enl1, enl2, sample; + mmfile_t tmf1, tmf2; xdlclassifier_t cf; memset(&cf, 0, sizeof(cf)); @@ -270,12 +345,14 @@ if (xdl_init_classifier(&cf, enl1 + enl2 + 1, xpp->flags) < 0) return -1; - if (xdl_prepare_ctx(1, mf1, enl1, xpp, &cf, &xe->xdf1) < 0) { + xdl_trim_files(mf1, mf2, TRIM_RESERVED_LINES, xe, &tmf1, &tmf2); + + if (xdl_prepare_ctx(1, &tmf1, enl1, xpp, &cf, &xe->xdf1) < 0) { xdl_free_classifier(&cf); return -1; } - if (xdl_prepare_ctx(2, mf2, enl2, xpp, &cf, &xe->xdf2) < 0) { + if (xdl_prepare_ctx(2, &tmf2, enl2, xpp, &cf, &xe->xdf2) < 0) { xdl_free_ctx(&xe->xdf1); xdl_free_classifier(&cf); diff --git a/mercurial/thirdparty/xdiff/xtypes.h b/mercurial/thirdparty/xdiff/xtypes.h --- a/mercurial/thirdparty/xdiff/xtypes.h +++ b/mercurial/thirdparty/xdiff/xtypes.h @@ -60,6 +60,7 @@ typedef struct s_xdfenv { xdfile_t xdf1, xdf2; + long nprefix, nsuffix; } xdfenv_t;