version 1.13, 2007/05/30 03:30:21 |
version 1.14, 2007/06/29 05:04:40 |
|
|
* |
* |
* @(#)diffreg.c 8.1 (Berkeley) 6/6/93 |
* @(#)diffreg.c 8.1 (Berkeley) 6/6/93 |
*/ |
*/ |
|
|
|
#include <sys/param.h> |
|
#include <sys/stat.h> |
|
|
|
#include <ctype.h> |
|
#include <errno.h> |
|
#include <regex.h> |
|
#include <stddef.h> |
|
#include <string.h> |
|
#include <unistd.h> |
|
|
|
#include "cvs.h" |
|
#include "diff.h" |
|
|
/* |
/* |
|
* diff - compare two files. |
|
*/ |
|
|
|
/* |
* Uses an algorithm due to Harold Stone, which finds |
* Uses an algorithm due to Harold Stone, which finds |
* a pair of longest identical subsequences in the two |
* a pair of longest identical subsequences in the two |
* files. |
* files. |
|
|
* 6n words for files of length n. |
* 6n words for files of length n. |
*/ |
*/ |
|
|
#include <sys/param.h> |
|
#include <sys/stat.h> |
|
|
|
#include <ctype.h> |
|
#include <errno.h> |
|
#include <regex.h> |
|
#include <stddef.h> |
|
#include <string.h> |
|
#include <unistd.h> |
|
|
|
#include "cvs.h" |
|
#include "diff.h" |
|
|
|
struct cand { |
struct cand { |
int x; |
int x; |
int y; |
int y; |
|
|
static void uni_range(int, int); |
static void uni_range(int, int); |
static void dump_context_vec(FILE *, FILE *); |
static void dump_context_vec(FILE *, FILE *); |
static void dump_unified_vec(FILE *, FILE *); |
static void dump_unified_vec(FILE *, FILE *); |
static int prepare(int, FILE *, off_t); |
static void prepare(int, FILE *, off_t); |
static void prune(void); |
static void prune(void); |
static void equiv(struct line *, int, struct line *, int, int *); |
static void equiv(struct line *, int, struct line *, int, int *); |
static void unravel(int); |
static void unravel(int); |
|
|
static int *member; /* will be overlaid on file[1] */ |
static int *member; /* will be overlaid on file[1] */ |
static int clen; |
static int clen; |
static int inifdef; /* whether or not we are in a #ifdef block */ |
static int inifdef; /* whether or not we are in a #ifdef block */ |
static int diff_len[2]; |
static int len[2]; |
static int pref, suff; /* length of prefix and suffix */ |
static int pref, suff; /* length of prefix and suffix */ |
static int slen[2]; |
static int slen[2]; |
static int anychange; |
static int anychange; |
|
|
static int lastmatchline; |
static int lastmatchline; |
BUF *diffbuf = NULL; |
BUF *diffbuf = NULL; |
|
|
|
|
/* |
/* |
* chrtran points to one of 2 translation tables: cup2low if folding upper to |
* chrtran points to one of 2 translation tables: cup2low if folding upper to |
* lower case clow2low if not folding case |
* lower case clow2low if not folding case |
|
|
cvs_log(LP_ERR, "%s", file2); |
cvs_log(LP_ERR, "%s", file2); |
goto closem; |
goto closem; |
} |
} |
|
|
switch (files_differ(f1, f2)) { |
switch (files_differ(f1, f2)) { |
case 0: |
case 0: |
goto closem; |
goto closem; |
|
|
rval = D_BINARY; |
rval = D_BINARY; |
goto closem; |
goto closem; |
} |
} |
if (prepare(0, f1, stb1.st_size) < 0 || |
|
prepare(1, f2, stb2.st_size) < 0) { |
prepare(0, f1, stb1.st_size); |
goto closem; |
prepare(1, f2, stb2.st_size); |
} |
|
prune(); |
prune(); |
sort(sfile[0], slen[0]); |
sort(sfile[0], slen[0]); |
sort(sfile[1], slen[1]); |
sort(sfile[1], slen[1]); |
|
|
clen = 0; |
clen = 0; |
clistlen = 100; |
clistlen = 100; |
clist = xcalloc(clistlen, sizeof(*clist)); |
clist = xcalloc(clistlen, sizeof(*clist)); |
|
i = stone(class, slen[0], member, klist); |
if ((i = stone(class, slen[0], member, klist)) < 0) |
|
goto closem; |
|
|
|
xfree(member); |
xfree(member); |
xfree(class); |
xfree(class); |
|
|
J = xrealloc(J, diff_len[0] + 2, sizeof(*J)); |
J = xrealloc(J, len[0] + 2, sizeof(*J)); |
unravel(klist[i]); |
unravel(klist[i]); |
xfree(clist); |
xfree(clist); |
xfree(klist); |
xfree(klist); |
|
|
ixold = xrealloc(ixold, diff_len[0] + 2, sizeof(*ixold)); |
ixold = xrealloc(ixold, len[0] + 2, sizeof(*ixold)); |
|
ixnew = xrealloc(ixnew, len[1] + 2, sizeof(*ixnew)); |
ixnew = xrealloc(ixnew, diff_len[1] + 2, sizeof(*ixnew)); |
|
check(f1, f2); |
check(f1, f2); |
output(f1, f2); |
output(f1, f2); |
|
|
closem: |
closem: |
if (anychange == 1) { |
if (anychange) { |
if (rval == D_SAME) |
if (rval == D_SAME) |
rval = D_DIFFER; |
rval = D_DIFFER; |
} |
} |
|
|
} |
} |
} |
} |
|
|
static int |
static void |
prepare(int i, FILE *fd, off_t filesize) |
prepare(int i, FILE *fd, off_t filesize) |
{ |
{ |
struct line *p; |
struct line *p; |
|
|
|
|
p = xcalloc(sz + 3, sizeof(*p)); |
p = xcalloc(sz + 3, sizeof(*p)); |
for (j = 0; (h = readhash(fd));) { |
for (j = 0; (h = readhash(fd));) { |
if (j == (int)sz) { |
if (j == sz) { |
sz = sz * 3 / 2; |
sz = sz * 3 / 2; |
p = xrealloc(p, sz + 3, sizeof(*p)); |
p = xrealloc(p, sz + 3, sizeof(*p)); |
} |
} |
p[++j].value = h; |
p[++j].value = h; |
} |
} |
diff_len[i] = j; |
len[i] = j; |
file[i] = p; |
file[i] = p; |
|
|
return (0); |
|
} |
} |
|
|
static void |
static void |
|
|
{ |
{ |
int i, j; |
int i, j; |
|
|
for (pref = 0; pref < diff_len[0] && pref < diff_len[1] && |
for (pref = 0; pref < len[0] && pref < len[1] && |
file[0][pref + 1].value == file[1][pref + 1].value; |
file[0][pref + 1].value == file[1][pref + 1].value; |
pref++) |
pref++) |
; |
; |
for (suff = 0; |
for (suff = 0; suff < len[0] - pref && suff < len[1] - pref && |
(suff < diff_len[0] - pref) && (suff < diff_len[1] - pref) && |
file[0][len[0] - suff].value == file[1][len[1] - suff].value; |
(file[0][diff_len[0] - suff].value == |
|
file[1][diff_len[1] - suff].value); |
|
suff++) |
suff++) |
; |
; |
for (j = 0; j < 2; j++) { |
for (j = 0; j < 2; j++) { |
sfile[j] = file[j] + pref; |
sfile[j] = file[j] + pref; |
slen[j] = diff_len[j] - pref - suff; |
slen[j] = len[j] - pref - suff; |
for (i = 0; i <= slen[j]; i++) |
for (i = 0; i <= slen[j]; i++) |
sfile[j][i].serial = i; |
sfile[j][i].serial = i; |
} |
} |
|
|
x = n / x; |
x = n / x; |
x += y; |
x += y; |
x /= 2; |
x /= 2; |
} while (x - y > 1 || x - y < -1); |
} while ((x - y) > 1 || (x - y) < -1); |
|
|
return (x); |
return (x); |
} |
} |
|
|
static int |
static int |
stone(int *a, int n, int *b, int *c) |
stone(int *a, int n, int *b, int *c) |
{ |
{ |
int ret; |
|
int i, k, y, j, l; |
int i, k, y, j, l; |
int oldc, tc, oldl; |
int oldc, tc, oldl; |
u_int numtries; |
u_int numtries; |
|
|
const u_int bound = dflag ? UINT_MAX : MAX(256, (u_int)isqrt(n)); |
const u_int bound = dflag ? UINT_MAX : MAX(256, (u_int)isqrt(n)); |
|
|
k = 0; |
k = 0; |
if ((ret = newcand(0, 0, 0)) < 0) |
c[0] = newcand(0, 0, 0); |
return (-1); |
|
c[0] = ret; |
|
for (i = 1; i <= n; i++) { |
for (i = 1; i <= n; i++) { |
j = a[i]; |
j = a[i]; |
if (j == 0) |
if (j == 0) |
|
|
if (clist[c[l]].y <= y) |
if (clist[c[l]].y <= y) |
continue; |
continue; |
tc = c[l]; |
tc = c[l]; |
if ((ret = newcand(i, y, oldc)) < 0) |
c[l] = newcand(i, y, oldc); |
return (-1); |
|
c[l] = ret; |
|
oldc = tc; |
oldc = tc; |
oldl = l; |
oldl = l; |
numtries++; |
numtries++; |
} else { |
} else { |
if ((ret = newcand(i, y, oldc)) < 0) |
c[l] = newcand(i, y, oldc); |
return (-1); |
|
c[l] = ret; |
|
k++; |
k++; |
break; |
break; |
} |
} |
|
|
struct cand *q; |
struct cand *q; |
int i; |
int i; |
|
|
for (i = 0; i <= diff_len[0]; i++) |
for (i = 0; i <= len[0]; i++) |
J[i] = i <= pref ? i : |
J[i] = i <= pref ? i : |
i > diff_len[0] - suff ? i + diff_len[1] - diff_len[0] : 0; |
i > len[0] - suff ? i + len[1] - len[0] : 0; |
for (q = clist + p; q->y != 0; q = clist + q->pred) |
for (q = clist + p; q->y != 0; q = clist + q->pred) |
J[q->x + pref] = q->y + pref; |
J[q->x + pref] = q->y + pref; |
} |
} |
|
|
ixold[0] = ixnew[0] = 0; |
ixold[0] = ixnew[0] = 0; |
jackpot = 0; |
jackpot = 0; |
ctold = ctnew = 0; |
ctold = ctnew = 0; |
for (i = 1; i <= diff_len[0]; i++) { |
for (i = 1; i <= len[0]; i++) { |
if (J[i] == 0) { |
if (J[i] == 0) { |
ixold[i] = ctold += skipline(f1); |
ixold[i] = ctold += skipline(f1); |
continue; |
continue; |
|
|
d = getc(f2); |
d = getc(f2); |
/* |
/* |
* GNU diff ignores a missing newline |
* GNU diff ignores a missing newline |
* in one file if bflag || wflag. |
* in one file for -b or -w. |
*/ |
*/ |
if ((bflag == 1 || wflag == 1) && |
if ((bflag == 1 || wflag == 1) && |
((c == EOF && d == '\n') || |
((c == EOF && d == '\n') || |
|
|
ixnew[j] = ctnew; |
ixnew[j] = ctnew; |
j++; |
j++; |
} |
} |
for (; j <= diff_len[1]; j++) |
for (; j <= len[1]; j++) |
ixnew[j] = ctnew += skipline(f2); |
ixnew[j] = ctnew += skipline(f2); |
/* |
/* |
* if (jackpot != 0) |
* if (jackpot) |
* cvs_printf("jackpot\n"); |
* fprintf(stderr, "jackpot\n"); |
*/ |
*/ |
} |
} |
|
|
|
|
|
|
rewind(f1); |
rewind(f1); |
rewind(f2); |
rewind(f2); |
m = diff_len[0]; |
m = len[0]; |
J[0] = 0; |
J[0] = 0; |
J[m + 1] = diff_len[1] + 1; |
J[m + 1] = len[1] + 1; |
for (i0 = 1; i0 <= m; i0 = i1 + 1) { |
for (i0 = 1; i0 <= m; i0 = i1 + 1) { |
while (i0 <= m && J[i0] == J[i0 - 1] + 1) |
while (i0 <= m && J[i0] == J[i0 - 1] + 1) |
i0++; |
i0++; |
|
|
change(f1, f2, i0, i1, j0, j1); |
change(f1, f2, i0, i1, j0, j1); |
} |
} |
if (m == 0) |
if (m == 0) |
change(f1, f2, 1, 0, 1, diff_len[1]); |
change(f1, f2, 1, 0, 1, len[1]); |
if (diff_format == D_IFDEF) { |
if (diff_format == D_IFDEF) { |
for (;;) { |
for (;;) { |
#define c i0 |
#define c i0 |
|
|
static void |
static void |
change(FILE *f1, FILE *f2, int a, int b, int c, int d) |
change(FILE *f1, FILE *f2, int a, int b, int c, int d) |
{ |
{ |
int i; |
|
static size_t max_context = 64; |
static size_t max_context = 64; |
char buf[64]; |
char buf[64]; |
struct tm *t; |
struct tm *t; |
|
int i; |
|
|
if (diff_format != D_IFDEF && a > b && c > d) |
if (diff_format != D_IFDEF && a > b && c > d) |
return; |
return; |
|
|
for (i = 0;;) { |
for (i = 0;;) { |
switch (t = getc(f)) { |
switch (t = getc(f)) { |
case '\t': |
case '\t': |
|
case '\r': |
|
case '\v': |
|
case '\f': |
case ' ': |
case ' ': |
space++; |
space++; |
continue; |
continue; |
|
|
static int |
static int |
asciifile(FILE *f) |
asciifile(FILE *f) |
{ |
{ |
char buf[BUFSIZ]; |
unsigned char buf[BUFSIZ]; |
size_t i, cnt; |
size_t i, cnt; |
|
|
if (aflag == 1 || f == NULL) |
if (aflag == 1 || f == NULL) |
|
|
|
|
#define begins_with(s, pre) (strncmp(s, pre, sizeof(pre)-1) == 0) |
#define begins_with(s, pre) (strncmp(s, pre, sizeof(pre)-1) == 0) |
|
|
static char* |
static char * |
match_function(const long *f, int pos, FILE *fp) |
match_function(const long *f, int pos, FILE *fp) |
{ |
{ |
unsigned char buf[FUNCTION_CONTEXT_SIZE]; |
unsigned char buf[FUNCTION_CONTEXT_SIZE]; |
|
|
if (!state) |
if (!state) |
state = " (public)"; |
state = " (public)"; |
} else { |
} else { |
strlcpy(lastbuf, (const char *)buf, |
strlcpy(lastbuf, buf, |
sizeof lastbuf); |
sizeof lastbuf); |
if (state) |
if (state) |
strlcat(lastbuf, state, |
strlcat(lastbuf, state, |
|
|
} |
} |
pos--; |
pos--; |
} |
} |
return (lastmatchline > 0) ? lastbuf : NULL; |
return lastmatchline > 0 ? lastbuf : NULL; |
} |
} |
|
|
|
|
/* dump accumulated "context" diff changes */ |
/* dump accumulated "context" diff changes */ |
static void |
static void |
dump_context_vec(FILE *f1, FILE *f2) |
dump_context_vec(FILE *f1, FILE *f2) |
|
|
|
|
b = d = 0; /* gcc */ |
b = d = 0; /* gcc */ |
lowa = MAX(1, cvp->a - context); |
lowa = MAX(1, cvp->a - context); |
upb = MIN(diff_len[0], context_vec_ptr->b + context); |
upb = MIN(len[0], context_vec_ptr->b + context); |
lowc = MAX(1, cvp->c - context); |
lowc = MAX(1, cvp->c - context); |
upd = MIN(diff_len[1], context_vec_ptr->d + context); |
upd = MIN(len[1], context_vec_ptr->d + context); |
|
|
diff_output("***************"); |
diff_output("***************"); |
if (diff_pflag == 1) { |
if (diff_pflag == 1) { |
f = match_function(ixold, lowa - 1, f1); |
f = match_function(ixold, lowa-1, f1); |
if (f != NULL) { |
if (f != NULL) { |
diff_output(" "); |
diff_output(" "); |
diff_output("%s", f); |
diff_output("%s", f); |
|
|
do_output++; |
do_output++; |
break; |
break; |
} |
} |
if (do_output != 0) { |
if (do_output) { |
while (cvp <= context_vec_ptr) { |
while (cvp <= context_vec_ptr) { |
a = cvp->a; |
a = cvp->a; |
b = cvp->b; |
b = cvp->b; |
|
|
do_output++; |
do_output++; |
break; |
break; |
} |
} |
if (do_output != 0) { |
if (do_output) { |
while (cvp <= context_vec_ptr) { |
while (cvp <= context_vec_ptr) { |
a = cvp->a; |
a = cvp->a; |
b = cvp->b; |
b = cvp->b; |
|
|
|
|
b = d = 0; /* gcc */ |
b = d = 0; /* gcc */ |
lowa = MAX(1, cvp->a - context); |
lowa = MAX(1, cvp->a - context); |
upb = MIN(diff_len[0], context_vec_ptr->b + context); |
upb = MIN(len[0], context_vec_ptr->b + context); |
lowc = MAX(1, cvp->c - context); |
lowc = MAX(1, cvp->c - context); |
upd = MIN(diff_len[1], context_vec_ptr->d + context); |
upd = MIN(len[1], context_vec_ptr->d + context); |
|
|
diff_output("@@ -"); |
diff_output("@@ -"); |
uni_range(lowa, upb); |
uni_range(lowa, upb); |
|
|
uni_range(lowc, upd); |
uni_range(lowc, upd); |
diff_output(" @@"); |
diff_output(" @@"); |
if (diff_pflag == 1) { |
if (diff_pflag == 1) { |
f = match_function(ixold, lowa - 1, f1); |
f = match_function(ixold, lowa-1, f1); |
if (f != NULL) { |
if (f != NULL) { |
diff_output(" "); |
diff_output(" "); |
diff_output("%s", f); |
diff_output("%s", f); |