2 #include "xdiff-interface.h"
3 #include "xdiff/xtypes.h"
4 #include "xdiff/xdiffi.h"
5 #include "xdiff/xemit.h"
6 #include "xdiff/xmacros.h"
8 struct xdiff_emit_state
{
9 xdiff_emit_consume_fn consume
;
10 void *consume_callback_data
;
11 struct strbuf remainder
;
14 static int parse_num(char **cp_p
, int *num_p
)
19 while ('0' <= *cp
&& *cp
<= '9')
20 num
= num
* 10 + *cp
++ - '0';
28 int parse_hunk_header(char *line
, int len
,
34 if (parse_num(&cp
, ob
)) {
36 return error("malformed diff output: %s", line
);
40 if (parse_num(&cp
, on
))
45 if (*cp
++ != ' ' || *cp
++ != '+')
47 if (parse_num(&cp
, nb
))
51 if (parse_num(&cp
, nn
))
56 return -!!memcmp(cp
, " @@", 3);
59 static void consume_one(void *priv_
, char *s
, unsigned long size
)
61 struct xdiff_emit_state
*priv
= priv_
;
64 unsigned long this_size
;
65 ep
= memchr(s
, '\n', size
);
66 this_size
= (ep
== NULL
) ? size
: (ep
- s
+ 1);
67 priv
->consume(priv
->consume_callback_data
, s
, this_size
);
73 static int xdiff_outf(void *priv_
, mmbuffer_t
*mb
, int nbuf
)
75 struct xdiff_emit_state
*priv
= priv_
;
78 for (i
= 0; i
< nbuf
; i
++) {
79 if (mb
[i
].ptr
[mb
[i
].size
-1] != '\n') {
81 strbuf_add(&priv
->remainder
, mb
[i
].ptr
, mb
[i
].size
);
85 /* we have a complete line */
86 if (!priv
->remainder
.len
) {
87 consume_one(priv
, mb
[i
].ptr
, mb
[i
].size
);
90 strbuf_add(&priv
->remainder
, mb
[i
].ptr
, mb
[i
].size
);
91 consume_one(priv
, priv
->remainder
.buf
, priv
->remainder
.len
);
92 strbuf_reset(&priv
->remainder
);
94 if (priv
->remainder
.len
) {
95 consume_one(priv
, priv
->remainder
.buf
, priv
->remainder
.len
);
96 strbuf_reset(&priv
->remainder
);
102 * Trim down common substring at the end of the buffers,
103 * but leave at least ctx lines at the end.
105 static void trim_common_tail(mmfile_t
*a
, mmfile_t
*b
, long ctx
)
107 const int blk
= 1024;
108 long trimmed
= 0, recovered
= 0;
109 char *ap
= a
->ptr
+ a
->size
;
110 char *bp
= b
->ptr
+ b
->size
;
111 long smaller
= (a
->size
< b
->size
) ? a
->size
: b
->size
;
116 while (blk
+ trimmed
<= smaller
&& !memcmp(ap
- blk
, bp
- blk
, blk
)) {
122 while (recovered
< trimmed
)
123 if (ap
[recovered
++] == '\n')
125 a
->size
-= trimmed
- recovered
;
126 b
->size
-= trimmed
- recovered
;
129 int xdi_diff(mmfile_t
*mf1
, mmfile_t
*mf2
, xpparam_t
const *xpp
, xdemitconf_t
const *xecfg
, xdemitcb_t
*xecb
)
134 trim_common_tail(&a
, &b
, xecfg
->ctxlen
);
136 return xdl_diff(&a
, &b
, xpp
, xecfg
, xecb
);
139 int xdi_diff_outf(mmfile_t
*mf1
, mmfile_t
*mf2
,
140 xdiff_emit_consume_fn fn
, void *consume_callback_data
,
141 xpparam_t
const *xpp
, xdemitconf_t
const *xecfg
)
144 struct xdiff_emit_state state
;
147 memset(&state
, 0, sizeof(state
));
149 state
.consume_callback_data
= consume_callback_data
;
150 memset(&ecb
, 0, sizeof(ecb
));
151 ecb
.outf
= xdiff_outf
;
153 strbuf_init(&state
.remainder
, 0);
154 ret
= xdi_diff(mf1
, mf2
, xpp
, xecfg
, &ecb
);
155 strbuf_release(&state
.remainder
);
159 struct xdiff_emit_hunk_state
{
160 xdiff_emit_hunk_consume_fn consume
;
161 void *consume_callback_data
;
164 static int process_diff(xdfenv_t
*xe
, xdchange_t
*xscr
, xdemitcb_t
*ecb
,
165 xdemitconf_t
const *xecfg
)
167 long s1
, s2
, same
, p_next
, t_next
;
168 xdchange_t
*xch
, *xche
;
169 struct xdiff_emit_hunk_state
*state
= ecb
->priv
;
170 xdiff_emit_hunk_consume_fn fn
= state
->consume
;
171 void *consume_callback_data
= state
->consume_callback_data
;
173 for (xch
= xscr
; xch
; xch
= xche
->next
) {
174 xche
= xdl_get_hunk(xch
, xecfg
);
176 s1
= XDL_MAX(xch
->i1
- xecfg
->ctxlen
, 0);
177 s2
= XDL_MAX(xch
->i2
- xecfg
->ctxlen
, 0);
178 same
= s2
+ XDL_MAX(xch
->i1
- s1
, 0);
179 p_next
= xche
->i1
+ xche
->chg1
;
180 t_next
= xche
->i2
+ xche
->chg2
;
182 fn(consume_callback_data
, same
, p_next
, t_next
);
187 int xdi_diff_hunks(mmfile_t
*mf1
, mmfile_t
*mf2
,
188 xdiff_emit_hunk_consume_fn fn
, void *consume_callback_data
,
189 xpparam_t
const *xpp
, xdemitconf_t
*xecfg
)
191 struct xdiff_emit_hunk_state state
;
194 memset(&state
, 0, sizeof(state
));
195 memset(&ecb
, 0, sizeof(ecb
));
197 state
.consume_callback_data
= consume_callback_data
;
198 xecfg
->emit_func
= (void (*)())process_diff
;
200 return xdi_diff(mf1
, mf2
, xpp
, xecfg
, &ecb
);
203 int read_mmfile(mmfile_t
*ptr
, const char *filename
)
209 if (stat(filename
, &st
))
210 return error("Could not stat %s", filename
);
211 if ((f
= fopen(filename
, "rb")) == NULL
)
212 return error("Could not open %s", filename
);
213 sz
= xsize_t(st
.st_size
);
214 ptr
->ptr
= xmalloc(sz
? sz
: 1);
215 if (sz
&& fread(ptr
->ptr
, sz
, 1, f
) != 1) {
217 return error("Could not read %s", filename
);
224 void read_mmblob(mmfile_t
*ptr
, const unsigned char *sha1
)
227 enum object_type type
;
229 if (!hashcmp(sha1
, null_sha1
)) {
230 ptr
->ptr
= xstrdup("");
235 ptr
->ptr
= read_sha1_file(sha1
, &type
, &size
);
236 if (!ptr
->ptr
|| type
!= OBJ_BLOB
)
237 die("unable to read blob object %s", sha1_to_hex(sha1
));
241 #define FIRST_FEW_BYTES 8000
242 int buffer_is_binary(const char *ptr
, unsigned long size
)
244 if (FIRST_FEW_BYTES
< size
)
245 size
= FIRST_FEW_BYTES
;
246 return !!memchr(ptr
, 0, size
);
257 static long ff_regexp(const char *line
, long len
,
258 char *buffer
, long buffer_size
, void *priv
)
261 struct ff_regs
*regs
= priv
;
262 regmatch_t pmatch
[2];
266 /* Exclude terminating newline (and cr) from matching */
267 if (len
> 0 && line
[len
-1] == '\n') {
268 if (len
> 1 && line
[len
-2] == '\r')
274 line_buffer
= xstrndup(line
, len
); /* make NUL terminated */
276 for (i
= 0; i
< regs
->nr
; i
++) {
277 struct ff_reg
*reg
= regs
->array
+ i
;
278 if (!regexec(®
->re
, line_buffer
, 2, pmatch
, 0)) {
286 i
= pmatch
[1].rm_so
>= 0 ? 1 : 0;
287 line
+= pmatch
[i
].rm_so
;
288 result
= pmatch
[i
].rm_eo
- pmatch
[i
].rm_so
;
289 if (result
> buffer_size
)
290 result
= buffer_size
;
291 while (result
> 0 && (isspace(line
[result
- 1])))
293 memcpy(buffer
, line
, result
);
299 void xdiff_set_find_func(xdemitconf_t
*xecfg
, const char *value
, int cflags
)
302 struct ff_regs
*regs
;
304 xecfg
->find_func
= ff_regexp
;
305 regs
= xecfg
->find_func_priv
= xmalloc(sizeof(struct ff_regs
));
306 for (i
= 0, regs
->nr
= 1; value
[i
]; i
++)
307 if (value
[i
] == '\n')
309 regs
->array
= xmalloc(regs
->nr
* sizeof(struct ff_reg
));
310 for (i
= 0; i
< regs
->nr
; i
++) {
311 struct ff_reg
*reg
= regs
->array
+ i
;
312 const char *ep
= strchr(value
, '\n'), *expression
;
315 reg
->negate
= (*value
== '!');
316 if (reg
->negate
&& i
== regs
->nr
- 1)
317 die("Last expression must not be negated: %s", value
);
321 expression
= buffer
= xstrndup(value
, ep
- value
);
324 if (regcomp(®
->re
, expression
, cflags
))
325 die("Invalid regexp to look for hunk header: %s", expression
);
331 void xdiff_clear_find_func(xdemitconf_t
*xecfg
)
333 if (xecfg
->find_func
) {
335 struct ff_regs
*regs
= xecfg
->find_func_priv
;
337 for (i
= 0; i
< regs
->nr
; i
++)
338 regfree(®s
->array
[i
].re
);
341 xecfg
->find_func
= NULL
;
342 xecfg
->find_func_priv
= NULL
;
346 int git_xmerge_style
= -1;
348 int git_xmerge_config(const char *var
, const char *value
, void *cb
)
350 if (!strcasecmp(var
, "merge.conflictstyle")) {
352 die("'%s' is not a boolean", var
);
353 if (!strcmp(value
, "diff3"))
354 git_xmerge_style
= XDL_MERGE_DIFF3
;
355 else if (!strcmp(value
, "merge"))
356 git_xmerge_style
= 0;
358 die("unknown style '%s' given for '%s'",
362 return git_default_config(var
, value
, cb
);