[git commit master] diff: fix flag -B, cleanups and a couple more tests V2

Denys Vlasenko vda.linux at googlemail.com
Fri Jan 22 03:20:16 UTC 2010


commit: http://git.busybox.net/busybox/commit/?id=6f99c91e431a5afb90ac6d041ea9b08d39c965eb
branch: http://git.busybox.net/busybox/commit/?id=refs/heads/master

function                                             old     new   delta
diffreg                                             1157    1268    +111
uni_range                                             51       -     -51

Signed-off-by: Matheus Izvekov <mizvekov at gmail.com>
Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 editors/diff.c       |   94 +++++++++++++++++++++----------------------------
 testsuite/diff.tests |   31 ++++++++++++++++
 2 files changed, 71 insertions(+), 54 deletions(-)

diff --git a/editors/diff.c b/editors/diff.c
index 2e3a455..e4d74ab 100644
--- a/editors/diff.c
+++ b/editors/diff.c
@@ -368,16 +368,6 @@ static int line_compar(const void *a, const void *b)
 #undef l1
 }
 
-static void uni_range(int a, int b)
-{
-	if (a < b)
-		printf("%d,%d", a, b - a + 1);
-	else if (a == b)
-		printf("%d", b);
-	else
-		printf("%d,0", b);
-}
-
 static void fetch(FILE_and_pos_t *ft, const off_t *ix, int a, int b, int ch)
 {
 	for (int i = a; i <= b; i++) {
@@ -561,17 +551,6 @@ start:
 	return J;
 }
 
-/*
- * The following struct is used to record change information
- * doing a "context" or "unified" diff.
- */
-struct context_vec {
-	int a;          /* start line in old file */
-	int b;          /* end line in old file */
-	int c;          /* start line in new file */
-	int d;          /* end line in new file */
-};
-
 static bool diff(FILE* fp[2], char *file[2])
 {
 	int nlen[2];
@@ -580,22 +559,23 @@ static bool diff(FILE* fp[2], char *file[2])
 	int *J = create_J(ft, nlen, ix);
 
 	bool anychange = false;
-	struct context_vec *vec = NULL;
-	int idx = -1, i = 1;
+	typedef struct { int a, b; } vec_t[2];
+	vec_t *vec = NULL;
+	int i = 1, idx = -1;
 
 	do {
 		bool nonempty = false;
 
 		while (1) {
-			struct context_vec v;
+			vec_t v;
 
-			for (v.a = i; v.a <= nlen[0] && J[v.a] == J[v.a - 1] + 1; v.a++)
+			for (v[0].a = i; v[0].a <= nlen[0] && J[v[0].a] == J[v[0].a - 1] + 1; v[0].a++)
 				continue;
-			v.c = J[v.a - 1] + 1;
+			v[1].a = J[v[0].a - 1] + 1;
 
-			for (v.b = v.a - 1; v.b < nlen[0] && !J[v.b + 1]; v.b++)
+			for (v[0].b = v[0].a - 1; v[0].b < nlen[0] && !J[v[0].b + 1]; v[0].b++)
 				continue;
-			v.d = J[v.b + 1] - 1;
+			v[1].b = J[v[0].b + 1] - 1;
 			/*
 			 * Indicate that there is a difference between lines a and b of the 'from' file
 			 * to get to lines c to d of the 'to' file. If a is greater than b then there
@@ -603,35 +583,36 @@ static bool diff(FILE* fp[2], char *file[2])
 			 * lines appended (beginning at b).  If c is greater than d then there are
 			 * lines missing from the 'to' file.
 			 */
-			if (v.a <= v.b || v.c <= v.d) {
+			if (v[0].a <= v[0].b || v[1].a <= v[1].b) {
 				/*
 				 * If this change is more than 'context' lines from the
 				 * previous change, dump the record and reset it.
 				 */
+				int ct = (2 * opt_U_context) + 1;
 				if (idx >= 0
-				 && v.a > vec[idx].b + (2 * opt_U_context) + 1
-				 && v.c > vec[idx].d + (2 * opt_U_context) + 1
+				 && v[0].a > vec[idx][0].b + ct
+				 && v[1].a > vec[idx][1].b + ct
 				) {
 					break;
 				}
-				nonempty |= (v.a >= v.b) && (v.c >= v.d);
+
+				for (int j = 0; j < 2; j++)
+					for (int k = v[j].a; k < v[j].b; k++)
+						nonempty |= (ix[j][k+1] - ix[j][k] != 1);
+
 				vec = xrealloc_vector(vec, 6, ++idx);
-				vec[idx] = v;
+				memcpy(vec[idx], v, sizeof(v));
 			}
 
-			i = v.b + 1;
+			i = v[0].b + 1;
 			if (i > nlen[0])
 				break;
-			J[v.b] = v.d;
+			J[v[0].b] = v[1].b;
 		}
-		if (idx < 0)
-			continue;
-		if (!(option_mask32 & (FLAG(q)+FLAG(B))) && !nonempty) {
-			struct context_vec *cvp = vec;
-			int lowa = MAX(1, cvp->a - opt_U_context);
-			int upb  = MIN(nlen[0], vec[idx].b + opt_U_context);
-			int lowc = MAX(1, cvp->c - opt_U_context);
-			int upd  = MIN(nlen[1], vec[idx].d + opt_U_context);
+		if (idx < 0 || ((option_mask32 & FLAG(B)) && !nonempty))
+			goto cont;
+		if (!(option_mask32 & FLAG(q))) {
+			vec_t span, *cvp = vec;
 
 			if (!anychange) {
 				/* Print the context/unidiff header first time through */
@@ -639,28 +620,33 @@ static bool diff(FILE* fp[2], char *file[2])
 				printf("+++ %s\n", label[1] ? label[1] : file[1]);
 			}
 
-			printf("@@ -");
-			uni_range(lowa, upb);
-			printf(" +");
-			uni_range(lowc, upd);
-			printf(" @@\n");
+			printf("@@");
+			for (int j = 0; j < 2; j++) {
+				int a = span[j].a = MAX(1, (*cvp)[j].a - opt_U_context);
+				int b = span[j].b = MIN(nlen[j], vec[idx][j].b + opt_U_context);
 
+				printf(" %c%d", j ? '+' : '-', MIN(a, b));
+				if (a == b)
+					continue;
+				printf(",%d", (a < b) ? b - a + 1 : 0);
+			}
+			printf(" @@\n");
 			/*
 			 * Output changes in "unified" diff format--the old and new lines
 			 * are printed together.
 			 */
-			while (1) {
+			for (int lowa = span[0].a; ; lowa = (*cvp++)[0].b + 1) {
 				bool end = cvp > &vec[idx];
-				fetch(&ft[0], ix[0], lowa, end ? upb : cvp->a - 1, ' ');
+				fetch(&ft[0], ix[0], lowa, end ? span[0].b : (*cvp)[0].a - 1, ' ');
 				if (end)
 					break;
-				fetch(&ft[0], ix[0], cvp->a, cvp->b, '-');
-				fetch(&ft[1], ix[1], cvp->c, cvp->d, '+');
-				lowa = cvp++->b + 1;
+				for (int j = 0; j < 2; j++)
+					fetch(&ft[j], ix[j], (*cvp)[j].a, (*cvp)[j].b, j ? '+' : '-');
 			}
 		}
-		idx = -1;
 		anychange = true;
+ cont:
+		idx = -1;
 	} while (i <= nlen[0]);
 
 	free(vec);
diff --git a/testsuite/diff.tests b/testsuite/diff.tests
index f7bde2f..72ebb6c 100755
--- a/testsuite/diff.tests
+++ b/testsuite/diff.tests
@@ -44,6 +44,17 @@ testing "diff of stdin, twice" \
 	"" \
 	"stdin"
 
+testing "diff of empty file against nonempty one" \
+	"diff -u - input | $TRIM_TAB" \
+"\
+--- -
++++ input
+@@ -0,0 +1 @@
++a
+" \
+	"a\n" \
+	""
+
 testing "diff -b treats EOF as whitespace" \
 	'diff -ub - input; echo $?' \
 	"0\n" \
@@ -56,6 +67,26 @@ testing "diff -b treats all spaces as equal" \
 	"a \t c\n" \
 	"a\t \tc\n"
 
+testing "diff -B ignores changes whose lines are all blank" \
+	'diff -uB - input; echo $?' \
+	"0\n" \
+	"a\n" \
+	"\na\n\n"
+
+testing "diff -B does not ignore changes whose lines are not all blank" \
+	"diff -uB - input | $TRIM_TAB" \
+"\
+--- -
++++ input
+@@ -1,3 +1 @@
+-
+-b
+-
++a
+" \
+	"a\n" \
+	"\nb\n\n"
+
 testing "diff always takes context from old file" \
 	"diff -ub - input | $TRIM_TAB" \
 "\
-- 
1.6.3.3



More information about the busybox-cvs mailing list