xdiff-interface.c 5.3 KB
Newer Older
1 2 3
#include "cache.h"
#include "xdiff-interface.h"

4
static int parse_num(char **cp_p, int *num_p)
5 6
{
	char *cp = *cp_p;
7
	int num = 0;
8 9 10 11 12 13 14 15 16 17 18 19
	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,
20 21
		      int *ob, int *on,
		      int *nb, int *nn)
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
{
	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);
}

50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
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);
		priv->consume(priv, s, this_size);
		size -= this_size;
		s += this_size;
	}
}

int xdiff_outf(void *priv_, mmbuffer_t *mb, int nbuf)
{
	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 */
J
Jonas Fonseca 已提交
72 73 74
			priv->remainder = xrealloc(priv->remainder,
						   priv->remainder_size +
						   mb[i].size);
75 76 77 78 79 80 81 82 83 84 85
			memcpy(priv->remainder + priv->remainder_size,
			       mb[i].ptr, mb[i].size);
			priv->remainder_size += mb[i].size;
			continue;
		}

		/* we have a complete line */
		if (!priv->remainder) {
			consume_one(priv, mb[i].ptr, mb[i].size);
			continue;
		}
J
Jonas Fonseca 已提交
86 87 88
		priv->remainder = xrealloc(priv->remainder,
					   priv->remainder_size +
					   mb[i].size);
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
		memcpy(priv->remainder + priv->remainder_size,
		       mb[i].ptr, mb[i].size);
		consume_one(priv, priv->remainder,
			    priv->remainder_size + mb[i].size);
		free(priv->remainder);
		priv->remainder = NULL;
		priv->remainder_size = 0;
	}
	if (priv->remainder) {
		consume_one(priv, priv->remainder, priv->remainder_size);
		free(priv->remainder);
		priv->remainder = NULL;
		priv->remainder_size = 0;
	}
	return 0;
}
105

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

121 122 123 124 125 126
	while (blk + trimmed <= smaller && !memcmp(ap - blk, bp - blk, blk)) {
		trimmed += blk;
		ap -= blk;
		bp -= blk;
	}

L
Linus Torvalds 已提交
127
	while (recovered < trimmed)
J
Jeff King 已提交
128
		if (ap[recovered++] == '\n')
L
Linus Torvalds 已提交
129 130 131
			break;
	a->size -= trimmed - recovered;
	b->size -= trimmed - recovered;
132 133
}

J
Junio C Hamano 已提交
134 135
int xdi_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, xdemitconf_t const *xecfg, xdemitcb_t *xecb)
{
136 137 138 139 140 141
	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 已提交
142 143
}

144 145 146 147
int read_mmfile(mmfile_t *ptr, const char *filename)
{
	struct stat st;
	FILE *f;
148
	size_t sz;
149 150 151 152 153

	if (stat(filename, &st))
		return error("Could not stat %s", filename);
	if ((f = fopen(filename, "rb")) == NULL)
		return error("Could not open %s", filename);
154
	sz = xsize_t(st.st_size);
155 156
	ptr->ptr = xmalloc(sz ? sz : 1);
	if (sz && fread(ptr->ptr, sz, 1, f) != 1)
157 158
		return error("Could not read %s", filename);
	fclose(f);
159
	ptr->size = sz;
160 161 162
	return 0;
}

163 164 165 166 167 168 169
#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);
}
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 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235

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;
}

void xdiff_set_find_func(xdemitconf_t *xecfg, const char *value)
{
	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;
		if (regcomp(&reg->re, expression, 0))
			die("Invalid regexp to look for hunk header: %s", expression);
236
		free(buffer);
237 238 239
		value = ep + 1;
	}
}