mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
vim-patch:8.2.3390: included xdiff code is outdated
Problem: Included xdiff code is outdated.
Solution: Sync with xdiff in git 2.33. (Christian Brabandt, closes vim/vim#8431)
ba02e4720f
This commit is contained in:
parent
11289ad733
commit
69f4438d35
@ -1059,7 +1059,7 @@ static int diff_file_internal(diffio_T *diffio)
|
|||||||
|
|
||||||
emit_cfg.ctxlen = 0; // don't need any diff_context here
|
emit_cfg.ctxlen = 0; // don't need any diff_context here
|
||||||
emit_cb.priv = &diffio->dio_diff;
|
emit_cb.priv = &diffio->dio_diff;
|
||||||
emit_cb.outf = xdiff_out;
|
emit_cb.out_line = xdiff_out;
|
||||||
if (xdl_diff(&diffio->dio_orig.din_mmfile,
|
if (xdl_diff(&diffio->dio_orig.din_mmfile,
|
||||||
&diffio->dio_new.din_mmfile,
|
&diffio->dio_new.din_mmfile,
|
||||||
¶m, &emit_cfg, &emit_cb) < 0) {
|
¶m, &emit_cfg, &emit_cb) < 0) {
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "nvim/vim.h"
|
#include "nvim/vim.h"
|
||||||
#include "nvim/xdiff/xdiff.h"
|
#include "xdiff/xdiff.h"
|
||||||
#include "nvim/lua/xdiff.h"
|
#include "nvim/lua/xdiff.h"
|
||||||
#include "nvim/lua/converter.h"
|
#include "nvim/lua/converter.h"
|
||||||
#include "nvim/lua/executor.h"
|
#include "nvim/lua/executor.h"
|
||||||
@ -294,7 +294,7 @@ int nlua_xdl_diff(lua_State *lstate)
|
|||||||
case kNluaXdiffModeUnified:
|
case kNluaXdiffModeUnified:
|
||||||
luaL_buffinit(lstate, &buf);
|
luaL_buffinit(lstate, &buf);
|
||||||
ecb.priv = &buf;
|
ecb.priv = &buf;
|
||||||
ecb.outf = write_string;
|
ecb.out_line = write_string;
|
||||||
break;
|
break;
|
||||||
case kNluaXdiffModeOnHunkCB:
|
case kNluaXdiffModeOnHunkCB:
|
||||||
priv = xmalloc(sizeof(*priv));
|
priv = xmalloc(sizeof(*priv));
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
The files in this directory come from the xdiff implementation in git.
|
The files in this directory come from the xdiff implementation in git.
|
||||||
You can find it here: https://github.com/git/git/tree/master/xdiff
|
You can find it here: https://github.com/git/git/tree/master/xdiff
|
||||||
The files were last updated 2018 September 10.
|
The files were last updated August 31, 2021 from git release v.2.33.0
|
||||||
|
|
||||||
This is originally based on libxdiff, which can be found here:
|
This is originally based on libxdiff, which can be found here:
|
||||||
http://www.xmailserver.org/xdiff-lib.html
|
http://www.xmailserver.org/xdiff-lib.html
|
||||||
|
@ -25,9 +25,9 @@
|
|||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif // #ifdef __cplusplus
|
#endif /* #ifdef __cplusplus */
|
||||||
|
|
||||||
// xpparm_t.flags
|
/* xpparm_t.flags */
|
||||||
#define XDF_NEED_MINIMAL (1 << 0)
|
#define XDF_NEED_MINIMAL (1 << 0)
|
||||||
|
|
||||||
#define XDF_IGNORE_WHITESPACE (1 << 1)
|
#define XDF_IGNORE_WHITESPACE (1 << 1)
|
||||||
@ -48,22 +48,23 @@ extern "C" {
|
|||||||
|
|
||||||
#define XDF_INDENT_HEURISTIC (1 << 23)
|
#define XDF_INDENT_HEURISTIC (1 << 23)
|
||||||
|
|
||||||
// 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)
|
||||||
|
|
||||||
// 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
|
||||||
#define XDL_MERGE_ZEALOUS 2
|
#define XDL_MERGE_ZEALOUS 2
|
||||||
#define XDL_MERGE_ZEALOUS_ALNUM 3
|
#define XDL_MERGE_ZEALOUS_ALNUM 3
|
||||||
|
|
||||||
// merge favor modes
|
/* merge favor modes */
|
||||||
#define XDL_MERGE_FAVOR_OURS 1
|
#define XDL_MERGE_FAVOR_OURS 1
|
||||||
#define XDL_MERGE_FAVOR_THEIRS 2
|
#define XDL_MERGE_FAVOR_THEIRS 2
|
||||||
#define XDL_MERGE_FAVOR_UNION 3
|
#define XDL_MERGE_FAVOR_UNION 3
|
||||||
|
|
||||||
// merge output styles
|
/* merge output styles */
|
||||||
#define XDL_MERGE_DIFF3 1
|
#define XDL_MERGE_DIFF3 1
|
||||||
|
|
||||||
typedef struct s_mmfile {
|
typedef struct s_mmfile {
|
||||||
@ -79,14 +80,24 @@ typedef struct s_mmbuffer {
|
|||||||
typedef struct s_xpparam {
|
typedef struct s_xpparam {
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
// See Documentation/diff-options.txt.
|
/* -I<regex> */
|
||||||
|
#if 0 // unused by Vim
|
||||||
|
regex_t **ignore_regex;
|
||||||
|
size_t ignore_regex_nr;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* See Documentation/diff-options.txt. */
|
||||||
char **anchors;
|
char **anchors;
|
||||||
size_t anchors_nr;
|
size_t anchors_nr;
|
||||||
} xpparam_t;
|
} xpparam_t;
|
||||||
|
|
||||||
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);
|
||||||
@ -126,9 +137,9 @@ typedef struct s_xmparam {
|
|||||||
int level;
|
int level;
|
||||||
int favor;
|
int favor;
|
||||||
int style;
|
int style;
|
||||||
const char *ancestor; // label for orig
|
const char *ancestor; /* label for orig */
|
||||||
const char *file1; // label for mf1
|
const char *file1; /* label for mf1 */
|
||||||
const char *file2; // label for mf2
|
const char *file2; /* label for mf2 */
|
||||||
} xmparam_t;
|
} xmparam_t;
|
||||||
|
|
||||||
#define DEFAULT_CONFLICT_MARKER_SIZE 7
|
#define DEFAULT_CONFLICT_MARKER_SIZE 7
|
||||||
@ -138,6 +149,6 @@ int xdl_merge(mmfile_t *orig, mmfile_t *mf1, mmfile_t *mf2,
|
|||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif // #ifdef __cplusplus
|
#endif /* #ifdef __cplusplus */
|
||||||
|
|
||||||
#endif // #if !defined(XDIFF_H)
|
#endif /* #if !defined(XDIFF_H) */
|
||||||
|
@ -38,9 +38,9 @@ typedef struct s_xdpsplit {
|
|||||||
* 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,
|
||||||
@ -63,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;
|
||||||
@ -98,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;
|
||||||
@ -138,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
|
||||||
@ -196,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;
|
||||||
@ -244,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,
|
||||||
@ -323,7 +328,9 @@ 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.
|
||||||
*/
|
*/
|
||||||
ndiags = xe->xdf1.nreff + xe->xdf2.nreff + 3;
|
ndiags = xe->xdf1.nreff + xe->xdf2.nreff + 3;
|
||||||
@ -418,13 +425,13 @@ static int xget_indent(xrecord_t *rec)
|
|||||||
ret += 1;
|
ret += 1;
|
||||||
else if (c == '\t')
|
else if (c == '\t')
|
||||||
ret += 8 - ret % 8;
|
ret += 8 - ret % 8;
|
||||||
// ignore other whitespace characters
|
/* ignore other whitespace characters */
|
||||||
|
|
||||||
if (ret >= MAX_INDENT)
|
if (ret >= MAX_INDENT)
|
||||||
return MAX_INDENT;
|
return MAX_INDENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The line contains only whitespace.
|
/* The line contains only whitespace. */
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -435,7 +442,7 @@ static int xget_indent(xrecord_t *rec)
|
|||||||
*/
|
*/
|
||||||
#define MAX_BLANKS 20
|
#define MAX_BLANKS 20
|
||||||
|
|
||||||
// Characteristics measured about a hypothetical split position.
|
/* Characteristics measured about a hypothetical split position. */
|
||||||
struct split_measurement {
|
struct split_measurement {
|
||||||
/*
|
/*
|
||||||
* Is the split at the end of the file (aside from any blank lines)?
|
* Is the split at the end of the file (aside from any blank lines)?
|
||||||
@ -443,8 +450,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;
|
||||||
|
|
||||||
@ -454,8 +461,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;
|
||||||
|
|
||||||
@ -472,10 +479,10 @@ struct split_measurement {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct split_score {
|
struct split_score {
|
||||||
// The effective indent of this split (smaller is preferred).
|
/* The effective indent of this split (smaller is preferred). */
|
||||||
int effective_indent;
|
int effective_indent;
|
||||||
|
|
||||||
// Penalty for this split (smaller is preferred).
|
/* Penalty for this split (smaller is preferred). */
|
||||||
int penalty;
|
int penalty;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -534,16 +541,16 @@ static void measure_split(const xdfile_t *xdf, long split,
|
|||||||
* integer math.
|
* integer math.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Penalty if there are no non-blank lines before the split
|
/* Penalty if there are no non-blank lines before the split */
|
||||||
#define START_OF_FILE_PENALTY 1
|
#define START_OF_FILE_PENALTY 1
|
||||||
|
|
||||||
// Penalty if there are no non-blank lines after the split
|
/* Penalty if there are no non-blank lines after the split */
|
||||||
#define END_OF_FILE_PENALTY 21
|
#define END_OF_FILE_PENALTY 21
|
||||||
|
|
||||||
// Multiplier for the number of blank lines around the split
|
/* Multiplier for the number of blank lines around the split */
|
||||||
#define TOTAL_BLANK_WEIGHT (-30)
|
#define TOTAL_BLANK_WEIGHT (-30)
|
||||||
|
|
||||||
// Multiplier for the number of blank lines after the split
|
/* Multiplier for the number of blank lines after the split */
|
||||||
#define POST_BLANK_WEIGHT 6
|
#define POST_BLANK_WEIGHT 6
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -581,13 +588,13 @@ static void measure_split(const xdfile_t *xdf, long split,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* 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)
|
||||||
{
|
{
|
||||||
@ -610,7 +617,7 @@ static void score_add_split(const struct split_measurement *m, struct split_scor
|
|||||||
post_blank = (m->indent == -1) ? 1 + m->post_blank : 0;
|
post_blank = (m->indent == -1) ? 1 + m->post_blank : 0;
|
||||||
total_blank = m->pre_blank + post_blank;
|
total_blank = m->pre_blank + post_blank;
|
||||||
|
|
||||||
// Penalties based on nearby blank lines:
|
/* Penalties based on nearby blank lines: */
|
||||||
s->penalty += TOTAL_BLANK_WEIGHT * total_blank;
|
s->penalty += TOTAL_BLANK_WEIGHT * total_blank;
|
||||||
s->penalty += POST_BLANK_WEIGHT * post_blank;
|
s->penalty += POST_BLANK_WEIGHT * post_blank;
|
||||||
|
|
||||||
@ -621,13 +628,13 @@ static void score_add_split(const struct split_measurement *m, struct split_scor
|
|||||||
|
|
||||||
any_blanks = (total_blank != 0);
|
any_blanks = (total_blank != 0);
|
||||||
|
|
||||||
// Note that the effective indent is -1 at the end of the file:
|
/* Note that the effective indent is -1 at the end of the file: */
|
||||||
s->effective_indent += indent;
|
s->effective_indent += indent;
|
||||||
|
|
||||||
if (indent == -1) {
|
if (indent == -1) {
|
||||||
// No additional adjustments needed.
|
/* No additional adjustments needed. */
|
||||||
} else if (m->pre_indent == -1) {
|
} else if (m->pre_indent == -1) {
|
||||||
// No additional adjustments needed.
|
/* No additional adjustments needed. */
|
||||||
} else if (indent > m->pre_indent) {
|
} else if (indent > m->pre_indent) {
|
||||||
/*
|
/*
|
||||||
* The line is indented more than its predecessor.
|
* The line is indented more than its predecessor.
|
||||||
@ -669,7 +676,7 @@ static void score_add_split(const struct split_measurement *m, struct split_scor
|
|||||||
|
|
||||||
static int score_cmp(struct split_score *s1, struct split_score *s2)
|
static int score_cmp(struct split_score *s1, struct split_score *s2)
|
||||||
{
|
{
|
||||||
// -1 if s1.effective_indent < s2->effective_indent, etc.
|
/* -1 if s1.effective_indent < s2->effective_indent, etc. */
|
||||||
int cmp_indents = ((s1->effective_indent > s2->effective_indent) -
|
int cmp_indents = ((s1->effective_indent > s2->effective_indent) -
|
||||||
(s1->effective_indent < s2->effective_indent));
|
(s1->effective_indent < s2->effective_indent));
|
||||||
|
|
||||||
@ -809,13 +816,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;
|
||||||
@ -828,7 +838,7 @@ 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, flags))
|
||||||
if (group_previous(xdfo, &go))
|
if (group_previous(xdfo, &go))
|
||||||
xdl_bug("group sync broken sliding up");
|
xdl_bug("group sync broken sliding up");
|
||||||
@ -842,7 +852,7 @@ int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) {
|
|||||||
if (go.end > go.start)
|
if (go.end > go.start)
|
||||||
end_matching_other = g.end;
|
end_matching_other = g.end;
|
||||||
|
|
||||||
// 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, flags))
|
||||||
break;
|
break;
|
||||||
@ -858,17 +868,17 @@ 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, flags))
|
||||||
@ -879,14 +889,15 @@ int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) {
|
|||||||
} 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;
|
||||||
@ -921,7 +932,7 @@ int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
next:
|
next:
|
||||||
// Move past the just-processed group:
|
/* Move past the just-processed group: */
|
||||||
if (group_next(xdf, &g))
|
if (group_next(xdf, &g))
|
||||||
break;
|
break;
|
||||||
if (group_next(xdfo, &go))
|
if (group_next(xdfo, &go))
|
||||||
@ -987,7 +998,7 @@ static int xdl_call_hunk_func(xdfenv_t *xe UNUSED, xdchange_t *xscr, xdemitcb_t
|
|||||||
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;
|
||||||
|
|
||||||
@ -1008,6 +1019,48 @@ static void xdl_mark_ignorable(xdchange_t *xscr, xdfenv_t *xe, long flags)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0 // unused by Vim
|
||||||
|
static int record_matches_regex(xrecord_t *rec, xpparam_t const *xpp) {
|
||||||
|
regmatch_t regmatch;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < xpp->ignore_regex_nr; i++)
|
||||||
|
if (!regexec_buf(xpp->ignore_regex[i], rec->ptr, rec->size, 1,
|
||||||
|
®match, 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
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;
|
||||||
@ -1027,7 +1080,12 @@ 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 0
|
||||||
|
if (xpp->ignore_regex)
|
||||||
|
xdl_mark_ignorable_regex(xscr, &xe, xpp);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (ef(&xe, xscr, ecb, xecfg) < 0) {
|
if (ef(&xe, xscr, ecb, xecfg) < 0) {
|
||||||
|
|
||||||
|
@ -61,4 +61,4 @@ int xdl_do_patience_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
|
|||||||
int xdl_do_histogram_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
|
int xdl_do_histogram_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
|
||||||
xdfenv_t *env);
|
xdfenv_t *env);
|
||||||
|
|
||||||
#endif // #if !defined(XDIFFI_H)
|
#endif /* #if !defined(XDIFFI_H) */
|
||||||
|
@ -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);
|
||||||
@ -54,9 +54,9 @@ xdchange_t *xdl_get_hunk(xdchange_t **xscr, xdemitconf_t const *xecfg)
|
|||||||
xdchange_t *xch, *xchp, *lxch;
|
xdchange_t *xch, *xchp, *lxch;
|
||||||
long max_common = 2 * xecfg->ctxlen + xecfg->interhunkctxlen;
|
long max_common = 2 * xecfg->ctxlen + xecfg->interhunkctxlen;
|
||||||
long max_ignorable = xecfg->ctxlen;
|
long max_ignorable = xecfg->ctxlen;
|
||||||
unsigned long ignored = 0; // number of ignored blank lines
|
unsigned long ignored = 0; /* number of ignored blank lines */
|
||||||
|
|
||||||
// remove ignorable changes that are too far before other changes
|
/* remove ignorable changes that are too far before other changes */
|
||||||
for (xchp = *xscr; xchp && xchp->ignore; xchp = xchp->next) {
|
for (xchp = *xscr; xchp && xchp->ignore; xchp = xchp->next) {
|
||||||
xch = xchp->next;
|
xch = xchp->next;
|
||||||
|
|
||||||
@ -99,9 +99,9 @@ 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 UNUSED)
|
static long def_ff(const char *rec, long len, char *buf, long sz, void *priv UNUSED)
|
||||||
{
|
{
|
||||||
if (len > 0 &&
|
if (len > 0 &&
|
||||||
(isalpha((unsigned char)*rec) || // identifier?
|
(isalpha((unsigned char)*rec) || /* identifier? */
|
||||||
*rec == '_' || // also identifier?
|
*rec == '_' || /* also identifier? */
|
||||||
*rec == '$')) { // identifiers from VMS and other esoterico
|
*rec == '$')) { /* identifiers from VMS and other esoterico */
|
||||||
if (len > sz)
|
if (len > sz)
|
||||||
len = sz;
|
len = sz;
|
||||||
while (0 < len && isspace((unsigned char)rec[len - 1]))
|
while (0 < len && isspace((unsigned char)rec[len - 1]))
|
||||||
@ -197,7 +197,7 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
|
|||||||
if (xecfg->flags & XDL_EMIT_FUNCCONTEXT) {
|
if (xecfg->flags & XDL_EMIT_FUNCCONTEXT) {
|
||||||
long fs1, i1 = xch->i1;
|
long fs1, i1 = xch->i1;
|
||||||
|
|
||||||
// Appended chunk?
|
/* Appended chunk? */
|
||||||
if (i1 >= xe->xdf1.nrec) {
|
if (i1 >= xe->xdf1.nrec) {
|
||||||
long i2 = xch->i2;
|
long i2 = xch->i2;
|
||||||
|
|
||||||
@ -225,8 +225,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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -249,7 +264,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -281,7 +296,8 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
|
|||||||
funclineprev = s1 - 1;
|
funclineprev = s1 - 1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
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;
|
||||||
|
|
||||||
|
@ -33,4 +33,4 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif // #if !defined(XEMIT_H)
|
#endif /* #if !defined(XEMIT_H) */
|
||||||
|
@ -42,8 +42,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "xinclude.h"
|
#include "xinclude.h"
|
||||||
#include "xtypes.h"
|
|
||||||
#include "xdiff.h"
|
|
||||||
|
|
||||||
#define MAX_PTR INT_MAX
|
#define MAX_PTR INT_MAX
|
||||||
#define MAX_CNT INT_MAX
|
#define MAX_CNT INT_MAX
|
||||||
@ -55,8 +53,8 @@ struct histindex {
|
|||||||
struct record {
|
struct record {
|
||||||
unsigned int ptr, cnt;
|
unsigned int ptr, cnt;
|
||||||
struct record *next;
|
struct record *next;
|
||||||
} **records, // an occurrence
|
} **records, /* an occurrence */
|
||||||
**line_map; // map of line to record chain
|
**line_map; /* map of line to record chain */
|
||||||
chastore_t rcha;
|
chastore_t rcha;
|
||||||
unsigned int *next_ptrs;
|
unsigned int *next_ptrs;
|
||||||
unsigned int table_bits,
|
unsigned int table_bits,
|
||||||
@ -128,7 +126,7 @@ static int scanA(struct histindex *index, int line1, int count1)
|
|||||||
*/
|
*/
|
||||||
NEXT_PTR(index, ptr) = rec->ptr;
|
NEXT_PTR(index, ptr) = rec->ptr;
|
||||||
rec->ptr = ptr;
|
rec->ptr = ptr;
|
||||||
// cap rec->cnt at MAX_CNT
|
/* cap rec->cnt at MAX_CNT */
|
||||||
rec->cnt = XDL_MIN(MAX_CNT, rec->cnt + 1);
|
rec->cnt = XDL_MIN(MAX_CNT, rec->cnt + 1);
|
||||||
LINE_MAP(index, ptr) = rec;
|
LINE_MAP(index, ptr) = rec;
|
||||||
goto continue_scan;
|
goto continue_scan;
|
||||||
@ -154,7 +152,7 @@ static int scanA(struct histindex *index, int line1, int count1)
|
|||||||
LINE_MAP(index, ptr) = rec;
|
LINE_MAP(index, ptr) = rec;
|
||||||
|
|
||||||
continue_scan:
|
continue_scan:
|
||||||
; // no op
|
; /* no op */
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -237,6 +235,8 @@ static int fall_back_to_classic_diff(xpparam_t const *xpp, xdfenv_t *env,
|
|||||||
int line1, int count1, int line2, int count2)
|
int line1, int count1, int line2, int count2)
|
||||||
{
|
{
|
||||||
xpparam_t xpparam;
|
xpparam_t xpparam;
|
||||||
|
|
||||||
|
memset(&xpparam, 0, sizeof(xpparam));
|
||||||
xpparam.flags = xpp->flags & ~XDF_DIFF_ALGORITHM_MASK;
|
xpparam.flags = xpp->flags & ~XDF_DIFF_ALGORITHM_MASK;
|
||||||
|
|
||||||
return xdl_fall_back_diff(env, &xpparam,
|
return xdl_fall_back_diff(env, &xpparam,
|
||||||
@ -266,7 +266,7 @@ static int find_lcs(xpparam_t const *xpp, xdfenv_t *env,
|
|||||||
|
|
||||||
index.records = NULL;
|
index.records = NULL;
|
||||||
index.line_map = NULL;
|
index.line_map = NULL;
|
||||||
// in case of early xdl_cha_free()
|
/* in case of early xdl_cha_free() */
|
||||||
index.rcha.head = NULL;
|
index.rcha.head = NULL;
|
||||||
|
|
||||||
index.table_bits = xdl_hashbits(count1);
|
index.table_bits = xdl_hashbits(count1);
|
||||||
@ -288,7 +288,7 @@ static int find_lcs(xpparam_t const *xpp, xdfenv_t *env,
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
memset(index.next_ptrs, 0, sz);
|
memset(index.next_ptrs, 0, sz);
|
||||||
|
|
||||||
// lines / 4 + 1 comes from xprepare.c:xdl_prepare_ctx()
|
/* lines / 4 + 1 comes from xprepare.c:xdl_prepare_ctx() */
|
||||||
if (xdl_cha_init(&index.rcha, sizeof(struct record), count1 / 4 + 1) < 0)
|
if (xdl_cha_init(&index.rcha, sizeof(struct record), count1 / 4 + 1) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
|
@ -40,6 +40,7 @@
|
|||||||
#if !defined(XINCLUDE_H)
|
#if !defined(XINCLUDE_H)
|
||||||
#define XINCLUDE_H
|
#define XINCLUDE_H
|
||||||
|
|
||||||
|
// This effectively re-verts b46054b3746271d23feab0 from git
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -48,7 +49,10 @@
|
|||||||
#endif
|
#endif
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
// This include comes from git, so uncomment it
|
||||||
|
#if 0
|
||||||
|
#include "git-compat-util.h"
|
||||||
|
#endif
|
||||||
#include "xmacros.h"
|
#include "xmacros.h"
|
||||||
#include "xdiff.h"
|
#include "xdiff.h"
|
||||||
#include "xtypes.h"
|
#include "xtypes.h"
|
||||||
@ -58,4 +62,4 @@
|
|||||||
#include "xemit.h"
|
#include "xemit.h"
|
||||||
|
|
||||||
|
|
||||||
#endif // #if !defined(XINCLUDE_H)
|
#endif /* #if !defined(XINCLUDE_H) */
|
||||||
|
@ -51,4 +51,4 @@ do { \
|
|||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
#endif // #if !defined(XMACROS_H)
|
#endif /* #if !defined(XMACROS_H) */
|
||||||
|
@ -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
|
||||||
@ -69,7 +67,7 @@ struct hashmap {
|
|||||||
*/
|
*/
|
||||||
unsigned anchor : 1;
|
unsigned anchor : 1;
|
||||||
} *entries, *first, *last;
|
} *entries, *first, *last;
|
||||||
// were common records found?
|
/* were common records found? */
|
||||||
unsigned long has_matches;
|
unsigned long has_matches;
|
||||||
mmfile_t *file1, *file2;
|
mmfile_t *file1, *file2;
|
||||||
xdfenv_t *env;
|
xdfenv_t *env;
|
||||||
@ -78,21 +76,21 @@ struct hashmap {
|
|||||||
|
|
||||||
static int is_anchor(xpparam_t const *xpp, const char *line)
|
static int is_anchor(xpparam_t const *xpp, const char *line)
|
||||||
{
|
{
|
||||||
size_t i;
|
int i;
|
||||||
for (i = 0; i < xpp->anchors_nr; i++) {
|
for (i = 0; i < (int)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;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The argument "pass" is 1 for the first file, 2 for the second.
|
/* The argument "pass" is 1 for the first file, 2 for the second. */
|
||||||
static void insert_record(xpparam_t const *xpp, int line, struct hashmap *map,
|
static void insert_record(xpparam_t const *xpp, int line, struct hashmap *map,
|
||||||
int pass)
|
int pass)
|
||||||
{
|
{
|
||||||
xrecord_t **records = pass == 1 ?
|
xrecord_t **records = pass == 1 ?
|
||||||
map->env->xdf1.recs : map->env->xdf2.recs;
|
map->env->xdf1.recs : map->env->xdf2.recs;
|
||||||
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,
|
|||||||
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;
|
||||||
@ -155,7 +149,7 @@ static int fill_hashmap(mmfile_t *file1, mmfile_t *file2,
|
|||||||
result->xpp = xpp;
|
result->xpp = xpp;
|
||||||
result->env = env;
|
result->env = env;
|
||||||
|
|
||||||
// We know exactly how large we want the hash map
|
/* We know exactly how large we want the hash map */
|
||||||
result->alloc = count1 * 2;
|
result->alloc = count1 * 2;
|
||||||
result->entries = (struct entry *)
|
result->entries = (struct entry *)
|
||||||
xdl_malloc(result->alloc * sizeof(struct entry));
|
xdl_malloc(result->alloc * sizeof(struct entry));
|
||||||
@ -163,11 +157,11 @@ static int fill_hashmap(mmfile_t *file1, mmfile_t *file2,
|
|||||||
return -1;
|
return -1;
|
||||||
memset(result->entries, 0, result->alloc * sizeof(struct entry));
|
memset(result->entries, 0, result->alloc * sizeof(struct entry));
|
||||||
|
|
||||||
// First, fill with entries from the first file
|
/* First, fill with entries from the first file */
|
||||||
while (count1--)
|
while (count1--)
|
||||||
insert_record(xpp, line1++, result, 1);
|
insert_record(xpp, line1++, result, 1);
|
||||||
|
|
||||||
// Then search for matches in the second file
|
/* Then search for matches in the second file */
|
||||||
while (count2--)
|
while (count2--)
|
||||||
insert_record(xpp, line2++, result, 2);
|
insert_record(xpp, line2++, result, 2);
|
||||||
|
|
||||||
@ -185,13 +179,13 @@ static int binary_search(struct entry **sequence, int longest,
|
|||||||
|
|
||||||
while (left + 1 < right) {
|
while (left + 1 < right) {
|
||||||
int middle = left + (right - left) / 2;
|
int middle = left + (right - left) / 2;
|
||||||
// by construction, no two entries can be equal
|
/* by construction, no two entries can be equal */
|
||||||
if (sequence[middle]->line2 > entry->line2)
|
if (sequence[middle]->line2 > entry->line2)
|
||||||
right = middle;
|
right = middle;
|
||||||
else
|
else
|
||||||
left = middle;
|
left = middle;
|
||||||
}
|
}
|
||||||
// return the index in "sequence", _not_ the sequence length
|
/* return the index in "sequence", _not_ the sequence length */
|
||||||
return left;
|
return left;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -206,9 +200,10 @@ static int binary_search(struct entry **sequence, int longest,
|
|||||||
*/
|
*/
|
||||||
static struct entry *find_longest_common_sequence(struct hashmap *map)
|
static struct entry *find_longest_common_sequence(struct hashmap *map)
|
||||||
{
|
{
|
||||||
struct entry **sequence = (struct entry **)xdl_malloc(map->nr * sizeof(struct entry *));
|
struct entry **sequence = xdl_malloc(map->nr * sizeof(struct entry *));
|
||||||
int longest = 0, i;
|
int longest = 0, i;
|
||||||
struct entry *entry;
|
struct entry *entry;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If not -1, this entry in sequence must never be overridden.
|
* If not -1, this entry in sequence must never be overridden.
|
||||||
* Therefore, overriding entries before this has no effect, so
|
* Therefore, overriding entries before this has no effect, so
|
||||||
@ -237,13 +232,13 @@ static struct entry *find_longest_common_sequence(struct hashmap *map)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// No common unique lines were found
|
/* No common unique lines were found */
|
||||||
if (!longest) {
|
if (!longest) {
|
||||||
xdl_free(sequence);
|
xdl_free(sequence);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Iterate starting at the last element, adjusting the "next" members
|
/* Iterate starting at the last element, adjusting the "next" members */
|
||||||
entry = sequence[longest - 1];
|
entry = sequence[longest - 1];
|
||||||
entry->next = NULL;
|
entry->next = NULL;
|
||||||
while (entry->previous) {
|
while (entry->previous) {
|
||||||
@ -258,8 +253,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,
|
||||||
@ -273,7 +267,7 @@ static int walk_common_sequence(struct hashmap *map, struct entry *first,
|
|||||||
int next1, next2;
|
int next1, next2;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
// Try to grow the line ranges of common lines
|
/* Try to grow the line ranges of common lines */
|
||||||
if (first) {
|
if (first) {
|
||||||
next1 = first->line1;
|
next1 = first->line1;
|
||||||
next2 = first->line2;
|
next2 = first->line2;
|
||||||
@ -292,11 +286,8 @@ static int walk_common_sequence(struct hashmap *map, struct entry *first,
|
|||||||
line2++;
|
line2++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 +314,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,
|
||||||
@ -343,7 +336,7 @@ static int patience_diff(mmfile_t *file1, mmfile_t *file2,
|
|||||||
struct entry *first;
|
struct entry *first;
|
||||||
int result = 0;
|
int result = 0;
|
||||||
|
|
||||||
// trivial case: one side is empty
|
/* trivial case: one side is empty */
|
||||||
if (!count1) {
|
if (!count1) {
|
||||||
while(count2--)
|
while(count2--)
|
||||||
env->xdf2.rchg[line2++ - 1] = 1;
|
env->xdf2.rchg[line2++ - 1] = 1;
|
||||||
@ -359,7 +352,7 @@ static int patience_diff(mmfile_t *file1, mmfile_t *file2,
|
|||||||
line1, count1, line2, count2))
|
line1, count1, line2, count2))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
// are there any matching lines at all?
|
/* are there any matching lines at all? */
|
||||||
if (!map.has_matches) {
|
if (!map.has_matches) {
|
||||||
while(count1--)
|
while(count1--)
|
||||||
env->xdf1.rchg[line1++ - 1] = 1;
|
env->xdf1.rchg[line1++ - 1] = 1;
|
||||||
@ -387,7 +380,7 @@ int xdl_do_patience_diff(mmfile_t *file1, mmfile_t *file2,
|
|||||||
if (xdl_prepare_env(file1, file2, xpp, env) < 0)
|
if (xdl_prepare_env(file1, file2, xpp, env) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
// environment is cleaned up in xdl_diff()
|
/* environment is cleaned up in xdl_diff() */
|
||||||
return patience_diff(file1, file2, xpp, env,
|
return patience_diff(file1, file2, xpp, env,
|
||||||
1, env->xdf1.nrec, 1, env->xdf2.nrec);
|
1, env->xdf1.nrec, 1, env->xdf2.nrec);
|
||||||
}
|
}
|
||||||
|
@ -31,4 +31,4 @@ void xdl_free_env(xdfenv_t *xe);
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif // #if !defined(XPREPARE_H)
|
#endif /* #if !defined(XPREPARE_H) */
|
||||||
|
@ -64,4 +64,4 @@ typedef struct s_xdfenv {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif // #if !defined(XTYPES_H)
|
#endif /* #if !defined(XTYPES_H) */
|
||||||
|
@ -20,13 +20,9 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <limits.h>
|
|
||||||
#include <assert.h>
|
|
||||||
#include "xinclude.h"
|
#include "xinclude.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
long xdl_bogosqrt(long n) {
|
long xdl_bogosqrt(long n) {
|
||||||
long i;
|
long i;
|
||||||
|
|
||||||
@ -51,10 +47,10 @@ int xdl_emit_diffrec(char const *rec, long size, char const *pre, long psize,
|
|||||||
mb[1].size = size;
|
mb[1].size = size;
|
||||||
if (size > 0 && rec[size - 1] != '\n') {
|
if (size > 0 && rec[size - 1] != '\n') {
|
||||||
mb[2].ptr = (char *) "\n\\ No newline at end of file\n";
|
mb[2].ptr = (char *) "\n\\ No newline at end of file\n";
|
||||||
mb[2].size = (long)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;
|
||||||
}
|
}
|
||||||
@ -168,7 +164,7 @@ static int ends_with_optional_cr(const char *l, long s, long i)
|
|||||||
s--;
|
s--;
|
||||||
if (s == i)
|
if (s == i)
|
||||||
return 1;
|
return 1;
|
||||||
// do not ignore CR at the end of an incomplete line
|
/* do not ignore CR at the end of an incomplete line */
|
||||||
if (complete && s == i + 1 && l[i] == '\r')
|
if (complete && s == i + 1 && l[i] == '\r')
|
||||||
return 1;
|
return 1;
|
||||||
return 0;
|
return 0;
|
||||||
@ -208,7 +204,7 @@ int xdl_recmatch(const char *l1, long s1, const char *l2, long s2, long flags)
|
|||||||
} else if (flags & XDF_IGNORE_WHITESPACE_CHANGE) {
|
} else if (flags & XDF_IGNORE_WHITESPACE_CHANGE) {
|
||||||
while (i1 < s1 && i2 < s2) {
|
while (i1 < s1 && i2 < s2) {
|
||||||
if (XDL_ISSPACE(l1[i1]) && XDL_ISSPACE(l2[i2])) {
|
if (XDL_ISSPACE(l1[i1]) && XDL_ISSPACE(l2[i2])) {
|
||||||
// Skip matching spaces and try again
|
/* Skip matching spaces and try again */
|
||||||
while (i1 < s1 && XDL_ISSPACE(l1[i1]))
|
while (i1 < s1 && XDL_ISSPACE(l1[i1]))
|
||||||
i1++;
|
i1++;
|
||||||
while (i2 < s2 && XDL_ISSPACE(l2[i2]))
|
while (i2 < s2 && XDL_ISSPACE(l2[i2]))
|
||||||
@ -224,7 +220,7 @@ int xdl_recmatch(const char *l1, long s1, const char *l2, long s2, long flags)
|
|||||||
i2++;
|
i2++;
|
||||||
}
|
}
|
||||||
} else if (flags & XDF_IGNORE_CR_AT_EOL) {
|
} else if (flags & XDF_IGNORE_CR_AT_EOL) {
|
||||||
// Find the first difference and see how the line ends
|
/* Find the first difference and see how the line ends */
|
||||||
while (i1 < s1 && i2 < s2 && l1[i1] == l2[i2]) {
|
while (i1 < s1 && i2 < s2 && l1[i1] == l2[i2]) {
|
||||||
i1++;
|
i1++;
|
||||||
i2++;
|
i2++;
|
||||||
@ -261,7 +257,7 @@ static unsigned long xdl_hash_record_with_whitespace(char const **data,
|
|||||||
|
|
||||||
for (; ptr < top && *ptr != '\n'; ptr++) {
|
for (; ptr < top && *ptr != '\n'; ptr++) {
|
||||||
if (cr_at_eol_only) {
|
if (cr_at_eol_only) {
|
||||||
// do not ignore CR at the end of an incomplete line
|
/* do not ignore CR at the end of an incomplete line */
|
||||||
if (*ptr == '\r' &&
|
if (*ptr == '\r' &&
|
||||||
(ptr + 1 < top && ptr[1] == '\n'))
|
(ptr + 1 < top && ptr[1] == '\n'))
|
||||||
continue;
|
continue;
|
||||||
@ -274,7 +270,7 @@ static unsigned long xdl_hash_record_with_whitespace(char const **data,
|
|||||||
ptr++;
|
ptr++;
|
||||||
at_eol = (top <= ptr + 1 || ptr[1] == '\n');
|
at_eol = (top <= ptr + 1 || ptr[1] == '\n');
|
||||||
if (flags & XDF_IGNORE_WHITESPACE)
|
if (flags & XDF_IGNORE_WHITESPACE)
|
||||||
; // already handled
|
; /* already handled */
|
||||||
else if (flags & XDF_IGNORE_WHITESPACE_CHANGE
|
else if (flags & XDF_IGNORE_WHITESPACE_CHANGE
|
||||||
&& !at_eol) {
|
&& !at_eol) {
|
||||||
ha += (ha << 5);
|
ha += (ha << 5);
|
||||||
@ -344,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];
|
||||||
@ -387,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,4 +44,4 @@ int xdl_fall_back_diff(xdfenv_t *diff_env, xpparam_t const *xpp,
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif // #if !defined(XUTILS_H)
|
#endif /* #if !defined(XUTILS_H) */
|
||||||
|
Loading…
Reference in New Issue
Block a user