diff options
Diffstat (limited to 'xdiff')
-rw-r--r-- | xdiff/xdiff.h | 6 | ||||
-rw-r--r-- | xdiff/xmerge.c | 237 |
2 files changed, 171 insertions, 72 deletions
diff --git a/xdiff/xdiff.h b/xdiff/xdiff.h index 413082e1fd..deebe02cd3 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; 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); |