xdiff-interface.c 5.7 KB
Newer Older
1 2
#include "cache.h"
#include "xdiff-interface.h"
3 4 5 6 7 8 9
#include "strbuf.h"

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

11
static int parse_num(char **cp_p, int *num_p)
12 13
{
	char *cp = *cp_p;
14
	int num = 0;
15 16 17 18 19 20 21 22 23 24 25 26
	int read_some;

	while ('0' <= *cp && *cp <= '9')
		num = num * 10 + *cp++ - '0';
	if (!(read_some = cp - *cp_p))
		return -1;
	*cp_p = cp;
	*num_p = num;
	return 0;
}

int parse_hunk_header(char *line, int len,
27 28
		      int *ob, int *on,
		      int *nb, int *nn)
29 30 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
{
	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);
}

57 58 59 60 61 62 63 64
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);
65
		priv->consume(priv->consume_callback_data, s, this_size);
66 67 68 69 70
		size -= this_size;
		s += this_size;
	}
}

71
static int xdiff_outf(void *priv_, mmbuffer_t *mb, int nbuf)
72 73 74 75 76 77 78
{
	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 */
79
			strbuf_add(&priv->remainder, mb[i].ptr, mb[i].size);
80 81 82 83
			continue;
		}

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

99 100 101 102
/*
 * Trim down common substring at the end of the buffers,
 * but leave at least ctx lines at the end.
 */
103
static void trim_common_tail(mmfile_t *a, mmfile_t *b, long ctx)
104 105
{
	const int blk = 1024;
J
Jeff King 已提交
106
	long trimmed = 0, recovered = 0;
107 108 109 110
	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 已提交
111 112 113
	if (ctx)
		return;

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

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

J
Junio C Hamano 已提交
127 128
int xdi_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, xdemitconf_t const *xecfg, xdemitcb_t *xecb)
{
129 130 131 132 133 134
	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 已提交
135 136
}

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

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

156 157 158 159
int read_mmfile(mmfile_t *ptr, const char *filename)
{
	struct stat st;
	FILE *f;
160
	size_t sz;
161 162 163 164 165

	if (stat(filename, &st))
		return error("Could not stat %s", filename);
	if ((f = fopen(filename, "rb")) == NULL)
		return error("Could not open %s", filename);
166
	sz = xsize_t(st.st_size);
167 168
	ptr->ptr = xmalloc(sz ? sz : 1);
	if (sz && fread(ptr->ptr, sz, 1, f) != 1)
169 170
		return error("Could not read %s", filename);
	fclose(f);
171
	ptr->size = sz;
172 173 174
	return 0;
}

175 176 177 178 179 180 181
#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);
}
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220

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)
{
	char *line_buffer = xstrndup(line, len); /* make NUL terminated */
	struct ff_regs *regs = priv;
	regmatch_t pmatch[2];
	int result = 0, i;

	for (i = 0; i < regs->nr; i++) {
		struct ff_reg *reg = regs->array + i;
		if (reg->negate ^ !!regexec(&reg->re,
					line_buffer, 2, pmatch, 0)) {
			free(line_buffer);
			return -1;
		}
	}
	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
		while (result > 0 && (isspace(line[result - 1]) ||
					line[result - 1] == '\n'))
			result--;
	memcpy(buffer, line, result);
	free(line_buffer);
	return result;
}

221
void xdiff_set_find_func(xdemitconf_t *xecfg, const char *value, int cflags)
222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
{
	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;
246
		if (regcomp(&reg->re, expression, cflags))
247
			die("Invalid regexp to look for hunk header: %s", expression);
248
		free(buffer);
249 250 251
		value = ep + 1;
	}
}