Commit 1458fb56 by Edward Thomson

xdiff: include new xdiff from git

Update to the xdiff used in git v2.35.0, with updates to our build
configuration to ignore the sort of warnings that we normally care
about (signed/unsigned mismatch, unused, etc.)

Any git-specific abstraction bits are now redefined for our use in
`git-xdiff.h`.  It is a (wildly optimistic) hope that we can use that
indirection layer to standardize on a shared xdiff implementation.
parent 12c2eef7
...@@ -206,7 +206,17 @@ endif() ...@@ -206,7 +206,17 @@ endif()
# errors for the xdiff sources until we've sorted them out # errors for the xdiff sources until we've sorted them out
if(MSVC) if(MSVC)
set_source_files_properties(xdiff/xdiffi.c PROPERTIES COMPILE_FLAGS -WX-) set_source_files_properties(xdiff/xdiffi.c PROPERTIES COMPILE_FLAGS -WX-)
set_source_files_properties(xdiff/xemit.c PROPERTIES COMPILE_FLAGS -WX-)
set_source_files_properties(xdiff/xhistogram.c PROPERTIES COMPILE_FLAGS -WX-)
set_source_files_properties(xdiff/xmerge.c PROPERTIES COMPILE_FLAGS -WX-)
set_source_files_properties(xdiff/xutils.c PROPERTIES COMPILE_FLAGS -WX-) set_source_files_properties(xdiff/xutils.c PROPERTIES COMPILE_FLAGS -WX-)
set_source_files_properties(xdiff/xpatience.c PROPERTIES COMPILE_FLAGS -WX-)
else()
set_source_files_properties(xdiff/xdiffi.c PROPERTIES COMPILE_FLAGS "-Wno-sign-compare -Wno-unused-parameter")
set_source_files_properties(xdiff/xemit.c PROPERTIES COMPILE_FLAGS "-Wno-sign-compare -Wno-unused-parameter")
set_source_files_properties(xdiff/xhistogram.c PROPERTIES COMPILE_FLAGS "-Wno-sign-compare")
set_source_files_properties(xdiff/xutils.c PROPERTIES COMPILE_FLAGS "-Wno-sign-compare")
set_source_files_properties(xdiff/xpatience.c PROPERTIES COMPILE_FLAGS "-Wno-sign-compare")
endif() endif()
# Determine architecture of the machine # Determine architecture of the machine
......
...@@ -393,7 +393,7 @@ static void fill_origin_blob(git_blame__origin *o, mmfile_t *file) ...@@ -393,7 +393,7 @@ static void fill_origin_blob(git_blame__origin *o, mmfile_t *file)
memset(file, 0, sizeof(*file)); memset(file, 0, sizeof(*file));
if (o->blob) { if (o->blob) {
file->ptr = (char*)git_blob_rawcontent(o->blob); file->ptr = (char*)git_blob_rawcontent(o->blob);
file->size = (size_t)git_blob_rawsize(o->blob); file->size = (long)git_blob_rawsize(o->blob);
} }
} }
......
...@@ -218,14 +218,9 @@ static int git_xdiff(git_patch_generated_output *output, git_patch_generated *pa ...@@ -218,14 +218,9 @@ static int git_xdiff(git_patch_generated_output *output, git_patch_generated *pa
* updates are needed to xo->params.flags * updates are needed to xo->params.flags
*/ */
git_patch_generated_old_data(&info.xd_old_data.ptr, &info.xd_old_data.size, patch); if (git_patch_generated_old_data(&info.xd_old_data.ptr, &info.xd_old_data.size, patch) < 0 ||
git_patch_generated_new_data(&info.xd_new_data.ptr, &info.xd_new_data.size, patch); git_patch_generated_new_data(&info.xd_new_data.ptr, &info.xd_new_data.size, patch) < 0)
if (info.xd_old_data.size > GIT_XDIFF_MAX_SIZE ||
info.xd_new_data.size > GIT_XDIFF_MAX_SIZE) {
git_error_set(GIT_ERROR_INVALID, "files too large for diff");
return -1; return -1;
}
xdl_diff(&info.xd_old_data, &info.xd_new_data, xdl_diff(&info.xd_old_data, &info.xd_new_data,
&xo->params, &xo->config, &xo->callback); &xo->params, &xo->config, &xo->callback);
...@@ -261,5 +256,5 @@ void git_xdiff_init(git_xdiff_output *xo, const git_diff_options *opts) ...@@ -261,5 +256,5 @@ void git_xdiff_init(git_xdiff_output *xo, const git_diff_options *opts)
if (flags & GIT_DIFF_IGNORE_BLANK_LINES) if (flags & GIT_DIFF_IGNORE_BLANK_LINES)
xo->params.flags |= XDF_IGNORE_BLANK_LINES; xo->params.flags |= XDF_IGNORE_BLANK_LINES;
xo->callback.outf = git_xdiff_cb; xo->callback.out_line = git_xdiff_cb;
} }
...@@ -86,22 +86,30 @@ static int merge_file__xdiff( ...@@ -86,22 +86,30 @@ static int merge_file__xdiff(
memset(&xmparam, 0x0, sizeof(xmparam_t)); memset(&xmparam, 0x0, sizeof(xmparam_t));
if (ours->size > LONG_MAX ||
theirs->size > LONG_MAX ||
(ancestor && ancestor->size > LONG_MAX)) {
git_error_set(GIT_ERROR_MERGE, "failed to merge files");
error = -1;
goto done;
}
if (ancestor) { if (ancestor) {
xmparam.ancestor = (options.ancestor_label) ? xmparam.ancestor = (options.ancestor_label) ?
options.ancestor_label : ancestor->path; options.ancestor_label : ancestor->path;
ancestor_mmfile.ptr = (char *)ancestor->ptr; ancestor_mmfile.ptr = (char *)ancestor->ptr;
ancestor_mmfile.size = ancestor->size; ancestor_mmfile.size = (long)ancestor->size;
} }
xmparam.file1 = (options.our_label) ? xmparam.file1 = (options.our_label) ?
options.our_label : ours->path; options.our_label : ours->path;
our_mmfile.ptr = (char *)ours->ptr; our_mmfile.ptr = (char *)ours->ptr;
our_mmfile.size = ours->size; our_mmfile.size = (long)ours->size;
xmparam.file2 = (options.their_label) ? xmparam.file2 = (options.their_label) ?
options.their_label : theirs->path; options.their_label : theirs->path;
their_mmfile.ptr = (char *)theirs->ptr; their_mmfile.ptr = (char *)theirs->ptr;
their_mmfile.size = theirs->size; their_mmfile.size = (long)theirs->size;
if (options.favor == GIT_MERGE_FILE_FAVOR_OURS) if (options.favor == GIT_MERGE_FILE_FAVOR_OURS)
xmparam.favor = XDL_MERGE_FAVOR_OURS; xmparam.favor = XDL_MERGE_FAVOR_OURS;
......
...@@ -750,18 +750,34 @@ git_diff_driver *git_patch_generated_driver(git_patch_generated *patch) ...@@ -750,18 +750,34 @@ git_diff_driver *git_patch_generated_driver(git_patch_generated *patch)
return patch->ofile.driver; return patch->ofile.driver;
} }
void git_patch_generated_old_data( int git_patch_generated_old_data(
char **ptr, size_t *len, git_patch_generated *patch) char **ptr, long *len, git_patch_generated *patch)
{ {
if (patch->ofile.map.len > LONG_MAX ||
patch->ofile.map.len > GIT_XDIFF_MAX_SIZE) {
git_error_set(GIT_ERROR_INVALID, "files too large for diff");
return -1;
}
*ptr = patch->ofile.map.data; *ptr = patch->ofile.map.data;
*len = patch->ofile.map.len; *len = (long)patch->ofile.map.len;
return 0;
} }
void git_patch_generated_new_data( int git_patch_generated_new_data(
char **ptr, size_t *len, git_patch_generated *patch) char **ptr, long *len, git_patch_generated *patch)
{ {
if (patch->ofile.map.len > LONG_MAX ||
patch->ofile.map.len > GIT_XDIFF_MAX_SIZE) {
git_error_set(GIT_ERROR_INVALID, "files too large for diff");
return -1;
}
*ptr = patch->nfile.map.data; *ptr = patch->nfile.map.data;
*len = patch->nfile.map.len; *len = (long)patch->nfile.map.len;
return 0;
} }
static int patch_generated_file_cb( static int patch_generated_file_cb(
......
...@@ -39,10 +39,10 @@ typedef struct git_patch_generated git_patch_generated; ...@@ -39,10 +39,10 @@ typedef struct git_patch_generated git_patch_generated;
extern git_diff_driver *git_patch_generated_driver(git_patch_generated *); extern git_diff_driver *git_patch_generated_driver(git_patch_generated *);
extern void git_patch_generated_old_data( extern int git_patch_generated_old_data(
char **, size_t *, git_patch_generated *); char **, long *, git_patch_generated *);
extern void git_patch_generated_new_data( extern int git_patch_generated_new_data(
char **, size_t *, git_patch_generated *); char **, long *, git_patch_generated *);
extern int git_patch_generated_from_diff( extern int git_patch_generated_from_diff(
git_patch **, git_diff *, size_t); git_patch **, git_diff *, size_t);
......
/*
* Copyright (C) the libgit2 contributors. All rights reserved.
*
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
/*
* This file provides the necessary indirection between xdiff and
* libgit2. libgit2-specific functionality should live here, so
* that git and libgit2 can share a common xdiff implementation.
*/
#ifndef INCLUDE_git_xdiff_h__
#define INCLUDE_git_xdiff_h__
#include "regexp.h"
#define xdl_malloc(x) git__malloc(x)
#define xdl_free(ptr) git__free(ptr)
#define xdl_realloc(ptr, x) git__realloc(ptr, x)
#define XDL_BUG(msg) GIT_ASSERT(msg)
#define xdl_regex_t git_regexp
#define xdl_regmatch_t git_regmatch
GIT_INLINE(int) xdl_regexec_buf(
const xdl_regex_t *preg, const char *buf, size_t size,
size_t nmatch, xdl_regmatch_t pmatch[], int eflags)
{
GIT_UNUSED(preg);
GIT_UNUSED(buf);
GIT_UNUSED(size);
GIT_UNUSED(nmatch);
GIT_UNUSED(pmatch);
GIT_UNUSED(eflags);
GIT_ASSERT("not implemented");
return -1;
}
#endif
...@@ -23,6 +23,8 @@ ...@@ -23,6 +23,8 @@
#if !defined(XDIFF_H) #if !defined(XDIFF_H)
#define XDIFF_H #define XDIFF_H
#include "git-xdiff.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* #ifdef __cplusplus */ #endif /* #ifdef __cplusplus */
...@@ -50,16 +52,9 @@ extern "C" { ...@@ -50,16 +52,9 @@ extern "C" {
/* xdemitconf_t.flags */ /* xdemitconf_t.flags */
#define XDL_EMIT_FUNCNAMES (1 << 0) #define XDL_EMIT_FUNCNAMES (1 << 0)
#define XDL_EMIT_NO_HUNK_HDR (1 << 1)
#define XDL_EMIT_FUNCCONTEXT (1 << 2) #define XDL_EMIT_FUNCCONTEXT (1 << 2)
#define XDL_MMB_READONLY (1 << 0)
#define XDL_MMF_ATOMIC (1 << 0)
#define XDL_BDOP_INS 1
#define XDL_BDOP_CPY 2
#define XDL_BDOP_INSB 3
/* merge simplification levels */ /* merge simplification levels */
#define XDL_MERGE_MINIMAL 0 #define XDL_MERGE_MINIMAL 0
#define XDL_MERGE_EAGER 1 #define XDL_MERGE_EAGER 1
...@@ -73,20 +68,25 @@ extern "C" { ...@@ -73,20 +68,25 @@ extern "C" {
/* merge output styles */ /* merge output styles */
#define XDL_MERGE_DIFF3 1 #define XDL_MERGE_DIFF3 1
#define XDL_MERGE_ZEALOUS_DIFF3 2
typedef struct s_mmfile { typedef struct s_mmfile {
char *ptr; char *ptr;
size_t size; long size;
} mmfile_t; } mmfile_t;
typedef struct s_mmbuffer { typedef struct s_mmbuffer {
char *ptr; char *ptr;
size_t size; long size;
} mmbuffer_t; } mmbuffer_t;
typedef struct s_xpparam { typedef struct s_xpparam {
unsigned long flags; unsigned long flags;
/* -I<regex> */
xdl_regex_t **ignore_regex;
size_t ignore_regex_nr;
/* See Documentation/diff-options.txt. */ /* See Documentation/diff-options.txt. */
char **anchors; char **anchors;
size_t anchors_nr; size_t anchors_nr;
...@@ -94,7 +94,11 @@ typedef struct s_xpparam { ...@@ -94,7 +94,11 @@ typedef struct s_xpparam {
typedef struct s_xdemitcb { typedef struct s_xdemitcb {
void *priv; void *priv;
int (*outf)(void *, mmbuffer_t *, int); int (*out_hunk)(void *,
long old_begin, long old_nr,
long new_begin, long new_nr,
const char *func, long funclen);
int (*out_line)(void *, mmbuffer_t *, int);
} xdemitcb_t; } xdemitcb_t;
typedef long (*find_func_t)(const char *line, long line_len, char *buffer, long buffer_size, void *priv); typedef long (*find_func_t)(const char *line, long line_len, char *buffer, long buffer_size, void *priv);
...@@ -117,10 +121,6 @@ typedef struct s_bdiffparam { ...@@ -117,10 +121,6 @@ typedef struct s_bdiffparam {
} bdiffparam_t; } bdiffparam_t;
#define xdl_malloc(x) git__malloc(x)
#define xdl_free(ptr) git__free(ptr)
#define xdl_realloc(ptr,x) git__realloc(ptr,x)
void *xdl_mmfile_first(mmfile_t *mmf, long *size); void *xdl_mmfile_first(mmfile_t *mmf, long *size);
long xdl_mmfile_size(mmfile_t *mmf); long xdl_mmfile_size(mmfile_t *mmf);
......
...@@ -21,8 +21,6 @@ ...@@ -21,8 +21,6 @@
*/ */
#include "xinclude.h" #include "xinclude.h"
#include "integer.h"
#define XDL_MAX_COST_MIN 256 #define XDL_MAX_COST_MIN 256
#define XDL_HEUR_MIN_COST 256 #define XDL_HEUR_MIN_COST 256
...@@ -30,41 +28,19 @@ ...@@ -30,41 +28,19 @@
#define XDL_SNAKE_CNT 20 #define XDL_SNAKE_CNT 20
#define XDL_K_HEUR 4 #define XDL_K_HEUR 4
/** Declare a function as always inlined. */
#if defined(_MSC_VER)
# define XDL_INLINE(type) static __inline type
#elif defined(__GNUC__)
# define XDL_INLINE(type) static __inline__ type
#else
# define XDL_INLINE(type) static type
#endif
typedef struct s_xdpsplit { typedef struct s_xdpsplit {
long i1, i2; long i1, i2;
int min_lo, min_hi; int min_lo, min_hi;
} xdpsplit_t; } xdpsplit_t;
static long xdl_split(unsigned long const *ha1, long off1, long lim1,
unsigned long const *ha2, long off2, long lim2,
long *kvdf, long *kvdb, int need_min, xdpsplit_t *spl,
xdalgoenv_t *xenv);
static xdchange_t *xdl_add_change(xdchange_t *xscr, long i1, long i2, long chg1, long chg2);
/* /*
* See "An O(ND) Difference Algorithm and its Variations", by Eugene Myers. * See "An O(ND) Difference Algorithm and its Variations", by Eugene Myers.
* Basically considers a "box" (off1, off2, lim1, lim2) and scan from both * Basically considers a "box" (off1, off2, lim1, lim2) and scan from both
* the forward diagonal starting from (off1, off2) and the backward diagonal * the forward diagonal starting from (off1, off2) and the backward diagonal
* starting from (lim1, lim2). If the K values on the same diagonal crosses * starting from (lim1, lim2). If the K values on the same diagonal crosses
* returns the furthest point of reach. We might end up having to expensive * returns the furthest point of reach. We might encounter expensive edge cases
* cases using this algorithm is full, so a little bit of heuristic is needed * using this algorithm, so a little bit of heuristic is needed to cut the
* to cut the search and to return a suboptimal point. * search and to return a suboptimal point.
*/ */
static long xdl_split(unsigned long const *ha1, long off1, long lim1, static long xdl_split(unsigned long const *ha1, long off1, long lim1,
unsigned long const *ha2, long off2, long lim2, unsigned long const *ha2, long off2, long lim2,
...@@ -87,11 +63,13 @@ static long xdl_split(unsigned long const *ha1, long off1, long lim1, ...@@ -87,11 +63,13 @@ static long xdl_split(unsigned long const *ha1, long off1, long lim1,
int got_snake = 0; int got_snake = 0;
/* /*
* We need to extent the diagonal "domain" by one. If the next * We need to extend the diagonal "domain" by one. If the next
* values exits the box boundaries we need to change it in the * values exits the box boundaries we need to change it in the
* opposite direction because (max - min) must be a power of two. * opposite direction because (max - min) must be a power of
* two.
*
* Also we initialize the external K value to -1 so that we can * Also we initialize the external K value to -1 so that we can
* avoid extra conditions check inside the core loop. * avoid extra conditions in the check inside the core loop.
*/ */
if (fmin > dmin) if (fmin > dmin)
kvdf[--fmin - 1] = -1; kvdf[--fmin - 1] = -1;
...@@ -122,11 +100,13 @@ static long xdl_split(unsigned long const *ha1, long off1, long lim1, ...@@ -122,11 +100,13 @@ static long xdl_split(unsigned long const *ha1, long off1, long lim1,
} }
/* /*
* We need to extent the diagonal "domain" by one. If the next * We need to extend the diagonal "domain" by one. If the next
* values exits the box boundaries we need to change it in the * values exits the box boundaries we need to change it in the
* opposite direction because (max - min) must be a power of two. * opposite direction because (max - min) must be a power of
* two.
*
* Also we initialize the external K value to -1 so that we can * Also we initialize the external K value to -1 so that we can
* avoid extra conditions check inside the core loop. * avoid extra conditions in the check inside the core loop.
*/ */
if (bmin > dmin) if (bmin > dmin)
kvdb[--bmin - 1] = XDL_LINE_MAX; kvdb[--bmin - 1] = XDL_LINE_MAX;
...@@ -162,7 +142,7 @@ static long xdl_split(unsigned long const *ha1, long off1, long lim1, ...@@ -162,7 +142,7 @@ static long xdl_split(unsigned long const *ha1, long off1, long lim1,
/* /*
* If the edit cost is above the heuristic trigger and if * If the edit cost is above the heuristic trigger and if
* we got a good snake, we sample current diagonals to see * we got a good snake, we sample current diagonals to see
* if some of the, have reached an "interesting" path. Our * if some of them have reached an "interesting" path. Our
* measure is a function of the distance from the diagonal * measure is a function of the distance from the diagonal
* corner (i1 + i2) penalized with the distance from the * corner (i1 + i2) penalized with the distance from the
* mid diagonal itself. If this value is above the current * mid diagonal itself. If this value is above the current
...@@ -220,8 +200,9 @@ static long xdl_split(unsigned long const *ha1, long off1, long lim1, ...@@ -220,8 +200,9 @@ static long xdl_split(unsigned long const *ha1, long off1, long lim1,
} }
/* /*
* Enough is enough. We spent too much time here and now we collect * Enough is enough. We spent too much time here and now we
* the furthest reaching path using the (i1 + i2) measure. * collect the furthest reaching path using the (i1 + i2)
* measure.
*/ */
if (ec >= xenv->mxcost) { if (ec >= xenv->mxcost) {
long fbest, fbest1, bbest, bbest1; long fbest, fbest1, bbest, bbest1;
...@@ -268,9 +249,9 @@ static long xdl_split(unsigned long const *ha1, long off1, long lim1, ...@@ -268,9 +249,9 @@ static long xdl_split(unsigned long const *ha1, long off1, long lim1,
/* /*
* Rule: "Divide et Impera". Recursively split the box in sub-boxes by calling * Rule: "Divide et Impera" (divide & conquer). Recursively split the box in
* the box splitting function. Note that the real job (marking changed lines) * sub-boxes by calling the box splitting function. Note that the real job
* is done in the two boundary reaching checks. * (marking changed lines) is done in the two boundary reaching checks.
*/ */
int xdl_recs_cmp(diffdata_t *dd1, long off1, long lim1, int xdl_recs_cmp(diffdata_t *dd1, long off1, long lim1,
diffdata_t *dd2, long off2, long lim2, diffdata_t *dd2, long off2, long lim2,
...@@ -330,7 +311,7 @@ int xdl_recs_cmp(diffdata_t *dd1, long off1, long lim1, ...@@ -330,7 +311,7 @@ int xdl_recs_cmp(diffdata_t *dd1, long off1, long lim1,
int xdl_do_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, int xdl_do_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
xdfenv_t *xe) { xdfenv_t *xe) {
size_t ndiags, allocsize; long ndiags;
long *kvd, *kvdf, *kvdb; long *kvd, *kvdf, *kvdb;
xdalgoenv_t xenv; xdalgoenv_t xenv;
diffdata_t dd1, dd2; diffdata_t dd1, dd2;
...@@ -347,15 +328,14 @@ int xdl_do_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, ...@@ -347,15 +328,14 @@ int xdl_do_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
} }
/* /*
* Allocate and setup K vectors to be used by the differential algorithm. * Allocate and setup K vectors to be used by the differential
* algorithm.
*
* One is to store the forward path and one to store the backward path. * One is to store the forward path and one to store the backward path.
*/ */
GIT_ERROR_CHECK_ALLOC_ADD3(&ndiags, xe->xdf1.nreff, xe->xdf2.nreff, 3); ndiags = xe->xdf1.nreff + xe->xdf2.nreff + 3;
GIT_ERROR_CHECK_ALLOC_MULTIPLY(&allocsize, ndiags, 2); if (!(kvd = (long *) xdl_malloc((2 * ndiags + 2) * sizeof(long)))) {
GIT_ERROR_CHECK_ALLOC_ADD(&allocsize, allocsize, 2);
GIT_ERROR_CHECK_ALLOC_MULTIPLY(&allocsize, allocsize, sizeof(long));
if (!(kvd = (long *) xdl_malloc(allocsize))) {
xdl_free_env(xe); xdl_free_env(xe);
return -1; return -1;
} }
...@@ -410,19 +390,16 @@ static xdchange_t *xdl_add_change(xdchange_t *xscr, long i1, long i2, long chg1, ...@@ -410,19 +390,16 @@ static xdchange_t *xdl_add_change(xdchange_t *xscr, long i1, long i2, long chg1,
} }
static int recs_match(xrecord_t *rec1, xrecord_t *rec2, long flags) static int recs_match(xrecord_t *rec1, xrecord_t *rec2)
{ {
return (rec1->ha == rec2->ha && return (rec1->ha == rec2->ha);
xdl_recmatch(rec1->ptr, rec1->size,
rec2->ptr, rec2->size,
flags));
} }
/* /*
* If a line is indented more than this, get_indent() just returns this value. * If a line is indented more than this, get_indent() just returns this value.
* This avoids having to do absurd amounts of work for data that are not * This avoids having to do absurd amounts of work for data that are not
* human-readable text, and also ensures that the output of get_indent fits within * human-readable text, and also ensures that the output of get_indent fits
* an int. * within an int.
*/ */
#define MAX_INDENT 200 #define MAX_INDENT 200
...@@ -456,9 +433,9 @@ static int get_indent(xrecord_t *rec) ...@@ -456,9 +433,9 @@ static int get_indent(xrecord_t *rec)
} }
/* /*
* If more than this number of consecutive blank rows are found, just return this * If more than this number of consecutive blank rows are found, just return
* value. This avoids requiring O(N^2) work for pathological cases, and also * this value. This avoids requiring O(N^2) work for pathological cases, and
* ensures that the output of score_split fits in an int. * also ensures that the output of score_split fits in an int.
*/ */
#define MAX_BLANKS 20 #define MAX_BLANKS 20
...@@ -470,8 +447,8 @@ struct split_measurement { ...@@ -470,8 +447,8 @@ struct split_measurement {
int end_of_file; int end_of_file;
/* /*
* How much is the line immediately following the split indented (or -1 if * How much is the line immediately following the split indented (or -1
* the line is blank): * if the line is blank):
*/ */
int indent; int indent;
...@@ -481,8 +458,8 @@ struct split_measurement { ...@@ -481,8 +458,8 @@ struct split_measurement {
int pre_blank; int pre_blank;
/* /*
* How much is the nearest non-blank line above the split indented (or -1 * How much is the nearest non-blank line above the split indented (or
* if there is no such line)? * -1 if there is no such line)?
*/ */
int pre_indent; int pre_indent;
...@@ -602,14 +579,19 @@ static void measure_split(const xdfile_t *xdf, long split, ...@@ -602,14 +579,19 @@ static void measure_split(const xdfile_t *xdf, long split,
#define INDENT_WEIGHT 60 #define INDENT_WEIGHT 60
/* /*
* How far do we slide a hunk at most?
*/
#define INDENT_HEURISTIC_MAX_SLIDING 100
/*
* Compute a badness score for the hypothetical split whose measurements are * Compute a badness score for the hypothetical split whose measurements are
* stored in m. The weight factors were determined empirically using the tools and * stored in m. The weight factors were determined empirically using the tools
* corpus described in * and corpus described in
* *
* https://github.com/mhagger/diff-slider-tools * https://github.com/mhagger/diff-slider-tools
* *
* Also see that project if you want to improve the weights based on, for example, * Also see that project if you want to improve the weights based on, for
* a larger or more diverse corpus. * example, a larger or more diverse corpus.
*/ */
static void score_add_split(const struct split_measurement *m, struct split_score *s) static void score_add_split(const struct split_measurement *m, struct split_score *s)
{ {
...@@ -741,7 +723,7 @@ static void group_init(xdfile_t *xdf, struct xdlgroup *g) ...@@ -741,7 +723,7 @@ static void group_init(xdfile_t *xdf, struct xdlgroup *g)
* Move g to describe the next (possibly empty) group in xdf and return 0. If g * Move g to describe the next (possibly empty) group in xdf and return 0. If g
* is already at the end of the file, do nothing and return -1. * is already at the end of the file, do nothing and return -1.
*/ */
XDL_INLINE(int) group_next(xdfile_t *xdf, struct xdlgroup *g) static inline int group_next(xdfile_t *xdf, struct xdlgroup *g)
{ {
if (g->end == xdf->nrec) if (g->end == xdf->nrec)
return -1; return -1;
...@@ -757,7 +739,7 @@ XDL_INLINE(int) group_next(xdfile_t *xdf, struct xdlgroup *g) ...@@ -757,7 +739,7 @@ XDL_INLINE(int) group_next(xdfile_t *xdf, struct xdlgroup *g)
* Move g to describe the previous (possibly empty) group in xdf and return 0. * Move g to describe the previous (possibly empty) group in xdf and return 0.
* If g is already at the beginning of the file, do nothing and return -1. * If g is already at the beginning of the file, do nothing and return -1.
*/ */
XDL_INLINE(int) group_previous(xdfile_t *xdf, struct xdlgroup *g) static inline int group_previous(xdfile_t *xdf, struct xdlgroup *g)
{ {
if (g->start == 0) if (g->start == 0)
return -1; return -1;
...@@ -774,10 +756,10 @@ XDL_INLINE(int) group_previous(xdfile_t *xdf, struct xdlgroup *g) ...@@ -774,10 +756,10 @@ XDL_INLINE(int) group_previous(xdfile_t *xdf, struct xdlgroup *g)
* following group, expand this group to include it. Return 0 on success or -1 * following group, expand this group to include it. Return 0 on success or -1
* if g cannot be slid down. * if g cannot be slid down.
*/ */
static int group_slide_down(xdfile_t *xdf, struct xdlgroup *g, long flags) static int group_slide_down(xdfile_t *xdf, struct xdlgroup *g)
{ {
if (g->end < xdf->nrec && if (g->end < xdf->nrec &&
recs_match(xdf->recs[g->start], xdf->recs[g->end], flags)) { recs_match(xdf->recs[g->start], xdf->recs[g->end])) {
xdf->rchg[g->start++] = 0; xdf->rchg[g->start++] = 0;
xdf->rchg[g->end++] = 1; xdf->rchg[g->end++] = 1;
...@@ -795,10 +777,10 @@ static int group_slide_down(xdfile_t *xdf, struct xdlgroup *g, long flags) ...@@ -795,10 +777,10 @@ static int group_slide_down(xdfile_t *xdf, struct xdlgroup *g, long flags)
* into a previous group, expand this group to include it. Return 0 on success * into a previous group, expand this group to include it. Return 0 on success
* or -1 if g cannot be slid up. * or -1 if g cannot be slid up.
*/ */
static int group_slide_up(xdfile_t *xdf, struct xdlgroup *g, long flags) static int group_slide_up(xdfile_t *xdf, struct xdlgroup *g)
{ {
if (g->start > 0 && if (g->start > 0 &&
recs_match(xdf->recs[g->start - 1], xdf->recs[g->end - 1], flags)) { recs_match(xdf->recs[g->start - 1], xdf->recs[g->end - 1])) {
xdf->rchg[--g->start] = 1; xdf->rchg[--g->start] = 1;
xdf->rchg[--g->end] = 0; xdf->rchg[--g->end] = 0;
...@@ -811,12 +793,6 @@ static int group_slide_up(xdfile_t *xdf, struct xdlgroup *g, long flags) ...@@ -811,12 +793,6 @@ static int group_slide_up(xdfile_t *xdf, struct xdlgroup *g, long flags)
} }
} }
static void xdl_bug(const char *msg)
{
fprintf(stderr, "BUG: %s\n", msg);
exit(1);
}
/* /*
* Move back and forward change groups for a consistent and pretty diff output. * Move back and forward change groups for a consistent and pretty diff output.
* This also helps in finding joinable change groups and reducing the diff * This also helps in finding joinable change groups and reducing the diff
...@@ -831,13 +807,16 @@ int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) { ...@@ -831,13 +807,16 @@ int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) {
group_init(xdfo, &go); group_init(xdfo, &go);
while (1) { while (1) {
/* If the group is empty in the to-be-compacted file, skip it: */ /*
* If the group is empty in the to-be-compacted file, skip it:
*/
if (g.end == g.start) if (g.end == g.start)
goto next; goto next;
/* /*
* Now shift the change up and then down as far as possible in * Now shift the change up and then down as far as possible in
* each direction. If it bumps into any other changes, merge them. * each direction. If it bumps into any other changes, merge
* them.
*/ */
do { do {
groupsize = g.end - g.start; groupsize = g.end - g.start;
...@@ -851,9 +830,9 @@ int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) { ...@@ -851,9 +830,9 @@ int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) {
end_matching_other = -1; end_matching_other = -1;
/* Shift the group backward as much as possible: */ /* Shift the group backward as much as possible: */
while (!group_slide_up(xdf, &g, flags)) while (!group_slide_up(xdf, &g))
if (group_previous(xdfo, &go)) if (group_previous(xdfo, &go))
xdl_bug("group sync broken sliding up"); XDL_BUG("group sync broken sliding up");
/* /*
* This is this highest that this group can be shifted. * This is this highest that this group can be shifted.
...@@ -866,10 +845,10 @@ int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) { ...@@ -866,10 +845,10 @@ int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) {
/* Now shift the group forward as far as possible: */ /* Now shift the group forward as far as possible: */
while (1) { while (1) {
if (group_slide_down(xdf, &g, flags)) if (group_slide_down(xdf, &g))
break; break;
if (group_next(xdfo, &go)) if (group_next(xdfo, &go))
xdl_bug("group sync broken sliding down"); XDL_BUG("group sync broken sliding down");
if (go.end > go.start) if (go.end > go.start)
end_matching_other = g.end; end_matching_other = g.end;
...@@ -880,40 +859,46 @@ int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) { ...@@ -880,40 +859,46 @@ int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) {
* If the group can be shifted, then we can possibly use this * If the group can be shifted, then we can possibly use this
* freedom to produce a more intuitive diff. * freedom to produce a more intuitive diff.
* *
* The group is currently shifted as far down as possible, so the * The group is currently shifted as far down as possible, so
* heuristics below only have to handle upwards shifts. * the heuristics below only have to handle upwards shifts.
*/ */
if (g.end == earliest_end) { if (g.end == earliest_end) {
/* no shifting was possible */ /* no shifting was possible */
} else if (end_matching_other != -1) { } else if (end_matching_other != -1) {
/* /*
* Move the possibly merged group of changes back to line * Move the possibly merged group of changes back to
* up with the last group of changes from the other file * line up with the last group of changes from the
* that it can align with. * other file that it can align with.
*/ */
while (go.end == go.start) { while (go.end == go.start) {
if (group_slide_up(xdf, &g, flags)) if (group_slide_up(xdf, &g))
xdl_bug("match disappeared"); XDL_BUG("match disappeared");
if (group_previous(xdfo, &go)) if (group_previous(xdfo, &go))
xdl_bug("group sync broken sliding to match"); XDL_BUG("group sync broken sliding to match");
} }
} else if (flags & XDF_INDENT_HEURISTIC) { } else if (flags & XDF_INDENT_HEURISTIC) {
/* /*
* Indent heuristic: a group of pure add/delete lines * Indent heuristic: a group of pure add/delete lines
* implies two splits, one between the end of the "before" * implies two splits, one between the end of the
* context and the start of the group, and another between * "before" context and the start of the group, and
* the end of the group and the beginning of the "after" * another between the end of the group and the
* context. Some splits are aesthetically better and some * beginning of the "after" context. Some splits are
* are worse. We compute a badness "score" for each split, * aesthetically better and some are worse. We compute
* and add the scores for the two splits to define a * a badness "score" for each split, and add the scores
* "score" for each position that the group can be shifted * for the two splits to define a "score" for each
* to. Then we pick the shift with the lowest score. * position that the group can be shifted to. Then we
* pick the shift with the lowest score.
*/ */
long shift, best_shift = -1; long shift, best_shift = -1;
struct split_score best_score; struct split_score best_score;
for (shift = earliest_end; shift <= g.end; shift++) { shift = earliest_end;
if (g.end - groupsize - 1 > shift)
shift = g.end - groupsize - 1;
if (g.end - INDENT_HEURISTIC_MAX_SLIDING > shift)
shift = g.end - INDENT_HEURISTIC_MAX_SLIDING;
for (; shift <= g.end; shift++) {
struct split_measurement m; struct split_measurement m;
struct split_score score = {0, 0}; struct split_score score = {0, 0};
...@@ -930,10 +915,10 @@ int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) { ...@@ -930,10 +915,10 @@ int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) {
} }
while (g.end > best_shift) { while (g.end > best_shift) {
if (group_slide_up(xdf, &g, flags)) if (group_slide_up(xdf, &g))
xdl_bug("best shift unreached"); XDL_BUG("best shift unreached");
if (group_previous(xdfo, &go)) if (group_previous(xdfo, &go))
xdl_bug("group sync broken sliding to blank line"); XDL_BUG("group sync broken sliding to blank line");
} }
} }
...@@ -942,11 +927,11 @@ int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) { ...@@ -942,11 +927,11 @@ int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) {
if (group_next(xdf, &g)) if (group_next(xdf, &g))
break; break;
if (group_next(xdfo, &go)) if (group_next(xdfo, &go))
xdl_bug("group sync broken moving to next group"); XDL_BUG("group sync broken moving to next group");
} }
if (!group_next(xdfo, &go)) if (!group_next(xdfo, &go))
xdl_bug("group sync broken at end of file"); XDL_BUG("group sync broken at end of file");
return 0; return 0;
} }
...@@ -992,8 +977,6 @@ static int xdl_call_hunk_func(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, ...@@ -992,8 +977,6 @@ static int xdl_call_hunk_func(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
{ {
xdchange_t *xch, *xche; xdchange_t *xch, *xche;
(void)xe;
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)
...@@ -1006,7 +989,7 @@ static int xdl_call_hunk_func(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, ...@@ -1006,7 +989,7 @@ static int xdl_call_hunk_func(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
return 0; return 0;
} }
static void xdl_mark_ignorable(xdchange_t *xscr, xdfenv_t *xe, long flags) static void xdl_mark_ignorable_lines(xdchange_t *xscr, xdfenv_t *xe, long flags)
{ {
xdchange_t *xch; xdchange_t *xch;
...@@ -1027,6 +1010,46 @@ static void xdl_mark_ignorable(xdchange_t *xscr, xdfenv_t *xe, long flags) ...@@ -1027,6 +1010,46 @@ static void xdl_mark_ignorable(xdchange_t *xscr, xdfenv_t *xe, long flags)
} }
} }
static int record_matches_regex(xrecord_t *rec, xpparam_t const *xpp) {
xdl_regmatch_t regmatch;
int i;
for (i = 0; i < xpp->ignore_regex_nr; i++)
if (!xdl_regexec_buf(xpp->ignore_regex[i], rec->ptr, rec->size, 1,
&regmatch, 0))
return 1;
return 0;
}
static void xdl_mark_ignorable_regex(xdchange_t *xscr, const xdfenv_t *xe,
xpparam_t const *xpp)
{
xdchange_t *xch;
for (xch = xscr; xch; xch = xch->next) {
xrecord_t **rec;
int ignore = 1;
long i;
/*
* Do not override --ignore-blank-lines.
*/
if (xch->ignore)
continue;
rec = &xe->xdf1.recs[xch->i1];
for (i = 0; i < xch->chg1 && ignore; i++)
ignore = record_matches_regex(rec[i], xpp);
rec = &xe->xdf2.recs[xch->i2];
for (i = 0; i < xch->chg2 && ignore; i++)
ignore = record_matches_regex(rec[i], xpp);
xch->ignore = ignore;
}
}
int xdl_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, int xdl_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
xdemitconf_t const *xecfg, xdemitcb_t *ecb) { xdemitconf_t const *xecfg, xdemitcb_t *ecb) {
xdchange_t *xscr; xdchange_t *xscr;
...@@ -1046,7 +1069,10 @@ int xdl_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, ...@@ -1046,7 +1069,10 @@ int xdl_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
} }
if (xscr) { if (xscr) {
if (xpp->flags & XDF_IGNORE_BLANK_LINES) if (xpp->flags & XDF_IGNORE_BLANK_LINES)
xdl_mark_ignorable(xscr, &xe, xpp->flags); xdl_mark_ignorable_lines(xscr, &xe, xpp->flags);
if (xpp->ignore_regex)
xdl_mark_ignorable_regex(xscr, &xe, xpp);
if (ef(&xe, xscr, ecb, xecfg) < 0) { if (ef(&xe, xscr, ecb, xecfg) < 0) {
......
...@@ -31,7 +31,7 @@ static long xdl_get_rec(xdfile_t *xdf, long ri, char const **rec) { ...@@ -31,7 +31,7 @@ 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 int xdl_emit_record(xdfile_t *xdf, long ri, char const *pre, xdemitcb_t *ecb) {
long size, psize = (long)strlen(pre); long size, psize = strlen(pre);
char const *rec; char const *rec;
size = xdl_get_rec(xdf, ri, &rec); size = xdl_get_rec(xdf, ri, &rec);
...@@ -81,7 +81,7 @@ xdchange_t *xdl_get_hunk(xdchange_t **xscr, xdemitconf_t const *xecfg) ...@@ -81,7 +81,7 @@ xdchange_t *xdl_get_hunk(xdchange_t **xscr, xdemitconf_t const *xecfg)
} else if (distance < max_ignorable && xch->ignore) { } else if (distance < max_ignorable && xch->ignore) {
ignored += xch->chg2; ignored += xch->chg2;
} else if (lxch != xchp && } else if (lxch != xchp &&
xch->i1 + ignored - (lxch->i1 + lxch->chg1) > (unsigned long)max_common) { xch->i1 + ignored - (lxch->i1 + lxch->chg1) > max_common) {
break; break;
} else if (!xch->ignore) { } else if (!xch->ignore) {
lxch = xch; lxch = xch;
...@@ -97,8 +97,6 @@ xdchange_t *xdl_get_hunk(xdchange_t **xscr, xdemitconf_t const *xecfg) ...@@ -97,8 +97,6 @@ xdchange_t *xdl_get_hunk(xdchange_t **xscr, xdemitconf_t const *xecfg)
static long def_ff(const char *rec, long len, char *buf, long sz, void *priv) static long def_ff(const char *rec, long len, char *buf, long sz, void *priv)
{ {
(void)priv;
if (len > 0 && if (len > 0 &&
(isalpha((unsigned char)*rec) || /* identifier? */ (isalpha((unsigned char)*rec) || /* identifier? */
*rec == '_' || /* also identifier? */ *rec == '_' || /* also identifier? */
...@@ -174,10 +172,12 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, ...@@ -174,10 +172,12 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
struct func_line func_line = { 0 }; struct func_line func_line = { 0 };
for (xch = xscr; xch; xch = xche->next) { for (xch = xscr; xch; xch = xche->next) {
xdchange_t *xchp = xch;
xche = xdl_get_hunk(&xch, xecfg); xche = xdl_get_hunk(&xch, xecfg);
if (!xch) if (!xch)
break; break;
pre_context_calculation:
s1 = XDL_MAX(xch->i1 - xecfg->ctxlen, 0); s1 = XDL_MAX(xch->i1 - xecfg->ctxlen, 0);
s2 = XDL_MAX(xch->i2 - xecfg->ctxlen, 0); s2 = XDL_MAX(xch->i2 - xecfg->ctxlen, 0);
...@@ -212,8 +212,23 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, ...@@ -212,8 +212,23 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
if (fs1 < 0) if (fs1 < 0)
fs1 = 0; fs1 = 0;
if (fs1 < s1) { if (fs1 < s1) {
s2 -= s1 - fs1; s2 = XDL_MAX(s2 - (s1 - fs1), 0);
s1 = fs1; s1 = fs1;
/*
* Did we extend context upwards into an
* ignored change?
*/
while (xchp != xch &&
xchp->i1 + xchp->chg1 <= s1 &&
xchp->i2 + xchp->chg2 <= s2)
xchp = xchp->next;
/* If so, show it after all. */
if (xchp != xch) {
xch = xchp;
goto pre_context_calculation;
}
} }
} }
...@@ -234,7 +249,7 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, ...@@ -234,7 +249,7 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
if (fe1 < 0) if (fe1 < 0)
fe1 = xe->xdf1.nrec; fe1 = xe->xdf1.nrec;
if (fe1 > e1) { if (fe1 > e1) {
e2 += fe1 - e1; e2 = XDL_MIN(e2 + (fe1 - e1), xe->xdf2.nrec);
e1 = fe1; e1 = fe1;
} }
...@@ -263,7 +278,8 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, ...@@ -263,7 +278,8 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
s1 - 1, funclineprev); s1 - 1, funclineprev);
funclineprev = s1 - 1; funclineprev = s1 - 1;
} }
if (xdl_emit_hunk_hdr(s1 + 1, e1 - s1, s2 + 1, e2 - s2, if (!(xecfg->flags & XDL_EMIT_NO_HUNK_HDR) &&
xdl_emit_hunk_hdr(s1 + 1, e1 - s1, s2 + 1, e2 - s2,
func_line.buf, func_line.len, ecb) < 0) func_line.buf, func_line.len, ecb) < 0)
return -1; return -1;
......
...@@ -42,8 +42,6 @@ ...@@ -42,8 +42,6 @@
*/ */
#include "xinclude.h" #include "xinclude.h"
#include "xtypes.h"
#include "xdiff.h"
#define MAX_PTR UINT_MAX #define MAX_PTR UINT_MAX
#define MAX_CNT UINT_MAX #define MAX_CNT UINT_MAX
...@@ -90,27 +88,21 @@ struct region { ...@@ -90,27 +88,21 @@ struct region {
#define REC(env, s, l) \ #define REC(env, s, l) \
(env->xdf##s.recs[l - 1]) (env->xdf##s.recs[l - 1])
static int cmp_recs(xpparam_t const *xpp, static int cmp_recs(xrecord_t *r1, xrecord_t *r2)
xrecord_t *r1, xrecord_t *r2)
{ {
return r1->ha == r2->ha && return r1->ha == r2->ha;
xdl_recmatch(r1->ptr, r1->size, r2->ptr, r2->size,
xpp->flags);
}
#define CMP_ENV(xpp, env, s1, l1, s2, l2) \ }
(cmp_recs(xpp, REC(env, s1, l1), REC(env, s2, l2)))
#define CMP(i, s1, l1, s2, l2) \ #define CMP(i, s1, l1, s2, l2) \
(cmp_recs(i->xpp, REC(i->env, s1, l1), REC(i->env, s2, l2))) (cmp_recs(REC(i->env, s1, l1), REC(i->env, s2, l2)))
#define TABLE_HASH(index, side, line) \ #define TABLE_HASH(index, side, line) \
XDL_HASHLONG((REC(index->env, side, line))->ha, index->table_bits) XDL_HASHLONG((REC(index->env, side, line))->ha, index->table_bits)
static int scanA(struct histindex *index, unsigned int line1, unsigned int count1) static int scanA(struct histindex *index, int line1, int count1)
{ {
unsigned int ptr; unsigned int ptr, tbl_idx;
unsigned int tbl_idx;
unsigned int chain_len; unsigned int chain_len;
struct record **rec_chain, *rec; struct record **rec_chain, *rec;
...@@ -161,10 +153,8 @@ continue_scan: ...@@ -161,10 +153,8 @@ continue_scan:
return 0; return 0;
} }
static int try_lcs( static int try_lcs(struct histindex *index, struct region *lcs, int b_ptr,
struct histindex *index, struct region *lcs, unsigned int b_ptr, int line1, int count1, int line2, int count2)
unsigned int line1, unsigned int count1,
unsigned int line2, unsigned int count2)
{ {
unsigned int b_next = b_ptr + 1; unsigned int b_next = b_ptr + 1;
struct record *rec = index->records[TABLE_HASH(index, 2, b_ptr)]; struct record *rec = index->records[TABLE_HASH(index, 2, b_ptr)];
...@@ -236,59 +226,33 @@ static int try_lcs( ...@@ -236,59 +226,33 @@ static int try_lcs(
return b_next; return b_next;
} }
static int find_lcs( static int fall_back_to_classic_diff(xpparam_t const *xpp, xdfenv_t *env,
struct histindex *index, struct region *lcs, int line1, int count1, int line2, int count2)
unsigned int line1, unsigned int count1,
unsigned int line2, unsigned int count2)
{ {
unsigned int b_ptr; xpparam_t xpparam;
if (scanA(index, line1, count1)) memset(&xpparam, 0, sizeof(xpparam));
return -1; xpparam.flags = xpp->flags & ~XDF_DIFF_ALGORITHM_MASK;
index->cnt = index->max_chain_length + 1; return xdl_fall_back_diff(env, &xpparam,
line1, count1, line2, count2);
for (b_ptr = line2; b_ptr <= LINE_END(2); )
b_ptr = try_lcs(index, lcs, b_ptr, line1, count1, line2, count2);
return index->has_common && index->max_chain_length < index->cnt;
} }
static int fall_back_to_classic_diff(struct histindex *index, static inline void free_index(struct histindex *index)
int line1, int count1, int line2, int count2)
{ {
xpparam_t xpp; xdl_free(index->records);
xpp.flags = index->xpp->flags & ~XDF_DIFF_ALGORITHM_MASK; xdl_free(index->line_map);
xdl_free(index->next_ptrs);
return xdl_fall_back_diff(index->env, &xpp, xdl_cha_free(&index->rcha);
line1, count1, line2, count2);
} }
static int histogram_diff( static int find_lcs(xpparam_t const *xpp, xdfenv_t *env,
xpparam_t const *xpp, xdfenv_t *env, struct region *lcs,
unsigned int line1, unsigned int count1, int line1, int count1, int line2, int count2)
unsigned int line2, unsigned int count2)
{ {
int b_ptr;
int sz, ret = -1;
struct histindex index; struct histindex index;
struct region lcs;
size_t sz;
int result = -1;
if (count1 <= 0 && count2 <= 0)
return 0;
if (LINE_END(1) >= MAX_PTR)
return -1;
if (!count1) {
while(count2--)
env->xdf2.rchg[line2++ - 1] = 1;
return 0;
} else if (!count2) {
while(count1--)
env->xdf1.rchg[line1++ - 1] = 1;
return 0;
}
memset(&index, 0, sizeof(index)); memset(&index, 0, sizeof(index));
...@@ -302,8 +266,7 @@ static int histogram_diff( ...@@ -302,8 +266,7 @@ static int histogram_diff(
index.table_bits = xdl_hashbits(count1); index.table_bits = xdl_hashbits(count1);
sz = index.records_size = 1 << index.table_bits; sz = index.records_size = 1 << index.table_bits;
GIT_ERROR_CHECK_ALLOC_MULTIPLY(&sz, sz, sizeof(struct record *)); sz *= sizeof(struct record *);
if (!(index.records = (struct record **) xdl_malloc(sz))) if (!(index.records = (struct record **) xdl_malloc(sz)))
goto cleanup; goto cleanup;
memset(index.records, 0, sz); memset(index.records, 0, sz);
...@@ -327,9 +290,55 @@ static int histogram_diff( ...@@ -327,9 +290,55 @@ static int histogram_diff(
index.ptr_shift = line1; index.ptr_shift = line1;
index.max_chain_length = 64; index.max_chain_length = 64;
if (scanA(&index, line1, count1))
goto cleanup;
index.cnt = index.max_chain_length + 1;
for (b_ptr = line2; b_ptr <= LINE_END(2); )
b_ptr = try_lcs(&index, lcs, b_ptr, line1, count1, line2, count2);
if (index.has_common && index.max_chain_length < index.cnt)
ret = 1;
else
ret = 0;
cleanup:
free_index(&index);
return ret;
}
static int histogram_diff(xpparam_t const *xpp, xdfenv_t *env,
int line1, int count1, int line2, int count2)
{
struct region lcs;
int lcs_found;
int result;
redo:
result = -1;
if (count1 <= 0 && count2 <= 0)
return 0;
if (LINE_END(1) >= MAX_PTR)
return -1;
if (!count1) {
while(count2--)
env->xdf2.rchg[line2++ - 1] = 1;
return 0;
} else if (!count2) {
while(count1--)
env->xdf1.rchg[line1++ - 1] = 1;
return 0;
}
memset(&lcs, 0, sizeof(lcs)); memset(&lcs, 0, sizeof(lcs));
if (find_lcs(&index, &lcs, line1, count1, line2, count2)) lcs_found = find_lcs(xpp, env, &lcs, line1, count1, line2, count2);
result = fall_back_to_classic_diff(&index, line1, count1, line2, count2); if (lcs_found < 0)
goto out;
else if (lcs_found)
result = fall_back_to_classic_diff(xpp, env, line1, count1, line2, count2);
else { else {
if (lcs.begin1 == 0 && lcs.begin2 == 0) { if (lcs.begin1 == 0 && lcs.begin2 == 0) {
while (count1--) while (count1--)
...@@ -342,21 +351,21 @@ static int histogram_diff( ...@@ -342,21 +351,21 @@ static int histogram_diff(
line1, lcs.begin1 - line1, line1, lcs.begin1 - line1,
line2, lcs.begin2 - line2); line2, lcs.begin2 - line2);
if (result) if (result)
goto cleanup; goto out;
result = histogram_diff(xpp, env, /*
lcs.end1 + 1, LINE_END(1) - lcs.end1, * result = histogram_diff(xpp, env,
lcs.end2 + 1, LINE_END(2) - lcs.end2); * lcs.end1 + 1, LINE_END(1) - lcs.end1,
if (result) * lcs.end2 + 1, LINE_END(2) - lcs.end2);
goto cleanup; * but let's optimize tail recursion ourself:
*/
count1 = LINE_END(1) - lcs.end1;
line1 = lcs.end1 + 1;
count2 = LINE_END(2) - lcs.end2;
line2 = lcs.end2 + 1;
goto redo;
} }
} }
out:
cleanup:
xdl_free(index.records);
xdl_free(index.line_map);
xdl_free(index.next_ptrs);
xdl_cha_free(&index.rcha);
return result; return result;
} }
......
...@@ -23,17 +23,7 @@ ...@@ -23,17 +23,7 @@
#if !defined(XINCLUDE_H) #if !defined(XINCLUDE_H)
#define XINCLUDE_H #define XINCLUDE_H
#include <ctype.h> #include "git-xdiff.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#ifdef _WIN32
#else
#include <unistd.h>
#endif
#include "xmacros.h" #include "xmacros.h"
#include "xdiff.h" #include "xdiff.h"
#include "xtypes.h" #include "xtypes.h"
...@@ -42,6 +32,5 @@ ...@@ -42,6 +32,5 @@
#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) */
...@@ -109,53 +109,44 @@ static int xdl_merge_cmp_lines(xdfenv_t *xe1, int i1, xdfenv_t *xe2, int i2, ...@@ -109,53 +109,44 @@ 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 needs_cr, int add_nl, char *dest) static int xdl_recs_copy_0(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; int size = 0;
*out = 0;
recs = (use_orig ? xe->xdf1.recs : xe->xdf2.recs) + i; recs = (use_orig ? xe->xdf1.recs : xe->xdf2.recs) + i;
if (count < 1) if (count < 1)
return 0; return 0;
for (i = 0; i < count; ) { for (i = 0; i < count; size += recs[i++]->size)
if (dest) if (dest)
memcpy(dest + size, recs[i]->ptr, recs[i]->size); memcpy(dest + size, recs[i]->ptr, recs[i]->size);
GIT_ERROR_CHECK_ALLOC_ADD(&size, size, recs[i++]->size);
}
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 (needs_cr) {
if (dest) if (dest)
dest[size] = '\r'; dest[size] = '\r';
GIT_ERROR_CHECK_ALLOC_ADD(&size, size, 1); size++;
} }
if (dest) if (dest)
dest[size] = '\n'; dest[size] = '\n';
size++;
GIT_ERROR_CHECK_ALLOC_ADD(&size, size, 1);
} }
} }
return size;
*out = size;
return 0;
} }
static int xdl_recs_copy(size_t *out, xdfenv_t *xe, int i, int count, int needs_cr, int add_nl, char *dest) static int xdl_recs_copy(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, needs_cr, add_nl, dest); return xdl_recs_copy_0(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 needs_cr, int add_nl, char *dest) static int xdl_orig_copy(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, needs_cr, add_nl, dest); return xdl_recs_copy_0(1, xe, i, count, needs_cr, add_nl, dest);
} }
/* /*
...@@ -202,32 +193,26 @@ static int is_cr_needed(xdfenv_t *xe1, xdfenv_t *xe2, xdmerge_t *m) ...@@ -202,32 +193,26 @@ static int is_cr_needed(xdfenv_t *xe1, xdfenv_t *xe2, xdmerge_t *m)
return needs_cr < 0 ? 0 : needs_cr; 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(xdfenv_t *xe1, const char *name1,
xdfenv_t *xe2, const char *name2, xdfenv_t *xe2, const char *name2,
const char *name3, const char *name3,
size_t size, int i, int style, int size, int i, int style,
xdmerge_t *m, char *dest, int marker_size) xdmerge_t *m, char *dest, int marker_size)
{ {
int marker1_size = (name1 ? (int)strlen(name1) + 1 : 0); int marker1_size = (name1 ? strlen(name1) + 1 : 0);
int marker2_size = (name2 ? (int)strlen(name2) + 1 : 0); int marker2_size = (name2 ? strlen(name2) + 1 : 0);
int marker3_size = (name3 ? (int)strlen(name3) + 1 : 0); int marker3_size = (name3 ? strlen(name3) + 1 : 0);
int needs_cr = is_cr_needed(xe1, xe2, m); int needs_cr = is_cr_needed(xe1, xe2, m);
size_t copied;
*out = 0;
if (marker_size <= 0) if (marker_size <= 0)
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, 0, size += xdl_recs_copy(xe1, i, m->i1 - i, 0, 0,
dest ? dest + size : NULL) < 0) dest ? dest + size : NULL);
return -1;
GIT_ERROR_CHECK_ALLOC_ADD(&size, size, copied);
if (!dest) { if (!dest) {
GIT_ERROR_CHECK_ALLOC_ADD5(&size, size, marker_size, 1, needs_cr, marker1_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;
...@@ -242,16 +227,13 @@ static int fill_conflict_hunk(size_t *out, xdfenv_t *xe1, const char *name1, ...@@ -242,16 +227,13 @@ static int fill_conflict_hunk(size_t *out, xdfenv_t *xe1, const char *name1,
} }
/* Postimage from side #1 */ /* Postimage from side #1 */
if (xdl_recs_copy(&copied, xe1, m->i1, m->chg1, needs_cr, 1, size += xdl_recs_copy(xe1, m->i1, m->chg1, needs_cr, 1,
dest ? dest + size : NULL) < 0) dest ? dest + size : NULL);
return -1;
GIT_ERROR_CHECK_ALLOC_ADD(&size, size, copied); if (style == XDL_MERGE_DIFF3 || style == XDL_MERGE_ZEALOUS_DIFF3) {
if (style == XDL_MERGE_DIFF3) {
/* Shared preimage */ /* Shared preimage */
if (!dest) { if (!dest) {
GIT_ERROR_CHECK_ALLOC_ADD5(&size, size, marker_size, 1, needs_cr, marker3_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;
...@@ -264,15 +246,12 @@ static int fill_conflict_hunk(size_t *out, xdfenv_t *xe1, const char *name1, ...@@ -264,15 +246,12 @@ static int fill_conflict_hunk(size_t *out, xdfenv_t *xe1, const char *name1,
dest[size++] = '\r'; dest[size++] = '\r';
dest[size++] = '\n'; dest[size++] = '\n';
} }
size += xdl_orig_copy(xe1, m->i0, m->chg0, needs_cr, 1,
if (xdl_orig_copy(&copied, xe1, m->i0, m->chg0, needs_cr, 1, dest ? dest + size : NULL);
dest ? dest + size : NULL) < 0)
return -1;
GIT_ERROR_CHECK_ALLOC_ADD(&size, size, copied);
} }
if (!dest) { if (!dest) {
GIT_ERROR_CHECK_ALLOC_ADD4(&size, size, marker_size, 1, needs_cr); size += marker_size + 1 + needs_cr;
} else { } else {
memset(dest + size, '=', marker_size); memset(dest + size, '=', marker_size);
size += marker_size; size += marker_size;
...@@ -282,14 +261,10 @@ static int fill_conflict_hunk(size_t *out, xdfenv_t *xe1, const char *name1, ...@@ -282,14 +261,10 @@ static int fill_conflict_hunk(size_t *out, xdfenv_t *xe1, const char *name1,
} }
/* Postimage from side #2 */ /* Postimage from side #2 */
size += xdl_recs_copy(xe2, m->i2, m->chg2, needs_cr, 1,
if (xdl_recs_copy(&copied, xe2, m->i2, m->chg2, needs_cr, 1, dest ? dest + size : NULL);
dest ? dest + size : NULL) < 0)
return -1;
GIT_ERROR_CHECK_ALLOC_ADD(&size, size, copied);
if (!dest) { if (!dest) {
GIT_ERROR_CHECK_ALLOC_ADD5(&size, size, marker_size, 1, needs_cr, marker2_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;
...@@ -302,71 +277,83 @@ static int fill_conflict_hunk(size_t *out, xdfenv_t *xe1, const char *name1, ...@@ -302,71 +277,83 @@ static int fill_conflict_hunk(size_t *out, xdfenv_t *xe1, const char *name1,
dest[size++] = '\r'; dest[size++] = '\r';
dest[size++] = '\n'; dest[size++] = '\n';
} }
return size;
*out = size;
return 0;
} }
static int xdl_fill_merge_buffer(size_t *out, static int xdl_fill_merge_buffer(xdfenv_t *xe1, const char *name1,
xdfenv_t *xe1, const char *name1,
xdfenv_t *xe2, const char *name2, xdfenv_t *xe2, const char *name2,
const char *ancestor_name, const char *ancestor_name,
int favor, int favor,
xdmerge_t *m, char *dest, int style, xdmerge_t *m, char *dest, int style,
int marker_size) int marker_size)
{ {
size_t size, copied; int size, i;
int i;
*out = 0;
for (size = i = 0; m; m = m->next) { for (size = i = 0; m; m = m->next) {
if (favor && !m->mode) if (favor && !m->mode)
m->mode = favor; m->mode = favor;
if (m->mode == 0) { if (m->mode == 0)
if (fill_conflict_hunk(&size, xe1, name1, xe2, name2, size = fill_conflict_hunk(xe1, name1, xe2, name2,
ancestor_name, ancestor_name,
size, i, style, m, dest, size, i, style, m, dest,
marker_size) < 0) marker_size);
return -1;
}
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, 0, size += xdl_recs_copy(xe1, i, m->i1 - i, 0, 0,
dest ? dest + size : NULL) < 0) dest ? dest + size : NULL);
return -1;
GIT_ERROR_CHECK_ALLOC_ADD(&size, size, copied);
/* Postimage from side #1 */ /* Postimage from side #1 */
if (m->mode & 1) { if (m->mode & 1) {
int needs_cr = is_cr_needed(xe1, xe2, m); int needs_cr = is_cr_needed(xe1, xe2, m);
if (xdl_recs_copy(&copied, xe1, m->i1, m->chg1, needs_cr, (m->mode & 2), size += xdl_recs_copy(xe1, m->i1, m->chg1, needs_cr, (m->mode & 2),
dest ? dest + size : NULL) < 0) dest ? dest + size : NULL);
return -1;
GIT_ERROR_CHECK_ALLOC_ADD(&size, size, copied);
} }
/* 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, 0, size += xdl_recs_copy(xe2, m->i2, m->chg2, 0, 0,
dest ? dest + size : NULL) < 0) dest ? dest + size : NULL);
return -1;
GIT_ERROR_CHECK_ALLOC_ADD(&size, size, copied);
}
} else } else
continue; continue;
i = m->i1 + m->chg1; i = m->i1 + m->chg1;
} }
size += xdl_recs_copy(xe1, i, xe1->xdf2.nrec - i, 0, 0,
dest ? dest + size : NULL);
return size;
}
if (xdl_recs_copy(&copied, xe1, i, xe1->xdf2.nrec - i, 0, 0, static int recmatch(xrecord_t *rec1, xrecord_t *rec2, unsigned long flags)
dest ? dest + size : NULL) < 0) {
return -1; return xdl_recmatch(rec1->ptr, rec1->size,
GIT_ERROR_CHECK_ALLOC_ADD(&size, size, copied); rec2->ptr, rec2->size, flags);
}
*out = size; /*
return 0; * Remove any common lines from the beginning and end of the conflicted region.
*/
static void xdl_refine_zdiff3_conflicts(xdfenv_t *xe1, xdfenv_t *xe2, xdmerge_t *m,
xpparam_t const *xpp)
{
xrecord_t **rec1 = xe1->xdf2.recs, **rec2 = xe2->xdf2.recs;
for (; m; m = m->next) {
/* let's handle just the conflicts */
if (m->mode)
continue;
while(m->chg1 && m->chg2 &&
recmatch(rec1[m->i1], rec2[m->i2], xpp->flags)) {
m->chg1--;
m->chg2--;
m->i1++;
m->i2++;
}
while (m->chg1 && m->chg2 &&
recmatch(rec1[m->i1 + m->chg1 - 1],
rec2[m->i2 + m->chg2 - 1], xpp->flags)) {
m->chg1--;
m->chg2--;
}
}
} }
/* /*
...@@ -529,7 +516,22 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, ...@@ -529,7 +516,22 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1,
int style = xmp->style; int style = xmp->style;
int favor = xmp->favor; int favor = xmp->favor;
if (style == XDL_MERGE_DIFF3) { /*
* XDL_MERGE_DIFF3 does not attempt to refine conflicts by looking
* at common areas of sides 1 & 2, because the base (side 0) does
* not match and is being shown. Similarly, simplification of
* non-conflicts is also skipped due to the skipping of conflict
* refinement.
*
* XDL_MERGE_ZEALOUS_DIFF3, on the other hand, will attempt to
* refine conflicts looking for common areas of sides 1 & 2.
* However, since the base is being shown and does not match,
* it will only look for common areas at the beginning or end
* of the conflict block. Since XDL_MERGE_ZEALOUS_DIFF3's
* conflict refinement is much more limited in this fashion, the
* conflict simplification will be skipped.
*/
if (style == XDL_MERGE_DIFF3 || style == XDL_MERGE_ZEALOUS_DIFF3) {
/* /*
* "diff3 -m" output does not make sense for anything * "diff3 -m" output does not make sense for anything
* more aggressive than XDL_MERGE_EAGER. * more aggressive than XDL_MERGE_EAGER.
...@@ -650,7 +652,9 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, ...@@ -650,7 +652,9 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1,
if (!changes) if (!changes)
changes = c; changes = c;
/* refine conflicts */ /* refine conflicts */
if (XDL_MERGE_ZEALOUS <= level && if (style == XDL_MERGE_ZEALOUS_DIFF3) {
xdl_refine_zdiff3_conflicts(xe1, xe2, changes, xpp);
} else if (XDL_MERGE_ZEALOUS <= level &&
(xdl_refine_conflicts(xe1, xe2, changes, xpp) < 0 || (xdl_refine_conflicts(xe1, xe2, changes, xpp) < 0 ||
xdl_simplify_non_conflicts(xe1, changes, xdl_simplify_non_conflicts(xe1, changes,
XDL_MERGE_ZEALOUS < level) < 0)) { XDL_MERGE_ZEALOUS < level) < 0)) {
...@@ -660,24 +664,19 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, ...@@ -660,24 +664,19 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1,
/* output */ /* output */
if (result) { if (result) {
int marker_size = xmp->marker_size; int marker_size = xmp->marker_size;
size_t size; int size = xdl_fill_merge_buffer(xe1, name1, xe2, name2,
if (xdl_fill_merge_buffer(&size, xe1, name1, xe2, name2,
ancestor_name, ancestor_name,
favor, changes, NULL, style, favor, changes, NULL, style,
marker_size) < 0) marker_size);
return -1;
result->ptr = xdl_malloc(size); result->ptr = xdl_malloc(size);
if (!result->ptr) { if (!result->ptr) {
xdl_cleanup_merge(changes); xdl_cleanup_merge(changes);
return -1; return -1;
} }
result->size = size; result->size = size;
if (xdl_fill_merge_buffer(&size, xe1, name1, xe2, name2, xdl_fill_merge_buffer(xe1, name1, xe2, name2,
ancestor_name, favor, changes, ancestor_name, favor, changes,
result->ptr, style, marker_size) < 0) result->ptr, style, marker_size);
return -1;
} }
return xdl_cleanup_merge(changes); return xdl_cleanup_merge(changes);
} }
...@@ -717,22 +716,10 @@ int xdl_merge(mmfile_t *orig, mmfile_t *mf1, mmfile_t *mf2, ...@@ -717,22 +716,10 @@ int xdl_merge(mmfile_t *orig, mmfile_t *mf1, mmfile_t *mf2,
status = 0; status = 0;
if (!xscr1) { if (!xscr1) {
result->ptr = xdl_malloc(mf2->size); result->ptr = xdl_malloc(mf2->size);
if (!result->ptr) {
xdl_free_script(xscr2);
xdl_free_env(&xe1);
xdl_free_env(&xe2);
return -1;
}
memcpy(result->ptr, mf2->ptr, mf2->size); memcpy(result->ptr, mf2->ptr, mf2->size);
result->size = mf2->size; result->size = mf2->size;
} else if (!xscr2) { } else if (!xscr2) {
result->ptr = xdl_malloc(mf1->size); result->ptr = xdl_malloc(mf1->size);
if (!result->ptr) {
xdl_free_script(xscr1);
xdl_free_env(&xe1);
xdl_free_env(&xe2);
return -1;
}
memcpy(result->ptr, mf1->ptr, mf1->size); memcpy(result->ptr, mf1->ptr, mf1->size);
result->size = mf1->size; result->size = mf1->size;
} else { } else {
......
...@@ -20,8 +20,6 @@ ...@@ -20,8 +20,6 @@
* *
*/ */
#include "xinclude.h" #include "xinclude.h"
#include "xtypes.h"
#include "xdiff.h"
/* /*
* The basic idea of patience diff is to find lines that are unique in * The basic idea of patience diff is to find lines that are unique in
...@@ -78,7 +76,7 @@ struct hashmap { ...@@ -78,7 +76,7 @@ struct hashmap {
static int is_anchor(xpparam_t const *xpp, const char *line) static int is_anchor(xpparam_t const *xpp, const char *line)
{ {
unsigned long i; int i;
for (i = 0; i < xpp->anchors_nr; i++) { for (i = 0; i < xpp->anchors_nr; i++) {
if (!strncmp(line, xpp->anchors[i], strlen(xpp->anchors[i]))) if (!strncmp(line, xpp->anchors[i], strlen(xpp->anchors[i])))
return 1; return 1;
...@@ -92,7 +90,7 @@ static void insert_record(xpparam_t const *xpp, int line, struct hashmap *map, ...@@ -92,7 +90,7 @@ static void insert_record(xpparam_t const *xpp, int line, struct hashmap *map,
{ {
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;
xrecord_t *record = records[line - 1], *other; xrecord_t *record = records[line - 1];
/* /*
* After xdl_prepare_env() (or more precisely, due to * After xdl_prepare_env() (or more precisely, due to
* xdl_classify_record()), the "ha" member of the records (AKA lines) * xdl_classify_record()), the "ha" member of the records (AKA lines)
...@@ -106,11 +104,7 @@ static void insert_record(xpparam_t const *xpp, int line, struct hashmap *map, ...@@ -106,11 +104,7 @@ static void insert_record(xpparam_t const *xpp, int line, struct hashmap *map,
int index = (int)((record->ha << 1) % map->alloc); int index = (int)((record->ha << 1) % map->alloc);
while (map->entries[index].line1) { while (map->entries[index].line1) {
other = map->env->xdf1.recs[map->entries[index].line1 - 1]; if (map->entries[index].hash != record->ha) {
if (map->entries[index].hash != record->ha ||
!xdl_recmatch(record->ptr, record->size,
other->ptr, other->size,
map->xpp->flags)) {
if (++index >= map->alloc) if (++index >= map->alloc)
index = 0; index = 0;
continue; continue;
...@@ -217,9 +211,6 @@ static struct entry *find_longest_common_sequence(struct hashmap *map) ...@@ -217,9 +211,6 @@ static struct entry *find_longest_common_sequence(struct hashmap *map)
*/ */
int anchor_i = -1; int anchor_i = -1;
if (!sequence)
return NULL;
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;
...@@ -258,8 +249,7 @@ static int match(struct hashmap *map, int line1, int line2) ...@@ -258,8 +249,7 @@ static int match(struct hashmap *map, int line1, int line2)
{ {
xrecord_t *record1 = map->env->xdf1.recs[line1 - 1]; xrecord_t *record1 = map->env->xdf1.recs[line1 - 1];
xrecord_t *record2 = map->env->xdf2.recs[line2 - 1]; xrecord_t *record2 = map->env->xdf2.recs[line2 - 1];
return xdl_recmatch(record1->ptr, record1->size, return record1->ha == record2->ha;
record2->ptr, record2->size, map->xpp->flags);
} }
static int patience_diff(mmfile_t *file1, mmfile_t *file2, static int patience_diff(mmfile_t *file1, mmfile_t *file2,
...@@ -294,9 +284,6 @@ static int walk_common_sequence(struct hashmap *map, struct entry *first, ...@@ -294,9 +284,6 @@ static int walk_common_sequence(struct hashmap *map, struct entry *first,
/* Recurse */ /* Recurse */
if (next1 > line1 || next2 > line2) { if (next1 > line1 || next2 > line2) {
struct hashmap submap;
memset(&submap, 0, sizeof(submap));
if (patience_diff(map->file1, map->file2, if (patience_diff(map->file1, map->file2,
map->xpp, map->env, map->xpp, map->env,
line1, next1 - line1, line1, next1 - line1,
...@@ -323,6 +310,8 @@ static int fall_back_to_classic_diff(struct hashmap *map, ...@@ -323,6 +310,8 @@ static int fall_back_to_classic_diff(struct hashmap *map,
int line1, int count1, int line2, int count2) int line1, int count1, int line2, int count2)
{ {
xpparam_t xpp; xpparam_t xpp;
memset(&xpp, 0, sizeof(xpp));
xpp.flags = map->xpp->flags & ~XDF_DIFF_ALGORITHM_MASK; xpp.flags = map->xpp->flags & ~XDF_DIFF_ALGORITHM_MASK;
return xdl_fall_back_diff(map->env, &xpp, return xdl_fall_back_diff(map->env, &xpp,
......
...@@ -181,15 +181,11 @@ static int xdl_prepare_ctx(unsigned int pass, mmfile_t *mf, long narec, xpparam_ ...@@ -181,15 +181,11 @@ static int xdl_prepare_ctx(unsigned int pass, mmfile_t *mf, long narec, xpparam_
if (!(recs = (xrecord_t **) xdl_malloc(narec * sizeof(xrecord_t *)))) if (!(recs = (xrecord_t **) xdl_malloc(narec * sizeof(xrecord_t *))))
goto abort; goto abort;
if (XDF_DIFF_ALG(xpp->flags) == XDF_HISTOGRAM_DIFF)
hbits = hsize = 0;
else {
hbits = xdl_hashbits((unsigned int) narec); hbits = xdl_hashbits((unsigned int) narec);
hsize = 1 << hbits; hsize = 1 << hbits;
if (!(rhash = (xrecord_t **) xdl_malloc(hsize * sizeof(xrecord_t *)))) if (!(rhash = (xrecord_t **) xdl_malloc(hsize * sizeof(xrecord_t *))))
goto abort; goto abort;
memset(rhash, 0, hsize * sizeof(xrecord_t *)); memset(rhash, 0, hsize * sizeof(xrecord_t *));
}
nrec = 0; nrec = 0;
if ((cur = blk = xdl_mmfile_first(mf, &bsize)) != NULL) { if ((cur = blk = xdl_mmfile_first(mf, &bsize)) != NULL) {
...@@ -208,9 +204,7 @@ static int xdl_prepare_ctx(unsigned int pass, mmfile_t *mf, long narec, xpparam_ ...@@ -208,9 +204,7 @@ static int xdl_prepare_ctx(unsigned int pass, mmfile_t *mf, long narec, xpparam_
crec->size = (long) (cur - prev); crec->size = (long) (cur - prev);
crec->ha = hav; crec->ha = hav;
recs[nrec++] = crec; recs[nrec++] = crec;
if (xdl_classify_record(pass, cf, rhash, hbits, crec) < 0)
if ((XDF_DIFF_ALG(xpp->flags) != XDF_HISTOGRAM_DIFF) &&
xdl_classify_record(pass, cf, rhash, hbits, crec) < 0)
goto abort; goto abort;
} }
} }
...@@ -219,10 +213,13 @@ static int xdl_prepare_ctx(unsigned int pass, mmfile_t *mf, long narec, xpparam_ ...@@ -219,10 +213,13 @@ static int xdl_prepare_ctx(unsigned int pass, mmfile_t *mf, long narec, xpparam_
goto abort; goto abort;
memset(rchg, 0, (nrec + 2) * sizeof(char)); memset(rchg, 0, (nrec + 2) * sizeof(char));
if (!(rindex = (long *) xdl_malloc((nrec + 1) * sizeof(long)))) if ((XDF_DIFF_ALG(xpp->flags) != XDF_PATIENCE_DIFF) &&
(XDF_DIFF_ALG(xpp->flags) != XDF_HISTOGRAM_DIFF)) {
if (!(rindex = xdl_malloc((nrec + 1) * sizeof(*rindex))))
goto abort; goto abort;
if (!(ha = (unsigned long *) xdl_malloc((nrec + 1) * sizeof(unsigned long)))) if (!(ha = xdl_malloc((nrec + 1) * sizeof(*ha))))
goto abort; goto abort;
}
xdf->nrec = nrec; xdf->nrec = nrec;
xdf->recs = recs; xdf->recs = recs;
...@@ -279,8 +276,7 @@ int xdl_prepare_env(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, ...@@ -279,8 +276,7 @@ int xdl_prepare_env(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
enl1 = xdl_guess_lines(mf1, sample) + 1; enl1 = xdl_guess_lines(mf1, sample) + 1;
enl2 = xdl_guess_lines(mf2, sample) + 1; enl2 = xdl_guess_lines(mf2, sample) + 1;
if (XDF_DIFF_ALG(xpp->flags) != XDF_HISTOGRAM_DIFF && if (xdl_init_classifier(&cf, enl1 + enl2 + 1, xpp->flags) < 0)
xdl_init_classifier(&cf, enl1 + enl2 + 1, xpp->flags) < 0)
return -1; return -1;
if (xdl_prepare_ctx(1, mf1, enl1, xpp, &cf, &xe->xdf1) < 0) { if (xdl_prepare_ctx(1, mf1, enl1, xpp, &cf, &xe->xdf1) < 0) {
...@@ -305,7 +301,6 @@ int xdl_prepare_env(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, ...@@ -305,7 +301,6 @@ int xdl_prepare_env(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
return -1; return -1;
} }
if (XDF_DIFF_ALG(xpp->flags) != XDF_HISTOGRAM_DIFF)
xdl_free_classifier(&cf); xdl_free_classifier(&cf);
return 0; return 0;
......
...@@ -23,8 +23,6 @@ ...@@ -23,8 +23,6 @@
#include "xinclude.h" #include "xinclude.h"
long xdl_bogosqrt(long n) { long xdl_bogosqrt(long n) {
long i; long i;
...@@ -52,7 +50,7 @@ int xdl_emit_diffrec(char const *rec, long size, char const *pre, long psize, ...@@ -52,7 +50,7 @@ int xdl_emit_diffrec(char const *rec, long size, char const *pre, long psize,
mb[2].size = strlen(mb[2].ptr); mb[2].size = strlen(mb[2].ptr);
i++; i++;
} }
if (ecb->outf(ecb->priv, mb, i) < 0) { if (ecb->out_line(ecb->priv, mb, i) < 0) {
return -1; return -1;
} }
...@@ -342,8 +340,9 @@ int xdl_num_out(char *out, long val) { ...@@ -342,8 +340,9 @@ int xdl_num_out(char *out, long val) {
return str - out; return str - out;
} }
int xdl_emit_hunk_hdr(long s1, long c1, long s2, long c2, static int xdl_format_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;
mmbuffer_t mb; mmbuffer_t mb;
char buf[128]; char buf[128];
...@@ -376,7 +375,7 @@ int xdl_emit_hunk_hdr(long s1, long c1, long s2, long c2, ...@@ -376,7 +375,7 @@ 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 > sizeof(buf) - nb - 1)
funclen = sizeof(buf) - nb - 1; funclen = sizeof(buf) - nb - 1;
memcpy(buf + nb, func, funclen); memcpy(buf + nb, func, funclen);
nb += funclen; nb += funclen;
...@@ -385,9 +384,21 @@ int xdl_emit_hunk_hdr(long s1, long c1, long s2, long c2, ...@@ -385,9 +384,21 @@ int xdl_emit_hunk_hdr(long s1, long c1, long s2, long c2,
mb.ptr = buf; mb.ptr = buf;
mb.size = nb; mb.size = nb;
if (ecb->outf(ecb->priv, &mb, 1) < 0) if (ecb->out_line(ecb->priv, &mb, 1) < 0)
return -1; return -1;
return 0;
}
int xdl_emit_hunk_hdr(long s1, long c1, long s2, long c2,
const char *func, long funclen,
xdemitcb_t *ecb) {
if (!ecb->out_hunk)
return xdl_format_hunk_hdr(s1, c1, s2, c2, func, funclen, ecb);
if (ecb->out_hunk(ecb->priv,
c1 ? s1 : s1 - 1, c1,
c2 ? s2 : s2 - 1, c2,
func, funclen) < 0)
return -1;
return 0; return 0;
} }
......
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