aboutsummaryrefslogtreecommitdiffstats
path: root/xdiff-interface.c
diff options
context:
space:
mode:
Diffstat (limited to 'xdiff-interface.c')
-rw-r--r--xdiff-interface.c112
1 files changed, 57 insertions, 55 deletions
diff --git a/xdiff-interface.c b/xdiff-interface.c
index ec6e574e4a..5baf6ceb94 100644
--- a/xdiff-interface.c
+++ b/xdiff-interface.c
@@ -1,5 +1,6 @@
#include "cache.h"
#include "config.h"
+#include "hex.h"
#include "object-store.h"
#include "xdiff-interface.h"
#include "xdiff/xtypes.h"
@@ -9,76 +10,58 @@
#include "xdiff/xutils.h"
struct xdiff_emit_state {
- xdiff_emit_consume_fn consume;
+ xdiff_emit_hunk_fn hunk_fn;
+ xdiff_emit_line_fn line_fn;
void *consume_callback_data;
struct strbuf remainder;
};
-static int parse_num(char **cp_p, int *num_p)
+static int xdiff_out_hunk(void *priv_,
+ long old_begin, long old_nr,
+ long new_begin, long new_nr,
+ const char *func, long funclen)
{
- char *cp = *cp_p;
- int num = 0;
+ struct xdiff_emit_state *priv = priv_;
- while ('0' <= *cp && *cp <= '9')
- num = num * 10 + *cp++ - '0';
- if (!(cp - *cp_p))
- return -1;
- *cp_p = cp;
- *num_p = num;
- return 0;
-}
+ if (priv->remainder.len)
+ BUG("xdiff emitted hunk in the middle of a line");
-int parse_hunk_header(char *line, int len,
- int *ob, int *on,
- int *nb, int *nn)
-{
- 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);
+ priv->hunk_fn(priv->consume_callback_data,
+ old_begin, old_nr, new_begin, new_nr,
+ func, funclen);
+ return 0;
}
-static void consume_one(void *priv_, char *s, unsigned long size)
+static int consume_one(void *priv_, char *s, unsigned long size)
{
struct xdiff_emit_state *priv = priv_;
char *ep;
while (size) {
unsigned long this_size;
+ int ret;
ep = memchr(s, '\n', size);
this_size = (ep == NULL) ? size : (ep - s + 1);
- priv->consume(priv->consume_callback_data, s, this_size);
+ ret = priv->line_fn(priv->consume_callback_data, s, this_size);
+ if (ret)
+ return ret;
size -= this_size;
s += this_size;
}
+ return 0;
}
static int xdiff_outf(void *priv_, mmbuffer_t *mb, int nbuf)
{
struct xdiff_emit_state *priv = priv_;
int i;
+ int stop = 0;
+
+ if (!priv->line_fn)
+ return 0;
for (i = 0; i < nbuf; i++) {
+ if (stop)
+ return 1;
if (mb[i].ptr[mb[i].size-1] != '\n') {
/* Incomplete line */
strbuf_add(&priv->remainder, mb[i].ptr, mb[i].size);
@@ -87,17 +70,21 @@ static int xdiff_outf(void *priv_, mmbuffer_t *mb, int nbuf)
/* we have a complete line */
if (!priv->remainder.len) {
- consume_one(priv, mb[i].ptr, mb[i].size);
+ stop = consume_one(priv, mb[i].ptr, mb[i].size);
continue;
}
strbuf_add(&priv->remainder, mb[i].ptr, mb[i].size);
- consume_one(priv, priv->remainder.buf, priv->remainder.len);
+ stop = consume_one(priv, priv->remainder.buf, priv->remainder.len);
strbuf_reset(&priv->remainder);
}
+ if (stop)
+ return -1;
if (priv->remainder.len) {
- consume_one(priv, priv->remainder.buf, priv->remainder.len);
+ stop = consume_one(priv, priv->remainder.buf, priv->remainder.len);
strbuf_reset(&priv->remainder);
}
+ if (stop)
+ return -1;
return 0;
}
@@ -109,8 +96,8 @@ static void trim_common_tail(mmfile_t *a, mmfile_t *b)
{
const int blk = 1024;
long trimmed = 0, recovered = 0;
- char *ap = a->ptr + a->size;
- char *bp = b->ptr + b->size;
+ char *ap = a->size ? a->ptr + a->size : a->ptr;
+ char *bp = b->size ? b->ptr + b->size : b->ptr;
long smaller = (a->size < b->size) ? a->size : b->size;
while (blk + trimmed <= smaller && !memcmp(ap - blk, bp - blk, blk)) {
@@ -141,7 +128,9 @@ int xdi_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, xdemitconf_t co
}
int xdi_diff_outf(mmfile_t *mf1, mmfile_t *mf2,
- xdiff_emit_consume_fn fn, void *consume_callback_data,
+ xdiff_emit_hunk_fn hunk_fn,
+ xdiff_emit_line_fn line_fn,
+ void *consume_callback_data,
xpparam_t const *xpp, xdemitconf_t const *xecfg)
{
int ret;
@@ -149,10 +138,13 @@ int xdi_diff_outf(mmfile_t *mf1, mmfile_t *mf2,
xdemitcb_t ecb;
memset(&state, 0, sizeof(state));
- state.consume = fn;
+ state.hunk_fn = hunk_fn;
+ state.line_fn = line_fn;
state.consume_callback_data = consume_callback_data;
memset(&ecb, 0, sizeof(ecb));
- ecb.outf = xdiff_outf;
+ if (hunk_fn)
+ ecb.out_hunk = xdiff_out_hunk;
+ ecb.out_line = xdiff_outf;
ecb.priv = &state;
strbuf_init(&state.remainder, 0);
ret = xdi_diff(mf1, mf2, xpp, xecfg, &ecb);
@@ -168,7 +160,7 @@ int read_mmfile(mmfile_t *ptr, const char *filename)
if (stat(filename, &st))
return error_errno("Could not stat %s", filename);
- if ((f = fopen(filename, "rb")) == NULL)
+ if (!(f = fopen(filename, "rb")))
return error_errno("Could not open %s", filename);
sz = xsize_t(st.st_size);
ptr->ptr = xmalloc(sz ? sz : 1);
@@ -186,7 +178,7 @@ void read_mmblob(mmfile_t *ptr, const struct object_id *oid)
unsigned long size;
enum object_type type;
- if (!oidcmp(oid, &null_oid)) {
+ if (oideq(oid, null_oid())) {
ptr->ptr = xstrdup("");
ptr->size = 0;
return;
@@ -264,9 +256,13 @@ void xdiff_set_find_func(xdemitconf_t *xecfg, const char *value, int cflags)
ALLOC_ARRAY(regs->array, regs->nr);
for (i = 0; i < regs->nr; i++) {
struct ff_reg *reg = regs->array + i;
- const char *ep = strchr(value, '\n'), *expression;
+ const char *ep, *expression;
char *buffer = NULL;
+ if (!value)
+ BUG("mismatch between line count and parsing");
+ ep = strchr(value, '\n');
+
reg->negate = (*value == '!');
if (reg->negate && i == regs->nr - 1)
die("Last expression must not be negated: %s", value);
@@ -279,7 +275,7 @@ void xdiff_set_find_func(xdemitconf_t *xecfg, const char *value, int cflags)
if (regcomp(&reg->re, expression, cflags))
die("Invalid regexp to look for hunk header: %s", expression);
free(buffer);
- value = ep + 1;
+ value = ep ? ep + 1 : NULL;
}
}
@@ -318,8 +314,14 @@ int git_xmerge_config(const char *var, const char *value, void *cb)
die("'%s' is not a boolean", var);
if (!strcmp(value, "diff3"))
git_xmerge_style = XDL_MERGE_DIFF3;
+ else if (!strcmp(value, "zdiff3"))
+ git_xmerge_style = XDL_MERGE_ZEALOUS_DIFF3;
else if (!strcmp(value, "merge"))
git_xmerge_style = 0;
+ /*
+ * Please update _git_checkout() in
+ * git-completion.bash when you add new merge config
+ */
else
die("unknown style '%s' given for '%s'",
value, var);