summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdward Thomson <ethomson@edwardthomson.com>2018-02-04 10:27:39 +0000
committerGitHub <noreply@github.com>2018-02-04 10:27:39 +0000
commit26f5d36d2f14dc1d711ed0a2c844ef4d7887a9b3 (patch)
treec8117a672f65bbdba472d2534f9c801a94b2f94f
parent8abd514c270ba3b3fc42c6d5feefedc4cc65dd9b (diff)
parent2a8841ae8750b52645eb85dd56305798a429a26d (diff)
downloadlibgit2-26f5d36d2f14dc1d711ed0a2c844ef4d7887a9b3.tar.gz
Merge pull request #4489 from libgit2/ethomson/conflicts_crlf
Conflict markers should match EOL style in conflicting files
-rw-r--r--src/common.h6
-rw-r--r--src/xdiff/xdiff.h37
-rw-r--r--src/xdiff/xdiffi.c5
-rw-r--r--src/xdiff/xdiffi.h4
-rw-r--r--src/xdiff/xemit.c102
-rw-r--r--src/xdiff/xemit.h4
-rw-r--r--src/xdiff/xhistogram.c1
-rw-r--r--src/xdiff/xinclude.h5
-rw-r--r--src/xdiff/xmacros.h4
-rw-r--r--src/xdiff/xmerge.c100
-rw-r--r--src/xdiff/xpatience.c50
-rw-r--r--src/xdiff/xprepare.c4
-rw-r--r--src/xdiff/xprepare.h4
-rw-r--r--src/xdiff/xtypes.h4
-rw-r--r--src/xdiff/xutils.c74
-rw-r--r--src/xdiff/xutils.h7
-rw-r--r--tests/merge/files.c48
17 files changed, 326 insertions, 133 deletions
diff --git a/src/common.h b/src/common.h
index 5fb4a608f..44063be12 100644
--- a/src/common.h
+++ b/src/common.h
@@ -230,6 +230,12 @@ GIT_INLINE(void) git__init_structure(void *structure, size_t len, unsigned int v
GIT_ADD_SIZET_OVERFLOW(out, *(out), three) || \
GIT_ADD_SIZET_OVERFLOW(out, *(out), four)) { return -1; }
+#define GITERR_CHECK_ALLOC_ADD5(out, one, two, three, four, five) \
+ if (GIT_ADD_SIZET_OVERFLOW(out, one, two) || \
+ GIT_ADD_SIZET_OVERFLOW(out, *(out), three) || \
+ GIT_ADD_SIZET_OVERFLOW(out, *(out), four) || \
+ GIT_ADD_SIZET_OVERFLOW(out, *(out), five)) { return -1; }
+
/** Check for multiplicative overflow, failing if it would occur. */
#define GITERR_CHECK_ALLOC_MULTIPLY(out, nelem, elsize) \
if (GIT_MULTIPLY_SIZET_OVERFLOW(out, nelem, elsize)) { return -1; }
diff --git a/src/xdiff/xdiff.h b/src/xdiff/xdiff.h
index b7dc05697..5b13e77a0 100644
--- a/src/xdiff/xdiff.h
+++ b/src/xdiff/xdiff.h
@@ -13,15 +13,13 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
*
* Davide Libenzi <davidel@xmailserver.org>
*
*/
-#include "../util.h"
-
#if !defined(XDIFF_H)
#define XDIFF_H
@@ -29,24 +27,29 @@
extern "C" {
#endif /* #ifdef __cplusplus */
+/* xpparm_t.flags */
+#define XDF_NEED_MINIMAL (1 << 0)
+
+#define XDF_IGNORE_WHITESPACE (1 << 1)
+#define XDF_IGNORE_WHITESPACE_CHANGE (1 << 2)
+#define XDF_IGNORE_WHITESPACE_AT_EOL (1 << 3)
+#define XDF_IGNORE_CR_AT_EOL (1 << 4)
+#define XDF_WHITESPACE_FLAGS (XDF_IGNORE_WHITESPACE | \
+ XDF_IGNORE_WHITESPACE_CHANGE | \
+ XDF_IGNORE_WHITESPACE_AT_EOL | \
+ XDF_IGNORE_CR_AT_EOL)
-#define XDF_NEED_MINIMAL (1 << 1)
-#define XDF_IGNORE_WHITESPACE (1 << 2)
-#define XDF_IGNORE_WHITESPACE_CHANGE (1 << 3)
-#define XDF_IGNORE_WHITESPACE_AT_EOL (1 << 4)
-#define XDF_WHITESPACE_FLAGS (XDF_IGNORE_WHITESPACE | XDF_IGNORE_WHITESPACE_CHANGE | XDF_IGNORE_WHITESPACE_AT_EOL)
+#define XDF_IGNORE_BLANK_LINES (1 << 7)
-#define XDF_PATIENCE_DIFF (1 << 5)
-#define XDF_HISTOGRAM_DIFF (1 << 6)
+#define XDF_PATIENCE_DIFF (1 << 14)
+#define XDF_HISTOGRAM_DIFF (1 << 15)
#define XDF_DIFF_ALGORITHM_MASK (XDF_PATIENCE_DIFF | XDF_HISTOGRAM_DIFF)
#define XDF_DIFF_ALG(x) ((x) & XDF_DIFF_ALGORITHM_MASK)
-#define XDF_IGNORE_BLANK_LINES (1 << 7)
-
-#define XDF_INDENT_HEURISTIC (1 << 8)
+#define XDF_INDENT_HEURISTIC (1 << 23)
+/* xdemitconf_t.flags */
#define XDL_EMIT_FUNCNAMES (1 << 0)
-#define XDL_EMIT_COMMON (1 << 1)
#define XDL_EMIT_FUNCCONTEXT (1 << 2)
#define XDL_MMB_READONLY (1 << 0)
@@ -83,6 +86,10 @@ typedef struct s_mmbuffer {
typedef struct s_xpparam {
unsigned long flags;
+
+ /* See Documentation/diff-options.txt. */
+ char **anchors;
+ size_t anchors_nr;
} xpparam_t;
typedef struct s_xdemitcb {
diff --git a/src/xdiff/xdiffi.c b/src/xdiff/xdiffi.c
index 3e65b6ce5..3a71ef678 100644
--- a/src/xdiff/xdiffi.c
+++ b/src/xdiff/xdiffi.c
@@ -13,15 +13,14 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
*
* Davide Libenzi <davidel@xmailserver.org>
*
*/
#include "xinclude.h"
-#include "common.h"
#include "integer.h"
diff --git a/src/xdiff/xdiffi.h b/src/xdiff/xdiffi.h
index 8b81206c9..8f1c7c8b0 100644
--- a/src/xdiff/xdiffi.h
+++ b/src/xdiff/xdiffi.h
@@ -13,8 +13,8 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
*
* Davide Libenzi <davidel@xmailserver.org>
*
diff --git a/src/xdiff/xemit.c b/src/xdiff/xemit.c
index 600fd1fdd..0ffa6553a 100644
--- a/src/xdiff/xemit.c
+++ b/src/xdiff/xemit.c
@@ -13,8 +13,8 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
*
* Davide Libenzi <davidel@xmailserver.org>
*
@@ -22,15 +22,6 @@
#include "xinclude.h"
-
-
-
-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 long xdl_get_rec(xdfile_t *xdf, long ri, char const **rec) {
*rec = xdf->recs[ri]->ptr;
@@ -110,7 +101,7 @@ static long def_ff(const char *rec, long len, char *buf, long sz, void *priv)
if (len > 0 &&
(isalpha((unsigned char)*rec) || /* identifier? */
- *rec == '_' || /* also identifier? */
+ *rec == '_' || /* also identifier? */
*rec == '$')) { /* identifiers from VMS and other esoterico */
if (len > sz)
len = sz;
@@ -122,22 +113,20 @@ static long def_ff(const char *rec, long len, char *buf, long sz, void *priv)
return -1;
}
-static int xdl_emit_common(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
- xdemitconf_t const *xecfg) {
- xdfile_t *xdf = &xe->xdf2;
- const char *rchg = xdf->rchg;
- long ix;
-
- (void)xscr;
- (void)xecfg;
+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);
+}
- for (ix = 0; ix < xdf->nrec; ix++) {
- if (rchg[ix])
- continue;
- if (xdl_emit_record(xdf, ix, "", ecb))
- return -1;
- }
- return 0;
+static int is_func_rec(xdfile_t *xdf, xdemitconf_t const *xecfg, long ri)
+{
+ char dummy[1];
+ return match_func_rec(xdf, xecfg, ri, dummy, sizeof(dummy)) >= 0;
}
struct func_line {
@@ -148,7 +137,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];
@@ -156,9 +144,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;
@@ -168,6 +154,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;
@@ -175,9 +173,6 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
long funclineprev = -1;
struct func_line func_line = { 0 };
- if (xecfg->flags & XDL_EMIT_COMMON)
- return xdl_emit_common(xe, xscr, ecb, xecfg);
-
for (xch = xscr; xch; xch = xche->next) {
xche = xdl_get_hunk(&xch, xecfg);
if (!xch)
@@ -187,7 +182,33 @@ 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) {
+ long i2 = xch->i2;
+
+ /*
+ * We don't need additional context if
+ * a whole function was added.
+ */
+ while (i2 < xe->xdf2.nrec) {
+ if (is_func_rec(&xe->xdf2, xecfg, i2))
+ goto post_context_calculation;
+ i2++;
+ }
+
+ /*
+ * Otherwise get more context from the
+ * pre-image.
+ */
+ i1 = xe->xdf1.nrec - 1;
+ }
+
+ fs1 = get_func_line(xe, xecfg, NULL, i1, -1);
+ while (fs1 > 0 && !is_empty_rec(&xe->xdf1, fs1 - 1) &&
+ !is_func_rec(&xe->xdf1, xecfg, fs1 - 1))
+ fs1--;
if (fs1 < 0)
fs1 = 0;
if (fs1 < s1) {
@@ -196,7 +217,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));
@@ -208,6 +229,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) {
@@ -221,11 +244,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;
- if (l <= e1 ||
+ long l = XDL_MIN(xche->next->i1,
+ xe->xdf1.nrec - 1);
+ if (l - xecfg->ctxlen <= e1 ||
get_func_line(xe, xecfg, NULL, l, e1) < 0) {
xche = xche->next;
- goto again;
+ goto post_context_calculation;
}
}
}
diff --git a/src/xdiff/xemit.h b/src/xdiff/xemit.h
index d29710770..1b9887e67 100644
--- a/src/xdiff/xemit.h
+++ b/src/xdiff/xemit.h
@@ -13,8 +13,8 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
*
* Davide Libenzi <davidel@xmailserver.org>
*
diff --git a/src/xdiff/xhistogram.c b/src/xdiff/xhistogram.c
index 0c2edb89c..ca8605e31 100644
--- a/src/xdiff/xhistogram.c
+++ b/src/xdiff/xhistogram.c
@@ -44,7 +44,6 @@
#include "xinclude.h"
#include "xtypes.h"
#include "xdiff.h"
-#include "common.h"
#define MAX_PTR UINT_MAX
#define MAX_CNT UINT_MAX
diff --git a/src/xdiff/xinclude.h b/src/xdiff/xinclude.h
index 4a1cde909..068ce42f8 100644
--- a/src/xdiff/xinclude.h
+++ b/src/xdiff/xinclude.h
@@ -13,8 +13,8 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
*
* Davide Libenzi <davidel@xmailserver.org>
*
@@ -42,5 +42,6 @@
#include "xdiffi.h"
#include "xemit.h"
+#include "common.h"
#endif /* #if !defined(XINCLUDE_H) */
diff --git a/src/xdiff/xmacros.h b/src/xdiff/xmacros.h
index 165a895a9..2809a28ca 100644
--- a/src/xdiff/xmacros.h
+++ b/src/xdiff/xmacros.h
@@ -13,8 +13,8 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
*
* Davide Libenzi <davidel@xmailserver.org>
*
diff --git a/src/xdiff/xmerge.c b/src/xdiff/xmerge.c
index 6448b5542..6fec95aa3 100644
--- a/src/xdiff/xmerge.c
+++ b/src/xdiff/xmerge.c
@@ -13,15 +13,14 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
*
* Davide Libenzi <davidel@xmailserver.org>
*
*/
#include "xinclude.h"
-#include "common.h"
typedef struct s_xdmerge {
struct s_xdmerge *next;
@@ -110,7 +109,7 @@ static int xdl_merge_cmp_lines(xdfenv_t *xe1, int i1, xdfenv_t *xe2, int i2,
return 0;
}
-static int xdl_recs_copy_0(size_t *out, int use_orig, xdfenv_t *xe, int i, int count, int add_nl, char *dest)
+static int xdl_recs_copy_0(size_t *out, int use_orig, xdfenv_t *xe, int i, int count, int needs_cr, int add_nl, char *dest)
{
xrecord_t **recs;
size_t size = 0;
@@ -132,6 +131,12 @@ static int xdl_recs_copy_0(size_t *out, int use_orig, xdfenv_t *xe, int i, int c
if (add_nl) {
i = recs[count - 1]->size;
if (i == 0 || recs[count - 1]->ptr[i - 1] != '\n') {
+ if (needs_cr) {
+ if (dest)
+ dest[size] = '\r';
+ GITERR_CHECK_ALLOC_ADD(&size, size, 1);
+ }
+
if (dest)
dest[size] = '\n';
@@ -143,14 +148,58 @@ static int xdl_recs_copy_0(size_t *out, int use_orig, xdfenv_t *xe, int i, int c
return 0;
}
-static int xdl_recs_copy(size_t *out, xdfenv_t *xe, int i, int count, int add_nl, char *dest)
+static int xdl_recs_copy(size_t *out, xdfenv_t *xe, int i, int count, int needs_cr, int add_nl, char *dest)
{
- return xdl_recs_copy_0(out, 0, xe, i, count, add_nl, dest);
+ return xdl_recs_copy_0(out, 0, xe, i, count, needs_cr, add_nl, dest);
}
-static int xdl_orig_copy(size_t *out, xdfenv_t *xe, int i, int count, int add_nl, char *dest)
+static int xdl_orig_copy(size_t *out, xdfenv_t *xe, int i, int count, int needs_cr, int add_nl, char *dest)
{
- return xdl_recs_copy_0(out, 1, xe, i, count, add_nl, dest);
+ return xdl_recs_copy_0(out, 1, xe, i, count, needs_cr, add_nl, dest);
+}
+
+/*
+ * Returns 1 if the i'th line ends in CR/LF (if it is the last line and
+ * has no eol, the preceding line, if any), 0 if it ends in LF-only, and
+ * -1 if the line ending cannot be determined.
+ */
+static int is_eol_crlf(xdfile_t *file, int i)
+{
+ long size;
+
+ if (i < file->nrec - 1)
+ /* All lines before the last *must* end in LF */
+ return (size = file->recs[i]->size) > 1 &&
+ file->recs[i]->ptr[size - 2] == '\r';
+ if (!file->nrec)
+ /* Cannot determine eol style from empty file */
+ return -1;
+ if ((size = file->recs[i]->size) &&
+ file->recs[i]->ptr[size - 1] == '\n')
+ /* Last line; ends in LF; Is it CR/LF? */
+ return size > 1 &&
+ file->recs[i]->ptr[size - 2] == '\r';
+ if (!i)
+ /* The only line has no eol */
+ return -1;
+ /* Determine eol from second-to-last line */
+ return (size = file->recs[i - 1]->size) > 1 &&
+ file->recs[i - 1]->ptr[size - 2] == '\r';
+}
+
+static int is_cr_needed(xdfenv_t *xe1, xdfenv_t *xe2, xdmerge_t *m)
+{
+ int needs_cr;
+
+ /* Match post-images' preceding, or first, lines' end-of-line style */
+ needs_cr = is_eol_crlf(&xe1->xdf2, m->i1 ? m->i1 - 1 : 0);
+ if (needs_cr)
+ needs_cr = is_eol_crlf(&xe2->xdf2, m->i2 ? m->i2 - 1 : 0);
+ /* Look at pre-image's first line, unless we already settled on LF */
+ if (needs_cr)
+ needs_cr = is_eol_crlf(&xe1->xdf1, 0);
+ /* If still undecided, use LF-only */
+ return needs_cr < 0 ? 0 : needs_cr;
}
static int fill_conflict_hunk(size_t *out, xdfenv_t *xe1, const char *name1,
@@ -162,6 +211,7 @@ static int fill_conflict_hunk(size_t *out, xdfenv_t *xe1, const char *name1,
int marker1_size = (name1 ? (int)strlen(name1) + 1 : 0);
int marker2_size = (name2 ? (int)strlen(name2) + 1 : 0);
int marker3_size = (name3 ? (int)strlen(name3) + 1 : 0);
+ int needs_cr = is_cr_needed(xe1, xe2, m);
size_t copied;
*out = 0;
@@ -170,14 +220,14 @@ static int fill_conflict_hunk(size_t *out, xdfenv_t *xe1, const char *name1,
marker_size = DEFAULT_CONFLICT_MARKER_SIZE;
/* Before conflicting part */
- if (xdl_recs_copy(&copied, xe1, i, m->i1 - i, 0,
+ if (xdl_recs_copy(&copied, xe1, i, m->i1 - i, 0, 0,
dest ? dest + size : NULL) < 0)
return -1;
GITERR_CHECK_ALLOC_ADD(&size, size, copied);
if (!dest) {
- GITERR_CHECK_ALLOC_ADD4(&size, size, marker_size, 1, marker1_size);
+ GITERR_CHECK_ALLOC_ADD5(&size, size, marker_size, 1, needs_cr, marker1_size);
} else {
memset(dest + size, '<', marker_size);
size += marker_size;
@@ -186,11 +236,13 @@ static int fill_conflict_hunk(size_t *out, xdfenv_t *xe1, const char *name1,
memcpy(dest + size + 1, name1, marker1_size - 1);
size += marker1_size;
}
+ if (needs_cr)
+ dest[size++] = '\r';
dest[size++] = '\n';
}
/* Postimage from side #1 */
- if (xdl_recs_copy(&copied, xe1, m->i1, m->chg1, 1,
+ if (xdl_recs_copy(&copied, xe1, m->i1, m->chg1, needs_cr, 1,
dest ? dest + size : NULL) < 0)
return -1;
@@ -199,7 +251,7 @@ static int fill_conflict_hunk(size_t *out, xdfenv_t *xe1, const char *name1,
if (style == XDL_MERGE_DIFF3) {
/* Shared preimage */
if (!dest) {
- GITERR_CHECK_ALLOC_ADD4(&size, size, marker_size, 1, marker3_size);
+ GITERR_CHECK_ALLOC_ADD5(&size, size, marker_size, 1, needs_cr, marker3_size);
} else {
memset(dest + size, '|', marker_size);
size += marker_size;
@@ -208,32 +260,36 @@ static int fill_conflict_hunk(size_t *out, xdfenv_t *xe1, const char *name1,
memcpy(dest + size + 1, name3, marker3_size - 1);
size += marker3_size;
}
+ if (needs_cr)
+ dest[size++] = '\r';
dest[size++] = '\n';
}
- if (xdl_orig_copy(&copied, xe1, m->i0, m->chg0, 1,
+ if (xdl_orig_copy(&copied, xe1, m->i0, m->chg0, needs_cr, 1,
dest ? dest + size : NULL) < 0)
return -1;
GITERR_CHECK_ALLOC_ADD(&size, size, copied);
}
if (!dest) {
- GITERR_CHECK_ALLOC_ADD3(&size, size, marker_size, 1);
+ GITERR_CHECK_ALLOC_ADD4(&size, size, marker_size, 1, needs_cr);
} else {
memset(dest + size, '=', marker_size);
size += marker_size;
+ if (needs_cr)
+ dest[size++] = '\r';
dest[size++] = '\n';
}
/* Postimage from side #2 */
- if (xdl_recs_copy(&copied, xe2, m->i2, m->chg2, 1,
+ if (xdl_recs_copy(&copied, xe2, m->i2, m->chg2, needs_cr, 1,
dest ? dest + size : NULL) < 0)
return -1;
GITERR_CHECK_ALLOC_ADD(&size, size, copied);
if (!dest) {
- GITERR_CHECK_ALLOC_ADD4(&size, size, marker_size, 1, marker2_size);
+ GITERR_CHECK_ALLOC_ADD5(&size, size, marker_size, 1, needs_cr, marker2_size);
} else {
memset(dest + size, '>', marker_size);
size += marker_size;
@@ -242,6 +298,8 @@ static int fill_conflict_hunk(size_t *out, xdfenv_t *xe1, const char *name1,
memcpy(dest + size + 1, name2, marker2_size - 1);
size += marker2_size;
}
+ if (needs_cr)
+ dest[size++] = '\r';
dest[size++] = '\n';
}
@@ -275,14 +333,16 @@ static int xdl_fill_merge_buffer(size_t *out,
}
else if (m->mode & 3) {
/* Before conflicting part */
- if (xdl_recs_copy(&copied, xe1, i, m->i1 - i, 0,
+ if (xdl_recs_copy(&copied, xe1, i, m->i1 - i, 0, 0,
dest ? dest + size : NULL) < 0)
return -1;
GITERR_CHECK_ALLOC_ADD(&size, size, copied);
/* Postimage from side #1 */
if (m->mode & 1) {
- if (xdl_recs_copy(&copied, xe1, m->i1, m->chg1, (m->mode & 2),
+ int needs_cr = is_cr_needed(xe1, xe2, m);
+
+ if (xdl_recs_copy(&copied, xe1, m->i1, m->chg1, needs_cr, (m->mode & 2),
dest ? dest + size : NULL) < 0)
return -1;
GITERR_CHECK_ALLOC_ADD(&size, size, copied);
@@ -290,7 +350,7 @@ static int xdl_fill_merge_buffer(size_t *out,
/* Postimage from side #2 */
if (m->mode & 2) {
- if (xdl_recs_copy(&copied, xe2, m->i2, m->chg2, 0,
+ if (xdl_recs_copy(&copied, xe2, m->i2, m->chg2, 0, 0,
dest ? dest + size : NULL) < 0)
return -1;
GITERR_CHECK_ALLOC_ADD(&size, size, copied);
@@ -300,7 +360,7 @@ static int xdl_fill_merge_buffer(size_t *out,
i = m->i1 + m->chg1;
}
- if (xdl_recs_copy(&copied, xe1, i, xe1->xdf2.nrec - i, 0,
+ if (xdl_recs_copy(&copied, xe1, i, xe1->xdf2.nrec - i, 0, 0,
dest ? dest + size : NULL) < 0)
return -1;
GITERR_CHECK_ALLOC_ADD(&size, size, copied);
diff --git a/src/xdiff/xpatience.c b/src/xdiff/xpatience.c
index 04e1a1ab2..cedf39cc3 100644
--- a/src/xdiff/xpatience.c
+++ b/src/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
@@ -13,8 +13,8 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
*
* Davide Libenzi <davidel@xmailserver.org>
*
@@ -62,6 +62,12 @@ struct hashmap {
* initially, "next" reflects only the order in file1.
*/
struct entry *next, *previous;
+
+ /*
+ * If 1, this entry can serve as an anchor. See
+ * Documentation/diff-options.txt for more information.
+ */
+ unsigned anchor : 1;
} *entries, *first, *last;
/* were common records found? */
unsigned long has_matches;
@@ -70,8 +76,19 @@ struct hashmap {
xpparam_t const *xpp;
};
+static int is_anchor(xpparam_t const *xpp, const char *line)
+{
+ unsigned long i;
+ for (i = 0; i < xpp->anchors_nr; i++) {
+ if (!strncmp(line, xpp->anchors[i], strlen(xpp->anchors[i])))
+ return 1;
+ }
+ return 0;
+}
+
/* The argument "pass" is 1 for the first file, 2 for the second. */
-static void insert_record(int line, struct hashmap *map, int pass)
+static void insert_record(xpparam_t const *xpp, int line, struct hashmap *map,
+ int pass)
{
xrecord_t **records = pass == 1 ?
map->env->xdf1.recs : map->env->xdf2.recs;
@@ -110,6 +127,7 @@ static void insert_record(int line, struct hashmap *map, int pass)
return;
map->entries[index].line1 = line;
map->entries[index].hash = record->ha;
+ map->entries[index].anchor = is_anchor(xpp, map->env->xdf1.recs[line - 1]->ptr);
if (!map->first)
map->first = map->entries + index;
if (map->last) {
@@ -147,11 +165,11 @@ static int fill_hashmap(mmfile_t *file1, mmfile_t *file2,
/* First, fill with entries from the first file */
while (count1--)
- insert_record(line1++, result, 1);
+ insert_record(xpp, line1++, result, 1);
/* Then search for matches in the second file */
while (count2--)
- insert_record(line2++, result, 2);
+ insert_record(xpp, line2++, result, 2);
return 0;
}
@@ -166,7 +184,7 @@ static int binary_search(struct entry **sequence, int longest,
int left = -1, right = longest;
while (left + 1 < right) {
- int middle = (left + right) / 2;
+ int middle = left + (right - left) / 2;
/* by construction, no two entries can be equal */
if (sequence[middle]->line2 > entry->line2)
right = middle;
@@ -192,14 +210,28 @@ static struct entry *find_longest_common_sequence(struct hashmap *map)
int longest = 0, i;
struct entry *entry;
+ /*
+ * If not -1, this entry in sequence must never be overridden.
+ * Therefore, overriding entries before this has no effect, so
+ * do not do that either.
+ */
+ int anchor_i = -1;
+
for (entry = map->first; entry; entry = entry->next) {
if (!entry->line2 || entry->line2 == NON_UNIQUE)
continue;
i = binary_search(sequence, longest, entry);
entry->previous = i < 0 ? NULL : sequence[i];
- sequence[++i] = entry;
- if (i == longest)
+ ++i;
+ if (i <= anchor_i)
+ continue;
+ sequence[i] = entry;
+ if (entry->anchor) {
+ anchor_i = i;
+ longest = anchor_i + 1;
+ } else if (i == longest) {
longest++;
+ }
}
/* No common unique lines were found */
diff --git a/src/xdiff/xprepare.c b/src/xdiff/xprepare.c
index 13b55aba7..abeb8fb84 100644
--- a/src/xdiff/xprepare.c
+++ b/src/xdiff/xprepare.c
@@ -13,8 +13,8 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
*
* Davide Libenzi <davidel@xmailserver.org>
*
diff --git a/src/xdiff/xprepare.h b/src/xdiff/xprepare.h
index 8fb06a537..947d9fc1b 100644
--- a/src/xdiff/xprepare.h
+++ b/src/xdiff/xprepare.h
@@ -13,8 +13,8 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
*
* Davide Libenzi <davidel@xmailserver.org>
*
diff --git a/src/xdiff/xtypes.h b/src/xdiff/xtypes.h
index 2511aef8d..8442bd436 100644
--- a/src/xdiff/xtypes.h
+++ b/src/xdiff/xtypes.h
@@ -13,8 +13,8 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
*
* Davide Libenzi <davidel@xmailserver.org>
*
diff --git a/src/xdiff/xutils.c b/src/xdiff/xutils.c
index 30f2a30ac..17c9ae184 100644
--- a/src/xdiff/xutils.c
+++ b/src/xdiff/xutils.c
@@ -13,8 +13,8 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
*
* Davide Libenzi <davidel@xmailserver.org>
*
@@ -62,14 +62,14 @@ int xdl_emit_diffrec(char const *rec, long size, char const *pre, long psize,
void *xdl_mmfile_first(mmfile_t *mmf, long *size)
{
- *size = (long)mmf->size;
+ *size = mmf->size;
return mmf->ptr;
}
long xdl_mmfile_size(mmfile_t *mmf)
{
- return (long)mmf->size;
+ return mmf->size;
}
@@ -154,6 +154,24 @@ int xdl_blankline(const char *line, long size, long flags)
return (i == size);
}
+/*
+ * Have we eaten everything on the line, except for an optional
+ * CR at the very end?
+ */
+static int ends_with_optional_cr(const char *l, long s, long i)
+{
+ int complete = s && l[s-1] == '\n';
+
+ if (complete)
+ s--;
+ if (s == i)
+ return 1;
+ /* do not ignore CR at the end of an incomplete line */
+ if (complete && s == i + 1 && l[i] == '\r')
+ return 1;
+ return 0;
+}
+
int xdl_recmatch(const char *l1, long s1, const char *l2, long s2, long flags)
{
int i1, i2;
@@ -168,7 +186,8 @@ int xdl_recmatch(const char *l1, long s1, const char *l2, long s2, long flags)
/*
* -w matches everything that matches with -b, and -b in turn
- * matches everything that matches with --ignore-space-at-eol.
+ * matches everything that matches with --ignore-space-at-eol,
+ * which in turn matches everything that matches with --ignore-cr-at-eol.
*
* Each flavor of ignoring needs different logic to skip whitespaces
* while we have both sides to compare.
@@ -198,8 +217,18 @@ 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++;
+ }
+ } else if (flags & XDF_IGNORE_CR_AT_EOL) {
+ /* Find the first difference and see how the line ends */
+ while (i1 < s1 && i2 < s2 && l1[i1] == l2[i2]) {
+ i1++;
+ i2++;
+ }
+ return (ends_with_optional_cr(l1, s1, i1) &&
+ ends_with_optional_cr(l2, s2, i2));
}
/*
@@ -226,9 +255,16 @@ static unsigned long xdl_hash_record_with_whitespace(char const **data,
char const *top, long flags) {
unsigned long ha = 5381;
char const *ptr = *data;
+ int cr_at_eol_only = (flags & XDF_WHITESPACE_FLAGS) == XDF_IGNORE_CR_AT_EOL;
for (; ptr < top && *ptr != '\n'; ptr++) {
- if (XDL_ISSPACE(*ptr)) {
+ if (cr_at_eol_only) {
+ /* do not ignore CR at the end of an incomplete line */
+ if (*ptr == '\r' &&
+ (ptr + 1 < top && ptr[1] == '\n'))
+ continue;
+ }
+ else if (XDL_ISSPACE(*ptr)) {
const char *ptr2 = ptr;
int at_eol;
while (ptr + 1 < top && XDL_ISSPACE(ptr[1])
@@ -260,7 +296,6 @@ static unsigned long xdl_hash_record_with_whitespace(char const **data,
return ha;
}
-
unsigned long xdl_hash_record(char const **data, char const *top, long flags) {
unsigned long ha = 5381;
char const *ptr = *data;
@@ -277,7 +312,6 @@ unsigned long xdl_hash_record(char const **data, char const *top, long flags) {
return ha;
}
-
unsigned int xdl_hashbits(unsigned int size) {
unsigned int val = 1, bits = 0;
@@ -305,23 +339,9 @@ int xdl_num_out(char *out, long val) {
*str++ = '0';
*str = '\0';
- return (int)(str - out);
-}
-
-
-long xdl_atol(char const *str, char const **next) {
- long val, base;
- char const *top;
-
- for (top = str; XDL_ISDIGIT(*top); top++);
- if (next)
- *next = top;
- for (val = 0, base = 1, top--; top >= str; top--, base *= 10)
- val += base * (long)(*top - '0');
- return 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) {
int nb = 0;
@@ -356,8 +376,8 @@ int xdl_emit_hunk_hdr(long s1, long c1, long s2, long c2,
nb += 3;
if (func && funclen) {
buf[nb++] = ' ';
- if (funclen > (long)sizeof(buf) - nb - 1)
- funclen = (long)sizeof(buf) - nb - 1;
+ if (funclen > (long)(sizeof(buf) - nb - 1))
+ funclen = sizeof(buf) - nb - 1;
memcpy(buf + nb, func, funclen);
nb += funclen;
}
diff --git a/src/xdiff/xutils.h b/src/xdiff/xutils.h
index 8f952a8e6..fba7bae03 100644
--- a/src/xdiff/xutils.h
+++ b/src/xdiff/xutils.h
@@ -13,8 +13,8 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
*
* Davide Libenzi <davidel@xmailserver.org>
*
@@ -31,15 +31,12 @@ int xdl_emit_diffrec(char const *rec, long size, char const *pre, long psize,
int xdl_cha_init(chastore_t *cha, long isize, long icount);
void xdl_cha_free(chastore_t *cha);
void *xdl_cha_alloc(chastore_t *cha);
-void *xdl_cha_first(chastore_t *cha);
-void *xdl_cha_next(chastore_t *cha);
long xdl_guess_lines(mmfile_t *mf, long sample);
int xdl_blankline(const char *line, long size, long flags);
int xdl_recmatch(const char *l1, long s1, const char *l2, long s2, long flags);
unsigned long xdl_hash_record(char const **data, char const *top, long flags);
unsigned int xdl_hashbits(unsigned int size);
int xdl_num_out(char *out, long val);
-long xdl_atol(char const *str, char const **next);
int xdl_emit_hunk_hdr(long s1, long c1, long s2, long c2,
const char *func, long funclen, xdemitcb_t *ecb);
int xdl_fall_back_diff(xdfenv_t *diff_env, xpparam_t const *xpp,
diff --git a/tests/merge/files.c b/tests/merge/files.c
index daa73fada..6f5a1fd9c 100644
--- a/tests/merge/files.c
+++ b/tests/merge/files.c
@@ -377,3 +377,51 @@ void test_merge_files__handles_binaries_when_favored(void)
git_merge_file_result_free(&result);
}
+
+void test_merge_files__crlf_conflict_markers_for_crlf_files(void)
+{
+ git_merge_file_input ancestor = GIT_MERGE_FILE_INPUT_INIT,
+ ours = GIT_MERGE_FILE_INPUT_INIT,
+ theirs = GIT_MERGE_FILE_INPUT_INIT;
+ git_merge_file_options opts = GIT_MERGE_FILE_OPTIONS_INIT;
+ git_merge_file_result result = {0};
+
+ const char *expected =
+ "<<<<<<< file.txt\r\nThis file\r\ndoes, too.\r\n"
+ "=======\r\nAnd so does\r\nthis one.\r\n>>>>>>> file.txt\r\n";
+ size_t expected_len = strlen(expected);
+
+ const char *expected_diff3 =
+ "<<<<<<< file.txt\r\nThis file\r\ndoes, too.\r\n"
+ "||||||| file.txt\r\nThis file has\r\nCRLF line endings.\r\n"
+ "=======\r\nAnd so does\r\nthis one.\r\n>>>>>>> file.txt\r\n";
+ size_t expected_diff3_len = strlen(expected_diff3);
+
+ ancestor.ptr = "This file has\r\nCRLF line endings.\r\n";
+ ancestor.size = 35;
+ ancestor.path = "file.txt";
+ ancestor.mode = 0100644;
+
+ ours.ptr = "This file\r\ndoes, too.\r\n";
+ ours.size = 23;
+ ours.path = "file.txt";
+ ours.mode = 0100644;
+
+ theirs.ptr = "And so does\r\nthis one.\r\n";
+ theirs.size = 24;
+ theirs.path = "file.txt";
+ theirs.mode = 0100644;
+
+ cl_git_pass(git_merge_file(&result, &ancestor, &ours, &theirs, &opts));
+ cl_assert_equal_i(0, result.automergeable);
+ cl_assert_equal_i(expected_len, result.len);
+ cl_assert(memcmp(expected, result.ptr, expected_len) == 0);
+ git_merge_file_result_free(&result);
+
+ opts.flags |= GIT_MERGE_FILE_STYLE_DIFF3;
+ cl_git_pass(git_merge_file(&result, &ancestor, &ours, &theirs, &opts));
+ cl_assert_equal_i(0, result.automergeable);
+ cl_assert_equal_i(expected_diff3_len, result.len);
+ cl_assert(memcmp(expected_diff3, result.ptr, expected_len) == 0);
+ git_merge_file_result_free(&result);
+}