Commit Diff


commit - c03c6cb3ff916176aa6bec7e11bd85761b622f2b
commit + 078e971d4f71f224136916ca245ed368072f3c05
blob - a67190d470a1f4c501efe0c444fb978c1c945b9e
blob + 27eab4c76697959df3eabaa6437bcc6ccec0fe44
--- lib/diff3.c
+++ lib/diff3.c
@@ -115,54 +115,57 @@ struct diff {
 	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;
 
@@ -262,15 +265,22 @@ merge_diff3(BUF **buf, char **av, int flags)
 	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;
@@ -344,7 +354,8 @@ merge_diff3(BUF **buf, char **av, int flags)
 	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;
@@ -387,37 +398,37 @@ out:
 
 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;
 }
@@ -540,18 +551,18 @@ ed_patch_lines(struct rcs_lines *dlines, struct rcs_li
  * 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++;
@@ -580,7 +591,7 @@ readin(char *name, struct diff **dd)
 		(*dd)[i].new.from = (*dd)[i-1].new.to;
 	}
 
-	(void)fclose(fp[0]);
+	(void)fclose(d3s->fp[0]);
 
 	return (i);
 }
@@ -644,21 +655,21 @@ get_line(FILE *b, size_t *n)
 }
 
 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,
@@ -669,11 +680,11 @@ merge(size_t m1, size_t m2)
 		/* 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;
@@ -681,11 +692,11 @@ merge(size_t m1, size_t m2)
 
 		/* 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;
@@ -695,7 +706,7 @@ merge(size_t m1, size_t m2)
 		 * 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++;
@@ -703,7 +714,7 @@ merge(size_t m1, size_t m2)
 		}
 
 		/* 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++;
@@ -711,7 +722,7 @@ merge(size_t m1, size_t m2)
 		}
 		/* 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);
 
@@ -719,14 +730,14 @@ merge(size_t m1, size_t m2)
 			 * 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;
@@ -752,7 +763,7 @@ merge(size_t m1, size_t m2)
 		}
 	}
 
-	return (edscript(j));
+	return (edscript(j, d3s));
 }
 
 static void
@@ -767,16 +778,16 @@ separate(const char *s)
  * 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);
 }
 
 /*
@@ -801,15 +812,15 @@ prange(struct range *rold)
  * 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);
 }
 
 /*
@@ -817,17 +828,17 @@ keep(int i, struct range *rnew)
  * 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);
 }
@@ -837,7 +848,7 @@ skip(int i, int from, char *pr)
  * 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;
@@ -845,121 +856,125 @@ duplicate(struct range *r1, struct range *r2)
 
 	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;
 }