1 #define USE_THE_REPOSITORY_VARIABLE
2 #define DISABLE_SIGN_COMPARE_WARNINGS
4 #include "git-compat-util.h"
10 #include "xdiff-interface.h"
11 #include "xdiff/xtypes.h"
12 #include "xdiff/xdiffi.h"
13 #include "xdiff/xutils.h"
15 struct xdiff_emit_state
{
16 xdiff_emit_hunk_fn hunk_fn
;
17 xdiff_emit_line_fn line_fn
;
18 void *consume_callback_data
;
19 struct strbuf remainder
;
22 static int xdiff_out_hunk(void *priv_
,
23 long old_begin
, long old_nr
,
24 long new_begin
, long new_nr
,
25 const char *func
, long funclen
)
27 struct xdiff_emit_state
*priv
= priv_
;
29 if (priv
->remainder
.len
)
30 BUG("xdiff emitted hunk in the middle of a line");
32 priv
->hunk_fn(priv
->consume_callback_data
,
33 old_begin
, old_nr
, new_begin
, new_nr
,
38 static int consume_one(void *priv_
, char *s
, unsigned long size
)
40 struct xdiff_emit_state
*priv
= priv_
;
43 unsigned long this_size
;
45 ep
= memchr(s
, '\n', size
);
46 this_size
= (ep
== NULL
) ? size
: (ep
- s
+ 1);
47 ret
= priv
->line_fn(priv
->consume_callback_data
, s
, this_size
);
56 static int xdiff_outf(void *priv_
, mmbuffer_t
*mb
, int nbuf
)
58 struct xdiff_emit_state
*priv
= priv_
;
65 for (i
= 0; i
< nbuf
; i
++) {
68 if (mb
[i
].ptr
[mb
[i
].size
-1] != '\n') {
70 strbuf_add(&priv
->remainder
, mb
[i
].ptr
, mb
[i
].size
);
74 /* we have a complete line */
75 if (!priv
->remainder
.len
) {
76 stop
= consume_one(priv
, mb
[i
].ptr
, mb
[i
].size
);
79 strbuf_add(&priv
->remainder
, mb
[i
].ptr
, mb
[i
].size
);
80 stop
= consume_one(priv
, priv
->remainder
.buf
, priv
->remainder
.len
);
81 strbuf_reset(&priv
->remainder
);
85 if (priv
->remainder
.len
) {
86 stop
= consume_one(priv
, priv
->remainder
.buf
, priv
->remainder
.len
);
87 strbuf_reset(&priv
->remainder
);
95 * Trim down common substring at the end of the buffers,
96 * but end on a complete line.
98 static void trim_common_tail(mmfile_t
*a
, mmfile_t
*b
)
100 const int blk
= 1024;
101 long trimmed
= 0, recovered
= 0;
102 char *ap
= a
->size
? a
->ptr
+ a
->size
: a
->ptr
;
103 char *bp
= b
->size
? b
->ptr
+ b
->size
: b
->ptr
;
104 long smaller
= (a
->size
< b
->size
) ? a
->size
: b
->size
;
106 while (blk
+ trimmed
<= smaller
&& !memcmp(ap
- blk
, bp
- blk
, blk
)) {
112 while (recovered
< trimmed
)
113 if (ap
[recovered
++] == '\n')
115 a
->size
-= trimmed
- recovered
;
116 b
->size
-= trimmed
- recovered
;
119 int xdi_diff(mmfile_t
*mf1
, mmfile_t
*mf2
, xpparam_t
const *xpp
, xdemitconf_t
const *xecfg
, xdemitcb_t
*xecb
)
124 if (mf1
->size
> MAX_XDIFF_SIZE
|| mf2
->size
> MAX_XDIFF_SIZE
)
127 if (!xecfg
->ctxlen
&& !(xecfg
->flags
& XDL_EMIT_FUNCCONTEXT
))
128 trim_common_tail(&a
, &b
);
130 return xdl_diff(&a
, &b
, xpp
, xecfg
, xecb
);
133 int xdi_diff_outf(mmfile_t
*mf1
, mmfile_t
*mf2
,
134 xdiff_emit_hunk_fn hunk_fn
,
135 xdiff_emit_line_fn line_fn
,
136 void *consume_callback_data
,
137 xpparam_t
const *xpp
, xdemitconf_t
const *xecfg
)
140 struct xdiff_emit_state state
;
143 memset(&state
, 0, sizeof(state
));
144 state
.hunk_fn
= hunk_fn
;
145 state
.line_fn
= line_fn
;
146 state
.consume_callback_data
= consume_callback_data
;
147 memset(&ecb
, 0, sizeof(ecb
));
149 ecb
.out_hunk
= xdiff_out_hunk
;
150 ecb
.out_line
= xdiff_outf
;
152 strbuf_init(&state
.remainder
, 0);
153 ret
= xdi_diff(mf1
, mf2
, xpp
, xecfg
, &ecb
);
154 strbuf_release(&state
.remainder
);
158 int read_mmfile(mmfile_t
*ptr
, const char *filename
)
164 if (stat(filename
, &st
))
165 return error_errno("Could not stat %s", filename
);
166 if (!(f
= fopen(filename
, "rb")))
167 return error_errno("Could not open %s", filename
);
168 sz
= xsize_t(st
.st_size
);
169 ptr
->ptr
= xmalloc(sz
? sz
: 1);
170 if (sz
&& fread(ptr
->ptr
, sz
, 1, f
) != 1) {
172 return error("Could not read %s", filename
);
179 void read_mmblob(mmfile_t
*ptr
, const struct object_id
*oid
)
182 enum object_type type
;
184 if (oideq(oid
, null_oid(the_hash_algo
))) {
185 ptr
->ptr
= xstrdup("");
190 ptr
->ptr
= odb_read_object(the_repository
->objects
, oid
, &type
, &size
);
191 if (!ptr
->ptr
|| type
!= OBJ_BLOB
)
192 die("unable to read blob object %s", oid_to_hex(oid
));
196 #define FIRST_FEW_BYTES 8000
197 int buffer_is_binary(const char *ptr
, unsigned long size
)
199 if (FIRST_FEW_BYTES
< size
)
200 size
= FIRST_FEW_BYTES
;
201 return !!memchr(ptr
, 0, size
);
212 static long ff_regexp(const char *line
, long len
,
213 char *buffer
, long buffer_size
, void *priv
)
215 struct ff_regs
*regs
= priv
;
216 regmatch_t pmatch
[2];
220 /* Exclude terminating newline (and cr) from matching */
221 if (len
> 0 && line
[len
-1] == '\n') {
222 if (len
> 1 && line
[len
-2] == '\r')
228 for (i
= 0; i
< regs
->nr
; i
++) {
229 struct ff_reg
*reg
= regs
->array
+ i
;
230 if (!regexec_buf(®
->re
, line
, len
, 2, pmatch
, 0)) {
238 i
= pmatch
[1].rm_so
>= 0 ? 1 : 0;
239 line
+= pmatch
[i
].rm_so
;
240 result
= pmatch
[i
].rm_eo
- pmatch
[i
].rm_so
;
241 if (result
> buffer_size
)
242 result
= buffer_size
;
243 while (result
> 0 && (isspace(line
[result
- 1])))
245 memcpy(buffer
, line
, result
);
249 void xdiff_set_find_func(xdemitconf_t
*xecfg
, const char *value
, int cflags
)
252 struct ff_regs
*regs
;
254 xecfg
->find_func
= ff_regexp
;
255 regs
= xecfg
->find_func_priv
= xmalloc(sizeof(struct ff_regs
));
256 for (i
= 0, regs
->nr
= 1; value
[i
]; i
++)
257 if (value
[i
] == '\n')
259 ALLOC_ARRAY(regs
->array
, regs
->nr
);
260 for (i
= 0; i
< regs
->nr
; i
++) {
261 struct ff_reg
*reg
= regs
->array
+ i
;
262 const char *ep
, *expression
;
266 BUG("mismatch between line count and parsing");
267 ep
= strchr(value
, '\n');
269 reg
->negate
= (*value
== '!');
270 if (reg
->negate
&& i
== regs
->nr
- 1)
271 die("Last expression must not be negated: %s", value
);
275 expression
= buffer
= xstrndup(value
, ep
- value
);
278 if (regcomp(®
->re
, expression
, cflags
))
279 die("Invalid regexp to look for hunk header: %s", expression
);
281 value
= ep
? ep
+ 1 : NULL
;
285 void xdiff_clear_find_func(xdemitconf_t
*xecfg
)
287 if (xecfg
->find_func
) {
289 struct ff_regs
*regs
= xecfg
->find_func_priv
;
291 for (i
= 0; i
< regs
->nr
; i
++)
292 regfree(®s
->array
[i
].re
);
295 xecfg
->find_func
= NULL
;
296 xecfg
->find_func_priv
= NULL
;
300 unsigned long xdiff_hash_string(const char *s
, size_t len
, long flags
)
302 return xdl_hash_record(&s
, s
+ len
, flags
);
305 int xdiff_compare_lines(const char *l1
, long s1
,
306 const char *l2
, long s2
, long flags
)
308 return xdl_recmatch(l1
, s1
, l2
, s2
, flags
);
311 int parse_conflict_style_name(const char *value
)
313 if (!strcmp(value
, "diff3"))
314 return XDL_MERGE_DIFF3
;
315 else if (!strcmp(value
, "zdiff3"))
316 return XDL_MERGE_ZEALOUS_DIFF3
;
317 else if (!strcmp(value
, "merge"))
320 * Please update _git_checkout() in git-completion.bash when
321 * you add new merge config
327 int git_xmerge_style
= -1;
329 int git_xmerge_config(const char *var
, const char *value
,
330 const struct config_context
*ctx
, void *cb
)
332 if (!strcmp(var
, "merge.conflictstyle")) {
334 return config_error_nonbool(var
);
335 git_xmerge_style
= parse_conflict_style_name(value
);
336 if (git_xmerge_style
== -1)
337 return error(_("unknown style '%s' given for '%s'"),
341 return git_default_config(var
, value
, ctx
, cb
);