xdiff-interface.c 7.9 KB
Newer Older
1 2
#include "cache.h"
#include "xdiff-interface.h"
3 4 5 6
#include "xdiff/xtypes.h"
#include "xdiff/xdiffi.h"
#include "xdiff/xemit.h"
#include "xdiff/xmacros.h"
7 8 9 10 11 12

struct xdiff_emit_state {
	xdiff_emit_consume_fn consume;
	void *consume_callback_data;
	struct strbuf remainder;
};
13

14
static int parse_num(char **cp_p, int *num_p)
15 16
{
	char *cp = *cp_p;
17
	int num = 0;
18 19 20

	while ('0' <= *cp && *cp <= '9')
		num = num * 10 + *cp++ - '0';
21
	if (!(cp - *cp_p))
22 23 24 25 26 27 28
		return -1;
	*cp_p = cp;
	*num_p = num;
	return 0;
}

int parse_hunk_header(char *line, int len,
29 30
		      int *ob, int *on,
		      int *nb, int *nn)
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
{
	char *cp;
	cp = line + 4;
	if (parse_num(&cp, ob)) {
	bad_line:
		return error("malformed diff output: %s", line);
	}
	if (*cp == ',') {
		cp++;
		if (parse_num(&cp, on))
			goto bad_line;
	}
	else
		*on = 1;
	if (*cp++ != ' ' || *cp++ != '+')
		goto bad_line;
	if (parse_num(&cp, nb))
		goto bad_line;
	if (*cp == ',') {
		cp++;
		if (parse_num(&cp, nn))
			goto bad_line;
	}
	else
		*nn = 1;
	return -!!memcmp(cp, " @@", 3);
}

59 60 61 62 63 64 65 66
static void consume_one(void *priv_, char *s, unsigned long size)
{
	struct xdiff_emit_state *priv = priv_;
	char *ep;
	while (size) {
		unsigned long this_size;
		ep = memchr(s, '\n', size);
		this_size = (ep == NULL) ? size : (ep - s + 1);
67
		priv->consume(priv->consume_callback_data, s, this_size);
68 69 70 71 72
		size -= this_size;
		s += this_size;
	}
}

73
static int xdiff_outf(void *priv_, mmbuffer_t *mb, int nbuf)
74 75 76 77 78 79 80
{
	struct xdiff_emit_state *priv = priv_;
	int i;

	for (i = 0; i < nbuf; i++) {
		if (mb[i].ptr[mb[i].size-1] != '\n') {
			/* Incomplete line */
81
			strbuf_add(&priv->remainder, mb[i].ptr, mb[i].size);
82 83 84 85
			continue;
		}

		/* we have a complete line */
86
		if (!priv->remainder.len) {
87 88 89
			consume_one(priv, mb[i].ptr, mb[i].size);
			continue;
		}
90 91 92
		strbuf_add(&priv->remainder, mb[i].ptr, mb[i].size);
		consume_one(priv, priv->remainder.buf, priv->remainder.len);
		strbuf_reset(&priv->remainder);
93
	}
94 95 96
	if (priv->remainder.len) {
		consume_one(priv, priv->remainder.buf, priv->remainder.len);
		strbuf_reset(&priv->remainder);
97 98 99
	}
	return 0;
}
100

101 102 103 104
/*
 * Trim down common substring at the end of the buffers,
 * but leave at least ctx lines at the end.
 */
105
static void trim_common_tail(mmfile_t *a, mmfile_t *b, long ctx)
106 107
{
	const int blk = 1024;
J
Jeff King 已提交
108
	long trimmed = 0, recovered = 0;
109 110 111 112
	char *ap = a->ptr + a->size;
	char *bp = b->ptr + b->size;
	long smaller = (a->size < b->size) ? a->size : b->size;

L
Linus Torvalds 已提交
113 114 115
	if (ctx)
		return;

116 117 118 119 120 121
	while (blk + trimmed <= smaller && !memcmp(ap - blk, bp - blk, blk)) {
		trimmed += blk;
		ap -= blk;
		bp -= blk;
	}

L
Linus Torvalds 已提交
122
	while (recovered < trimmed)
J
Jeff King 已提交
123
		if (ap[recovered++] == '\n')
L
Linus Torvalds 已提交
124 125 126
			break;
	a->size -= trimmed - recovered;
	b->size -= trimmed - recovered;
127 128
}

