diff: fix flag -B, cleanups and a couple more tests V2
function old new delta diffreg 1157 1268 +111 uni_range 51 - -51 Signed-off-by: Matheus Izvekov <mizvekov@gmail.com> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
feadfe742a
commit
6f99c91e43
@ -368,16 +368,6 @@ static int line_compar(const void *a, const void *b)
|
|||||||
#undef l1
|
#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)
|
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++) {
|
for (int i = a; i <= b; i++) {
|
||||||
@ -561,17 +551,6 @@ start:
|
|||||||
return J;
|
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])
|
static bool diff(FILE* fp[2], char *file[2])
|
||||||
{
|
{
|
||||||
int nlen[2];
|
int nlen[2];
|
||||||
@ -580,22 +559,23 @@ static bool diff(FILE* fp[2], char *file[2])
|
|||||||
int *J = create_J(ft, nlen, ix);
|
int *J = create_J(ft, nlen, ix);
|
||||||
|
|
||||||
bool anychange = false;
|
bool anychange = false;
|
||||||
struct context_vec *vec = NULL;
|
typedef struct { int a, b; } vec_t[2];
|
||||||
int idx = -1, i = 1;
|
vec_t *vec = NULL;
|
||||||
|
int i = 1, idx = -1;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
bool nonempty = false;
|
bool nonempty = false;
|
||||||
|
|
||||||
while (1) {
|
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;
|
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;
|
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
|
* 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
|
* 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 appended (beginning at b). If c is greater than d then there are
|
||||||
* lines missing from the 'to' file.
|
* 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
|
* If this change is more than 'context' lines from the
|
||||||
* previous change, dump the record and reset it.
|
* previous change, dump the record and reset it.
|
||||||
*/
|
*/
|
||||||
|
int ct = (2 * opt_U_context) + 1;
|
||||||
if (idx >= 0
|
if (idx >= 0
|
||||||
&& v.a > vec[idx].b + (2 * opt_U_context) + 1
|
&& v[0].a > vec[idx][0].b + ct
|
||||||
&& v.c > vec[idx].d + (2 * opt_U_context) + 1
|
&& v[1].a > vec[idx][1].b + ct
|
||||||
) {
|
) {
|
||||||
break;
|
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 = 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])
|
if (i > nlen[0])
|
||||||
break;
|
break;
|
||||||
J[v.b] = v.d;
|
J[v[0].b] = v[1].b;
|
||||||
}
|
}
|
||||||
if (idx < 0)
|
if (idx < 0 || ((option_mask32 & FLAG(B)) && !nonempty))
|
||||||
continue;
|
goto cont;
|
||||||
if (!(option_mask32 & (FLAG(q)+FLAG(B))) && !nonempty) {
|
if (!(option_mask32 & FLAG(q))) {
|
||||||
struct context_vec *cvp = vec;
|
vec_t span, *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 (!anychange) {
|
if (!anychange) {
|
||||||
/* Print the context/unidiff header first time through */
|
/* 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("+++ %s\n", label[1] ? label[1] : file[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("@@ -");
|
printf("@@");
|
||||||
uni_range(lowa, upb);
|
for (int j = 0; j < 2; j++) {
|
||||||
printf(" +");
|
int a = span[j].a = MAX(1, (*cvp)[j].a - opt_U_context);
|
||||||
uni_range(lowc, upd);
|
int b = span[j].b = MIN(nlen[j], vec[idx][j].b + opt_U_context);
|
||||||
printf(" @@\n");
|
|
||||||
|
|
||||||
|
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
|
* Output changes in "unified" diff format--the old and new lines
|
||||||
* are printed together.
|
* are printed together.
|
||||||
*/
|
*/
|
||||||
while (1) {
|
for (int lowa = span[0].a; ; lowa = (*cvp++)[0].b + 1) {
|
||||||
bool end = cvp > &vec[idx];
|
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)
|
if (end)
|
||||||
break;
|
break;
|
||||||
fetch(&ft[0], ix[0], cvp->a, cvp->b, '-');
|
for (int j = 0; j < 2; j++)
|
||||||
fetch(&ft[1], ix[1], cvp->c, cvp->d, '+');
|
fetch(&ft[j], ix[j], (*cvp)[j].a, (*cvp)[j].b, j ? '+' : '-');
|
||||||
lowa = cvp++->b + 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
idx = -1;
|
|
||||||
anychange = true;
|
anychange = true;
|
||||||
|
cont:
|
||||||
|
idx = -1;
|
||||||
} while (i <= nlen[0]);
|
} while (i <= nlen[0]);
|
||||||
|
|
||||||
free(vec);
|
free(vec);
|
||||||
|
@ -44,6 +44,17 @@ testing "diff of stdin, twice" \
|
|||||||
"" \
|
"" \
|
||||||
"stdin"
|
"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" \
|
testing "diff -b treats EOF as whitespace" \
|
||||||
'diff -ub - input; echo $?' \
|
'diff -ub - input; echo $?' \
|
||||||
"0\n" \
|
"0\n" \
|
||||||
@ -56,6 +67,26 @@ testing "diff -b treats all spaces as equal" \
|
|||||||
"a \t c\n" \
|
"a \t c\n" \
|
||||||
"a\t \tc\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" \
|
testing "diff always takes context from old file" \
|
||||||
"diff -ub - input | $TRIM_TAB" \
|
"diff -ub - input | $TRIM_TAB" \
|
||||||
"\
|
"\
|
||||||
|
Loading…
Reference in New Issue
Block a user