Commit 7f52bc5a by Edward Thomson

xdiff: upgrade to git's included xdiff

Upgrade xdiff to git's most recent version, which includes changes to
CR/LF handling.  Now CR/LF included in the input files will be detected
and conflict markers will be emitted with CR/LF when appropriate.
parent 45f58409
......@@ -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; }
......
......@@ -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 {
......
......@@ -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"
......
......@@ -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>
*
......
......@@ -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;
}
}
}
......
......@@ -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>
*
......
......@@ -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
......
......@@ -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) */
......@@ -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>
*
......
......@@ -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);
......
/*
* 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 */
......
......@@ -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>
*
......
......@@ -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>
*
......
......@@ -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>
*
......
......@@ -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;
}
......
......@@ -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,
......
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