J
Junio C Hamano 已提交
129 130
int xdi_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, xdemitconf_t const *xecfg, xdemitcb_t *xecb)
{
131 132 133 134 135 136
	mmfile_t a = *mf1;
	mmfile_t b = *mf2;

	trim_common_tail(&a, &b, xecfg->ctxlen);

	return xdl_diff(&a, &b, xpp, xecfg, xecb);
J
Junio C Hamano 已提交
137 138
}

139
int xdi_diff_outf(mmfile_t *mf1, mmfile_t *mf2,
140 141
		  xdiff_emit_consume_fn fn, void *consume_callback_data,
		  xpparam_t const *xpp,
142 143 144
		  xdemitconf_t const *xecfg, xdemitcb_t *xecb)
{
	int ret;
145 146 147 148 149
	struct xdiff_emit_state state;

	memset(&state, 0, sizeof(state));
	state.consume = fn;
	state.consume_callback_data = consume_callback_data;
150
	xecb->outf = xdiff_outf;
151 152
	xecb->priv = &state;
	strbuf_init(&state.remainder, 0);
153
	ret = xdi_diff(mf1, mf2, xpp, xecfg, xecb);
154
	strbuf_release(&state.remainder);
155 156 157
	return ret;
}

158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
struct xdiff_emit_hunk_state {
	xdiff_emit_hunk_consume_fn consume;
	void *consume_callback_data;
};

static int process_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
			xdemitconf_t const *xecfg)
{
	long s1, s2, same, p_next, t_next;
	xdchange_t *xch, *xche;
	struct xdiff_emit_hunk_state *state = ecb->priv;
	xdiff_emit_hunk_consume_fn fn = state->consume;
	void *consume_callback_data = state->consume_callback_data;

	for (xch = xscr; xch; xch = xche->next) {
		xche = xdl_get_hunk(xch, xecfg);

		s1 = XDL_MAX(xch->i1 - xecfg->ctxlen, 0);
		s2 = XDL_MAX(xch->i2 - xecfg->ctxlen, 0);
		same = s2 + XDL_MAX(xch->i1 - s1, 0);
		p_next = xche->i1 + xche->chg1;
		t_next = xche->i2 + xche->chg2;

		fn(consume_callback_data, same, p_next, t_next);
	}
	return 0;
}

int xdi_diff_hunks(mmfile_t *mf1, mmfile_t *mf2,
		   xdiff_emit_hunk_consume_fn fn, void *consume_callback_data,
		   xpparam_t const *xpp, xdemitconf_t *xecfg)
{
	struct xdiff_emit_hunk_state state;
	xdemitcb_t ecb;

	memset(&state, 0, sizeof(state));
	memset(&ecb, 0, sizeof(ecb));
	state.consume = fn;
	state.consume_callback_data = consume_callback_data;
	xecfg->emit_func = (void (*)())process_diff;
	ecb.priv = &state;
	return xdi_diff(mf1, mf2, xpp, xecfg, &ecb);
}

202 203 204 205
int read_mmfile(mmfile_t *ptr, const char *filename)
{
	struct stat st;
	FILE *f;
206
	size_t sz;
207 208 209 210 211

	if (stat(filename, &st))
		return error("Could not stat %s", filename);
	if ((f = fopen(filename, "rb")) == NULL)
		return error("Could not open %s", filename);
212
	sz = xsize_t(st.st_size);
213 214
	ptr->ptr = xmalloc(sz ? sz : 1);
	if (sz && fread(ptr->ptr, sz, 1, f) != 1)
215 216
		return error("Could not read %s", filename);
	fclose(f);
217
	ptr->size = sz;
218 219 220
	return 0;
}

