Unverified Commit 26f5d36d by Edward Thomson Committed by GitHub

Merge pull request #4489 from libgit2/ethomson/conflicts_crlf

Conflict markers should match EOL style in conflicting files
parents 8abd514c 2a8841ae
...@@ -230,6 +230,12 @@ GIT_INLINE(void) git__init_structure(void *structure, size_t len, unsigned int v ...@@ -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), three) || \
GIT_ADD_SIZET_OVERFLOW(out, *(out), four)) { return -1; } 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. */ /** Check for multiplicative overflow, failing if it would occur. */
#define GITERR_CHECK_ALLOC_MULTIPLY(out, nelem, elsize) \ #define GITERR_CHECK_ALLOC_MULTIPLY(out, nelem, elsize) \
if (GIT_MULTIPLY_SIZET_OVERFLOW(out, nelem, elsize)) { return -1; } if (GIT_MULTIPLY_SIZET_OVERFLOW(out, nelem, elsize)) { return -1; }
......
...@@ -13,15 +13,13 @@ ...@@ -13,15 +13,13 @@
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software * License along with this library; if not, see
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * <http://www.gnu.org/licenses/>.
* *
* Davide Libenzi <davidel@xmailserver.org> * Davide Libenzi <davidel@xmailserver.org>
* *
*/ */
#include "../util.h"
#if !defined(XDIFF_H) #if !defined(XDIFF_H)
#define XDIFF_H #define XDIFF_H
...@@ -29,24 +27,29 @@ ...@@ -29,24 +27,29 @@
extern "C" { extern "C" {
#endif /* #ifdef __cplusplus */ #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_BLANK_LINES (1 << 7)
#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_PATIENCE_DIFF (1 << 5) #define XDF_PATIENCE_DIFF (1 << 14)
#define XDF_HISTOGRAM_DIFF (1 << 6) #define XDF_HISTOGRAM_DIFF (1 << 15)
#define XDF_DIFF_ALGORITHM_MASK (XDF_PATIENCE_DIFF | XDF_HISTOGRAM_DIFF) #define XDF_DIFF_ALGORITHM_MASK (XDF_PATIENCE_DIFF | XDF_HISTOGRAM_DIFF)
#define XDF_DIFF_ALG(x) ((x) & XDF_DIFF_ALGORITHM_MASK) #define XDF_DIFF_ALG(x) ((x) & XDF_DIFF_ALGORITHM_MASK)
#define XDF_IGNORE_BLANK_LINES (1 << 7) #define XDF_INDENT_HEURISTIC (1 << 23)
#define XDF_INDENT_HEURISTIC (1 << 8)
/* xdemitconf_t.flags */
#define XDL_EMIT_FUNCNAMES (1 << 0) #define XDL_EMIT_FUNCNAMES (1 << 0)
#define XDL_EMIT_COMMON (1 << 1)
#define XDL_EMIT_FUNCCONTEXT (1 << 2) #define XDL_EMIT_FUNCCONTEXT (1 << 2)
#define XDL_MMB_READONLY (1 << 0) #define XDL_MMB_READONLY (1 << 0)
...@@ -83,6 +86,10 @@ typedef struct s_mmbuffer { ...@@ -83,6 +86,10 @@ typedef struct s_mmbuffer {
typedef struct s_xpparam { typedef struct s_xpparam {
unsigned long flags; unsigned long flags;
/* See Documentation/diff-options.txt. */
char **anchors;
size_t anchors_nr;
} xpparam_t; } xpparam_t;
typedef struct s_xdemitcb { typedef struct s_xdemitcb {
......
...@@ -13,15 +13,14 @@ ...@@ -13,15 +13,14 @@
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software * License along with this library; if not, see
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * <http://www.gnu.org/licenses/>.
* *
* Davide Libenzi <davidel@xmailserver.org> * Davide Libenzi <davidel@xmailserver.org>
* *
*/ */
#include "xinclude.h" #include "xinclude.h"
#include "common.h"
#include "integer.h" #include "integer.h"
......
...@@ -13,8 +13,8 @@ ...@@ -13,8 +13,8 @@
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software * License along with this library; if not, see
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * <http://www.gnu.org/licenses/>.
* *
* Davide Libenzi <davidel@xmailserver.org> * Davide Libenzi <davidel@xmailserver.org>
* *
......
...@@ -13,8 +13,8 @@ ...@@ -13,8 +13,8 @@
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software * License along with this library; if not, see
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * <http://www.gnu.org/licenses/>.
* *
* Davide Libenzi <davidel@xmailserver.org> * Davide Libenzi <davidel@xmailserver.org>
* *
...@@ -22,15 +22,6 @@ ...@@ -22,15 +22,6 @@
#include "xinclude.h" #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) { static long xdl_get_rec(xdfile_t *xdf, long ri, char const **rec) {
*rec = xdf->recs[ri]->ptr; *rec = xdf->recs[ri]->ptr;
...@@ -110,7 +101,7 @@ static long def_ff(const char *rec, long len, char *buf, long sz, void *priv) ...@@ -110,7 +101,7 @@ static long def_ff(const char *rec, long len, char *buf, long sz, void *priv)
if (len > 0 && if (len > 0 &&
(isalpha((unsigned char)*rec) || /* identifier? */ (isalpha((unsigned char)*rec) || /* identifier? */
*rec == '_' || /* also identifier? */ *rec == '_' || /* also identifier? */
*rec == '$')) { /* identifiers from VMS and other esoterico */ *rec == '$')) { /* identifiers from VMS and other esoterico */
if (len > sz) if (len > sz)
len = sz; len = sz;
...@@ -122,22 +113,20 @@ static long def_ff(const char *rec, long len, char *buf, long sz, void *priv) ...@@ -122,22 +113,20 @@ static long def_ff(const char *rec, long len, char *buf, long sz, void *priv)
return -1; return -1;
} }
static int xdl_emit_common(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, static long match_func_rec(xdfile_t *xdf, xdemitconf_t const *xecfg, long ri,
xdemitconf_t const *xecfg) { char *buf, long sz)
xdfile_t *xdf = &xe->xdf2; {
const char *rchg = xdf->rchg; const char *rec;
long ix; long len = xdl_get_rec(xdf, ri, &rec);
if (!xecfg->find_func)
(void)xscr; return def_ff(rec, len, buf, sz, xecfg->find_func_priv);
(void)xecfg; return xecfg->find_func(rec, len, buf, sz, xecfg->find_func_priv);
}
for (ix = 0; ix < xdf->nrec; ix++) { static int is_func_rec(xdfile_t *xdf, xdemitconf_t const *xecfg, long ri)
if (rchg[ix]) {
continue; char dummy[1];
if (xdl_emit_record(xdf, ix, "", ecb)) return match_func_rec(xdf, xecfg, ri, dummy, sizeof(dummy)) >= 0;
return -1;
}
return 0;
} }
struct func_line { struct func_line {
...@@ -148,7 +137,6 @@ struct func_line { ...@@ -148,7 +137,6 @@ struct func_line {
static long get_func_line(xdfenv_t *xe, xdemitconf_t const *xecfg, static long get_func_line(xdfenv_t *xe, xdemitconf_t const *xecfg,
struct func_line *func_line, long start, long limit) 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; long l, size, step = (start > limit) ? -1 : 1;
char *buf, dummy[1]; char *buf, dummy[1];
...@@ -156,9 +144,7 @@ static long get_func_line(xdfenv_t *xe, xdemitconf_t const *xecfg, ...@@ -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); size = func_line ? sizeof(func_line->buf) : sizeof(dummy);
for (l = start; l != limit && 0 <= l && l < xe->xdf1.nrec; l += step) { for (l = start; l != limit && 0 <= l && l < xe->xdf1.nrec; l += step) {
const char *rec; long len = match_func_rec(&xe->xdf1, xecfg, l, buf, size);
long reclen = xdl_get_rec(&xe->xdf1, l, &rec);
long len = ff(rec, reclen, buf, size, xecfg->find_func_priv);
if (len >= 0) { if (len >= 0) {
if (func_line) if (func_line)
func_line->len = len; func_line->len = len;
...@@ -168,6 +154,18 @@ static long get_func_line(xdfenv_t *xe, xdemitconf_t const *xecfg, ...@@ -168,6 +154,18 @@ static long get_func_line(xdfenv_t *xe, xdemitconf_t const *xecfg,
return -1; 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, int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
xdemitconf_t const *xecfg) { xdemitconf_t const *xecfg) {
long s1, s2, e1, e2, lctx; long s1, s2, e1, e2, lctx;
...@@ -175,9 +173,6 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, ...@@ -175,9 +173,6 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
long funclineprev = -1; long funclineprev = -1;
struct func_line func_line = { 0 }; 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) { for (xch = xscr; xch; xch = xche->next) {
xche = xdl_get_hunk(&xch, xecfg); xche = xdl_get_hunk(&xch, xecfg);
if (!xch) if (!xch)
...@@ -187,7 +182,33 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, ...@@ -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); s2 = XDL_MAX(xch->i2 - xecfg->ctxlen, 0);
if (xecfg->flags & XDL_EMIT_FUNCCONTEXT) { 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) if (fs1 < 0)
fs1 = 0; fs1 = 0;
if (fs1 < s1) { if (fs1 < s1) {
...@@ -196,7 +217,7 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, ...@@ -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 = xecfg->ctxlen;
lctx = XDL_MIN(lctx, xe->xdf1.nrec - (xche->i1 + xche->chg1)); lctx = XDL_MIN(lctx, xe->xdf1.nrec - (xche->i1 + xche->chg1));
lctx = XDL_MIN(lctx, xe->xdf2.nrec - (xche->i2 + xche->chg2)); 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, ...@@ -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, long fe1 = get_func_line(xe, xecfg, NULL,
xche->i1 + xche->chg1, xche->i1 + xche->chg1,
xe->xdf1.nrec); xe->xdf1.nrec);
while (fe1 > 0 && is_empty_rec(&xe->xdf1, fe1 - 1))
fe1--;
if (fe1 < 0) if (fe1 < 0)
fe1 = xe->xdf1.nrec; fe1 = xe->xdf1.nrec;
if (fe1 > e1) { if (fe1 > e1) {
...@@ -221,11 +244,12 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, ...@@ -221,11 +244,12 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
* its new end. * its new end.
*/ */
if (xche->next) { if (xche->next) {
long l = xche->next->i1; long l = XDL_MIN(xche->next->i1,
if (l <= e1 || xe->xdf1.nrec - 1);
if (l - xecfg->ctxlen <= e1 ||
get_func_line(xe, xecfg, NULL, l, e1) < 0) { get_func_line(xe, xecfg, NULL, l, e1) < 0) {
xche = xche->next; xche = xche->next;
goto again; goto post_context_calculation;
} }
} }
} }
......
...@@ -13,8 +13,8 @@ ...@@ -13,8 +13,8 @@
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software * License along with this library; if not, see
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * <http://www.gnu.org/licenses/>.
* *
* Davide Libenzi <davidel@xmailserver.org> * Davide Libenzi <davidel@xmailserver.org>
* *
......
...@@ -44,7 +44,6 @@ ...@@ -44,7 +44,6 @@
#include "xinclude.h" #include "xinclude.h"
#include "xtypes.h" #include "xtypes.h"
#include "xdiff.h" #include "xdiff.h"
#include "common.h"
#define MAX_PTR UINT_MAX #define MAX_PTR UINT_MAX
#define MAX_CNT UINT_MAX #define MAX_CNT UINT_MAX
......
...@@ -13,8 +13,8 @@ ...@@ -13,8 +13,8 @@
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software * License along with this library; if not, see
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * <http://www.gnu.org/licenses/>.
* *
* Davide Libenzi <davidel@xmailserver.org> * Davide Libenzi <davidel@xmailserver.org>
* *
...@@ -42,5 +42,6 @@ ...@@ -42,5 +42,6 @@
#include "xdiffi.h" #include "xdiffi.h"
#include "xemit.h" #include "xemit.h"
#include "common.h"
#endif /* #if !defined(XINCLUDE_H) */ #endif /* #if !defined(XINCLUDE_H) */
...@@ -13,8 +13,8 @@ ...@@ -13,8 +13,8 @@
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software * License along with this library; if not, see
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * <http://www.gnu.org/licenses/>.
* *
* Davide Libenzi <davidel@xmailserver.org> * Davide Libenzi <davidel@xmailserver.org>
* *
......
...@@ -13,15 +13,14 @@ ...@@ -13,15 +13,14 @@
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software * License along with this library; if not, see
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * <http://www.gnu.org/licenses/>.
* *
* Davide Libenzi <davidel@xmailserver.org> * Davide Libenzi <davidel@xmailserver.org>
* *
*/ */
#include "xinclude.h" #include "xinclude.h"
#include "common.h"
typedef struct s_xdmerge { typedef struct s_xdmerge {
struct s_xdmerge *next; struct s_xdmerge *next;
...@@ -110,7 +109,7 @@ static int xdl_merge_cmp_lines(xdfenv_t *xe1, int i1, xdfenv_t *xe2, int i2, ...@@ -110,7 +109,7 @@ static int xdl_merge_cmp_lines(xdfenv_t *xe1, int i1, xdfenv_t *xe2, int i2,
return 0; 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; xrecord_t **recs;
size_t size = 0; 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 ...@@ -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) { if (add_nl) {
i = recs[count - 1]->size; i = recs[count - 1]->size;
if (i == 0 || recs[count - 1]->ptr[i - 1] != '\n') { 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) if (dest)
dest[size] = '\n'; 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 ...@@ -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; 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, 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, ...@@ -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 marker1_size = (name1 ? (int)strlen(name1) + 1 : 0);
int marker2_size = (name2 ? (int)strlen(name2) + 1 : 0); int marker2_size = (name2 ? (int)strlen(name2) + 1 : 0);
int marker3_size = (name3 ? (int)strlen(name3) + 1 : 0); int marker3_size = (name3 ? (int)strlen(name3) + 1 : 0);
int needs_cr = is_cr_needed(xe1, xe2, m);
size_t copied; size_t copied;
*out = 0; *out = 0;
...@@ -170,14 +220,14 @@ static int fill_conflict_hunk(size_t *out, xdfenv_t *xe1, const char *name1, ...@@ -170,14 +220,14 @@ static int fill_conflict_hunk(size_t *out, xdfenv_t *xe1, const char *name1,
marker_size = DEFAULT_CONFLICT_MARKER_SIZE; marker_size = DEFAULT_CONFLICT_MARKER_SIZE;
/* Before conflicting part */ /* 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) dest ? dest + size : NULL) < 0)
return -1; return -1;
GITERR_CHECK_ALLOC_ADD(&size, size, copied); GITERR_CHECK_ALLOC_ADD(&size, size, copied);
if (!dest) { 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 { } else {
memset(dest + size, '<', marker_size); memset(dest + size, '<', marker_size);
size += marker_size; size += marker_size;
...@@ -186,11 +236,13 @@ static int fill_conflict_hunk(size_t *out, xdfenv_t *xe1, const char *name1, ...@@ -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); memcpy(dest + size + 1, name1, marker1_size - 1);
size += marker1_size; size += marker1_size;
} }
if (needs_cr)
dest[size++] = '\r';
dest[size++] = '\n'; dest[size++] = '\n';
} }
/* Postimage from side #1 */ /* 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) dest ? dest + size : NULL) < 0)
return -1; return -1;
...@@ -199,7 +251,7 @@ static int fill_conflict_hunk(size_t *out, xdfenv_t *xe1, const char *name1, ...@@ -199,7 +251,7 @@ static int fill_conflict_hunk(size_t *out, xdfenv_t *xe1, const char *name1,
if (style == XDL_MERGE_DIFF3) { if (style == XDL_MERGE_DIFF3) {
/* Shared preimage */ /* Shared preimage */
if (!dest) { 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 { } else {
memset(dest + size, '|', marker_size); memset(dest + size, '|', marker_size);
size += marker_size; size += marker_size;
...@@ -208,32 +260,36 @@ static int fill_conflict_hunk(size_t *out, xdfenv_t *xe1, const char *name1, ...@@ -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); memcpy(dest + size + 1, name3, marker3_size - 1);
size += marker3_size; size += marker3_size;
} }
if (needs_cr)
dest[size++] = '\r';
dest[size++] = '\n'; 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) dest ? dest + size : NULL) < 0)
return -1; return -1;
GITERR_CHECK_ALLOC_ADD(&size, size, copied); GITERR_CHECK_ALLOC_ADD(&size, size, copied);
} }
if (!dest) { if (!dest) {
GITERR_CHECK_ALLOC_ADD3(&size, size, marker_size, 1); GITERR_CHECK_ALLOC_ADD4(&size, size, marker_size, 1, needs_cr);
} else { } else {
memset(dest + size, '=', marker_size); memset(dest + size, '=', marker_size);
size += marker_size; size += marker_size;
if (needs_cr)
dest[size++] = '\r';
dest[size++] = '\n'; dest[size++] = '\n';
} }
/* Postimage from side #2 */ /* 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) dest ? dest + size : NULL) < 0)
return -1; return -1;
GITERR_CHECK_ALLOC_ADD(&size, size, copied); GITERR_CHECK_ALLOC_ADD(&size, size, copied);
if (!dest) { 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 { } else {
memset(dest + size, '>', marker_size); memset(dest + size, '>', marker_size);
size += marker_size; size += marker_size;
...@@ -242,6 +298,8 @@ static int fill_conflict_hunk(size_t *out, xdfenv_t *xe1, const char *name1, ...@@ -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); memcpy(dest + size + 1, name2, marker2_size - 1);
size += marker2_size; size += marker2_size;
} }
if (needs_cr)
dest[size++] = '\r';
dest[size++] = '\n'; dest[size++] = '\n';
} }
...@@ -275,14 +333,16 @@ static int xdl_fill_merge_buffer(size_t *out, ...@@ -275,14 +333,16 @@ static int xdl_fill_merge_buffer(size_t *out,
} }
else if (m->mode & 3) { else if (m->mode & 3) {
/* Before conflicting part */ /* 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) dest ? dest + size : NULL) < 0)
return -1; return -1;
GITERR_CHECK_ALLOC_ADD(&size, size, copied); GITERR_CHECK_ALLOC_ADD(&size, size, copied);
/* Postimage from side #1 */ /* Postimage from side #1 */
if (m->mode & 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) dest ? dest + size : NULL) < 0)
return -1; return -1;
GITERR_CHECK_ALLOC_ADD(&size, size, copied); GITERR_CHECK_ALLOC_ADD(&size, size, copied);
...@@ -290,7 +350,7 @@ static int xdl_fill_merge_buffer(size_t *out, ...@@ -290,7 +350,7 @@ static int xdl_fill_merge_buffer(size_t *out,
/* Postimage from side #2 */ /* Postimage from side #2 */
if (m->mode & 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) dest ? dest + size : NULL) < 0)
return -1; return -1;
GITERR_CHECK_ALLOC_ADD(&size, size, copied); GITERR_CHECK_ALLOC_ADD(&size, size, copied);
...@@ -300,7 +360,7 @@ static int xdl_fill_merge_buffer(size_t *out, ...@@ -300,7 +360,7 @@ static int xdl_fill_merge_buffer(size_t *out,
i = m->i1 + m->chg1; 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) dest ? dest + size : NULL) < 0)
return -1; return -1;
GITERR_CHECK_ALLOC_ADD(&size, size, copied); GITERR_CHECK_ALLOC_ADD(&size, size, copied);
......
/* /*
* LibXDiff by Davide Libenzi ( File Differential Library ) * 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 * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
...@@ -13,8 +13,8 @@ ...@@ -13,8 +13,8 @@
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software * License along with this library; if not, see
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * <http://www.gnu.org/licenses/>.
* *
* Davide Libenzi <davidel@xmailserver.org> * Davide Libenzi <davidel@xmailserver.org>
* *
...@@ -62,6 +62,12 @@ struct hashmap { ...@@ -62,6 +62,12 @@ struct hashmap {
* initially, "next" reflects only the order in file1. * initially, "next" reflects only the order in file1.
*/ */
struct entry *next, *previous; 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; } *entries, *first, *last;
/* were common records found? */ /* were common records found? */
unsigned long has_matches; unsigned long has_matches;
...@@ -70,8 +76,19 @@ struct hashmap { ...@@ -70,8 +76,19 @@ struct hashmap {
xpparam_t const *xpp; 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. */ /* 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 ? xrecord_t **records = pass == 1 ?
map->env->xdf1.recs : map->env->xdf2.recs; map->env->xdf1.recs : map->env->xdf2.recs;
...@@ -110,6 +127,7 @@ static void insert_record(int line, struct hashmap *map, int pass) ...@@ -110,6 +127,7 @@ static void insert_record(int line, struct hashmap *map, int pass)
return; return;
map->entries[index].line1 = line; map->entries[index].line1 = line;
map->entries[index].hash = record->ha; map->entries[index].hash = record->ha;
map->entries[index].anchor = is_anchor(xpp, map->env->xdf1.recs[line - 1]->ptr);
if (!map->first) if (!map->first)
map->first = map->entries + index; map->first = map->entries + index;
if (map->last) { if (map->last) {
...@@ -147,11 +165,11 @@ static int fill_hashmap(mmfile_t *file1, mmfile_t *file2, ...@@ -147,11 +165,11 @@ static int fill_hashmap(mmfile_t *file1, mmfile_t *file2,
/* First, fill with entries from the first file */ /* First, fill with entries from the first file */
while (count1--) while (count1--)
insert_record(line1++, result, 1); insert_record(xpp, line1++, result, 1);
/* Then search for matches in the second file */ /* Then search for matches in the second file */
while (count2--) while (count2--)
insert_record(line2++, result, 2); insert_record(xpp, line2++, result, 2);
return 0; return 0;
} }
...@@ -166,7 +184,7 @@ static int binary_search(struct entry **sequence, int longest, ...@@ -166,7 +184,7 @@ static int binary_search(struct entry **sequence, int longest,
int left = -1, right = longest; int left = -1, right = longest;
while (left + 1 < right) { while (left + 1 < right) {
int middle = (left + right) / 2; int middle = left + (right - left) / 2;
/* by construction, no two entries can be equal */ /* by construction, no two entries can be equal */
if (sequence[middle]->line2 > entry->line2) if (sequence[middle]->line2 > entry->line2)
right = middle; right = middle;
...@@ -192,14 +210,28 @@ static struct entry *find_longest_common_sequence(struct hashmap *map) ...@@ -192,14 +210,28 @@ static struct entry *find_longest_common_sequence(struct hashmap *map)
int longest = 0, i; int longest = 0, i;
struct entry *entry; 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) { for (entry = map->first; entry; entry = entry->next) {
if (!entry->line2 || entry->line2 == NON_UNIQUE) if (!entry->line2 || entry->line2 == NON_UNIQUE)
continue; continue;
i = binary_search(sequence, longest, entry); i = binary_search(sequence, longest, entry);
entry->previous = i < 0 ? NULL : sequence[i]; entry->previous = i < 0 ? NULL : sequence[i];
sequence[++i] = entry; ++i;
if (i == longest) if (i <= anchor_i)
continue;
sequence[i] = entry;
if (entry->anchor) {
anchor_i = i;
longest = anchor_i + 1;
} else if (i == longest) {
longest++; longest++;
}
} }
/* No common unique lines were found */ /* No common unique lines were found */
......
...@@ -13,8 +13,8 @@ ...@@ -13,8 +13,8 @@
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software * License along with this library; if not, see
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * <http://www.gnu.org/licenses/>.
* *
* Davide Libenzi <davidel@xmailserver.org> * Davide Libenzi <davidel@xmailserver.org>
* *
......
...@@ -13,8 +13,8 @@ ...@@ -13,8 +13,8 @@
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software * License along with this library; if not, see
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * <http://www.gnu.org/licenses/>.
* *
* Davide Libenzi <davidel@xmailserver.org> * Davide Libenzi <davidel@xmailserver.org>
* *
......
...@@ -13,8 +13,8 @@ ...@@ -13,8 +13,8 @@
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software * License along with this library; if not, see
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * <http://www.gnu.org/licenses/>.
* *
* Davide Libenzi <davidel@xmailserver.org> * Davide Libenzi <davidel@xmailserver.org>
* *
......
...@@ -13,8 +13,8 @@ ...@@ -13,8 +13,8 @@
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software * License along with this library; if not, see
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * <http://www.gnu.org/licenses/>.
* *
* Davide Libenzi <davidel@xmailserver.org> * Davide Libenzi <davidel@xmailserver.org>
* *
...@@ -62,14 +62,14 @@ int xdl_emit_diffrec(char const *rec, long size, char const *pre, long psize, ...@@ -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) void *xdl_mmfile_first(mmfile_t *mmf, long *size)
{ {
*size = (long)mmf->size; *size = mmf->size;
return mmf->ptr; return mmf->ptr;
} }
long xdl_mmfile_size(mmfile_t *mmf) 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) ...@@ -154,6 +154,24 @@ int xdl_blankline(const char *line, long size, long flags)
return (i == size); 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 xdl_recmatch(const char *l1, long s1, const char *l2, long s2, long flags)
{ {
int i1, i2; int i1, i2;
...@@ -168,7 +186,8 @@ int xdl_recmatch(const char *l1, long s1, const char *l2, long s2, long flags) ...@@ -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 * -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 * Each flavor of ignoring needs different logic to skip whitespaces
* while we have both sides to compare. * 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) ...@@ -198,8 +217,18 @@ int xdl_recmatch(const char *l1, long s1, const char *l2, long s2, long flags)
return 0; return 0;
} }
} else if (flags & XDF_IGNORE_WHITESPACE_AT_EOL) { } else if (flags & XDF_IGNORE_WHITESPACE_AT_EOL) {
while (i1 < s1 && i2 < s2 && l1[i1++] == l2[i2++]) while (i1 < s1 && i2 < s2 && l1[i1] == l2[i2]) {
; /* keep going */ 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, ...@@ -226,9 +255,16 @@ static unsigned long xdl_hash_record_with_whitespace(char const **data,
char const *top, long flags) { char const *top, long flags) {
unsigned long ha = 5381; unsigned long ha = 5381;
char const *ptr = *data; char const *ptr = *data;
int cr_at_eol_only = (flags & XDF_WHITESPACE_FLAGS) == XDF_IGNORE_CR_AT_EOL;
for (; ptr < top && *ptr != '\n'; ptr++) { 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; const char *ptr2 = ptr;
int at_eol; int at_eol;
while (ptr + 1 < top && XDL_ISSPACE(ptr[1]) while (ptr + 1 < top && XDL_ISSPACE(ptr[1])
...@@ -260,7 +296,6 @@ static unsigned long xdl_hash_record_with_whitespace(char const **data, ...@@ -260,7 +296,6 @@ static unsigned long xdl_hash_record_with_whitespace(char const **data,
return ha; return ha;
} }
unsigned long xdl_hash_record(char const **data, char const *top, long flags) { unsigned long xdl_hash_record(char const **data, char const *top, long flags) {
unsigned long ha = 5381; unsigned long ha = 5381;
char const *ptr = *data; char const *ptr = *data;
...@@ -277,7 +312,6 @@ unsigned long xdl_hash_record(char const **data, char const *top, long flags) { ...@@ -277,7 +312,6 @@ unsigned long xdl_hash_record(char const **data, char const *top, long flags) {
return ha; return ha;
} }
unsigned int xdl_hashbits(unsigned int size) { unsigned int xdl_hashbits(unsigned int size) {
unsigned int val = 1, bits = 0; unsigned int val = 1, bits = 0;
...@@ -305,23 +339,9 @@ int xdl_num_out(char *out, long val) { ...@@ -305,23 +339,9 @@ int xdl_num_out(char *out, long val) {
*str++ = '0'; *str++ = '0';
*str = '\0'; *str = '\0';
return (int)(str - out); return 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;
} }
int xdl_emit_hunk_hdr(long s1, long c1, long s2, long c2, int xdl_emit_hunk_hdr(long s1, long c1, long s2, long c2,
const char *func, long funclen, xdemitcb_t *ecb) { const char *func, long funclen, xdemitcb_t *ecb) {
int nb = 0; int nb = 0;
...@@ -356,8 +376,8 @@ int xdl_emit_hunk_hdr(long s1, long c1, long s2, long c2, ...@@ -356,8 +376,8 @@ int xdl_emit_hunk_hdr(long s1, long c1, long s2, long c2,
nb += 3; nb += 3;
if (func && funclen) { if (func && funclen) {
buf[nb++] = ' '; buf[nb++] = ' ';
if (funclen > (long)sizeof(buf) - nb - 1) if (funclen > (long)(sizeof(buf) - nb - 1))
funclen = (long)sizeof(buf) - nb - 1; funclen = sizeof(buf) - nb - 1;
memcpy(buf + nb, func, funclen); memcpy(buf + nb, func, funclen);
nb += funclen; nb += funclen;
} }
......
...@@ -13,8 +13,8 @@ ...@@ -13,8 +13,8 @@
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software * License along with this library; if not, see
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * <http://www.gnu.org/licenses/>.
* *
* Davide Libenzi <davidel@xmailserver.org> * Davide Libenzi <davidel@xmailserver.org>
* *
...@@ -31,15 +31,12 @@ int xdl_emit_diffrec(char const *rec, long size, char const *pre, long psize, ...@@ -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); int xdl_cha_init(chastore_t *cha, long isize, long icount);
void xdl_cha_free(chastore_t *cha); void xdl_cha_free(chastore_t *cha);
void *xdl_cha_alloc(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); long xdl_guess_lines(mmfile_t *mf, long sample);
int xdl_blankline(const char *line, long size, long flags); 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); 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 long xdl_hash_record(char const **data, char const *top, long flags);
unsigned int xdl_hashbits(unsigned int size); unsigned int xdl_hashbits(unsigned int size);
int xdl_num_out(char *out, long val); 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, int xdl_emit_hunk_hdr(long s1, long c1, long s2, long c2,
const char *func, long funclen, xdemitcb_t *ecb); const char *func, long funclen, xdemitcb_t *ecb);
int xdl_fall_back_diff(xdfenv_t *diff_env, xpparam_t const *xpp, int xdl_fall_back_diff(xdfenv_t *diff_env, xpparam_t const *xpp,
......
...@@ -377,3 +377,51 @@ void test_merge_files__handles_binaries_when_favored(void) ...@@ -377,3 +377,51 @@ void test_merge_files__handles_binaries_when_favored(void)
git_merge_file_result_free(&result); 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);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment