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:
Christian Clason 2021-09-08 22:18:44 +02:00
parent 11289ad733
commit 69f4438d35
16 changed files with 237 additions and 146 deletions

View File

@ -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,
&param, &emit_cfg, &emit_cb) < 0) { &param, &emit_cfg, &emit_cb) < 0) {

View File

@ -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));

View File

@ -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

View File

@ -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) */

View File

@ -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,
&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;
}
}
#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) {

View File

@ -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) */

View File

@ -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;

View File

@ -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) */

View File

@ -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;

View File

@ -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) */

View File

@ -51,4 +51,4 @@ do { \
} while (0) } while (0)
#endif // #if !defined(XMACROS_H) #endif /* #if !defined(XMACROS_H) */

View File

@ -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);
} }

View File

@ -31,4 +31,4 @@ void xdl_free_env(xdfenv_t *xe);
#endif // #if !defined(XPREPARE_H) #endif /* #if !defined(XPREPARE_H) */

View File

@ -64,4 +64,4 @@ typedef struct s_xdfenv {
#endif // #if !defined(XTYPES_H) #endif /* #if !defined(XTYPES_H) */

View File

@ -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;
} }

View File

@ -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) */