2 #include "xdiff-interface.h"
5 struct xdiff_emit_state
{
6 xdiff_emit_consume_fn consume
;
7 void *consume_callback_data
;
8 struct strbuf remainder
;
11 static int parse_num(char **cp_p
, int *num_p
)
17 while ('0' <= *cp
&& *cp
<= '9')
18 num
= num
* 10 + *cp
++ - '0';
19 if (!(read_some
= cp
- *cp_p
))
26 int parse_hunk_header(char *line
, int len
,
32 if (parse_num(&cp
, ob
)) {
34 return error("malformed diff output: %s", line
);
38 if (parse_num(&cp
, on
))
43 if (*cp
++ != ' ' || *cp
++ != '+')
45 if (parse_num(&cp
, nb
))
49 if (parse_num(&cp
, nn
))
54 return -!!memcmp(cp
, " @@", 3);
57 static void consume_one(void *priv_
, char *s
, unsigned long size
)
59 struct xdiff_emit_state
*priv
= priv_
;
62 unsigned long this_size
;
63 ep
= memchr(s
, '\n', size
);
64 this_size
= (ep
== NULL
) ? size
: (ep
- s
+ 1);
65 priv
->consume(priv
->consume_callback_data
, s
, this_size
);
71 static int xdiff_outf(void *priv_
, mmbuffer_t
*mb
, int nbuf
)
73 struct xdiff_emit_state
*priv
= priv_
;
76 for (i
= 0; i
< nbuf
; i
++) {
77 if (mb
[i
].ptr
[mb
[i
].size
-1] != '\n') {
79 strbuf_add(&priv
->remainder
, mb
[i
].ptr
, mb
[i
].size
);
83 /* we have a complete line */
84 if (!priv
->remainder
.len
) {
85 consume_one(priv
, mb
[i
].ptr
, mb
[i
].size
);
88 strbuf_add(&priv
->remainder
, mb
[i
].ptr
, mb
[i
].size
);
89 consume_one(priv
, priv
->remainder
.buf
, priv
->remainder
.len
);
90 strbuf_reset(&priv
->remainder
);
92 if (priv
->remainder
.len
) {
93 consume_one(priv
, priv
->remainder
.buf
, priv
->remainder
.len
);
94 strbuf_reset(&priv
->remainder
);
100 * Trim down common substring at the end of the buffers,
101 * but leave at least ctx lines at the end.
103 static void trim_common_tail(mmfile_t
*a
, mmfile_t
*b
, long ctx
)
105 const int blk
= 1024;
106 long trimmed
= 0, recovered
= 0;
107 char *ap
= a
->ptr
+ a
->size
;
108 char *bp
= b
->ptr
+ b
->size
;
109 long smaller
= (a
->size
< b
->size
) ? a
->size
: b
->size
;
114 while (blk
+ trimmed
<= smaller
&& !memcmp(ap
- blk
, bp
- blk
, blk
)) {
120 while (recovered
< trimmed
)
121 if (ap
[recovered
++] == '\n')
123 a
->size
-= trimmed
- recovered
;
124 b
->size
-= trimmed
- recovered
;
127 int xdi_diff(mmfile_t
*mf1
, mmfile_t
*mf2
, xpparam_t
const *xpp
, xdemitconf_t
const *xecfg
, xdemitcb_t
*xecb
)
132 trim_common_tail(&a
, &b
, xecfg
->ctxlen
);
134 return xdl_diff(&a
, &b
, xpp
, xecfg
, xecb
);
137 int xdi_diff_outf(mmfile_t
*mf1
, mmfile_t
*mf2
,
138 xdiff_emit_consume_fn fn
, void *consume_callback_data
,
139 xpparam_t
const *xpp
,
140 xdemitconf_t
const *xecfg
, xdemitcb_t
*xecb
)
143 struct xdiff_emit_state state
;
145 memset(&state
, 0, sizeof(state
));
147 state
.consume_callback_data
= consume_callback_data
;
148 xecb
->outf
= xdiff_outf
;
150 strbuf_init(&state
.remainder
, 0);
151 ret
= xdi_diff(mf1
, mf2
, xpp
, xecfg
, xecb
);
152 strbuf_release(&state
.remainder
);
156 int read_mmfile(mmfile_t
*ptr
, const char *filename
)
162 if (stat(filename
, &st
))
163 return error("Could not stat %s", filename
);
164 if ((f
= fopen(filename
, "rb")) == NULL
)
165 return error("Could not open %s", filename
);
166 sz
= xsize_t(st
.st_size
);
167 ptr
->ptr
= xmalloc(sz
? sz
: 1);
168 if (sz
&& fread(ptr
->ptr
, sz
, 1, f
) != 1)
169 return error("Could not read %s", filename
);
175 #define FIRST_FEW_BYTES 8000
176 int buffer_is_binary(const char *ptr
, unsigned long size
)
178 if (FIRST_FEW_BYTES
< size
)
179 size
= FIRST_FEW_BYTES
;
180 return !!memchr(ptr
, 0, size
);
191 static long ff_regexp(const char *line
, long len
,
192 char *buffer
, long buffer_size
, void *priv
)
194 char *line_buffer
= xstrndup(line
, len
); /* make NUL terminated */
195 struct ff_regs
*regs
= priv
;
196 regmatch_t pmatch
[2];
199 for (i
= 0; i
< regs
->nr
; i
++) {
200 struct ff_reg
*reg
= regs
->array
+ i
;
201 if (reg
->negate
^ !!regexec(®
->re
,
202 line_buffer
, 2, pmatch
, 0)) {
207 i
= pmatch
[1].rm_so
>= 0 ? 1 : 0;
208 line
+= pmatch
[i
].rm_so
;
209 result
= pmatch
[i
].rm_eo
- pmatch
[i
].rm_so
;
210 if (result
> buffer_size
)
211 result
= buffer_size
;
213 while (result
> 0 && (isspace(line
[result
- 1]) ||
214 line
[result
- 1] == '\n'))
216 memcpy(buffer
, line
, result
);
221 void xdiff_set_find_func(xdemitconf_t
*xecfg
, const char *value
, int cflags
)
224 struct ff_regs
*regs
;
226 xecfg
->find_func
= ff_regexp
;
227 regs
= xecfg
->find_func_priv
= xmalloc(sizeof(struct ff_regs
));
228 for (i
= 0, regs
->nr
= 1; value
[i
]; i
++)
229 if (value
[i
] == '\n')
231 regs
->array
= xmalloc(regs
->nr
* sizeof(struct ff_reg
));
232 for (i
= 0; i
< regs
->nr
; i
++) {
233 struct ff_reg
*reg
= regs
->array
+ i
;
234 const char *ep
= strchr(value
, '\n'), *expression
;
237 reg
->negate
= (*value
== '!');
238 if (reg
->negate
&& i
== regs
->nr
- 1)
239 die("Last expression must not be negated: %s", value
);
243 expression
= buffer
= xstrndup(value
, ep
- value
);
246 if (regcomp(®
->re
, expression
, cflags
))
247 die("Invalid regexp to look for hunk header: %s", expression
);