version 1.70, 2007/09/11 15:47:17 |
version 1.71, 2009/06/06 15:00:27 |
|
|
|
|
static FILE *opentemp(const char *); |
static FILE *opentemp(const char *); |
static void output(char *, FILE *, char *, FILE *, int); |
static void output(char *, FILE *, char *, FILE *, int); |
static void check(char *, FILE *, char *, FILE *); |
static void check(char *, FILE *, char *, FILE *, int); |
static void range(int, int, char *); |
static void range(int, int, char *); |
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 *, int); |
static void dump_unified_vec(FILE *, FILE *); |
static void dump_unified_vec(FILE *, FILE *, int); |
static void prepare(int, FILE *, off_t); |
static void prepare(int, FILE *, off_t, int); |
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 void print_header(const char *, const char *); |
static void print_header(const char *, const char *); |
static int ignoreline(char *); |
static int ignoreline(char *); |
static int asciifile(FILE *); |
static int asciifile(FILE *); |
static int fetch(long *, int, int, FILE *, int, int); |
static int fetch(long *, int, int, FILE *, int, int, int); |
static int newcand(int, int, int); |
static int newcand(int, int, int); |
static int search(int *, int, int); |
static int search(int *, int, int); |
static int skipline(FILE *); |
static int skipline(FILE *); |
static int isqrt(int); |
static int isqrt(int); |
static int stone(int *, int, int *, int *); |
static int stone(int *, int, int *, int *, int); |
static int readhash(FILE *); |
static int readhash(FILE *, int); |
static int files_differ(FILE *, FILE *, int); |
static int files_differ(FILE *, FILE *, int); |
static char *match_function(const long *, int, FILE *); |
static char *match_function(const long *, int, FILE *); |
static char *preadline(int, size_t, off_t); |
static char *preadline(int, size_t, off_t); |
|
|
{ |
{ |
char *file1 = ofile1; |
char *file1 = ofile1; |
char *file2 = ofile2; |
char *file2 = ofile2; |
FILE *f1 = NULL; |
FILE *f1, *f2; |
FILE *f2 = NULL; |
int i, rval, ostdout = -1; |
int rval = D_SAME; |
|
int i, ostdout = -1; |
|
pid_t pid = -1; |
pid_t pid = -1; |
|
|
|
f1 = f2 = NULL; |
|
rval = D_SAME; |
anychange = 0; |
anychange = 0; |
lastline = 0; |
lastline = 0; |
lastmatchline = 0; |
lastmatchline = 0; |
context_vec_ptr = context_vec_start - 1; |
context_vec_ptr = context_vec_start - 1; |
chrtran = (iflag ? cup2low : clow2low); |
if (flags & D_IGNORECASE) |
|
chrtran = cup2low; |
|
else |
|
chrtran = clow2low; |
if (S_ISDIR(stb1.st_mode) != S_ISDIR(stb2.st_mode)) |
if (S_ISDIR(stb1.st_mode) != S_ISDIR(stb2.st_mode)) |
return (S_ISDIR(stb1.st_mode) ? D_MISMATCH1 : D_MISMATCH2); |
return (S_ISDIR(stb1.st_mode) ? D_MISMATCH1 : D_MISMATCH2); |
if (strcmp(file1, "-") == 0 && strcmp(file2, "-") == 0) |
if (strcmp(file1, "-") == 0 && strcmp(file2, "-") == 0) |
|
|
goto closem; |
goto closem; |
} |
} |
|
|
if (!asciifile(f1) || !asciifile(f2)) { |
if ((flags & D_FORCEASCII) == 0 && |
|
(!asciifile(f1) || !asciifile(f2))) { |
rval = D_BINARY; |
rval = D_BINARY; |
status |= 1; |
status |= 1; |
goto closem; |
goto closem; |
|
|
xfree(header); |
xfree(header); |
} |
} |
} |
} |
prepare(0, f1, stb1.st_size); |
prepare(0, f1, stb1.st_size, flags); |
prepare(1, f2, stb2.st_size); |
prepare(1, f2, stb2.st_size, flags); |
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 = xmalloc(clistlen * sizeof(*clist)); |
clist = xmalloc(clistlen * sizeof(*clist)); |
i = stone(class, slen[0], member, klist); |
i = stone(class, slen[0], member, klist, flags); |
xfree(member); |
xfree(member); |
xfree(class); |
xfree(class); |
|
|
|
|
|
|
ixold = xrealloc(ixold, len[0] + 2, sizeof(*ixold)); |
ixold = xrealloc(ixold, len[0] + 2, sizeof(*ixold)); |
ixnew = xrealloc(ixnew, len[1] + 2, sizeof(*ixnew)); |
ixnew = xrealloc(ixnew, len[1] + 2, sizeof(*ixnew)); |
check(file1, f1, file2, f2); |
check(file1, f1, file2, f2, flags); |
output(file1, f1, file2, f2, (flags & D_HEADER)); |
output(file1, f1, file2, f2, flags); |
if (ostdout != -1) { |
if (ostdout != -1) { |
int wstatus; |
int wstatus; |
|
|
|
|
xfree(file1); |
xfree(file1); |
if (file2 != ofile2) |
if (file2 != ofile2) |
xfree(file2); |
xfree(file2); |
|
|
return (rval); |
return (rval); |
} |
} |
|
|
|
|
} |
} |
|
|
static void |
static void |
prepare(int i, FILE *fd, off_t filesize) |
prepare(int i, FILE *fd, off_t filesize, int flags) |
{ |
{ |
struct line *p; |
struct line *p; |
int j, h; |
int j, h; |
|
|
sz = 100; |
sz = 100; |
|
|
p = xmalloc((sz + 3) * sizeof(*p)); |
p = xmalloc((sz + 3) * sizeof(*p)); |
for (j = 0; (h = readhash(fd));) { |
for (j = 0; (h = readhash(fd, flags));) { |
if (j == 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)); |
|
|
} |
} |
|
|
static int |
static int |
stone(int *a, int n, int *b, int *c) |
stone(int *a, int n, int *b, int *c, int flags) |
{ |
{ |
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, isqrt(n)); |
/* XXX move the isqrt() out of the macro to avoid multiple calls */ |
|
const u_int bound = (flags & D_MINIMAL) ? UINT_MAX : |
|
MAX(256, isqrt(n)); |
|
|
k = 0; |
k = 0; |
c[0] = newcand(0, 0, 0); |
c[0] = newcand(0, 0, 0); |
|
|
return (k + 1); |
return (k + 1); |
i = 0; |
i = 0; |
j = k + 1; |
j = k + 1; |
while (1) { |
for (;;) { |
l = i + j; |
l = (i + j) / 2; |
if ((l >>= 1) <= i) |
if (l <= i) |
break; |
break; |
t = clist[c[l]].y; |
t = clist[c[l]].y; |
if (t > y) |
if (t > y) |
|
|
* 2. collect random access indexes to the two files |
* 2. collect random access indexes to the two files |
*/ |
*/ |
static void |
static void |
check(char *file1, FILE *f1, char *file2, FILE *f2) |
check(char *file1, FILE *f1, char *file2, FILE *f2, int flags) |
{ |
{ |
int i, j, jackpot, c, d; |
int i, j, jackpot, c, d; |
long ctold, ctnew; |
long ctold, ctnew; |
|
|
ixnew[j] = ctnew += skipline(f2); |
ixnew[j] = ctnew += skipline(f2); |
j++; |
j++; |
} |
} |
if (bflag || wflag || iflag) { |
if (flags & (D_FOLDBLANKS|D_IGNOREBLANKS|D_IGNORECASE)) { |
for (;;) { |
for (;;) { |
c = getc(f1); |
c = getc(f1); |
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 || wflag) && |
if ((flags & (D_FOLDBLANKS|D_IGNOREBLANKS)) && |
((c == EOF && d == '\n') || |
((c == EOF && d == '\n') || |
(c == '\n' && d == EOF))) { |
(c == '\n' && d == EOF))) { |
break; |
break; |
} |
} |
ctold++; |
ctold++; |
ctnew++; |
ctnew++; |
if (bflag && isspace(c) && isspace(d)) { |
if ((flags & D_FOLDBLANKS) && isspace(c) && |
|
isspace(d)) { |
do { |
do { |
if (c == '\n') |
if (c == '\n') |
break; |
break; |
|
|
break; |
break; |
ctnew++; |
ctnew++; |
} while (isspace(d = getc(f2))); |
} while (isspace(d = getc(f2))); |
} else if (wflag) { |
} else if ((flags & D_IGNOREBLANKS)) { |
while (isspace(c) && c != '\n') { |
while (isspace(c) && c != '\n') { |
c = getc(f1); |
c = getc(f1); |
ctold++; |
ctold++; |
|
|
} |
} |
if (anychange != 0) { |
if (anychange != 0) { |
if (format == D_CONTEXT) |
if (format == D_CONTEXT) |
dump_context_vec(f1, f2); |
dump_context_vec(f1, f2, flags); |
else if (format == D_UNIFIED) |
else if (format == D_UNIFIED) |
dump_unified_vec(f1, f2); |
dump_unified_vec(f1, f2, flags); |
} |
} |
} |
} |
|
|
|
|
} |
} |
|
|
static char * |
static char * |
preadline(int fd, size_t len, off_t off) |
preadline(int fd, size_t rlen, off_t off) |
{ |
{ |
char *line; |
char *line; |
ssize_t nr; |
ssize_t nr; |
|
|
line = xmalloc(len + 1); |
line = xmalloc(rlen + 1); |
if ((nr = pread(fd, line, len, off)) < 0) |
if ((nr = pread(fd, line, rlen, off)) < 0) |
err(1, "preadline"); |
err(1, "preadline"); |
if (nr > 0 && line[nr-1] == '\n') |
if (nr > 0 && line[nr-1] == '\n') |
nr--; |
nr--; |
|
|
* previous change, dump the record and reset it. |
* previous change, dump the record and reset it. |
*/ |
*/ |
if (format == D_CONTEXT) |
if (format == D_CONTEXT) |
dump_context_vec(f1, f2); |
dump_context_vec(f1, f2, *pflags); |
else |
else |
dump_unified_vec(f1, f2); |
dump_unified_vec(f1, f2, *pflags); |
} |
} |
context_vec_ptr++; |
context_vec_ptr++; |
context_vec_ptr->a = a; |
context_vec_ptr->a = a; |
|
|
break; |
break; |
} |
} |
if (format == D_NORMAL || format == D_IFDEF) { |
if (format == D_NORMAL || format == D_IFDEF) { |
fetch(ixold, a, b, f1, '<', 1); |
fetch(ixold, a, b, f1, '<', 1, *pflags); |
if (a <= b && c <= d && format == D_NORMAL) |
if (a <= b && c <= d && format == D_NORMAL) |
puts("---"); |
puts("---"); |
} |
} |
i = fetch(ixnew, c, d, f2, format == D_NORMAL ? '>' : '\0', 0); |
i = fetch(ixnew, c, d, f2, format == D_NORMAL ? '>' : '\0', 0, *pflags); |
if (i != 0 && format == D_EDIT) { |
if (i != 0 && format == D_EDIT) { |
/* |
/* |
* A non-zero return value for D_EDIT indicates that the |
* A non-zero return value for D_EDIT indicates that the |
|
|
} |
} |
|
|
static int |
static int |
fetch(long *f, int a, int b, FILE *lb, int ch, int oldfile) |
fetch(long *f, int a, int b, FILE *lb, int ch, int oldfile, int flags) |
{ |
{ |
int i, j, c, lastc, col, nc; |
int i, j, c, lastc, col, nc; |
|
|
|
|
puts("\n\\ No newline at end of file"); |
puts("\n\\ No newline at end of file"); |
return (0); |
return (0); |
} |
} |
if (c == '\t' && tflag) { |
if (c == '\t' && (flags & D_EXPANDTABS)) { |
do { |
do { |
putchar(' '); |
putchar(' '); |
} while (++col & 7); |
} while (++col & 7); |
|
|
* Hash function taken from Robert Sedgewick, Algorithms in C, 3d ed., p 578. |
* Hash function taken from Robert Sedgewick, Algorithms in C, 3d ed., p 578. |
*/ |
*/ |
static int |
static int |
readhash(FILE *f) |
readhash(FILE *f, int flags) |
{ |
{ |
int i, t, space; |
int i, t, space; |
int sum; |
int sum; |
|
|
sum = 1; |
sum = 1; |
space = 0; |
space = 0; |
if (!bflag && !wflag) { |
if ((flags & (D_FOLDBLANKS|D_IGNOREBLANKS)) == 0) { |
if (iflag) |
if (flags & D_IGNORECASE) |
for (i = 0; (t = getc(f)) != '\n'; i++) { |
for (i = 0; (t = getc(f)) != '\n'; i++) { |
if (t == EOF) { |
if (t == EOF) { |
if (i == 0) |
if (i == 0) |
|
|
space++; |
space++; |
continue; |
continue; |
default: |
default: |
if (space && !wflag) { |
if (space && (flags & D_IGNOREBLANKS) == 0) { |
i++; |
i++; |
space = 0; |
space = 0; |
} |
} |
|
|
asciifile(FILE *f) |
asciifile(FILE *f) |
{ |
{ |
unsigned char buf[BUFSIZ]; |
unsigned char buf[BUFSIZ]; |
int i, cnt; |
size_t i, cnt; |
|
|
if (aflag || f == NULL) |
if (f == NULL) |
return (1); |
return (1); |
|
|
rewind(f); |
rewind(f); |
|
|
#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 *file) |
match_function(const long *f, int pos, FILE *fp) |
{ |
{ |
unsigned char buf[FUNCTION_CONTEXT_SIZE]; |
unsigned char buf[FUNCTION_CONTEXT_SIZE]; |
size_t nc; |
size_t nc; |
|
|
|
|
lastline = pos; |
lastline = pos; |
while (pos > last) { |
while (pos > last) { |
fseek(file, f[pos - 1], SEEK_SET); |
fseek(fp, f[pos - 1], SEEK_SET); |
nc = f[pos] - f[pos - 1]; |
nc = f[pos] - f[pos - 1]; |
if (nc >= sizeof(buf)) |
if (nc >= sizeof(buf)) |
nc = sizeof(buf) - 1; |
nc = sizeof(buf) - 1; |
nc = fread(buf, 1, nc, file); |
nc = fread(buf, 1, nc, fp); |
if (nc > 0) { |
if (nc > 0) { |
buf[nc] = '\0'; |
buf[nc] = '\0'; |
buf[strcspn(buf, "\n")] = '\0'; |
buf[strcspn(buf, "\n")] = '\0'; |
|
|
|
|
/* 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, int flags) |
{ |
{ |
struct context_vec *cvp = context_vec_start; |
struct context_vec *cvp = context_vec_start; |
int lowa, upb, lowc, upd, do_output; |
int lowa, upb, lowc, upd, do_output; |
|
|
upd = MIN(len[1], context_vec_ptr->d + context); |
upd = MIN(len[1], context_vec_ptr->d + context); |
|
|
printf("***************"); |
printf("***************"); |
if (pflag) { |
if ((flags & D_PROTOTYPE)) { |
f = match_function(ixold, lowa-1, f1); |
f = match_function(ixold, lowa-1, f1); |
if (f != NULL) { |
if (f != NULL) { |
putchar(' '); |
putchar(' '); |
|
|
ch = (a <= b) ? 'd' : 'a'; |
ch = (a <= b) ? 'd' : 'a'; |
|
|
if (ch == 'a') |
if (ch == 'a') |
fetch(ixold, lowa, b, f1, ' ', 0); |
fetch(ixold, lowa, b, f1, ' ', 0, flags); |
else { |
else { |
fetch(ixold, lowa, a - 1, f1, ' ', 0); |
fetch(ixold, lowa, a - 1, f1, ' ', 0, flags); |
fetch(ixold, a, b, f1, |
fetch(ixold, a, b, f1, |
ch == 'c' ? '!' : '-', 0); |
ch == 'c' ? '!' : '-', 0, flags); |
} |
} |
lowa = b + 1; |
lowa = b + 1; |
cvp++; |
cvp++; |
} |
} |
fetch(ixold, b + 1, upb, f1, ' ', 0); |
fetch(ixold, b + 1, upb, f1, ' ', 0, flags); |
} |
} |
/* output changes to the "new" file */ |
/* output changes to the "new" file */ |
printf("--- "); |
printf("--- "); |
|
|
ch = (a <= b) ? 'd' : 'a'; |
ch = (a <= b) ? 'd' : 'a'; |
|
|
if (ch == 'd') |
if (ch == 'd') |
fetch(ixnew, lowc, d, f2, ' ', 0); |
fetch(ixnew, lowc, d, f2, ' ', 0, flags); |
else { |
else { |
fetch(ixnew, lowc, c - 1, f2, ' ', 0); |
fetch(ixnew, lowc, c - 1, f2, ' ', 0, flags); |
fetch(ixnew, c, d, f2, |
fetch(ixnew, c, d, f2, |
ch == 'c' ? '!' : '+', 0); |
ch == 'c' ? '!' : '+', 0, flags); |
} |
} |
lowc = d + 1; |
lowc = d + 1; |
cvp++; |
cvp++; |
} |
} |
fetch(ixnew, d + 1, upd, f2, ' ', 0); |
fetch(ixnew, d + 1, upd, f2, ' ', 0, flags); |
} |
} |
context_vec_ptr = context_vec_start - 1; |
context_vec_ptr = context_vec_start - 1; |
} |
} |
|
|
/* dump accumulated "unified" diff changes */ |
/* dump accumulated "unified" diff changes */ |
static void |
static void |
dump_unified_vec(FILE *f1, FILE *f2) |
dump_unified_vec(FILE *f1, FILE *f2, int flags) |
{ |
{ |
struct context_vec *cvp = context_vec_start; |
struct context_vec *cvp = context_vec_start; |
int lowa, upb, lowc, upd; |
int lowa, upb, lowc, upd; |
|
|
fputs(" +", stdout); |
fputs(" +", stdout); |
uni_range(lowc, upd); |
uni_range(lowc, upd); |
fputs(" @@", stdout); |
fputs(" @@", stdout); |
if (pflag) { |
if ((flags & D_PROTOTYPE)) { |
f = match_function(ixold, lowa-1, f1); |
f = match_function(ixold, lowa-1, f1); |
if (f != NULL) { |
if (f != NULL) { |
putchar(' '); |
putchar(' '); |
|
|
|
|
switch (ch) { |
switch (ch) { |
case 'c': |
case 'c': |
fetch(ixold, lowa, a - 1, f1, ' ', 0); |
fetch(ixold, lowa, a - 1, f1, ' ', 0, flags); |
fetch(ixold, a, b, f1, '-', 0); |
fetch(ixold, a, b, f1, '-', 0, flags); |
fetch(ixnew, c, d, f2, '+', 0); |
fetch(ixnew, c, d, f2, '+', 0, flags); |
break; |
break; |
case 'd': |
case 'd': |
fetch(ixold, lowa, a - 1, f1, ' ', 0); |
fetch(ixold, lowa, a - 1, f1, ' ', 0, flags); |
fetch(ixold, a, b, f1, '-', 0); |
fetch(ixold, a, b, f1, '-', 0, flags); |
break; |
break; |
case 'a': |
case 'a': |
fetch(ixnew, lowc, c - 1, f2, ' ', 0); |
fetch(ixnew, lowc, c - 1, f2, ' ', 0, flags); |
fetch(ixnew, c, d, f2, '+', 0); |
fetch(ixnew, c, d, f2, '+', 0, flags); |
break; |
break; |
} |
} |
lowa = b + 1; |
lowa = b + 1; |
lowc = d + 1; |
lowc = d + 1; |
} |
} |
fetch(ixnew, d + 1, upd, f2, ' ', 0); |
fetch(ixnew, d + 1, upd, f2, ' ', 0, flags); |
|
|
context_vec_ptr = context_vec_start - 1; |
context_vec_ptr = context_vec_start - 1; |
} |
} |