summaryrefslogtreecommitdiff
path: root/xdiff
diff options
context:
space:
mode:
Diffstat (limited to 'xdiff')
-rw-r--r--xdiff/xdiff.h7
-rw-r--r--xdiff/xdiffi.c4
-rw-r--r--xdiff/xemit.c3
-rw-r--r--xdiff/xemit.h3
-rw-r--r--xdiff/xmerge.c237
-rw-r--r--xdiff/xprepare.c15
6 files changed, 192 insertions, 77 deletions
diff --git a/xdiff/xdiff.h b/xdiff/xdiff.h
index 413082e1fd..84fff583e2 100644
--- a/xdiff/xdiff.h
+++ b/xdiff/xdiff.h
@@ -50,10 +50,16 @@ extern "C" {
#define XDL_BDOP_CPY 2
#define XDL_BDOP_INSB 3
+/* merge simplification levels */
#define XDL_MERGE_MINIMAL 0
#define XDL_MERGE_EAGER 1
#define XDL_MERGE_ZEALOUS 2
#define XDL_MERGE_ZEALOUS_ALNUM 3
+#define XDL_MERGE_LEVEL_MASK 0x0f
+
+/* merge output styles */
+#define XDL_MERGE_DIFF3 0x8000
+#define XDL_MERGE_STYLE_MASK 0x8000
typedef struct s_mmfile {
char *ptr;
@@ -81,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 {
diff --git a/xdiff/xdiffi.c b/xdiff/xdiffi.c
index 1bad8462fb..9d0324a38c 100644
--- a/xdiff/xdiffi.c
+++ b/xdiff/xdiffi.c
@@ -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);
diff --git a/xdiff/xemit.c b/xdiff/xemit.c
index d3d9c845c6..4625c1b421 100644
--- a/xdiff/xemit.c
+++ b/xdiff/xemit.c
@@ -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)
diff --git a/xdiff/xemit.h b/xdiff/xemit.h
index 440a7390fa..c2e2e83027 100644
--- a/xdiff/xemit.h
+++ b/xdiff/xemit.h
@@ -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);
diff --git a/xdiff/xmerge.c b/xdiff/xmerge.c
index 82b3573e7a..d9737f04c2 100644
--- a/xdiff/xmerge.c
+++ b/xdiff/xmerge.c
@@ -30,17 +30,32 @@ typedef struct s_xdmerge {
* 2 = no conflict, take second.
*/
int mode;
+ /*
+ * These point at the respective postimages. E.g. <i1,chg1> is
+ * how side #1 wants to change the common ancestor; if there is no
+ * overlap, lines before i1 in the postimage of side #1 appear
+ * in the merge result as a region touched by neither side.
+ */
long i1, i2;
long chg1, chg2;
+ /*
+ * These point at the preimage; of course there is just one
+ * preimage, that is from the shared common ancestor.
+ */
+ long i0;
+ long chg0;
} xdmerge_t;
static int xdl_append_merge(xdmerge_t **merge, int mode,
- long i1, long chg1, long i2, long chg2)
+ long i0, long chg0,
+ long i1, long chg1,
+ long i2, long chg2)
{
xdmerge_t *m = *merge;
if (m && (i1 <= m->i1 + m->chg1 || i2 <= m->i2 + m->chg2)) {
if (mode != m->mode)
m->mode = 0;
+ m->chg0 = i0 + chg0 - m->i0;
m->chg1 = i1 + chg1 - m->i1;
m->chg2 = i2 + chg2 - m->i2;
} else {
@@ -49,6 +64,8 @@ static int xdl_append_merge(xdmerge_t **merge, int mode,
return -1;
m->next = NULL;
m->mode = mode;
+ m->i0 = i0;
+ m->chg0 = chg0;
m->i1 = i1;
m->chg1 = chg1;
m->i2 = i2;
@@ -91,11 +108,13 @@ static int xdl_merge_cmp_lines(xdfenv_t *xe1, int i1, xdfenv_t *xe2, int i2,
return 0;
}
-static int xdl_recs_copy(xdfenv_t *xe, int i, int count, int add_nl, char *dest)
+static int xdl_recs_copy_0(int use_orig, xdfenv_t *xe, int i, int count, int add_nl, char *dest)
{
- xrecord_t **recs = xe->xdf2.recs + i;
+ xrecord_t **recs;
int size = 0;
+ recs = (use_orig ? xe->xdf1.recs : xe->xdf2.recs) + i;
+
if (count < 1)
return 0;
@@ -113,65 +132,109 @@ static int xdl_recs_copy(xdfenv_t *xe, int i, int count, int add_nl, char *dest)
return size;
}
-static int xdl_fill_merge_buffer(xdfenv_t *xe1, const char *name1,
- xdfenv_t *xe2, const char *name2, xdmerge_t *m, char *dest)
+static int xdl_recs_copy(xdfenv_t *xe, int i, int count, int add_nl, char *dest)
+{
+ return xdl_recs_copy_0(0, xe, i, count, add_nl, dest);
+}
+
+static int xdl_orig_copy(xdfenv_t *xe, int i, int count, int add_nl, char *dest)
+{
+ return xdl_recs_copy_0(1, xe, i, count, add_nl, dest);
+}
+
+static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1,
+ xdfenv_t *xe2, const char *name2,
+ int size, int i, int style,
+ xdmerge_t *m, char *dest)
{
const int marker_size = 7;
int marker1_size = (name1 ? strlen(name1) + 1 : 0);
int marker2_size = (name2 ? strlen(name2) + 1 : 0);
- int conflict_marker_size = 3 * (marker_size + 1)
- + marker1_size + marker2_size;
- int size, i1, j;
-
- for (size = i1 = 0; m; m = m->next) {
- if (m->mode == 0) {
- size += xdl_recs_copy(xe1, i1, m->i1 - i1, 0,
- dest ? dest + size : NULL);
- if (dest) {
- for (j = 0; j < marker_size; j++)
- dest[size++] = '<';
- if (marker1_size) {
- dest[size] = ' ';
- memcpy(dest + size + 1, name1,
- marker1_size - 1);
- size += marker1_size;
- }
- dest[size++] = '\n';
- } else
- size += conflict_marker_size;
- size += xdl_recs_copy(xe1, m->i1, m->chg1, 1,
- dest ? dest + size : NULL);
- if (dest) {
- for (j = 0; j < marker_size; j++)
- dest[size++] = '=';
- dest[size++] = '\n';
- }
- size += xdl_recs_copy(xe2, m->i2, m->chg2, 1,
- dest ? dest + size : NULL);
- if (dest) {
- for (j = 0; j < marker_size; j++)
- dest[size++] = '>';
- if (marker2_size) {
- dest[size] = ' ';
- memcpy(dest + size + 1, name2,
- marker2_size - 1);
- size += marker2_size;
- }
- dest[size++] = '\n';
- }
- } else if (m->mode == 1)
- size += xdl_recs_copy(xe1, i1, m->i1 + m->chg1 - i1, 0,
- dest ? dest + size : NULL);
+ int j;
+
+ /* Before conflicting part */
+ size += xdl_recs_copy(xe1, i, m->i1 - i, 0,
+ dest ? dest + size : NULL);
+
+ if (!dest) {
+ size += marker_size + 1 + marker1_size;
+ } else {
+ for (j = 0; j < marker_size; j++)
+ dest[size++] = '<';
+ if (marker1_size) {
+ dest[size] = ' ';
+ memcpy(dest + size + 1, name1, marker1_size - 1);
+ size += marker1_size;
+ }
+ dest[size++] = '\n';
+ }
+
+ /* Postimage from side #1 */
+ size += xdl_recs_copy(xe1, m->i1, m->chg1, 1,
+ dest ? dest + size : NULL);
+
+ if (style == XDL_MERGE_DIFF3) {
+ /* Shared preimage */
+ if (!dest) {
+ size += marker_size + 1;
+ } else {
+ for (j = 0; j < marker_size; j++)
+ dest[size++] = '|';
+ dest[size++] = '\n';
+ }
+ size += xdl_orig_copy(xe1, m->i0, m->chg0, 1,
+ dest ? dest + size : NULL);
+ }
+
+ if (!dest) {
+ size += marker_size + 1;
+ } else {
+ for (j = 0; j < marker_size; j++)
+ dest[size++] = '=';
+ dest[size++] = '\n';
+ }
+
+ /* Postimage from side #2 */
+ size += xdl_recs_copy(xe2, m->i2, m->chg2, 1,
+ dest ? dest + size : NULL);
+ if (!dest) {
+ size += marker_size + 1 + marker2_size;
+ } else {
+ for (j = 0; j < marker_size; j++)
+ dest[size++] = '>';
+ if (marker2_size) {
+ dest[size] = ' ';
+ memcpy(dest + size + 1, name2, marker2_size - 1);
+ size += marker2_size;
+ }
+ dest[size++] = '\n';
+ }
+ return size;
+}
+
+static int xdl_fill_merge_buffer(xdfenv_t *xe1, const char *name1,
+ xdfenv_t *xe2, const char *name2,
+ xdmerge_t *m, char *dest, int style)
+{
+ int size, i;
+
+ for (size = i = 0; m; m = m->next) {
+ if (m->mode == 0)
+ size = fill_conflict_hunk(xe1, name1, xe2, name2,
+ size, i, style, m, dest);
+ else if (m->mode == 1)
+ size += xdl_recs_copy(xe1, i, m->i1 + m->chg1 - i, 0,
+ dest ? dest + size : NULL);
else if (m->mode == 2)
- size += xdl_recs_copy(xe2, m->i2 - m->i1 + i1,
- m->i1 + m->chg2 - i1, 0,
- dest ? dest + size : NULL);
+ size += xdl_recs_copy(xe2, m->i2 - m->i1 + i,
+ m->i1 + m->chg2 - i, 0,
+ dest ? dest + size : NULL);
else
continue;
- i1 = m->i1 + m->chg1;
+ i = m->i1 + m->chg1;
}
- size += xdl_recs_copy(xe1, i1, xe1->xdf2.nrec - i1, 0,
- dest ? dest + size : NULL);
+ size += xdl_recs_copy(xe1, i, xe1->xdf2.nrec - i, 0,
+ dest ? dest + size : NULL);
return size;
}
@@ -323,9 +386,20 @@ static int xdl_simplify_non_conflicts(xdfenv_t *xe1, xdmerge_t *m,
*/
static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1,
xdfenv_t *xe2, xdchange_t *xscr2, const char *name2,
- int level, xpparam_t const *xpp, mmbuffer_t *result) {
+ int flags, xpparam_t const *xpp, mmbuffer_t *result) {
xdmerge_t *changes, *c;
- int i1, i2, chg1, chg2;
+ int i0, i1, i2, chg0, chg1, chg2;
+ int level = flags & XDL_MERGE_LEVEL_MASK;
+ int style = flags & XDL_MERGE_STYLE_MASK;
+
+ if (style == XDL_MERGE_DIFF3) {
+ /*
+ * "diff3 -m" output does not make sense for anything
+ * more aggressive than XDL_MERGE_EAGER.
+ */
+ if (XDL_MERGE_EAGER < level)
+ level = XDL_MERGE_EAGER;
+ }
c = changes = NULL;
@@ -333,11 +407,14 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1,
if (!changes)
changes = c;
if (xscr1->i1 + xscr1->chg1 < xscr2->i1) {
+ i0 = xscr1->i1;
i1 = xscr1->i2;
i2 = xscr2->i2 - xscr2->i1 + xscr1->i1;
+ chg0 = xscr1->chg1;
chg1 = xscr1->chg2;
chg2 = xscr1->chg1;
- if (xdl_append_merge(&c, 1, i1, chg1, i2, chg2)) {
+ if (xdl_append_merge(&c, 1,
+ i0, chg0, i1, chg1, i2, chg2)) {
xdl_cleanup_merge(changes);
return -1;
}
@@ -345,18 +422,21 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1,
continue;
}
if (xscr2->i1 + xscr2->chg1 < xscr1->i1) {
+ i0 = xscr2->i1;
i1 = xscr1->i2 - xscr1->i1 + xscr2->i1;
i2 = xscr2->i2;
+ chg0 = xscr2->chg1;
chg1 = xscr2->chg1;
chg2 = xscr2->chg2;
- if (xdl_append_merge(&c, 2, i1, chg1, i2, chg2)) {
+ if (xdl_append_merge(&c, 2,
+ i0, chg0, i1, chg1, i2, chg2)) {
xdl_cleanup_merge(changes);
return -1;
}
xscr2 = xscr2->next;
continue;
}
- if (level < 1 || xscr1->i1 != xscr2->i1 ||
+ if (level == XDL_MERGE_MINIMAL || xscr1->i1 != xscr2->i1 ||
xscr1->chg1 != xscr2->chg1 ||
xscr1->chg2 != xscr2->chg2 ||
xdl_merge_cmp_lines(xe1, xscr1->i2,
@@ -366,19 +446,25 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1,
int off = xscr1->i1 - xscr2->i1;
int ffo = off + xscr1->chg1 - xscr2->chg1;
+ i0 = xscr1->i1;
i1 = xscr1->i2;
i2 = xscr2->i2;
- if (off > 0)
+ if (off > 0) {
+ i0 -= off;
i1 -= off;
+ }
else
i2 += off;
+ chg0 = xscr1->i1 + xscr1->chg1 - i0;
chg1 = xscr1->i2 + xscr1->chg2 - i1;
chg2 = xscr2->i2 + xscr2->chg2 - i2;
- if (ffo > 0)
- chg2 += ffo;
- else
+ if (ffo < 0) {
+ chg0 -= ffo;
chg1 -= ffo;
- if (xdl_append_merge(&c, 0, i1, chg1, i2, chg2)) {
+ } else
+ chg2 += ffo;
+ if (xdl_append_merge(&c, 0,
+ i0, chg0, i1, chg1, i2, chg2)) {
xdl_cleanup_merge(changes);
return -1;
}
@@ -395,11 +481,14 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1,
while (xscr1) {
if (!changes)
changes = c;
+ i0 = xscr1->i1;
i1 = xscr1->i2;
i2 = xscr1->i1 + xe2->xdf2.nrec - xe2->xdf1.nrec;
+ chg0 = xscr1->chg1;
chg1 = xscr1->chg2;
chg2 = xscr1->chg1;
- if (xdl_append_merge(&c, 1, i1, chg1, i2, chg2)) {
+ if (xdl_append_merge(&c, 1,
+ i0, chg0, i1, chg1, i2, chg2)) {
xdl_cleanup_merge(changes);
return -1;
}
@@ -408,11 +497,14 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1,
while (xscr2) {
if (!changes)
changes = c;
+ i0 = xscr2->i1;
i1 = xscr2->i1 + xe1->xdf2.nrec - xe1->xdf1.nrec;
i2 = xscr2->i2;
+ chg0 = xscr2->chg1;
chg1 = xscr2->chg1;
chg2 = xscr2->chg2;
- if (xdl_append_merge(&c, 2, i1, chg1, i2, chg2)) {
+ if (xdl_append_merge(&c, 2,
+ i0, chg0, i1, chg1, i2, chg2)) {
xdl_cleanup_merge(changes);
return -1;
}
@@ -421,16 +513,17 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1,
if (!changes)
changes = c;
/* refine conflicts */
- if (level > 1 &&
+ if (XDL_MERGE_ZEALOUS <= level &&
(xdl_refine_conflicts(xe1, xe2, changes, xpp) < 0 ||
- xdl_simplify_non_conflicts(xe1, changes, level > 2) < 0)) {
+ xdl_simplify_non_conflicts(xe1, changes,
+ XDL_MERGE_ZEALOUS < level) < 0)) {
xdl_cleanup_merge(changes);
return -1;
}
/* output */
if (result) {
int size = xdl_fill_merge_buffer(xe1, name1, xe2, name2,
- changes, NULL);
+ changes, NULL, style);
result->ptr = xdl_malloc(size);
if (!result->ptr) {
xdl_cleanup_merge(changes);
@@ -438,14 +531,14 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1,
}
result->size = size;
xdl_fill_merge_buffer(xe1, name1, xe2, name2, changes,
- result->ptr);
+ result->ptr, style);
}
return xdl_cleanup_merge(changes);
}
int xdl_merge(mmfile_t *orig, mmfile_t *mf1, const char *name1,
mmfile_t *mf2, const char *name2,
- xpparam_t const *xpp, int level, mmbuffer_t *result) {
+ xpparam_t const *xpp, int flags, mmbuffer_t *result) {
xdchange_t *xscr1, *xscr2;
xdfenv_t xe1, xe2;
int status;
@@ -482,7 +575,7 @@ int xdl_merge(mmfile_t *orig, mmfile_t *mf1, const char *name1,
} else {
status = xdl_do_merge(&xe1, xscr1, name1,
&xe2, xscr2, name2,
- level, xpp, result);
+ flags, xpp, result);
}
xdl_free_script(xscr1);
xdl_free_script(xscr2);
diff --git a/xdiff/xprepare.c b/xdiff/xprepare.c
index e87ab57c65..a43aa72cd0 100644
--- a/xdiff/xprepare.c
+++ b/xdiff/xprepare.c
@@ -23,10 +23,9 @@
#include "xinclude.h"
-
#define XDL_KPDIS_RUN 4
#define XDL_MAX_EQLIMIT 1024
-
+#define XDL_SIMSCAN_WINDOW 100
typedef struct s_xdlclass {
@@ -313,6 +312,18 @@ static int xdl_clean_mmatch(char const *dis, long i, long s, long e) {
long r, rdis0, rpdis0, rdis1, rpdis1;
/*
+ * Limits the window the is examined during the similar-lines
+ * scan. The loops below stops when dis[i - r] == 1 (line that
+ * has no match), but there are corner cases where the loop
+ * proceed all the way to the extremities by causing huge
+ * performance penalties in case of big files.
+ */
+ if (i - s > XDL_SIMSCAN_WINDOW)
+ s = i - XDL_SIMSCAN_WINDOW;
+ if (e - i > XDL_SIMSCAN_WINDOW)
+ e = i + XDL_SIMSCAN_WINDOW;
+
+ /*
* Scans the lines before 'i' to find a run of lines that either
* have no match (dis[j] == 0) or have multiple matches (dis[j] > 1).
* Note that we always call this function with dis[i] > 1, so the