221 222 223 224 225 226 227
#define FIRST_FEW_BYTES 8000
int buffer_is_binary(const char *ptr, unsigned long size)
{
	if (FIRST_FEW_BYTES < size)
		size = FIRST_FEW_BYTES;
	return !!memchr(ptr, 0, size);
}
228 229 230 231 232 233 234 235 236 237 238 239

struct ff_regs {
	int nr;
	struct ff_reg {
		regex_t re;
		int negate;
	} *array;
};

static long ff_regexp(const char *line, long len,
		char *buffer, long buffer_size, void *priv)
{
240
	char *line_buffer;
241 242
	struct ff_regs *regs = priv;
	regmatch_t pmatch[2];
243 244
	int i;
	int result = -1;
245

246 247
	/* Exclude terminating newline (and cr) from matching */
	if (len > 0 && line[len-1] == '\n') {
J
Junio C Hamano 已提交
248 249 250 251 252 253 254
		if (len > 1 && line[len-2] == '\r')
			len -= 2;
		else
			len--;
	}

	line_buffer = xstrndup(line, len); /* make NUL terminated */
255 256 257

	for (i = 0; i < regs->nr; i++) {
		struct ff_reg *reg = regs->array + i;
258 259 260 261
		if (!regexec(&reg->re, line_buffer, 2, pmatch, 0)) {
			if (reg->negate)
				goto fail;
			break;
262 263
		}
	}
264 265
	if (regs->nr <= i)
		goto fail;
266 267 268 269 270 271
	i = pmatch[1].rm_so >= 0 ? 1 : 0;
	line += pmatch[i].rm_so;
	result = pmatch[i].rm_eo - pmatch[i].rm_so;
	if (result > buffer_size)
		result = buffer_size;
	else
272
		while (result > 0 && (isspace(line[result - 1])))
273 274
			result--;
	memcpy(buffer, line, result);
275
 fail:
276 277 278 279
	free(line_buffer);
	return result;
}

280
void xdiff_set_find_func(xdemitconf_t *xecfg, const char *value, int cflags)
281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304
{
	int i;
	struct ff_regs *regs;

	xecfg->find_func = ff_regexp;
	regs = xecfg->find_func_priv = xmalloc(sizeof(struct ff_regs));
	for (i = 0, regs->nr = 1; value[i]; i++)
		if (value[i] == '\n')
			regs->nr++;
	regs->array = xmalloc(regs->nr * sizeof(struct ff_reg));
	for (i = 0; i < regs->nr; i++) {
		struct ff_reg *reg = regs->array + i;
		const char *ep = strchr(value, '\n'), *expression;
		char *buffer = NULL;

		reg->negate = (*value == '!');
		if (reg->negate && i == regs->nr - 1)
			die("Last expression must not be negated: %s", value);
		if (*value == '!')
			value++;
		if (ep)
			expression = buffer = xstrndup(value, ep - value);
		else
			expression = value;
305
		if (regcomp(&reg->re, expression, cflags))
306
			die("Invalid regexp to look for hunk header: %s", expression);
307
		free(buffer);
308 309 310
		value = ep + 1;
	}
}
311

312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
void xdiff_clear_find_func(xdemitconf_t *xecfg)
{
	if (xecfg->find_func) {
		int i;
		struct ff_regs *regs = xecfg->find_func_priv;

		for (i = 0; i < regs->nr; i++)
			regfree(&regs->array[i].re);
		free(regs->array);
		free(regs);
		xecfg->find_func = NULL;
		xecfg->find_func_priv = NULL;
	}
}

327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344
int git_xmerge_style = -1;

int git_xmerge_config(const char *var, const char *value, void *cb)
{
	if (!strcasecmp(var, "merge.conflictstyle")) {
		if (!value)
			die("'%s' is not a boolean", var);
		if (!strcmp(value, "diff3"))
			git_xmerge_style = XDL_MERGE_DIFF3;
		else if (!strcmp(value, "merge"))
			git_xmerge_style = 0;
		else
			die("unknown style '%s' given for '%s'",
			    value, var);
		return 0;
	}
	return git_default_config(var, value, cb);
}