Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
G
git2
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
lvzhengyang
git2
Commits
18a477e7
Unverified
Commit
18a477e7
authored
Feb 02, 2022
by
Edward Thomson
Committed by
GitHub
Feb 02, 2022
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #6195 from libgit2/ethomson/zdiff3
merge: support zdiff3 conflict styles
parents
50fada79
c629d2a1
Hide whitespace changes
Inline
Side-by-side
Showing
22 changed files
with
635 additions
and
403 deletions
+635
-403
include/git2/checkout.h
+4
-1
include/git2/merge.h
+4
-1
src/CMakeLists.txt
+10
-0
src/blame_git.c
+1
-1
src/checkout.c
+5
-0
src/diff_xdiff.c
+3
-8
src/merge_file.c
+13
-3
src/patch_generate.c
+22
-6
src/patch_generate.h
+4
-4
src/xdiff/git-xdiff.h
+42
-0
src/xdiff/xdiff.h
+15
-15
src/xdiff/xdiffi.c
+134
-108
src/xdiff/xemit.c
+23
-7
src/xdiff/xhistogram.c
+87
-78
src/xdiff/xinclude.h
+1
-12
src/xdiff/xmerge.c
+102
-115
src/xdiff/xpatience.c
+6
-17
src/xdiff/xprepare.c
+15
-20
src/xdiff/xutils.c
+18
-7
tests/merge/conflict_data.h
+9
-0
tests/merge/files.c
+39
-0
tests/merge/workdir/simple.c
+78
-0
No files found.
include/git2/checkout.h
View file @
18a477e7
...
...
@@ -182,7 +182,10 @@ typedef enum {
* notifications; don't update the working directory or index.
*/
GIT_CHECKOUT_DRY_RUN
=
(
1u
<<
24
),
/** Include common ancestor data in zdiff3 format for conflicts */
GIT_CHECKOUT_CONFLICT_STYLE_ZDIFF3
=
(
1u
<<
25
),
/**
* THE FOLLOWING OPTIONS ARE NOT YET IMPLEMENTED
*/
...
...
include/git2/merge.h
View file @
18a477e7
...
...
@@ -159,7 +159,10 @@ typedef enum {
GIT_MERGE_FILE_DIFF_PATIENCE
=
(
1
<<
6
),
/** Take extra time to find minimal diff */
GIT_MERGE_FILE_DIFF_MINIMAL
=
(
1
<<
7
)
GIT_MERGE_FILE_DIFF_MINIMAL
=
(
1
<<
7
),
/** Create zdiff3 ("zealous diff3")-style files */
GIT_MERGE_FILE_STYLE_ZDIFF3
=
(
1
<<
8
)
}
git_merge_file_flag_t
;
#define GIT_MERGE_CONFLICT_MARKER_SIZE 7
...
...
src/CMakeLists.txt
View file @
18a477e7
...
...
@@ -207,7 +207,17 @@ endif()
# errors for the xdiff sources until we've sorted them out
if
(
MSVC
)
set_source_files_properties
(
xdiff/xdiffi.c PROPERTIES COMPILE_FLAGS -WX-
)
set_source_files_properties
(
xdiff/xemit.c PROPERTIES COMPILE_FLAGS -WX-
)
set_source_files_properties
(
xdiff/xhistogram.c PROPERTIES COMPILE_FLAGS -WX-
)
set_source_files_properties
(
xdiff/xmerge.c PROPERTIES COMPILE_FLAGS -WX-
)
set_source_files_properties
(
xdiff/xutils.c PROPERTIES COMPILE_FLAGS -WX-
)
set_source_files_properties
(
xdiff/xpatience.c PROPERTIES COMPILE_FLAGS -WX-
)
else
()
set_source_files_properties
(
xdiff/xdiffi.c PROPERTIES COMPILE_FLAGS
"-Wno-sign-compare -Wno-unused-parameter"
)
set_source_files_properties
(
xdiff/xemit.c PROPERTIES COMPILE_FLAGS
"-Wno-sign-compare -Wno-unused-parameter"
)
set_source_files_properties
(
xdiff/xhistogram.c PROPERTIES COMPILE_FLAGS
"-Wno-sign-compare"
)
set_source_files_properties
(
xdiff/xutils.c PROPERTIES COMPILE_FLAGS
"-Wno-sign-compare"
)
set_source_files_properties
(
xdiff/xpatience.c PROPERTIES COMPILE_FLAGS
"-Wno-sign-compare"
)
endif
()
# Determine architecture of the machine
...
...
src/blame_git.c
View file @
18a477e7
...
...
@@ -393,7 +393,7 @@ static void fill_origin_blob(git_blame__origin *o, mmfile_t *file)
memset
(
file
,
0
,
sizeof
(
*
file
));
if
(
o
->
blob
)
{
file
->
ptr
=
(
char
*
)
git_blob_rawcontent
(
o
->
blob
);
file
->
size
=
(
size_t
)
git_blob_rawsize
(
o
->
blob
);
file
->
size
=
(
long
)
git_blob_rawsize
(
o
->
blob
);
}
}
...
...
src/checkout.c
View file @
18a477e7
...
...
@@ -2070,6 +2070,9 @@ static int checkout_write_merge(
if
(
data
->
opts
.
checkout_strategy
&
GIT_CHECKOUT_CONFLICT_STYLE_DIFF3
)
opts
.
flags
|=
GIT_MERGE_FILE_STYLE_DIFF3
;
if
(
data
->
opts
.
checkout_strategy
&
GIT_CHECKOUT_CONFLICT_STYLE_ZDIFF3
)
opts
.
flags
|=
GIT_MERGE_FILE_STYLE_ZDIFF3
;
opts
.
ancestor_label
=
data
->
opts
.
ancestor_label
?
data
->
opts
.
ancestor_label
:
"ancestor"
;
opts
.
our_label
=
data
->
opts
.
our_label
?
...
...
@@ -2493,6 +2496,8 @@ static int checkout_data_init(
data
->
opts
.
checkout_strategy
|=
GIT_CHECKOUT_CONFLICT_STYLE_MERGE
;
else
if
(
strcmp
(
conflict_style
->
value
,
"diff3"
)
==
0
)
data
->
opts
.
checkout_strategy
|=
GIT_CHECKOUT_CONFLICT_STYLE_DIFF3
;
else
if
(
strcmp
(
conflict_style
->
value
,
"zdiff3"
)
==
0
)
data
->
opts
.
checkout_strategy
|=
GIT_CHECKOUT_CONFLICT_STYLE_ZDIFF3
;
else
{
git_error_set
(
GIT_ERROR_CHECKOUT
,
"unknown style '%s' given for 'merge.conflictstyle'"
,
conflict_style
->
value
);
...
...
src/diff_xdiff.c
View file @
18a477e7
...
...
@@ -218,14 +218,9 @@ static int git_xdiff(git_patch_generated_output *output, git_patch_generated *pa
* updates are needed to xo->params.flags
*/
git_patch_generated_old_data
(
&
info
.
xd_old_data
.
ptr
,
&
info
.
xd_old_data
.
size
,
patch
);
git_patch_generated_new_data
(
&
info
.
xd_new_data
.
ptr
,
&
info
.
xd_new_data
.
size
,
patch
);
if
(
info
.
xd_old_data
.
size
>
GIT_XDIFF_MAX_SIZE
||
info
.
xd_new_data
.
size
>
GIT_XDIFF_MAX_SIZE
)
{
git_error_set
(
GIT_ERROR_INVALID
,
"files too large for diff"
);
if
(
git_patch_generated_old_data
(
&
info
.
xd_old_data
.
ptr
,
&
info
.
xd_old_data
.
size
,
patch
)
<
0
||
git_patch_generated_new_data
(
&
info
.
xd_new_data
.
ptr
,
&
info
.
xd_new_data
.
size
,
patch
)
<
0
)
return
-
1
;
}
xdl_diff
(
&
info
.
xd_old_data
,
&
info
.
xd_new_data
,
&
xo
->
params
,
&
xo
->
config
,
&
xo
->
callback
);
...
...
@@ -261,5 +256,5 @@ void git_xdiff_init(git_xdiff_output *xo, const git_diff_options *opts)
if
(
flags
&
GIT_DIFF_IGNORE_BLANK_LINES
)
xo
->
params
.
flags
|=
XDF_IGNORE_BLANK_LINES
;
xo
->
callback
.
out
f
=
git_xdiff_cb
;
xo
->
callback
.
out
_line
=
git_xdiff_cb
;
}
src/merge_file.c
View file @
18a477e7
...
...
@@ -86,22 +86,30 @@ static int merge_file__xdiff(
memset
(
&
xmparam
,
0x0
,
sizeof
(
xmparam_t
));
if
(
ours
->
size
>
LONG_MAX
||
theirs
->
size
>
LONG_MAX
||
(
ancestor
&&
ancestor
->
size
>
LONG_MAX
))
{
git_error_set
(
GIT_ERROR_MERGE
,
"failed to merge files"
);
error
=
-
1
;
goto
done
;
}
if
(
ancestor
)
{
xmparam
.
ancestor
=
(
options
.
ancestor_label
)
?
options
.
ancestor_label
:
ancestor
->
path
;
ancestor_mmfile
.
ptr
=
(
char
*
)
ancestor
->
ptr
;
ancestor_mmfile
.
size
=
ancestor
->
size
;
ancestor_mmfile
.
size
=
(
long
)
ancestor
->
size
;
}
xmparam
.
file1
=
(
options
.
our_label
)
?
options
.
our_label
:
ours
->
path
;
our_mmfile
.
ptr
=
(
char
*
)
ours
->
ptr
;
our_mmfile
.
size
=
ours
->
size
;
our_mmfile
.
size
=
(
long
)
ours
->
size
;
xmparam
.
file2
=
(
options
.
their_label
)
?
options
.
their_label
:
theirs
->
path
;
their_mmfile
.
ptr
=
(
char
*
)
theirs
->
ptr
;
their_mmfile
.
size
=
theirs
->
size
;
their_mmfile
.
size
=
(
long
)
theirs
->
size
;
if
(
options
.
favor
==
GIT_MERGE_FILE_FAVOR_OURS
)
xmparam
.
favor
=
XDL_MERGE_FAVOR_OURS
;
...
...
@@ -115,6 +123,8 @@ static int merge_file__xdiff(
if
(
options
.
flags
&
GIT_MERGE_FILE_STYLE_DIFF3
)
xmparam
.
style
=
XDL_MERGE_DIFF3
;
if
(
options
.
flags
&
GIT_MERGE_FILE_STYLE_ZDIFF3
)
xmparam
.
style
=
XDL_MERGE_ZEALOUS_DIFF3
;
if
(
options
.
flags
&
GIT_MERGE_FILE_IGNORE_WHITESPACE
)
xmparam
.
xpp
.
flags
|=
XDF_IGNORE_WHITESPACE
;
...
...
src/patch_generate.c
View file @
18a477e7
...
...
@@ -750,18 +750,34 @@ git_diff_driver *git_patch_generated_driver(git_patch_generated *patch)
return
patch
->
ofile
.
driver
;
}
void
git_patch_generated_old_data
(
char
**
ptr
,
size_t
*
len
,
git_patch_generated
*
patch
)
int
git_patch_generated_old_data
(
char
**
ptr
,
long
*
len
,
git_patch_generated
*
patch
)
{
if
(
patch
->
ofile
.
map
.
len
>
LONG_MAX
||
patch
->
ofile
.
map
.
len
>
GIT_XDIFF_MAX_SIZE
)
{
git_error_set
(
GIT_ERROR_INVALID
,
"files too large for diff"
);
return
-
1
;
}
*
ptr
=
patch
->
ofile
.
map
.
data
;
*
len
=
patch
->
ofile
.
map
.
len
;
*
len
=
(
long
)
patch
->
ofile
.
map
.
len
;
return
0
;
}
void
git_patch_generated_new_data
(
char
**
ptr
,
size_t
*
len
,
git_patch_generated
*
patch
)
int
git_patch_generated_new_data
(
char
**
ptr
,
long
*
len
,
git_patch_generated
*
patch
)
{
if
(
patch
->
ofile
.
map
.
len
>
LONG_MAX
||
patch
->
ofile
.
map
.
len
>
GIT_XDIFF_MAX_SIZE
)
{
git_error_set
(
GIT_ERROR_INVALID
,
"files too large for diff"
);
return
-
1
;
}
*
ptr
=
patch
->
nfile
.
map
.
data
;
*
len
=
patch
->
nfile
.
map
.
len
;
*
len
=
(
long
)
patch
->
nfile
.
map
.
len
;
return
0
;
}
static
int
patch_generated_file_cb
(
...
...
src/patch_generate.h
View file @
18a477e7
...
...
@@ -39,10 +39,10 @@ typedef struct git_patch_generated git_patch_generated;
extern
git_diff_driver
*
git_patch_generated_driver
(
git_patch_generated
*
);
extern
void
git_patch_generated_old_data
(
char
**
,
size_t
*
,
git_patch_generated
*
);
extern
void
git_patch_generated_new_data
(
char
**
,
size_t
*
,
git_patch_generated
*
);
extern
int
git_patch_generated_old_data
(
char
**
,
long
*
,
git_patch_generated
*
);
extern
int
git_patch_generated_new_data
(
char
**
,
long
*
,
git_patch_generated
*
);
extern
int
git_patch_generated_from_diff
(
git_patch
**
,
git_diff
*
,
size_t
);
...
...
src/xdiff/git-xdiff.h
0 → 100644
View file @
18a477e7
/*
* Copyright (C) the libgit2 contributors. All rights reserved.
*
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
/*
* This file provides the necessary indirection between xdiff and
* libgit2. libgit2-specific functionality should live here, so
* that git and libgit2 can share a common xdiff implementation.
*/
#ifndef INCLUDE_git_xdiff_h__
#define INCLUDE_git_xdiff_h__
#include "regexp.h"
#define xdl_malloc(x) git__malloc(x)
#define xdl_free(ptr) git__free(ptr)
#define xdl_realloc(ptr, x) git__realloc(ptr, x)
#define XDL_BUG(msg) GIT_ASSERT(msg)
#define xdl_regex_t git_regexp
#define xdl_regmatch_t git_regmatch
GIT_INLINE
(
int
)
xdl_regexec_buf
(
const
xdl_regex_t
*
preg
,
const
char
*
buf
,
size_t
size
,
size_t
nmatch
,
xdl_regmatch_t
pmatch
[],
int
eflags
)
{
GIT_UNUSED
(
preg
);
GIT_UNUSED
(
buf
);
GIT_UNUSED
(
size
);
GIT_UNUSED
(
nmatch
);
GIT_UNUSED
(
pmatch
);
GIT_UNUSED
(
eflags
);
GIT_ASSERT
(
"not implemented"
);
return
-
1
;
}
#endif
src/xdiff/xdiff.h
View file @
18a477e7
...
...
@@ -23,6 +23,8 @@
#if !defined(XDIFF_H)
#define XDIFF_H
#include "git-xdiff.h"
#ifdef __cplusplus
extern
"C"
{
#endif
/* #ifdef __cplusplus */
...
...
@@ -50,16 +52,9 @@ extern "C" {
/* xdemitconf_t.flags */
#define XDL_EMIT_FUNCNAMES (1 << 0)
#define XDL_EMIT_NO_HUNK_HDR (1 << 1)
#define XDL_EMIT_FUNCCONTEXT (1 << 2)
#define XDL_MMB_READONLY (1 << 0)
#define XDL_MMF_ATOMIC (1 << 0)
#define XDL_BDOP_INS 1
#define XDL_BDOP_CPY 2
#define XDL_BDOP_INSB 3
/* merge simplification levels */
#define XDL_MERGE_MINIMAL 0
#define XDL_MERGE_EAGER 1
...
...
@@ -73,20 +68,25 @@ extern "C" {
/* merge output styles */
#define XDL_MERGE_DIFF3 1
#define XDL_MERGE_ZEALOUS_DIFF3 2
typedef
struct
s_mmfile
{
char
*
ptr
;
size_t
size
;
long
size
;
}
mmfile_t
;
typedef
struct
s_mmbuffer
{
char
*
ptr
;
size_t
size
;
long
size
;
}
mmbuffer_t
;
typedef
struct
s_xpparam
{
unsigned
long
flags
;
/* -I<regex> */
xdl_regex_t
**
ignore_regex
;
size_t
ignore_regex_nr
;
/* See Documentation/diff-options.txt. */
char
**
anchors
;
size_t
anchors_nr
;
...
...
@@ -94,7 +94,11 @@ typedef struct s_xpparam {
typedef
struct
s_xdemitcb
{
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
;
typedef
long
(
*
find_func_t
)(
const
char
*
line
,
long
line_len
,
char
*
buffer
,
long
buffer_size
,
void
*
priv
);
...
...
@@ -117,10 +121,6 @@ typedef struct s_bdiffparam {
}
bdiffparam_t
;
#define xdl_malloc(x) git__malloc(x)
#define xdl_free(ptr) git__free(ptr)
#define xdl_realloc(ptr,x) git__realloc(ptr,x)
void
*
xdl_mmfile_first
(
mmfile_t
*
mmf
,
long
*
size
);
long
xdl_mmfile_size
(
mmfile_t
*
mmf
);
...
...
src/xdiff/xdiffi.c
View file @
18a477e7
...
...
@@ -21,8 +21,6 @@
*/
#include "xinclude.h"
#include "integer.h"
#define XDL_MAX_COST_MIN 256
#define XDL_HEUR_MIN_COST 256
...
...
@@ -30,41 +28,19 @@
#define XDL_SNAKE_CNT 20
#define XDL_K_HEUR 4
/** Declare a function as always inlined. */
#if defined(_MSC_VER)
# define XDL_INLINE(type) static __inline type
#elif defined(__GNUC__)
# define XDL_INLINE(type) static __inline__ type
#else
# define XDL_INLINE(type) static type
#endif
typedef
struct
s_xdpsplit
{
long
i1
,
i2
;
int
min_lo
,
min_hi
;
}
xdpsplit_t
;
static
long
xdl_split
(
unsigned
long
const
*
ha1
,
long
off1
,
long
lim1
,
unsigned
long
const
*
ha2
,
long
off2
,
long
lim2
,
long
*
kvdf
,
long
*
kvdb
,
int
need_min
,
xdpsplit_t
*
spl
,
xdalgoenv_t
*
xenv
);
static
xdchange_t
*
xdl_add_change
(
xdchange_t
*
xscr
,
long
i1
,
long
i2
,
long
chg1
,
long
chg2
);
/*
* See "An O(ND) Difference Algorithm and its Variations", by Eugene Myers.
* Basically considers a "box" (off1, off2, lim1, lim2) and scan from both
* the forward diagonal starting from (off1, off2) and the backward diagonal
* starting from (lim1, lim2). If the K values on the same diagonal crosses
* returns the furthest point of reach. We might en
d up having to expensive
*
cases using this algorithm is full, so a little bit of heuristic is needed
*
to cut the
search and to return a suboptimal point.
* returns the furthest point of reach. We might en
counter expensive edge cases
*
using this algorithm, so a little bit of heuristic is needed to cut the
* search and to return a suboptimal point.
*/
static
long
xdl_split
(
unsigned
long
const
*
ha1
,
long
off1
,
long
lim1
,
unsigned
long
const
*
ha2
,
long
off2
,
long
lim2
,
...
...
@@ -87,11 +63,13 @@ static long xdl_split(unsigned long const *ha1, long off1, long lim1,
int
got_snake
=
0
;
/*
* We need to exten
t
the diagonal "domain" by one. If the next
* We need to exten
d
the diagonal "domain" by one. If the next
* 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
* avoid extra conditions check inside the core loop.
* avoid extra conditions
in the
check inside the core loop.
*/
if
(
fmin
>
dmin
)
kvdf
[
--
fmin
-
1
]
=
-
1
;
...
...
@@ -122,11 +100,13 @@ static long xdl_split(unsigned long const *ha1, long off1, long lim1,
}
/*
* We need to exten
t
the diagonal "domain" by one. If the next
* We need to exten
d
the diagonal "domain" by one. If the next
* 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
* avoid extra conditions check inside the core loop.
* avoid extra conditions
in the
check inside the core loop.
*/
if
(
bmin
>
dmin
)
kvdb
[
--
bmin
-
1
]
=
XDL_LINE_MAX
;
...
...
@@ -162,7 +142,7 @@ static long xdl_split(unsigned long const *ha1, long off1, long lim1,
/*
* If the edit cost is above the heuristic trigger and if
* we got a good snake, we sample current diagonals to see
* if some of the
,
have reached an "interesting" path. Our
* if some of the
m
have reached an "interesting" path. Our
* measure is a function of the distance from the diagonal
* corner (i1 + i2) penalized with the distance from the
* mid diagonal itself. If this value is above the current
...
...
@@ -220,8 +200,9 @@ static long xdl_split(unsigned long const *ha1, long off1, long lim1,
}
/*
* Enough is enough. We spent too much time here and now we collect
* the furthest reaching path using the (i1 + i2) measure.
* Enough is enough. We spent too much time here and now we
* collect the furthest reaching path using the (i1 + i2)
* measure.
*/
if
(
ec
>=
xenv
->
mxcost
)
{
long
fbest
,
fbest1
,
bbest
,
bbest1
;
...
...
@@ -268,9 +249,9 @@ static long xdl_split(unsigned long const *ha1, long off1, long lim1,
/*
* Rule: "Divide et Impera"
. Recursively split the box in sub-boxes by calling
*
the box splitting function. Note that the real job (marking changed lines)
* is done in the two boundary reaching checks.
* Rule: "Divide et Impera"
(divide & conquer). Recursively split the box in
*
sub-boxes by calling the box splitting function. Note that the real job
*
(marking changed lines)
is done in the two boundary reaching checks.
*/
int
xdl_recs_cmp
(
diffdata_t
*
dd1
,
long
off1
,
long
lim1
,
diffdata_t
*
dd2
,
long
off2
,
long
lim2
,
...
...
@@ -330,7 +311,7 @@ int xdl_recs_cmp(diffdata_t *dd1, long off1, long lim1,
int
xdl_do_diff
(
mmfile_t
*
mf1
,
mmfile_t
*
mf2
,
xpparam_t
const
*
xpp
,
xdfenv_t
*
xe
)
{
size_t
ndiags
,
allocsize
;
long
ndiags
;
long
*
kvd
,
*
kvdf
,
*
kvdb
;
xdalgoenv_t
xenv
;
diffdata_t
dd1
,
dd2
;
...
...
@@ -347,15 +328,14 @@ int xdl_do_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
}
/*
* Allocate and setup K vectors to be used by the differential algorithm.
* Allocate and setup K vectors to be used by the differential
* algorithm.
*
* One is to store the forward path and one to store the backward path.
*/
GIT_ERROR_CHECK_ALLOC_ADD3
(
&
ndiags
,
xe
->
xdf1
.
nreff
,
xe
->
xdf2
.
nreff
,
3
);
GIT_ERROR_CHECK_ALLOC_MULTIPLY
(
&
allocsize
,
ndiags
,
2
);
GIT_ERROR_CHECK_ALLOC_ADD
(
&
allocsize
,
allocsize
,
2
);
GIT_ERROR_CHECK_ALLOC_MULTIPLY
(
&
allocsize
,
allocsize
,
sizeof
(
long
));
ndiags
=
xe
->
xdf1
.
nreff
+
xe
->
xdf2
.
nreff
+
3
;
if
(
!
(
kvd
=
(
long
*
)
xdl_malloc
((
2
*
ndiags
+
2
)
*
sizeof
(
long
))))
{
if
(
!
(
kvd
=
(
long
*
)
xdl_malloc
(
allocsize
)))
{
xdl_free_env
(
xe
);
return
-
1
;
}
...
...
@@ -410,19 +390,16 @@ static xdchange_t *xdl_add_change(xdchange_t *xscr, long i1, long i2, long chg1,
}
static
int
recs_match
(
xrecord_t
*
rec1
,
xrecord_t
*
rec2
,
long
flags
)
static
int
recs_match
(
xrecord_t
*
rec1
,
xrecord_t
*
rec2
)
{
return
(
rec1
->
ha
==
rec2
->
ha
&&
xdl_recmatch
(
rec1
->
ptr
,
rec1
->
size
,
rec2
->
ptr
,
rec2
->
size
,
flags
));
return
(
rec1
->
ha
==
rec2
->
ha
);
}
/*
* If a line is indented more than this, get_indent() just returns this value.
* This avoids having to do absurd amounts of work for data that are not
* human-readable text, and also ensures that the output of get_indent fits
within
* an int.
* human-readable text, and also ensures that the output of get_indent fits
*
within
an int.
*/
#define MAX_INDENT 200
...
...
@@ -456,9 +433,9 @@ static int get_indent(xrecord_t *rec)
}
/*
* If more than this number of consecutive blank rows are found, just return
this
*
value. This avoids requiring O(N^2) work for pathological cases, and also
* ensures that the output of score_split fits in an int.
* If more than this number of consecutive blank rows are found, just return
*
this value. This avoids requiring O(N^2) work for pathological cases, and
*
also
ensures that the output of score_split fits in an int.
*/
#define MAX_BLANKS 20
...
...
@@ -470,8 +447,8 @@ struct split_measurement {
int
end_of_file
;
/*
* How much is the line immediately following the split indented (or -1
if
* the line is blank):
* How much is the line immediately following the split indented (or -1
*
if
the line is blank):
*/
int
indent
;
...
...
@@ -481,8 +458,8 @@ struct split_measurement {
int
pre_blank
;
/*
* How much is the nearest non-blank line above the split indented (or
-1
* if there is no such line)?
* How much is the nearest non-blank line above the split indented (or
*
-1
if there is no such line)?
*/
int
pre_indent
;
...
...
@@ -602,14 +579,19 @@ static void measure_split(const xdfile_t *xdf, long split,
#define INDENT_WEIGHT 60
/*
* How far do we slide a hunk at most?
*/
#define INDENT_HEURISTIC_MAX_SLIDING 100
/*
* Compute a badness score for the hypothetical split whose measurements are
* stored in m. The weight factors were determined empirically using the tools
and
* corpus described in
* stored in m. The weight factors were determined empirically using the tools
*
and
corpus described in
*
* https://github.com/mhagger/diff-slider-tools
*
* Also see that project if you want to improve the weights based on, for
example,
* a larger or more diverse corpus.
* Also see that project if you want to improve the weights based on, for
*
example,
a larger or more diverse corpus.
*/
static
void
score_add_split
(
const
struct
split_measurement
*
m
,
struct
split_score
*
s
)
{
...
...
@@ -741,7 +723,7 @@ static void group_init(xdfile_t *xdf, struct xdlgroup *g)
* Move g to describe the next (possibly empty) group in xdf and return 0. If g
* is already at the end of the file, do nothing and return -1.
*/
XDL_INLINE
(
int
)
group_next
(
xdfile_t
*
xdf
,
struct
xdlgroup
*
g
)
static
inline
int
group_next
(
xdfile_t
*
xdf
,
struct
xdlgroup
*
g
)
{
if
(
g
->
end
==
xdf
->
nrec
)
return
-
1
;
...
...
@@ -757,7 +739,7 @@ XDL_INLINE(int) group_next(xdfile_t *xdf, struct xdlgroup *g)
* Move g to describe the previous (possibly empty) group in xdf and return 0.
* If g is already at the beginning of the file, do nothing and return -1.
*/
XDL_INLINE
(
int
)
group_previous
(
xdfile_t
*
xdf
,
struct
xdlgroup
*
g
)
static
inline
int
group_previous
(
xdfile_t
*
xdf
,
struct
xdlgroup
*
g
)
{
if
(
g
->
start
==
0
)
return
-
1
;
...
...
@@ -774,10 +756,10 @@ XDL_INLINE(int) group_previous(xdfile_t *xdf, struct xdlgroup *g)
* following group, expand this group to include it. Return 0 on success or -1
* if g cannot be slid down.
*/
static
int
group_slide_down
(
xdfile_t
*
xdf
,
struct
xdlgroup
*
g
,
long
flags
)
static
int
group_slide_down
(
xdfile_t
*
xdf
,
struct
xdlgroup
*
g
)
{
if
(
g
->
end
<
xdf
->
nrec
&&
recs_match
(
xdf
->
recs
[
g
->
start
],
xdf
->
recs
[
g
->
end
]
,
flags
))
{
recs_match
(
xdf
->
recs
[
g
->
start
],
xdf
->
recs
[
g
->
end
]))
{
xdf
->
rchg
[
g
->
start
++
]
=
0
;
xdf
->
rchg
[
g
->
end
++
]
=
1
;
...
...
@@ -795,10 +777,10 @@ static int group_slide_down(xdfile_t *xdf, struct xdlgroup *g, long flags)
* into a previous group, expand this group to include it. Return 0 on success
* or -1 if g cannot be slid up.
*/
static
int
group_slide_up
(
xdfile_t
*
xdf
,
struct
xdlgroup
*
g
,
long
flags
)
static
int
group_slide_up
(
xdfile_t
*
xdf
,
struct
xdlgroup
*
g
)
{
if
(
g
->
start
>
0
&&
recs_match
(
xdf
->
recs
[
g
->
start
-
1
],
xdf
->
recs
[
g
->
end
-
1
]
,
flags
))
{
recs_match
(
xdf
->
recs
[
g
->
start
-
1
],
xdf
->
recs
[
g
->
end
-
1
]))
{
xdf
->
rchg
[
--
g
->
start
]
=
1
;
xdf
->
rchg
[
--
g
->
end
]
=
0
;
...
...
@@ -811,12 +793,6 @@ static int group_slide_up(xdfile_t *xdf, struct xdlgroup *g, long flags)
}
}
static
void
xdl_bug
(
const
char
*
msg
)
{
fprintf
(
stderr
,
"BUG: %s
\n
"
,
msg
);
exit
(
1
);
}
/*
* Move back and forward change groups for a consistent and pretty diff output.
* This also helps in finding joinable change groups and reducing the diff
...
...
@@ -831,13 +807,16 @@ int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) {
group_init
(
xdfo
,
&
go
);
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
)
goto
next
;
/*
* 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
{
groupsize
=
g
.
end
-
g
.
start
;
...
...
@@ -851,9 +830,9 @@ int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) {
end_matching_other
=
-
1
;
/* Shift the group backward as much as possible: */
while
(
!
group_slide_up
(
xdf
,
&
g
,
flags
))
while
(
!
group_slide_up
(
xdf
,
&
g
))
if
(
group_previous
(
xdfo
,
&
go
))
xdl_bug
(
"group sync broken sliding up"
);
XDL_BUG
(
"group sync broken sliding up"
);
/*
* This is this highest that this group can be shifted.
...
...
@@ -866,10 +845,10 @@ int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) {
/* Now shift the group forward as far as possible: */
while
(
1
)
{
if
(
group_slide_down
(
xdf
,
&
g
,
flags
))
if
(
group_slide_down
(
xdf
,
&
g
))
break
;
if
(
group_next
(
xdfo
,
&
go
))
xdl_bug
(
"group sync broken sliding down"
);
XDL_BUG
(
"group sync broken sliding down"
);
if
(
go
.
end
>
go
.
start
)
end_matching_other
=
g
.
end
;
...
...
@@ -880,40 +859,46 @@ int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) {
* If the group can be shifted, then we can possibly use this
* freedom to produce a more intuitive diff.
*
* The group is currently shifted as far down as possible, so
the
* heuristics below only have to handle upwards shifts.
* The group is currently shifted as far down as possible, so
*
the
heuristics below only have to handle upwards shifts.
*/
if
(
g
.
end
==
earliest_end
)
{
/* no shifting was possible */
}
else
if
(
end_matching_other
!=
-
1
)
{
/*
* Move the possibly merged group of changes back to
line
*
up with the last group of changes from the other fil
e
* that it can align with.
* Move the possibly merged group of changes back to
*
line up with the last group of changes from th
e
*
other file
that it can align with.
*/
while
(
go
.
end
==
go
.
start
)
{
if
(
group_slide_up
(
xdf
,
&
g
,
flags
))
xdl_bug
(
"match disappeared"
);
if
(
group_slide_up
(
xdf
,
&
g
))
XDL_BUG
(
"match disappeared"
);
if
(
group_previous
(
xdfo
,
&
go
))
xdl_bug
(
"group sync broken sliding to match"
);
XDL_BUG
(
"group sync broken sliding to match"
);
}
}
else
if
(
flags
&
XDF_INDENT_HEURISTIC
)
{
/*
* Indent heuristic: a group of pure add/delete lines
* implies two splits, one between the end of the "before"
* context and the start of the group, and another between
* the end of the group and the beginning of the "after"
* context. Some splits are aesthetically better and some
* are worse. We compute a badness "score" for each split,
* and add the scores for the two splits to define a
* "score" for each position that the group can be shifted
* to. Then we pick the shift with the lowest score.
* implies two splits, one between the end of the
* "before" context and the start of the group, and
* another between the end of the group and the
* beginning of the "after" context. Some splits are
* aesthetically better and some are worse. We compute
* a badness "score" for each split, and add the scores
* for the two splits to define a "score" for each
* position that the group can be shifted to. Then we
* pick the shift with the lowest score.
*/
long
shift
,
best_shift
=
-
1
;
struct
split_score
best_score
;
for
(
shift
=
earliest_end
;
shift
<=
g
.
end
;
shift
++
)
{
shift
=
earliest_end
;
if
(
g
.
end
-
groupsize
-
1
>
shift
)
shift
=
g
.
end
-
groupsize
-
1
;
if
(
g
.
end
-
INDENT_HEURISTIC_MAX_SLIDING
>
shift
)
shift
=
g
.
end
-
INDENT_HEURISTIC_MAX_SLIDING
;
for
(;
shift
<=
g
.
end
;
shift
++
)
{
struct
split_measurement
m
;
struct
split_score
score
=
{
0
,
0
};
...
...
@@ -930,10 +915,10 @@ int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) {
}
while
(
g
.
end
>
best_shift
)
{
if
(
group_slide_up
(
xdf
,
&
g
,
flags
))
xdl_bug
(
"best shift unreached"
);
if
(
group_slide_up
(
xdf
,
&
g
))
XDL_BUG
(
"best shift unreached"
);
if
(
group_previous
(
xdfo
,
&
go
))
xdl_bug
(
"group sync broken sliding to blank line"
);
XDL_BUG
(
"group sync broken sliding to blank line"
);
}
}
...
...
@@ -942,11 +927,11 @@ int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) {
if
(
group_next
(
xdf
,
&
g
))
break
;
if
(
group_next
(
xdfo
,
&
go
))
xdl_bug
(
"group sync broken moving to next group"
);
XDL_BUG
(
"group sync broken moving to next group"
);
}
if
(
!
group_next
(
xdfo
,
&
go
))
xdl_bug
(
"group sync broken at end of file"
);
XDL_BUG
(
"group sync broken at end of file"
);
return
0
;
}
...
...
@@ -992,8 +977,6 @@ static int xdl_call_hunk_func(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
{
xdchange_t
*
xch
,
*
xche
;
(
void
)
xe
;
for
(
xch
=
xscr
;
xch
;
xch
=
xche
->
next
)
{
xche
=
xdl_get_hunk
(
&
xch
,
xecfg
);
if
(
!
xch
)
...
...
@@ -1006,7 +989,7 @@ static int xdl_call_hunk_func(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
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
;
...
...
@@ -1027,6 +1010,46 @@ static void xdl_mark_ignorable(xdchange_t *xscr, xdfenv_t *xe, long flags)
}
}
static
int
record_matches_regex
(
xrecord_t
*
rec
,
xpparam_t
const
*
xpp
)
{
xdl_regmatch_t
regmatch
;
int
i
;
for
(
i
=
0
;
i
<
xpp
->
ignore_regex_nr
;
i
++
)
if
(
!
xdl_regexec_buf
(
xpp
->
ignore_regex
[
i
],
rec
->
ptr
,
rec
->
size
,
1
,
&
regmatch
,
0
))
return
1
;
return
0
;
}
static
void
xdl_mark_ignorable_regex
(
xdchange_t
*
xscr
,
const
xdfenv_t
*
xe
,
xpparam_t
const
*
xpp
)
{
xdchange_t
*
xch
;
for
(
xch
=
xscr
;
xch
;
xch
=
xch
->
next
)
{
xrecord_t
**
rec
;
int
ignore
=
1
;
long
i
;
/*
* Do not override --ignore-blank-lines.
*/
if
(
xch
->
ignore
)
continue
;
rec
=
&
xe
->
xdf1
.
recs
[
xch
->
i1
];
for
(
i
=
0
;
i
<
xch
->
chg1
&&
ignore
;
i
++
)
ignore
=
record_matches_regex
(
rec
[
i
],
xpp
);
rec
=
&
xe
->
xdf2
.
recs
[
xch
->
i2
];
for
(
i
=
0
;
i
<
xch
->
chg2
&&
ignore
;
i
++
)
ignore
=
record_matches_regex
(
rec
[
i
],
xpp
);
xch
->
ignore
=
ignore
;
}
}
int
xdl_diff
(
mmfile_t
*
mf1
,
mmfile_t
*
mf2
,
xpparam_t
const
*
xpp
,
xdemitconf_t
const
*
xecfg
,
xdemitcb_t
*
ecb
)
{
xdchange_t
*
xscr
;
...
...
@@ -1046,7 +1069,10 @@ int xdl_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
}
if
(
xscr
)
{
if
(
xpp
->
flags
&
XDF_IGNORE_BLANK_LINES
)
xdl_mark_ignorable
(
xscr
,
&
xe
,
xpp
->
flags
);
xdl_mark_ignorable_lines
(
xscr
,
&
xe
,
xpp
->
flags
);
if
(
xpp
->
ignore_regex
)
xdl_mark_ignorable_regex
(
xscr
,
&
xe
,
xpp
);
if
(
ef
(
&
xe
,
xscr
,
ecb
,
xecfg
)
<
0
)
{
...
...
src/xdiff/xemit.c
View file @
18a477e7
...
...
@@ -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
)
{
long
size
,
psize
=
(
long
)
strlen
(
pre
);
long
size
,
psize
=
strlen
(
pre
);
char
const
*
rec
;
size
=
xdl_get_rec
(
xdf
,
ri
,
&
rec
);
...
...
@@ -81,7 +81,7 @@ xdchange_t *xdl_get_hunk(xdchange_t **xscr, xdemitconf_t const *xecfg)
}
else
if
(
distance
<
max_ignorable
&&
xch
->
ignore
)
{
ignored
+=
xch
->
chg2
;
}
else
if
(
lxch
!=
xchp
&&
xch
->
i1
+
ignored
-
(
lxch
->
i1
+
lxch
->
chg1
)
>
(
unsigned
long
)
max_common
)
{
xch
->
i1
+
ignored
-
(
lxch
->
i1
+
lxch
->
chg1
)
>
max_common
)
{
break
;
}
else
if
(
!
xch
->
ignore
)
{
lxch
=
xch
;
...
...
@@ -97,8 +97,6 @@ xdchange_t *xdl_get_hunk(xdchange_t **xscr, xdemitconf_t const *xecfg)
static
long
def_ff
(
const
char
*
rec
,
long
len
,
char
*
buf
,
long
sz
,
void
*
priv
)
{
(
void
)
priv
;
if
(
len
>
0
&&
(
isalpha
((
unsigned
char
)
*
rec
)
||
/* identifier? */
*
rec
==
'_'
||
/* also identifier? */
...
...
@@ -174,10 +172,12 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
struct
func_line
func_line
=
{
0
};
for
(
xch
=
xscr
;
xch
;
xch
=
xche
->
next
)
{
xdchange_t
*
xchp
=
xch
;
xche
=
xdl_get_hunk
(
&
xch
,
xecfg
);
if
(
!
xch
)
break
;
pre_context_calculation:
s1
=
XDL_MAX
(
xch
->
i1
-
xecfg
->
ctxlen
,
0
);
s2
=
XDL_MAX
(
xch
->
i2
-
xecfg
->
ctxlen
,
0
);
...
...
@@ -212,8 +212,23 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
if
(
fs1
<
0
)
fs1
=
0
;
if
(
fs1
<
s1
)
{
s2
-=
s1
-
fs1
;
s2
=
XDL_MAX
(
s2
-
(
s1
-
fs1
),
0
)
;
s1
=
fs1
;
/*
* Did we extend context upwards into an
* ignored change?
*/
while
(
xchp
!=
xch
&&
xchp
->
i1
+
xchp
->
chg1
<=
s1
&&
xchp
->
i2
+
xchp
->
chg2
<=
s2
)
xchp
=
xchp
->
next
;
/* If so, show it after all. */
if
(
xchp
!=
xch
)
{
xch
=
xchp
;
goto
pre_context_calculation
;
}
}
}
...
...
@@ -234,7 +249,7 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
if
(
fe1
<
0
)
fe1
=
xe
->
xdf1
.
nrec
;
if
(
fe1
>
e1
)
{
e2
+=
fe1
-
e1
;
e2
=
XDL_MIN
(
e2
+
(
fe1
-
e1
),
xe
->
xdf2
.
nrec
)
;
e1
=
fe1
;
}
...
...
@@ -263,7 +278,8 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
s1
-
1
,
funclineprev
);
funclineprev
=
s1
-
1
;
}
if
(
xdl_emit_hunk_hdr
(
s1
+
1
,
e1
-
s1
,
s2
+
1
,
e2
-
s2
,
if
(
!
(
xecfg
->
flags
&
XDL_EMIT_NO_HUNK_HDR
)
&&
xdl_emit_hunk_hdr
(
s1
+
1
,
e1
-
s1
,
s2
+
1
,
e2
-
s2
,
func_line
.
buf
,
func_line
.
len
,
ecb
)
<
0
)
return
-
1
;
...
...
src/xdiff/xhistogram.c
View file @
18a477e7
...
...
@@ -42,8 +42,6 @@
*/
#include "xinclude.h"
#include "xtypes.h"
#include "xdiff.h"
#define MAX_PTR UINT_MAX
#define MAX_CNT UINT_MAX
...
...
@@ -90,27 +88,21 @@ struct region {
#define REC(env, s, l) \
(env->xdf##s.recs[l - 1])
static
int
cmp_recs
(
xpparam_t
const
*
xpp
,
xrecord_t
*
r1
,
xrecord_t
*
r2
)
static
int
cmp_recs
(
xrecord_t
*
r1
,
xrecord_t
*
r2
)
{
return
r1
->
ha
==
r2
->
ha
&&
xdl_recmatch
(
r1
->
ptr
,
r1
->
size
,
r2
->
ptr
,
r2
->
size
,
xpp
->
flags
);
}
return
r1
->
ha
==
r2
->
ha
;
#define CMP_ENV(xpp, env, s1, l1, s2, l2) \
(cmp_recs(xpp, REC(env, s1, l1), REC(env, s2, l2)))
}
#define CMP(i, s1, l1, s2, l2) \
(cmp_recs(
i->xpp,
REC(i->env, s1, l1), REC(i->env, s2, l2)))
(cmp_recs(REC(i->env, s1, l1), REC(i->env, s2, l2)))
#define TABLE_HASH(index, side, line) \
XDL_HASHLONG((REC(index->env, side, line))->ha, index->table_bits)
static
int
scanA
(
struct
histindex
*
index
,
unsigned
int
line1
,
unsigned
int
count1
)
static
int
scanA
(
struct
histindex
*
index
,
int
line1
,
int
count1
)
{
unsigned
int
ptr
;
unsigned
int
tbl_idx
;
unsigned
int
ptr
,
tbl_idx
;
unsigned
int
chain_len
;
struct
record
**
rec_chain
,
*
rec
;
...
...
@@ -161,10 +153,8 @@ continue_scan:
return
0
;
}
static
int
try_lcs
(
struct
histindex
*
index
,
struct
region
*
lcs
,
unsigned
int
b_ptr
,
unsigned
int
line1
,
unsigned
int
count1
,
unsigned
int
line2
,
unsigned
int
count2
)
static
int
try_lcs
(
struct
histindex
*
index
,
struct
region
*
lcs
,
int
b_ptr
,
int
line1
,
int
count1
,
int
line2
,
int
count2
)
{
unsigned
int
b_next
=
b_ptr
+
1
;
struct
record
*
rec
=
index
->
records
[
TABLE_HASH
(
index
,
2
,
b_ptr
)];
...
...
@@ -236,59 +226,33 @@ static int try_lcs(
return
b_next
;
}
static
int
find_lcs
(
struct
histindex
*
index
,
struct
region
*
lcs
,
unsigned
int
line1
,
unsigned
int
count1
,
unsigned
int
line2
,
unsigned
int
count2
)
static
int
fall_back_to_classic_diff
(
xpparam_t
const
*
xpp
,
xdfenv_t
*
env
,
int
line1
,
int
count1
,
int
line2
,
int
count2
)
{
unsigned
int
b_ptr
;
if
(
scanA
(
index
,
line1
,
count1
))
return
-
1
;
index
->
cnt
=
index
->
max_chain_length
+
1
;
xpparam_t
xpparam
;
for
(
b_ptr
=
line2
;
b_ptr
<=
LINE_END
(
2
);
)
b_ptr
=
try_lcs
(
index
,
lcs
,
b_ptr
,
line1
,
count1
,
line2
,
count2
)
;
memset
(
&
xpparam
,
0
,
sizeof
(
xpparam
));
xpparam
.
flags
=
xpp
->
flags
&
~
XDF_DIFF_ALGORITHM_MASK
;
return
index
->
has_common
&&
index
->
max_chain_length
<
index
->
cnt
;
return
xdl_fall_back_diff
(
env
,
&
xpparam
,
line1
,
count1
,
line2
,
count2
);
}
static
int
fall_back_to_classic_diff
(
struct
histindex
*
index
,
int
line1
,
int
count1
,
int
line2
,
int
count2
)
static
inline
void
free_index
(
struct
histindex
*
index
)
{
xpparam_t
xpp
;
xpp
.
flags
=
index
->
xpp
->
flags
&
~
XDF_DIFF_ALGORITHM_MASK
;
return
xdl_fall_back_diff
(
index
->
env
,
&
xpp
,
line1
,
count1
,
line2
,
count2
);
xdl_free
(
index
->
records
);
xdl_free
(
index
->
line_map
);
xdl_free
(
index
->
next_ptrs
);
xdl_cha_free
(
&
index
->
rcha
);
}
static
int
histogram_diff
(
xpparam_t
const
*
xpp
,
xdfenv_t
*
env
,
unsigned
int
line1
,
unsigned
int
count1
,
unsigned
int
line2
,
unsigned
int
count2
)
static
int
find_lcs
(
xpparam_t
const
*
xpp
,
xdfenv_t
*
env
,
struct
region
*
lcs
,
int
line1
,
int
count1
,
int
line2
,
int
count2
)
{
int
b_ptr
;
int
sz
,
ret
=
-
1
;
struct
histindex
index
;
struct
region
lcs
;
size_t
sz
;
int
result
=
-
1
;
if
(
count1
<=
0
&&
count2
<=
0
)
return
0
;
if
(
LINE_END
(
1
)
>=
MAX_PTR
)
return
-
1
;
if
(
!
count1
)
{
while
(
count2
--
)
env
->
xdf2
.
rchg
[
line2
++
-
1
]
=
1
;
return
0
;
}
else
if
(
!
count2
)
{
while
(
count1
--
)
env
->
xdf1
.
rchg
[
line1
++
-
1
]
=
1
;
return
0
;
}
memset
(
&
index
,
0
,
sizeof
(
index
));
...
...
@@ -302,8 +266,7 @@ static int histogram_diff(
index
.
table_bits
=
xdl_hashbits
(
count1
);
sz
=
index
.
records_size
=
1
<<
index
.
table_bits
;
GIT_ERROR_CHECK_ALLOC_MULTIPLY
(
&
sz
,
sz
,
sizeof
(
struct
record
*
));
sz
*=
sizeof
(
struct
record
*
);
if
(
!
(
index
.
records
=
(
struct
record
**
)
xdl_malloc
(
sz
)))
goto
cleanup
;
memset
(
index
.
records
,
0
,
sz
);
...
...
@@ -327,9 +290,55 @@ static int histogram_diff(
index
.
ptr_shift
=
line1
;
index
.
max_chain_length
=
64
;
if
(
scanA
(
&
index
,
line1
,
count1
))
goto
cleanup
;
index
.
cnt
=
index
.
max_chain_length
+
1
;
for
(
b_ptr
=
line2
;
b_ptr
<=
LINE_END
(
2
);
)
b_ptr
=
try_lcs
(
&
index
,
lcs
,
b_ptr
,
line1
,
count1
,
line2
,
count2
);
if
(
index
.
has_common
&&
index
.
max_chain_length
<
index
.
cnt
)
ret
=
1
;
else
ret
=
0
;
cleanup:
free_index
(
&
index
);
return
ret
;
}
static
int
histogram_diff
(
xpparam_t
const
*
xpp
,
xdfenv_t
*
env
,
int
line1
,
int
count1
,
int
line2
,
int
count2
)
{
struct
region
lcs
;
int
lcs_found
;
int
result
;
redo:
result
=
-
1
;
if
(
count1
<=
0
&&
count2
<=
0
)
return
0
;
if
(
LINE_END
(
1
)
>=
MAX_PTR
)
return
-
1
;
if
(
!
count1
)
{
while
(
count2
--
)
env
->
xdf2
.
rchg
[
line2
++
-
1
]
=
1
;
return
0
;
}
else
if
(
!
count2
)
{
while
(
count1
--
)
env
->
xdf1
.
rchg
[
line1
++
-
1
]
=
1
;
return
0
;
}
memset
(
&
lcs
,
0
,
sizeof
(
lcs
));
if
(
find_lcs
(
&
index
,
&
lcs
,
line1
,
count1
,
line2
,
count2
))
result
=
fall_back_to_classic_diff
(
&
index
,
line1
,
count1
,
line2
,
count2
);
lcs_found
=
find_lcs
(
xpp
,
env
,
&
lcs
,
line1
,
count1
,
line2
,
count2
);
if
(
lcs_found
<
0
)
goto
out
;
else
if
(
lcs_found
)
result
=
fall_back_to_classic_diff
(
xpp
,
env
,
line1
,
count1
,
line2
,
count2
);
else
{
if
(
lcs
.
begin1
==
0
&&
lcs
.
begin2
==
0
)
{
while
(
count1
--
)
...
...
@@ -342,21 +351,21 @@ static int histogram_diff(
line1
,
lcs
.
begin1
-
line1
,
line2
,
lcs
.
begin2
-
line2
);
if
(
result
)
goto
cleanup
;
result
=
histogram_diff
(
xpp
,
env
,
lcs
.
end1
+
1
,
LINE_END
(
1
)
-
lcs
.
end1
,
lcs
.
end2
+
1
,
LINE_END
(
2
)
-
lcs
.
end2
);
if
(
result
)
goto
cleanup
;
goto
out
;
/*
* result = histogram_diff(xpp, env,
* lcs.end1 + 1, LINE_END(1) - lcs.end1,
* lcs.end2 + 1, LINE_END(2) - lcs.end2);
* but let's optimize tail recursion ourself:
*/
count1
=
LINE_END
(
1
)
-
lcs
.
end1
;
line1
=
lcs
.
end1
+
1
;
count2
=
LINE_END
(
2
)
-
lcs
.
end2
;
line2
=
lcs
.
end2
+
1
;
goto
redo
;
}
}
cleanup:
xdl_free
(
index
.
records
);
xdl_free
(
index
.
line_map
);
xdl_free
(
index
.
next_ptrs
);
xdl_cha_free
(
&
index
.
rcha
);
out:
return
result
;
}
...
...
src/xdiff/xinclude.h
View file @
18a477e7
...
...
@@ -23,17 +23,7 @@
#if !defined(XINCLUDE_H)
#define XINCLUDE_H
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#ifdef _WIN32
#else
#include <unistd.h>
#endif
#include "git-xdiff.h"
#include "xmacros.h"
#include "xdiff.h"
#include "xtypes.h"
...
...
@@ -42,6 +32,5 @@
#include "xdiffi.h"
#include "xemit.h"
#include "common.h"
#endif
/* #if !defined(XINCLUDE_H) */
src/xdiff/xmerge.c
View file @
18a477e7
...
...
@@ -109,53 +109,44 @@ static int xdl_merge_cmp_lines(xdfenv_t *xe1, int i1, xdfenv_t *xe2, int i2,
return
0
;
}
static
int
xdl_recs_copy_0
(
size_t
*
out
,
int
use_orig
,
xdfenv_t
*
xe
,
int
i
,
int
count
,
int
needs_cr
,
int
add_nl
,
char
*
dest
)
static
int
xdl_recs_copy_0
(
int
use_orig
,
xdfenv_t
*
xe
,
int
i
,
int
count
,
int
needs_cr
,
int
add_nl
,
char
*
dest
)
{
xrecord_t
**
recs
;
size_t
size
=
0
;
*
out
=
0
;
int
size
=
0
;
recs
=
(
use_orig
?
xe
->
xdf1
.
recs
:
xe
->
xdf2
.
recs
)
+
i
;
if
(
count
<
1
)
return
0
;
for
(
i
=
0
;
i
<
count
;
)
{
for
(
i
=
0
;
i
<
count
;
size
+=
recs
[
i
++
]
->
size
)
if
(
dest
)
memcpy
(
dest
+
size
,
recs
[
i
]
->
ptr
,
recs
[
i
]
->
size
);
GIT_ERROR_CHECK_ALLOC_ADD
(
&
size
,
size
,
recs
[
i
++
]
->
size
);
}
if
(
add_nl
)
{
i
=
recs
[
count
-
1
]
->
size
;
if
(
i
==
0
||
recs
[
count
-
1
]
->
ptr
[
i
-
1
]
!=
'\n'
)
{
if
(
needs_cr
)
{
if
(
dest
)
dest
[
size
]
=
'\r'
;
GIT_ERROR_CHECK_ALLOC_ADD
(
&
size
,
size
,
1
)
;
size
++
;
}
if
(
dest
)
dest
[
size
]
=
'\n'
;
GIT_ERROR_CHECK_ALLOC_ADD
(
&
size
,
size
,
1
);
size
++
;
}
}
*
out
=
size
;
return
0
;
return
size
;
}
static
int
xdl_recs_copy
(
size_t
*
out
,
xdfenv_t
*
xe
,
int
i
,
int
count
,
int
needs_cr
,
int
add_nl
,
char
*
dest
)
static
int
xdl_recs_copy
(
xdfenv_t
*
xe
,
int
i
,
int
count
,
int
needs_cr
,
int
add_nl
,
char
*
dest
)
{
return
xdl_recs_copy_0
(
out
,
0
,
xe
,
i
,
count
,
needs_cr
,
add_nl
,
dest
);
return
xdl_recs_copy_0
(
0
,
xe
,
i
,
count
,
needs_cr
,
add_nl
,
dest
);
}
static
int
xdl_orig_copy
(
size_t
*
out
,
xdfenv_t
*
xe
,
int
i
,
int
count
,
int
needs_cr
,
int
add_nl
,
char
*
dest
)
static
int
xdl_orig_copy
(
xdfenv_t
*
xe
,
int
i
,
int
count
,
int
needs_cr
,
int
add_nl
,
char
*
dest
)
{
return
xdl_recs_copy_0
(
out
,
1
,
xe
,
i
,
count
,
needs_cr
,
add_nl
,
dest
);
return
xdl_recs_copy_0
(
1
,
xe
,
i
,
count
,
needs_cr
,
add_nl
,
dest
);
}
/*
...
...
@@ -202,32 +193,26 @@ static int is_cr_needed(xdfenv_t *xe1, xdfenv_t *xe2, xdmerge_t *m)
return
needs_cr
<
0
?
0
:
needs_cr
;
}
static
int
fill_conflict_hunk
(
size_t
*
out
,
xdfenv_t
*
xe1
,
const
char
*
name1
,
static
int
fill_conflict_hunk
(
xdfenv_t
*
xe1
,
const
char
*
name1
,
xdfenv_t
*
xe2
,
const
char
*
name2
,
const
char
*
name3
,
size_
t
size
,
int
i
,
int
style
,
in
t
size
,
int
i
,
int
style
,
xdmerge_t
*
m
,
char
*
dest
,
int
marker_size
)
{
int
marker1_size
=
(
name1
?
(
int
)
strlen
(
name1
)
+
1
:
0
);
int
marker2_size
=
(
name2
?
(
int
)
strlen
(
name2
)
+
1
:
0
);
int
marker3_size
=
(
name3
?
(
int
)
strlen
(
name3
)
+
1
:
0
);
int
marker1_size
=
(
name1
?
strlen
(
name1
)
+
1
:
0
);
int
marker2_size
=
(
name2
?
strlen
(
name2
)
+
1
:
0
);
int
marker3_size
=
(
name3
?
strlen
(
name3
)
+
1
:
0
);
int
needs_cr
=
is_cr_needed
(
xe1
,
xe2
,
m
);
size_t
copied
;
*
out
=
0
;
if
(
marker_size
<=
0
)
marker_size
=
DEFAULT_CONFLICT_MARKER_SIZE
;
/* Before conflicting part */
if
(
xdl_recs_copy
(
&
copied
,
xe1
,
i
,
m
->
i1
-
i
,
0
,
0
,
dest
?
dest
+
size
:
NULL
)
<
0
)
return
-
1
;
GIT_ERROR_CHECK_ALLOC_ADD
(
&
size
,
size
,
copied
);
size
+=
xdl_recs_copy
(
xe1
,
i
,
m
->
i1
-
i
,
0
,
0
,
dest
?
dest
+
size
:
NULL
);
if
(
!
dest
)
{
GIT_ERROR_CHECK_ALLOC_ADD5
(
&
size
,
size
,
marker_size
,
1
,
needs_cr
,
marker1_size
)
;
size
+=
marker_size
+
1
+
needs_cr
+
marker1_size
;
}
else
{
memset
(
dest
+
size
,
'<'
,
marker_size
);
size
+=
marker_size
;
...
...
@@ -242,16 +227,13 @@ static int fill_conflict_hunk(size_t *out, xdfenv_t *xe1, const char *name1,
}
/* Postimage from side #1 */
if
(
xdl_recs_copy
(
&
copied
,
xe1
,
m
->
i1
,
m
->
chg1
,
needs_cr
,
1
,
dest
?
dest
+
size
:
NULL
)
<
0
)
return
-
1
;
size
+=
xdl_recs_copy
(
xe1
,
m
->
i1
,
m
->
chg1
,
needs_cr
,
1
,
dest
?
dest
+
size
:
NULL
);
GIT_ERROR_CHECK_ALLOC_ADD
(
&
size
,
size
,
copied
);
if
(
style
==
XDL_MERGE_DIFF3
)
{
if
(
style
==
XDL_MERGE_DIFF3
||
style
==
XDL_MERGE_ZEALOUS_DIFF3
)
{
/* Shared preimage */
if
(
!
dest
)
{
GIT_ERROR_CHECK_ALLOC_ADD5
(
&
size
,
size
,
marker_size
,
1
,
needs_cr
,
marker3_size
)
;
size
+=
marker_size
+
1
+
needs_cr
+
marker3_size
;
}
else
{
memset
(
dest
+
size
,
'|'
,
marker_size
);
size
+=
marker_size
;
...
...
@@ -264,15 +246,12 @@ static int fill_conflict_hunk(size_t *out, xdfenv_t *xe1, const char *name1,
dest
[
size
++
]
=
'\r'
;
dest
[
size
++
]
=
'\n'
;
}
if
(
xdl_orig_copy
(
&
copied
,
xe1
,
m
->
i0
,
m
->
chg0
,
needs_cr
,
1
,
dest
?
dest
+
size
:
NULL
)
<
0
)
return
-
1
;
GIT_ERROR_CHECK_ALLOC_ADD
(
&
size
,
size
,
copied
);
size
+=
xdl_orig_copy
(
xe1
,
m
->
i0
,
m
->
chg0
,
needs_cr
,
1
,
dest
?
dest
+
size
:
NULL
);
}
if
(
!
dest
)
{
GIT_ERROR_CHECK_ALLOC_ADD4
(
&
size
,
size
,
marker_size
,
1
,
needs_cr
)
;
size
+=
marker_size
+
1
+
needs_cr
;
}
else
{
memset
(
dest
+
size
,
'='
,
marker_size
);
size
+=
marker_size
;
...
...
@@ -282,14 +261,10 @@ static int fill_conflict_hunk(size_t *out, xdfenv_t *xe1, const char *name1,
}
/* Postimage from side #2 */
if
(
xdl_recs_copy
(
&
copied
,
xe2
,
m
->
i2
,
m
->
chg2
,
needs_cr
,
1
,
dest
?
dest
+
size
:
NULL
)
<
0
)
return
-
1
;
GIT_ERROR_CHECK_ALLOC_ADD
(
&
size
,
size
,
copied
);
size
+=
xdl_recs_copy
(
xe2
,
m
->
i2
,
m
->
chg2
,
needs_cr
,
1
,
dest
?
dest
+
size
:
NULL
);
if
(
!
dest
)
{
GIT_ERROR_CHECK_ALLOC_ADD5
(
&
size
,
size
,
marker_size
,
1
,
needs_cr
,
marker2_size
)
;
size
+=
marker_size
+
1
+
needs_cr
+
marker2_size
;
}
else
{
memset
(
dest
+
size
,
'>'
,
marker_size
);
size
+=
marker_size
;
...
...
@@ -302,71 +277,83 @@ static int fill_conflict_hunk(size_t *out, xdfenv_t *xe1, const char *name1,
dest
[
size
++
]
=
'\r'
;
dest
[
size
++
]
=
'\n'
;
}
*
out
=
size
;
return
0
;
return
size
;
}
static
int
xdl_fill_merge_buffer
(
size_t
*
out
,
xdfenv_t
*
xe1
,
const
char
*
name1
,
static
int
xdl_fill_merge_buffer
(
xdfenv_t
*
xe1
,
const
char
*
name1
,
xdfenv_t
*
xe2
,
const
char
*
name2
,
const
char
*
ancestor_name
,
int
favor
,
xdmerge_t
*
m
,
char
*
dest
,
int
style
,
int
marker_size
)
{
size_t
size
,
copied
;
int
i
;
*
out
=
0
;
int
size
,
i
;
for
(
size
=
i
=
0
;
m
;
m
=
m
->
next
)
{
if
(
favor
&&
!
m
->
mode
)
m
->
mode
=
favor
;
if
(
m
->
mode
==
0
)
{
if
(
fill_conflict_hunk
(
&
size
,
xe1
,
name1
,
xe2
,
name2
,
if
(
m
->
mode
==
0
)
size
=
fill_conflict_hunk
(
xe1
,
name1
,
xe2
,
name2
,
ancestor_name
,
size
,
i
,
style
,
m
,
dest
,
marker_size
)
<
0
)
return
-
1
;
}
marker_size
);
else
if
(
m
->
mode
&
3
)
{
/* Before conflicting part */
if
(
xdl_recs_copy
(
&
copied
,
xe1
,
i
,
m
->
i1
-
i
,
0
,
0
,
dest
?
dest
+
size
:
NULL
)
<
0
)
return
-
1
;
GIT_ERROR_CHECK_ALLOC_ADD
(
&
size
,
size
,
copied
);
size
+=
xdl_recs_copy
(
xe1
,
i
,
m
->
i1
-
i
,
0
,
0
,
dest
?
dest
+
size
:
NULL
);
/* Postimage from side #1 */
if
(
m
->
mode
&
1
)
{
int
needs_cr
=
is_cr_needed
(
xe1
,
xe2
,
m
);
if
(
xdl_recs_copy
(
&
copied
,
xe1
,
m
->
i1
,
m
->
chg1
,
needs_cr
,
(
m
->
mode
&
2
),
dest
?
dest
+
size
:
NULL
)
<
0
)
return
-
1
;
GIT_ERROR_CHECK_ALLOC_ADD
(
&
size
,
size
,
copied
);
size
+=
xdl_recs_copy
(
xe1
,
m
->
i1
,
m
->
chg1
,
needs_cr
,
(
m
->
mode
&
2
),
dest
?
dest
+
size
:
NULL
);
}
/* Postimage from side #2 */
if
(
m
->
mode
&
2
)
{
if
(
xdl_recs_copy
(
&
copied
,
xe2
,
m
->
i2
,
m
->
chg2
,
0
,
0
,
dest
?
dest
+
size
:
NULL
)
<
0
)
return
-
1
;
GIT_ERROR_CHECK_ALLOC_ADD
(
&
size
,
size
,
copied
);
}
if
(
m
->
mode
&
2
)
size
+=
xdl_recs_copy
(
xe2
,
m
->
i2
,
m
->
chg2
,
0
,
0
,
dest
?
dest
+
size
:
NULL
);
}
else
continue
;
i
=
m
->
i1
+
m
->
chg1
;
}
size
+=
xdl_recs_copy
(
xe1
,
i
,
xe1
->
xdf2
.
nrec
-
i
,
0
,
0
,
dest
?
dest
+
size
:
NULL
);
return
size
;
}
if
(
xdl_recs_copy
(
&
copied
,
xe1
,
i
,
xe1
->
xdf2
.
nrec
-
i
,
0
,
0
,
dest
?
dest
+
size
:
NULL
)
<
0
)
return
-
1
;
GIT_ERROR_CHECK_ALLOC_ADD
(
&
size
,
size
,
copied
);
static
int
recmatch
(
xrecord_t
*
rec1
,
xrecord_t
*
rec2
,
unsigned
long
flags
)
{
return
xdl_recmatch
(
rec1
->
ptr
,
rec1
->
size
,
rec2
->
ptr
,
rec2
->
size
,
flags
);
}
*
out
=
size
;
return
0
;
/*
* Remove any common lines from the beginning and end of the conflicted region.
*/
static
void
xdl_refine_zdiff3_conflicts
(
xdfenv_t
*
xe1
,
xdfenv_t
*
xe2
,
xdmerge_t
*
m
,
xpparam_t
const
*
xpp
)
{
xrecord_t
**
rec1
=
xe1
->
xdf2
.
recs
,
**
rec2
=
xe2
->
xdf2
.
recs
;
for
(;
m
;
m
=
m
->
next
)
{
/* let's handle just the conflicts */
if
(
m
->
mode
)
continue
;
while
(
m
->
chg1
&&
m
->
chg2
&&
recmatch
(
rec1
[
m
->
i1
],
rec2
[
m
->
i2
],
xpp
->
flags
))
{
m
->
chg1
--
;
m
->
chg2
--
;
m
->
i1
++
;
m
->
i2
++
;
}
while
(
m
->
chg1
&&
m
->
chg2
&&
recmatch
(
rec1
[
m
->
i1
+
m
->
chg1
-
1
],
rec2
[
m
->
i2
+
m
->
chg2
-
1
],
xpp
->
flags
))
{
m
->
chg1
--
;
m
->
chg2
--
;
}
}
}
/*
...
...
@@ -529,7 +516,22 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1,
int
style
=
xmp
->
style
;
int
favor
=
xmp
->
favor
;
if
(
style
==
XDL_MERGE_DIFF3
)
{
/*
* XDL_MERGE_DIFF3 does not attempt to refine conflicts by looking
* at common areas of sides 1 & 2, because the base (side 0) does
* not match and is being shown. Similarly, simplification of
* non-conflicts is also skipped due to the skipping of conflict
* refinement.
*
* XDL_MERGE_ZEALOUS_DIFF3, on the other hand, will attempt to
* refine conflicts looking for common areas of sides 1 & 2.
* However, since the base is being shown and does not match,
* it will only look for common areas at the beginning or end
* of the conflict block. Since XDL_MERGE_ZEALOUS_DIFF3's
* conflict refinement is much more limited in this fashion, the
* conflict simplification will be skipped.
*/
if
(
style
==
XDL_MERGE_DIFF3
||
style
==
XDL_MERGE_ZEALOUS_DIFF3
)
{
/*
* "diff3 -m" output does not make sense for anything
* more aggressive than XDL_MERGE_EAGER.
...
...
@@ -650,34 +652,31 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1,
if
(
!
changes
)
changes
=
c
;
/* refine conflicts */
if
(
XDL_MERGE_ZEALOUS
<=
level
&&
(
xdl_refine_conflicts
(
xe1
,
xe2
,
changes
,
xpp
)
<
0
||
xdl_simplify_non_conflicts
(
xe1
,
changes
,
XDL_MERGE_ZEALOUS
<
level
)
<
0
))
{
if
(
style
==
XDL_MERGE_ZEALOUS_DIFF3
)
{
xdl_refine_zdiff3_conflicts
(
xe1
,
xe2
,
changes
,
xpp
);
}
else
if
(
XDL_MERGE_ZEALOUS
<=
level
&&
(
xdl_refine_conflicts
(
xe1
,
xe2
,
changes
,
xpp
)
<
0
||
xdl_simplify_non_conflicts
(
xe1
,
changes
,
XDL_MERGE_ZEALOUS
<
level
)
<
0
))
{
xdl_cleanup_merge
(
changes
);
return
-
1
;
}
/* output */
if
(
result
)
{
int
marker_size
=
xmp
->
marker_size
;
size_t
size
;
if
(
xdl_fill_merge_buffer
(
&
size
,
xe1
,
name1
,
xe2
,
name2
,
int
size
=
xdl_fill_merge_buffer
(
xe1
,
name1
,
xe2
,
name2
,
ancestor_name
,
favor
,
changes
,
NULL
,
style
,
marker_size
)
<
0
)
return
-
1
;
marker_size
);
result
->
ptr
=
xdl_malloc
(
size
);
if
(
!
result
->
ptr
)
{
xdl_cleanup_merge
(
changes
);
return
-
1
;
}
result
->
size
=
size
;
if
(
xdl_fill_merge_buffer
(
&
size
,
xe1
,
name1
,
xe2
,
name2
,
xdl_fill_merge_buffer
(
xe1
,
name1
,
xe2
,
name2
,
ancestor_name
,
favor
,
changes
,
result
->
ptr
,
style
,
marker_size
)
<
0
)
return
-
1
;
result
->
ptr
,
style
,
marker_size
);
}
return
xdl_cleanup_merge
(
changes
);
}
...
...
@@ -717,22 +716,10 @@ int xdl_merge(mmfile_t *orig, mmfile_t *mf1, mmfile_t *mf2,
status
=
0
;
if
(
!
xscr1
)
{
result
->
ptr
=
xdl_malloc
(
mf2
->
size
);
if
(
!
result
->
ptr
)
{
xdl_free_script
(
xscr2
);
xdl_free_env
(
&
xe1
);
xdl_free_env
(
&
xe2
);
return
-
1
;
}
memcpy
(
result
->
ptr
,
mf2
->
ptr
,
mf2
->
size
);
result
->
size
=
mf2
->
size
;
}
else
if
(
!
xscr2
)
{
result
->
ptr
=
xdl_malloc
(
mf1
->
size
);
if
(
!
result
->
ptr
)
{
xdl_free_script
(
xscr1
);
xdl_free_env
(
&
xe1
);
xdl_free_env
(
&
xe2
);
return
-
1
;
}
memcpy
(
result
->
ptr
,
mf1
->
ptr
,
mf1
->
size
);
result
->
size
=
mf1
->
size
;
}
else
{
...
...
src/xdiff/xpatience.c
View file @
18a477e7
...
...
@@ -20,8 +20,6 @@
*
*/
#include "xinclude.h"
#include "xtypes.h"
#include "xdiff.h"
/*
* The basic idea of patience diff is to find lines that are unique in
...
...
@@ -78,7 +76,7 @@ struct hashmap {
static
int
is_anchor
(
xpparam_t
const
*
xpp
,
const
char
*
line
)
{
unsigned
long
i
;
int
i
;
for
(
i
=
0
;
i
<
xpp
->
anchors_nr
;
i
++
)
{
if
(
!
strncmp
(
line
,
xpp
->
anchors
[
i
],
strlen
(
xpp
->
anchors
[
i
])))
return
1
;
...
...
@@ -92,7 +90,7 @@ static void insert_record(xpparam_t const *xpp, int line, struct hashmap *map,
{
xrecord_t
**
records
=
pass
==
1
?
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
* 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
);
while
(
map
->
entries
[
index
].
line1
)
{
other
=
map
->
env
->
xdf1
.
recs
[
map
->
entries
[
index
].
line1
-
1
];
if
(
map
->
entries
[
index
].
hash
!=
record
->
ha
||
!
xdl_recmatch
(
record
->
ptr
,
record
->
size
,
other
->
ptr
,
other
->
size
,
map
->
xpp
->
flags
))
{
if
(
map
->
entries
[
index
].
hash
!=
record
->
ha
)
{
if
(
++
index
>=
map
->
alloc
)
index
=
0
;
continue
;
...
...
@@ -217,9 +211,6 @@ static struct entry *find_longest_common_sequence(struct hashmap *map)
*/
int
anchor_i
=
-
1
;
if
(
!
sequence
)
return
NULL
;
for
(
entry
=
map
->
first
;
entry
;
entry
=
entry
->
next
)
{
if
(
!
entry
->
line2
||
entry
->
line2
==
NON_UNIQUE
)
continue
;
...
...
@@ -258,8 +249,7 @@ static int match(struct hashmap *map, int line1, int line2)
{
xrecord_t
*
record1
=
map
->
env
->
xdf1
.
recs
[
line1
-
1
];
xrecord_t
*
record2
=
map
->
env
->
xdf2
.
recs
[
line2
-
1
];
return
xdl_recmatch
(
record1
->
ptr
,
record1
->
size
,
record2
->
ptr
,
record2
->
size
,
map
->
xpp
->
flags
);
return
record1
->
ha
==
record2
->
ha
;
}
static
int
patience_diff
(
mmfile_t
*
file1
,
mmfile_t
*
file2
,
...
...
@@ -294,9 +284,6 @@ static int walk_common_sequence(struct hashmap *map, struct entry *first,
/* Recurse */
if
(
next1
>
line1
||
next2
>
line2
)
{
struct
hashmap
submap
;
memset
(
&
submap
,
0
,
sizeof
(
submap
));
if
(
patience_diff
(
map
->
file1
,
map
->
file2
,
map
->
xpp
,
map
->
env
,
line1
,
next1
-
line1
,
...
...
@@ -323,6 +310,8 @@ static int fall_back_to_classic_diff(struct hashmap *map,
int
line1
,
int
count1
,
int
line2
,
int
count2
)
{
xpparam_t
xpp
;
memset
(
&
xpp
,
0
,
sizeof
(
xpp
));
xpp
.
flags
=
map
->
xpp
->
flags
&
~
XDF_DIFF_ALGORITHM_MASK
;
return
xdl_fall_back_diff
(
map
->
env
,
&
xpp
,
...
...
src/xdiff/xprepare.c
View file @
18a477e7
...
...
@@ -181,15 +181,11 @@ static int xdl_prepare_ctx(unsigned int pass, mmfile_t *mf, long narec, xpparam_
if
(
!
(
recs
=
(
xrecord_t
**
)
xdl_malloc
(
narec
*
sizeof
(
xrecord_t
*
))))
goto
abort
;
if
(
XDF_DIFF_ALG
(
xpp
->
flags
)
==
XDF_HISTOGRAM_DIFF
)
hbits
=
hsize
=
0
;
else
{
hbits
=
xdl_hashbits
((
unsigned
int
)
narec
);
hsize
=
1
<<
hbits
;
if
(
!
(
rhash
=
(
xrecord_t
**
)
xdl_malloc
(
hsize
*
sizeof
(
xrecord_t
*
))))
goto
abort
;
memset
(
rhash
,
0
,
hsize
*
sizeof
(
xrecord_t
*
));
}
hbits
=
xdl_hashbits
((
unsigned
int
)
narec
);
hsize
=
1
<<
hbits
;
if
(
!
(
rhash
=
(
xrecord_t
**
)
xdl_malloc
(
hsize
*
sizeof
(
xrecord_t
*
))))
goto
abort
;
memset
(
rhash
,
0
,
hsize
*
sizeof
(
xrecord_t
*
));
nrec
=
0
;
if
((
cur
=
blk
=
xdl_mmfile_first
(
mf
,
&
bsize
))
!=
NULL
)
{
...
...
@@ -208,9 +204,7 @@ static int xdl_prepare_ctx(unsigned int pass, mmfile_t *mf, long narec, xpparam_
crec
->
size
=
(
long
)
(
cur
-
prev
);
crec
->
ha
=
hav
;
recs
[
nrec
++
]
=
crec
;
if
((
XDF_DIFF_ALG
(
xpp
->
flags
)
!=
XDF_HISTOGRAM_DIFF
)
&&
xdl_classify_record
(
pass
,
cf
,
rhash
,
hbits
,
crec
)
<
0
)
if
(
xdl_classify_record
(
pass
,
cf
,
rhash
,
hbits
,
crec
)
<
0
)
goto
abort
;
}
}
...
...
@@ -219,10 +213,13 @@ static int xdl_prepare_ctx(unsigned int pass, mmfile_t *mf, long narec, xpparam_
goto
abort
;
memset
(
rchg
,
0
,
(
nrec
+
2
)
*
sizeof
(
char
));
if
(
!
(
rindex
=
(
long
*
)
xdl_malloc
((
nrec
+
1
)
*
sizeof
(
long
))))
goto
abort
;
if
(
!
(
ha
=
(
unsigned
long
*
)
xdl_malloc
((
nrec
+
1
)
*
sizeof
(
unsigned
long
))))
goto
abort
;
if
((
XDF_DIFF_ALG
(
xpp
->
flags
)
!=
XDF_PATIENCE_DIFF
)
&&
(
XDF_DIFF_ALG
(
xpp
->
flags
)
!=
XDF_HISTOGRAM_DIFF
))
{
if
(
!
(
rindex
=
xdl_malloc
((
nrec
+
1
)
*
sizeof
(
*
rindex
))))
goto
abort
;
if
(
!
(
ha
=
xdl_malloc
((
nrec
+
1
)
*
sizeof
(
*
ha
))))
goto
abort
;
}
xdf
->
nrec
=
nrec
;
xdf
->
recs
=
recs
;
...
...
@@ -279,8 +276,7 @@ int xdl_prepare_env(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
enl1
=
xdl_guess_lines
(
mf1
,
sample
)
+
1
;
enl2
=
xdl_guess_lines
(
mf2
,
sample
)
+
1
;
if
(
XDF_DIFF_ALG
(
xpp
->
flags
)
!=
XDF_HISTOGRAM_DIFF
&&
xdl_init_classifier
(
&
cf
,
enl1
+
enl2
+
1
,
xpp
->
flags
)
<
0
)
if
(
xdl_init_classifier
(
&
cf
,
enl1
+
enl2
+
1
,
xpp
->
flags
)
<
0
)
return
-
1
;
if
(
xdl_prepare_ctx
(
1
,
mf1
,
enl1
,
xpp
,
&
cf
,
&
xe
->
xdf1
)
<
0
)
{
...
...
@@ -305,8 +301,7 @@ int xdl_prepare_env(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
return
-
1
;
}
if
(
XDF_DIFF_ALG
(
xpp
->
flags
)
!=
XDF_HISTOGRAM_DIFF
)
xdl_free_classifier
(
&
cf
);
xdl_free_classifier
(
&
cf
);
return
0
;
}
...
...
src/xdiff/xutils.c
View file @
18a477e7
...
...
@@ -23,8 +23,6 @@
#include "xinclude.h"
long
xdl_bogosqrt
(
long
n
)
{
long
i
;
...
...
@@ -52,7 +50,7 @@ int xdl_emit_diffrec(char const *rec, long size, char const *pre, long psize,
mb
[
2
].
size
=
strlen
(
mb
[
2
].
ptr
);
i
++
;
}
if
(
ecb
->
out
f
(
ecb
->
priv
,
mb
,
i
)
<
0
)
{
if
(
ecb
->
out
_line
(
ecb
->
priv
,
mb
,
i
)
<
0
)
{
return
-
1
;
}
...
...
@@ -342,8 +340,9 @@ int xdl_num_out(char *out, long val) {
return
str
-
out
;
}
int
xdl_emit_hunk_hdr
(
long
s1
,
long
c1
,
long
s2
,
long
c2
,
const
char
*
func
,
long
funclen
,
xdemitcb_t
*
ecb
)
{
static
int
xdl_format_hunk_hdr
(
long
s1
,
long
c1
,
long
s2
,
long
c2
,
const
char
*
func
,
long
funclen
,
xdemitcb_t
*
ecb
)
{
int
nb
=
0
;
mmbuffer_t
mb
;
char
buf
[
128
];
...
...
@@ -376,7 +375,7 @@ int xdl_emit_hunk_hdr(long s1, long c1, long s2, long c2,
nb
+=
3
;
if
(
func
&&
funclen
)
{
buf
[
nb
++
]
=
' '
;
if
(
funclen
>
(
long
)(
sizeof
(
buf
)
-
nb
-
1
)
)
if
(
funclen
>
sizeof
(
buf
)
-
nb
-
1
)
funclen
=
sizeof
(
buf
)
-
nb
-
1
;
memcpy
(
buf
+
nb
,
func
,
funclen
);
nb
+=
funclen
;
...
...
@@ -385,9 +384,21 @@ int xdl_emit_hunk_hdr(long s1, long c1, long s2, long c2,
mb
.
ptr
=
buf
;
mb
.
size
=
nb
;
if
(
ecb
->
out
f
(
ecb
->
priv
,
&
mb
,
1
)
<
0
)
if
(
ecb
->
out
_line
(
ecb
->
priv
,
&
mb
,
1
)
<
0
)
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
;
}
...
...
tests/merge/conflict_data.h
View file @
18a477e7
...
...
@@ -36,6 +36,15 @@
"this file is changed in branch and master\n" \
">>>>>>> 7cb63eed597130ba4abb87b3e544b85021905520\n"
#define CONFLICTING_ZDIFF3_FILE \
"<<<<<<< HEAD\n" \
"this file is changed in master and branch\n" \
"||||||| initial\n" \
"this file is a conflict\n" \
"=======\n" \
"this file is changed in branch and master\n" \
">>>>>>> 7cb63eed597130ba4abb87b3e544b85021905520\n"
#define CONFLICTING_UNION_FILE \
"this file is changed in master and branch\n" \
"this file is changed in branch and master\n"
...
...
tests/merge/files.c
View file @
18a477e7
...
...
@@ -424,3 +424,42 @@ void test_merge_files__crlf_conflict_markers_for_crlf_files(void)
cl_assert
(
memcmp
(
expected_diff3
,
result
.
ptr
,
expected_len
)
==
0
);
git_merge_file_result_free
(
&
result
);
}
void
test_merge_files__conflicts_in_zdiff3
(
void
)
{
git_merge_file_input
ancestor
=
GIT_MERGE_FILE_INPUT_INIT
,
ours
=
GIT_MERGE_FILE_INPUT_INIT
,
theirs
=
GIT_MERGE_FILE_INPUT_INIT
;
git_merge_file_options
opts
=
GIT_MERGE_FILE_OPTIONS_INIT
;
git_merge_file_result
result
=
{
0
};
const
char
*
expected_zdiff3
=
"1,
\n
foo,
\n
bar,
\n
"
\
"<<<<<<< file.txt
\n
"
\
"||||||| file.txt
\n
# add more here
\n
"
\
"=======
\n
quux,
\n
woot,
\n
"
\
">>>>>>> file.txt
\n
baz,
\n
3,
\n
"
;
size_t
expected_zdiff3_len
=
strlen
(
expected_zdiff3
);
ancestor
.
ptr
=
"1,
\n
# add more here
\n
3,
\n
"
;
ancestor
.
size
=
strlen
(
ancestor
.
ptr
);
ancestor
.
path
=
"file.txt"
;
ancestor
.
mode
=
0100644
;
ours
.
ptr
=
"1,
\n
foo,
\n
bar,
\n
baz,
\n
3,
\n
"
;
ours
.
size
=
strlen
(
ours
.
ptr
);
ours
.
path
=
"file.txt"
;
ours
.
mode
=
0100644
;
theirs
.
ptr
=
"1,
\n
foo,
\n
bar,
\n
quux,
\n
woot,
\n
baz,
\n
3,
\n
"
;
theirs
.
size
=
strlen
(
theirs
.
ptr
);
theirs
.
path
=
"file.txt"
;
theirs
.
mode
=
0100644
;
opts
.
flags
|=
GIT_MERGE_FILE_STYLE_ZDIFF3
;
cl_git_pass
(
git_merge_file
(
&
result
,
&
ancestor
,
&
ours
,
&
theirs
,
&
opts
));
cl_assert_equal_i
(
0
,
result
.
automergeable
);
cl_assert_equal_i
(
expected_zdiff3_len
,
result
.
len
);
cl_assert
(
memcmp
(
expected_zdiff3
,
result
.
ptr
,
expected_zdiff3_len
)
==
0
);
git_merge_file_result_free
(
&
result
);
}
tests/merge/workdir/simple.c
View file @
18a477e7
...
...
@@ -323,6 +323,42 @@ void test_merge_workdir_simple__diff3(void)
cl_assert
(
merge_test_reuc
(
repo_index
,
merge_reuc_entries
,
3
));
}
void
test_merge_workdir_simple__zdiff3
(
void
)
{
git_str
conflicting_buf
=
GIT_STR_INIT
;
struct
merge_index_entry
merge_index_entries
[]
=
{
ADDED_IN_MASTER_INDEX_ENTRY
,
AUTOMERGEABLE_INDEX_ENTRY
,
CHANGED_IN_BRANCH_INDEX_ENTRY
,
CHANGED_IN_MASTER_INDEX_ENTRY
,
{
0100644
,
"d427e0b2e138501a3d15cc376077a3631e15bd46"
,
1
,
"conflicting.txt"
},
{
0100644
,
"4e886e602529caa9ab11d71f86634bd1b6e0de10"
,
2
,
"conflicting.txt"
},
{
0100644
,
"2bd0a343aeef7a2cf0d158478966a6e587ff3863"
,
3
,
"conflicting.txt"
},
UNCHANGED_INDEX_ENTRY
,
};
struct
merge_reuc_entry
merge_reuc_entries
[]
=
{
AUTOMERGEABLE_REUC_ENTRY
,
REMOVED_IN_BRANCH_REUC_ENTRY
,
REMOVED_IN_MASTER_REUC_ENTRY
};
set_core_autocrlf_to
(
repo
,
false
);
merge_simple_branch
(
0
,
GIT_CHECKOUT_CONFLICT_STYLE_ZDIFF3
);
cl_git_pass
(
git_futils_readbuffer
(
&
conflicting_buf
,
TEST_REPO_PATH
"/conflicting.txt"
));
cl_assert_equal_s
(
CONFLICTING_ZDIFF3_FILE
,
conflicting_buf
.
ptr
);
git_str_dispose
(
&
conflicting_buf
);
cl_assert
(
merge_test_index
(
repo_index
,
merge_index_entries
,
8
));
cl_assert
(
merge_test_reuc
(
repo_index
,
merge_reuc_entries
,
3
));
}
void
test_merge_workdir_simple__union
(
void
)
{
git_str
conflicting_buf
=
GIT_STR_INIT
;
...
...
@@ -436,6 +472,48 @@ void test_merge_workdir_simple__diff3_from_config(void)
git_config_free
(
config
);
}
void
test_merge_workdir_simple__zdiff3_from_config
(
void
)
{
git_config
*
config
;
git_str
conflicting_buf
=
GIT_STR_INIT
;
struct
merge_index_entry
merge_index_entries
[]
=
{
ADDED_IN_MASTER_INDEX_ENTRY
,
AUTOMERGEABLE_INDEX_ENTRY
,
CHANGED_IN_BRANCH_INDEX_ENTRY
,
CHANGED_IN_MASTER_INDEX_ENTRY
,
{
0100644
,
"d427e0b2e138501a3d15cc376077a3631e15bd46"
,
1
,
"conflicting.txt"
},
{
0100644
,
"4e886e602529caa9ab11d71f86634bd1b6e0de10"
,
2
,
"conflicting.txt"
},
{
0100644
,
"2bd0a343aeef7a2cf0d158478966a6e587ff3863"
,
3
,
"conflicting.txt"
},
UNCHANGED_INDEX_ENTRY
,
};
struct
merge_reuc_entry
merge_reuc_entries
[]
=
{
AUTOMERGEABLE_REUC_ENTRY
,
REMOVED_IN_BRANCH_REUC_ENTRY
,
REMOVED_IN_MASTER_REUC_ENTRY
};
cl_git_pass
(
git_repository_config
(
&
config
,
repo
));
cl_git_pass
(
git_config_set_string
(
config
,
"merge.conflictstyle"
,
"zdiff3"
));
set_core_autocrlf_to
(
repo
,
false
);
merge_simple_branch
(
0
,
0
);
cl_git_pass
(
git_futils_readbuffer
(
&
conflicting_buf
,
TEST_REPO_PATH
"/conflicting.txt"
));
cl_assert
(
strcmp
(
conflicting_buf
.
ptr
,
CONFLICTING_ZDIFF3_FILE
)
==
0
);
git_str_dispose
(
&
conflicting_buf
);
cl_assert
(
merge_test_index
(
repo_index
,
merge_index_entries
,
8
));
cl_assert
(
merge_test_reuc
(
repo_index
,
merge_reuc_entries
,
3
));
git_config_free
(
config
);
}
void
test_merge_workdir_simple__merge_overrides_config
(
void
)
{
git_config
*
config
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment