commit - c03c6cb3ff916176aa6bec7e11bd85761b622f2b
commit + 078e971d4f71f224136916ca245ed368072f3c05
blob - a67190d470a1f4c501efe0c444fb978c1c945b9e
blob + 27eab4c76697959df3eabaa6437bcc6ccec0fe44
--- lib/diff3.c
+++ lib/diff3.c
struct range new;
};
-static size_t szchanges;
+struct diff3_state {
+ size_t szchanges;
-static struct diff *d13;
-static struct diff *d23;
+ struct diff *d13;
+ struct diff *d23;
-/*
- * "de" is used to gather editing scripts. These are later spewed out in
- * reverse order. Its first element must be all zero, the "new" component
- * of "de" contains line positions or byte positions depending on when you
- * look (!?). Array overlap indicates which sections in "de" correspond to
- * lines that are different in all three files.
- */
-static struct diff *de;
-static char *overlap;
-static int overlapcnt = 0;
-static FILE *fp[3];
-static int cline[3]; /* # of the last-read line in each file (0-2) */
+ /*
+ * "de" is used to gather editing scripts. These are later spewed out
+ * in reverse order. Its first element must be all zero, the "new"
+ * component of "de" contains line positions or byte positions
+ * depending on when you look (!?). Array overlap indicates which
+ * sections in "de" correspond to lines that are different in all
+ * three files.
+ */
+ struct diff *de;
+ char *overlap;
+ int overlapcnt;
+ FILE *fp[3];
+ int cline[3]; /* # of the last-read line in each file (0-2) */
+ /*
+ * the latest known correspondence between line numbers of the 3 files
+ * is stored in last[1-3];
+ */
+ int last[4];
+ int eflag;
+ int oflag;
+ int debug;
+ char f1mark[PATH_MAX], f3mark[PATH_MAX]; /* markers for -E and -X */
+};
+
static BUF *diffbuf;
-/*
- * the latest known correspondence between line numbers of the 3 files
- * is stored in last[1-3];
- */
-static int last[4];
-static int eflag = 3; /* default -E for compatibility with former RCS */
-static int oflag = 1; /* default -E for compatibility with former RCS */
-static int debug = 0;
-static char f1mark[PATH_MAX], f3mark[PATH_MAX]; /* markers for -E and -X */
-
-static int duplicate(struct range *, struct range *);
-static int edit(struct diff *, int, int);
+static int duplicate(struct range *, struct range *, struct diff3_state *);
+static int edit(struct diff *, int, int, struct diff3_state *);
static char *getchange(FILE *);
static char *get_line(FILE *, size_t *);
static int number(char **);
-static ssize_t readin(char *, struct diff **);
+static ssize_t readin(char *, struct diff **, struct diff3_state *);
static int ed_patch_lines(struct rcs_lines *, struct rcs_lines *);
-static int skip(int, int, char *);
-static int edscript(int);
-static int merge(size_t, size_t);
-static void change(int, struct range *, int);
-static void keep(int, struct range *);
+static int skip(int, int, char *, struct diff3_state *);
+static int edscript(int, struct diff3_state *);
+static int merge(size_t, size_t, struct diff3_state *);
+static void change(int, struct range *, int, struct diff3_state *);
+static void keep(int, struct range *, struct diff3_state *);
static void prange(struct range *);
-static void repos(int);
+static void repos(int, struct diff3_state *);
static void separate(const char *);
-static const struct got_error *increase(void);
+static const struct got_error *increase(struct diff3_state *);
static const struct got_error *diff3_internal(char *, char *, char *,
- char *, char *, const char *, const char *);
+ char *, char *, const char *, const char *, struct diff3_state *);
int diff3_conflicts = 0;
u_char *data, *patch;
size_t dlen, plen;
struct wklhead temp_files;
+ struct diff3_state *d3s;
*buf = NULL;
+ d3s = calloc(1, sizeof(*d3s));
+ if (d3s == NULL)
+ return got_error_from_errno();
+ d3s->eflag = 3; /* default -E for compatibility with former RCS */
+ d3s->oflag = 1; /* default -E for compatibility with former RCS */
+
b1 = b2 = b3 = d1 = d2 = diffb = NULL;
dp13 = dp23 = path1 = path2 = path3 = NULL;
data = patch = NULL;
if ((flags & MERGE_EFLAG) && !(flags & MERGE_OFLAG))
- oflag = 0;
+ d3s->oflag = 0;
if ((b1 = buf_load(av[0])) == NULL)
goto out;
d2 = NULL;
diffbuf = diffb;
- err = diff3_internal(dp13, dp23, path1, path2, path3, av[0], av[2]);
+ err = diff3_internal(dp13, dp23, path1, path2, path3, av[0], av[2],
+ d3s);
if (err) {
buf_free(diffb);
diffb = NULL;
static const struct got_error *
diff3_internal(char *dp13, char *dp23, char *path1, char *path2, char *path3,
- const char *fmark, const char *rmark)
+ const char *fmark, const char *rmark, struct diff3_state *d3s)
{
const struct got_error *err = NULL;
ssize_t m, n;
int i;
- i = snprintf(f1mark, sizeof(f1mark), "<<<<<<< %s", fmark);
- if (i < 0 || i >= (int)sizeof(f1mark))
+ i = snprintf(d3s->f1mark, sizeof(d3s->f1mark), "<<<<<<< %s", fmark);
+ if (i < 0 || i >= (int)sizeof(d3s->f1mark))
return got_error(GOT_ERR_NO_SPACE);
- i = snprintf(f3mark, sizeof(f3mark), ">>>>>>> %s", rmark);
- if (i < 0 || i >= (int)sizeof(f3mark))
+ i = snprintf(d3s->f3mark, sizeof(d3s->f3mark), ">>>>>>> %s", rmark);
+ if (i < 0 || i >= (int)sizeof(d3s->f3mark))
return got_error(GOT_ERR_NO_SPACE);
- err = increase();
+ err = increase(d3s);
if (err)
return err;
- if ((m = readin(dp13, &d13)) < 0)
+ if ((m = readin(dp13, &d3s->d13, d3s)) < 0)
return got_error_from_errno();
- if ((n = readin(dp23, &d23)) < 0)
+ if ((n = readin(dp23, &d3s->d23, d3s)) < 0)
return got_error_from_errno();
/* XXX LEAK: at present we never close these files! */
- if ((fp[0] = fopen(path1, "r")) == NULL)
+ if ((d3s->fp[0] = fopen(path1, "r")) == NULL)
return got_error_from_errno();
- if ((fp[1] = fopen(path2, "r")) == NULL)
+ if ((d3s->fp[1] = fopen(path2, "r")) == NULL)
return got_error_from_errno();
- if ((fp[2] = fopen(path3, "r")) == NULL)
+ if ((d3s->fp[2] = fopen(path3, "r")) == NULL)
return got_error_from_errno();
- if (merge(m, n) < 0)
+ if (merge(m, n, d3s) < 0)
return got_error_from_errno();
return NULL;
}
* The vector could be optimized out of existence)
*/
static ssize_t
-readin(char *name, struct diff **dd)
+readin(char *name, struct diff **dd, struct diff3_state *d3s)
{
int a, b, c, d;
char kind, *p;
size_t i;
- fp[0] = fopen(name, "r");
- if (fp[0] == NULL)
+ d3s->fp[0] = fopen(name, "r");
+ if (d3s->fp[0] == NULL)
return (-1);
- for (i = 0; (p = getchange(fp[0])); i++) {
- if (i >= szchanges - 1)
- increase();
+ for (i = 0; (p = getchange(d3s->fp[0])); i++) {
+ if (i >= d3s->szchanges - 1)
+ increase(d3s); /* XXX check error! */
a = b = number(&p);
if (*p == ',') {
p++;
(*dd)[i].new.from = (*dd)[i-1].new.to;
}
- (void)fclose(fp[0]);
+ (void)fclose(d3s->fp[0]);
return (i);
}
}
static int
-merge(size_t m1, size_t m2)
+merge(size_t m1, size_t m2, struct diff3_state *d3s)
{
struct diff *d1, *d2, *d3;
int dpl, j, t1, t2;
- d1 = d13;
- d2 = d23;
+ d1 = d3s->d13;
+ d2 = d3s->d23;
j = 0;
for (;;) {
- t1 = (d1 < d13 + m1);
- t2 = (d2 < d23 + m2);
+ t1 = (d1 < d3s->d13 + m1);
+ t2 = (d2 < d3s->d23 + m2);
if (!t1 && !t2)
break;
- if (debug) {
+ if (d3s->debug) {
printf("%d,%d=%d,%d %d,%d=%d,%d\n",
d1->old.from, d1->old.to,
d1->new.from, d1->new.to,
/* first file is different from others */
if (!t2 || (t1 && d1->new.to < d2->new.from)) {
/* stuff peculiar to 1st file */
- if (eflag==0) {
+ if (d3s->eflag == 0) {
separate("1");
- change(1, &d1->old, 0);
- keep(2, &d1->new);
- change(3, &d1->new, 0);
+ change(1, &d1->old, 0, d3s);
+ keep(2, &d1->new, d3s);
+ change(3, &d1->new, 0, d3s);
}
d1++;
continue;
/* second file is different from others */
if (!t1 || (t2 && d2->new.to < d1->new.from)) {
- if (eflag==0) {
+ if (d3s->eflag == 0) {
separate("2");
- keep(1, &d2->new);
- change(2, &d2->old, 0);
- change(3, &d2->new, 0);
+ keep(1, &d2->new, d3s);
+ change(2, &d2->old, 0, d3s);
+ change(3, &d2->new, 0, d3s);
}
d2++;
continue;
* Merge overlapping changes in first file
* this happens after extension (see below).
*/
- if (d1 + 1 < d13 + m1 && d1->new.to >= d1[1].new.from) {
+ if (d1 + 1 < d3s->d13 + m1 && d1->new.to >= d1[1].new.from) {
d1[1].old.from = d1->old.from;
d1[1].new.from = d1->new.from;
d1++;
}
/* merge overlapping changes in second */
- if (d2 + 1 < d23 + m2 && d2->new.to >= d2[1].new.from) {
+ if (d2 + 1 < d3s->d23 + m2 && d2->new.to >= d2[1].new.from) {
d2[1].old.from = d2->old.from;
d2[1].new.from = d2->new.from;
d2++;
}
/* stuff peculiar to third file or different in all */
if (d1->new.from == d2->new.from && d1->new.to == d2->new.to) {
- dpl = duplicate(&d1->old,&d2->old);
+ dpl = duplicate(&d1->old, &d2->old, d3s);
if (dpl == -1)
return (-1);
* dpl = 0 means all files differ
* dpl = 1 means files 1 and 2 identical
*/
- if (eflag==0) {
+ if (d3s->eflag == 0) {
separate(dpl ? "3" : "");
- change(1, &d1->old, dpl);
- change(2, &d2->old, 0);
+ change(1, &d1->old, dpl, d3s);
+ change(2, &d2->old, 0, d3s);
d3 = d1->old.to > d1->old.from ? d1 : d2;
- change(3, &d3->new, 0);
+ change(3, &d3->new, 0, d3s);
} else
- j = edit(d1, dpl, j);
+ j = edit(d1, dpl, j, d3s);
d1++;
d2++;
continue;
}
}
- return (edscript(j));
+ return (edscript(j, d3s));
}
static void
* printed later.
*/
static void
-change(int i, struct range *rold, int fdup)
+change(int i, struct range *rold, int fdup, struct diff3_state *d3s)
{
diff_output("%d:", i);
- last[i] = rold->to;
+ d3s->last[i] = rold->to;
prange(rold);
- if (fdup || debug)
+ if (fdup || d3s->debug)
return;
i--;
- (void)skip(i, rold->from, NULL);
- (void)skip(i, rold->to, " ");
+ (void)skip(i, rold->from, NULL, d3s);
+ (void)skip(i, rold->to, " ", d3s);
}
/*
* correspond to the change reported in the other file.
*/
static void
-keep(int i, struct range *rnew)
+keep(int i, struct range *rnew, struct diff3_state *d3s)
{
int delta;
struct range trange;
- delta = last[3] - last[i];
+ delta = d3s->last[3] - d3s->last[i];
trange.from = rnew->from - delta;
trange.to = rnew->to - delta;
- change(i, &trange, 1);
+ change(i, &trange, 1, d3s);
}
/*
* print all skipped stuff with string pr as a prefix.
*/
static int
-skip(int i, int from, char *pr)
+skip(int i, int from, char *pr, struct diff3_state *d3s)
{
size_t j, n;
char *line;
- for (n = 0; cline[i] < from - 1; n += j) {
- if ((line = get_line(fp[i], &j)) == NULL)
+ for (n = 0; d3s->cline[i] < from - 1; n += j) {
+ if ((line = get_line(d3s->fp[i], &j)) == NULL)
return (-1);
if (pr != NULL)
diff_output("%s%s", pr, line);
- cline[i]++;
+ d3s->cline[i]++;
}
return ((int) n);
}
* the same data as the new range (in file 2).
*/
static int
-duplicate(struct range *r1, struct range *r2)
+duplicate(struct range *r1, struct range *r2, struct diff3_state *d3s)
{
int c,d;
int nchar;
if (r1->to-r1->from != r2->to-r2->from)
return (0);
- (void)skip(0, r1->from, NULL);
- (void)skip(1, r2->from, NULL);
+ (void)skip(0, r1->from, NULL, d3s);
+ (void)skip(1, r2->from, NULL, d3s);
nchar = 0;
for (nline=0; nline < r1->to - r1->from; nline++) {
do {
- c = getc(fp[0]);
- d = getc(fp[1]);
+ c = getc(d3s->fp[0]);
+ d = getc(d3s->fp[1]);
if (c == -1 || d== -1)
return (-1);
nchar++;
if (c != d) {
- repos(nchar);
+ repos(nchar, d3s);
return (0);
}
} while (c != '\n');
}
- repos(nchar);
+ repos(nchar, d3s);
return (1);
}
static void
-repos(int nchar)
+repos(int nchar, struct diff3_state *d3s)
{
int i;
for (i = 0; i < 2; i++)
- (void)fseek(fp[i], (long)-nchar, SEEK_CUR);
+ (void)fseek(d3s->fp[i], (long)-nchar, SEEK_CUR);
}
/*
* collect an editing script for later regurgitation
*/
static int
-edit(struct diff *diff, int fdup, int j)
+edit(struct diff *diff, int fdup, int j, struct diff3_state *d3s)
{
- if (((fdup + 1) & eflag) == 0)
+ if (((fdup + 1) & d3s->eflag) == 0)
return (j);
j++;
- overlap[j] = !fdup;
+ d3s->overlap[j] = !fdup;
if (!fdup)
- overlapcnt++;
- de[j].old.from = diff->old.from;
- de[j].old.to = diff->old.to;
- de[j].new.from = de[j-1].new.to + skip(2, diff->new.from, NULL);
- de[j].new.to = de[j].new.from + skip(2, diff->new.to, NULL);
+ d3s->overlapcnt++;
+ d3s->de[j].old.from = diff->old.from;
+ d3s->de[j].old.to = diff->old.to;
+ d3s->de[j].new.from =
+ d3s->de[j-1].new.to + skip(2, diff->new.from, NULL, d3s);
+ d3s->de[j].new.to =
+ d3s->de[j].new.from + skip(2, diff->new.to, NULL, d3s);
return (j);
}
/* regurgitate */
static int
-edscript(int n)
+edscript(int n, struct diff3_state *d3s)
{
int j, k;
char block[BUFSIZ+1];
for (; n > 0; n--) {
- if (!oflag || !overlap[n])
- prange(&de[n].old);
+ if (!d3s->oflag || !d3s->overlap[n])
+ prange(&d3s->de[n].old);
else
- diff_output("%da\n=======\n", de[n].old.to -1);
- (void)fseek(fp[2], (long)de[n].new.from, SEEK_SET);
- for (k = de[n].new.to-de[n].new.from; k > 0; k-= j) {
+ diff_output("%da\n=======\n", d3s->de[n].old.to -1);
+ (void)fseek(d3s->fp[2], (long)d3s->de[n].new.from, SEEK_SET);
+ k = d3s->de[n].new.to - d3s->de[n].new.from;
+ for (; k > 0; k-= j) {
j = k > BUFSIZ ? BUFSIZ : k;
- if (fread(block, 1, j, fp[2]) != (size_t)j)
+ if (fread(block, 1, j, d3s->fp[2]) != (size_t)j)
return (-1);
block[j] = '\0';
diff_output("%s", block);
}
- if (!oflag || !overlap[n])
+ if (!d3s->oflag || !d3s->overlap[n])
diff_output(".\n");
else {
- diff_output("%s\n.\n", f3mark);
- diff_output("%da\n%s\n.\n", de[n].old.from - 1, f1mark);
+ diff_output("%s\n.\n", d3s->f3mark);
+ diff_output("%da\n%s\n.\n", d3s->de[n].old.from - 1,
+ d3s->f1mark);
}
}
- return (overlapcnt);
+ return (d3s->overlapcnt);
}
static const struct got_error *
-increase(void)
+increase(struct diff3_state *d3s)
{
size_t newsz, incr;
struct diff *d;
char *s;
/* are the memset(3) calls needed? */
- newsz = szchanges == 0 ? 64 : 2 * szchanges;
- incr = newsz - szchanges;
+ newsz = d3s->szchanges == 0 ? 64 : 2 * d3s->szchanges;
+ incr = newsz - d3s->szchanges;
- d = reallocarray(d13, newsz, sizeof(*d13));
+ d = reallocarray(d3s->d13, newsz, sizeof(*d3s->d13));
if (d == NULL)
return got_error_from_errno();
- d13 = d;
- memset(d13 + szchanges, 0, incr * sizeof(*d13));
+ d3s->d13 = d;
+ memset(d3s->d13 + d3s->szchanges, 0, incr * sizeof(*d3s->d13));
- d = reallocarray(d23, newsz, sizeof(*d23));
+ d = reallocarray(d3s->d23, newsz, sizeof(*d3s->d23));
if (d == NULL)
return got_error_from_errno();
- d23 = d;
- memset(d23 + szchanges, 0, incr * sizeof(*d23));
+ d3s->d23 = d;
+ memset(d3s->d23 + d3s->szchanges, 0, incr * sizeof(*d3s->d23));
- d = reallocarray(de, newsz, sizeof(*de));
+ d = reallocarray(d3s->de, newsz, sizeof(*d3s->de));
if (d == NULL)
return got_error_from_errno();
- de = d;
- memset(de + szchanges, 0, incr * sizeof(*de));
+ d3s->de = d;
+ memset(d3s->de + d3s->szchanges, 0, incr * sizeof(*d3s->de));
- s = reallocarray(overlap, newsz, sizeof(*overlap));
+ s = reallocarray(d3s->overlap, newsz, sizeof(*d3s->overlap));
if (s == NULL)
return got_error_from_errno();
- overlap = s;
- memset(overlap + szchanges, 0, incr * sizeof(*overlap));
- szchanges = newsz;
+ d3s->overlap = s;
+ memset(d3s->overlap + d3s->szchanges, 0, incr * sizeof(*d3s->overlap));
+ d3s->szchanges = newsz;
return NULL;
}