version 1.26, 2003/07/04 17:37:07 |
version 1.27, 2003/07/06 20:48:59 |
|
|
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
* POSSIBILITY OF SUCH DAMAGE. |
* POSSIBILITY OF SUCH DAMAGE. |
*/ |
*/ |
|
/*- |
|
* Copyright (c) 1991, 1993 |
|
* The Regents of the University of California. All rights reserved. |
|
* |
|
* Redistribution and use in source and binary forms, with or without |
|
* modification, are permitted provided that the following conditions |
|
* are met: |
|
* 1. Redistributions of source code must retain the above copyright |
|
* notice, this list of conditions and the following disclaimer. |
|
* 2. Redistributions in binary form must reproduce the above copyright |
|
* notice, this list of conditions and the following disclaimer in the |
|
* documentation and/or other materials provided with the distribution. |
|
* 3. Neither the name of the University nor the names of its contributors |
|
* may be used to endorse or promote products derived from this software |
|
* without specific prior written permission. |
|
* |
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
|
* SUCH DAMAGE. |
|
* |
|
* @(#)diffreg.c 8.1 (Berkeley) 6/6/93 |
|
*/ |
|
|
|
#ifndef lint |
|
static const char rcsid[] = "$OpenBSD$"; |
|
#endif /* not lint */ |
|
|
#include <sys/types.h> |
#include <sys/types.h> |
|
#include <sys/stat.h> |
|
|
#include <stdlib.h> |
#include <ctype.h> |
#include <unistd.h> |
#include <err.h> |
#include <fcntl.h> |
#include <fcntl.h> |
|
#include <libgen.h> |
|
#include <paths.h> |
|
#include <signal.h> |
|
#include <stdio.h> |
|
#include <stdlib.h> |
#include <string.h> |
#include <string.h> |
|
#include <unistd.h> |
|
|
#include "diff.h" |
#include "diff.h" |
#include "pathnames.h" |
|
|
|
#if 0 |
|
static char const sccsid[] = "@(#)diffreg.c 4.21 4/6/90"; |
|
#endif |
|
|
|
/* |
/* |
* diff - compare two files. |
* diff - compare two files. |
*/ |
*/ |
|
|
* 6n words for files of length n. |
* 6n words for files of length n. |
*/ |
*/ |
|
|
#define prints(s) fputs(s,stdout) |
|
|
|
FILE *input[2]; |
|
|
|
struct cand { |
struct cand { |
int x; |
int x; |
int y; |
int y; |
|
|
int value; |
int value; |
} *file[2]; |
} *file[2]; |
|
|
int len[2]; |
static int *J; /* will be overlaid on class */ |
struct line *sfile[2]; /* shortened by pruning common prefix and suffix */ |
static int *class; /* will be overlaid on file[0] */ |
int slen[2]; |
static int *klist; /* will be overlaid on file[0] after class */ |
int pref, suff; /* length of prefix and suffix */ |
static int *member; /* will be overlaid on file[1] */ |
int inifdef; /* whether or not we are in a #ifdef block */ |
static int clen; |
int *class; /* will be overlaid on file[0] */ |
static int inifdef; /* whether or not we are in a #ifdef block */ |
int *member; /* will be overlaid on file[1] */ |
static int len[2]; |
int *klist; /* will be overlaid on file[0] after class */ |
static int pref, suff; /* length of prefix and suffix */ |
struct cand *clist; /* merely a free storage pot for candidates */ |
static int slen[2]; |
int clen = 0; |
static int anychange; |
int *J; /* will be overlaid on class */ |
static long *ixnew; /* will be overlaid on file[1] */ |
long *ixold; /* will be overlaid on klist */ |
static long *ixold; /* will be overlaid on klist */ |
long *ixnew; /* will be overlaid on file[1] */ |
static struct cand *clist; /* merely a free storage pot for candidates */ |
u_char *chrtran; /* translation table for case-folding */ |
static struct line *sfile[2]; /* shortened by pruning common prefix/suffix */ |
|
static u_char *chrtran; /* translation table for case-folding */ |
|
|
static void fetch(long *, int, int, FILE *, char *, int); |
static void fetch(long *, int, int, FILE *, char *, int); |
static void output(void); |
static void output(char *, FILE *, char *, FILE *); |
static void check(void); |
static void check(char *, FILE *, char *, FILE *); |
static void range(int, int, char *); |
static void range(int, int, char *); |
static void dump_context_vec(void); |
static void dump_context_vec(FILE *, FILE *); |
static void dump_unified_vec(void); |
static void dump_unified_vec(FILE *, FILE *); |
static void prepare(int, FILE *); |
static void prepare(int, FILE *); |
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 unsort(struct line *, int, int *); |
static void unsort(struct line *, int, int *); |
static void change(int, int, int, int); |
static void change(char *, FILE *, char *, FILE *, int, int, int, int); |
static void sort(struct line *, int); |
static void sort(struct line *, int); |
static int newcand(int, int, int); |
static int asciifile(FILE *); |
static int search(int *, int, int); |
static int newcand(int, int, int); |
static int skipline(int); |
static int search(int *, int, int); |
static int asciifile(FILE *); |
static int skipline(FILE *); |
static int stone(int *, int, int *, int *); |
static int stone(int *, int, int *, int *); |
static int readhash(FILE *); |
static int readhash(FILE *); |
|
static int files_differ(FILE *, FILE *, int); |
|
|
/* |
/* |
* 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 |
|
|
}; |
}; |
|
|
void |
void |
diffreg(void) |
diffreg(char *ofile1, char *ofile2, int flags) |
{ |
{ |
char buf1[BUFSIZ], buf2[BUFSIZ]; |
char *file1 = ofile1; |
FILE *f1, *f2; |
char *file2 = ofile2; |
int i, j; |
FILE *f1 = NULL; |
|
FILE *f2 = NULL; |
|
int i; |
|
|
|
anychange = 0; |
chrtran = (iflag ? cup2low : clow2low); |
chrtran = (iflag ? cup2low : clow2low); |
if (strcmp(file1, "-") == 0 && strcmp(file2, "-") == 0) |
if (strcmp(file1, "-") == 0 && strcmp(file2, "-") == 0) |
errorx("can't specify - -"); |
goto notsame; |
if (S_ISDIR(stb1.st_mode)) { |
|
file1 = splice(file1, file2); |
/* XXX - only make temp file for stdin if not seekable? (millert) */ |
if (stat(file1, &stb1) < 0) |
if (flags & D_EMPTY1) |
error("%s", file1); |
f1 = fopen(_PATH_DEVNULL, "r"); |
} else if (strcmp(file1, "-") == 0 || |
else { |
(!S_ISREG(stb1.st_mode) && strcmp(file1, _PATH_DEVNULL) != 0)) { |
if (S_ISDIR(stb1.st_mode)) { |
file1 = copytemp(file1, 1); |
file1 = splice(file1, file2); |
if (stat(file1, &stb1) < 0) |
if (stat(file1, &stb1) < 0) { |
error("%s", file1); |
warn("%s", file1); |
|
status |= 2; |
|
goto closem; |
|
} |
|
} else if (strcmp(file1, "-") == 0 || !S_ISREG(stb1.st_mode)) { |
|
file1 = copytemp(file1, 1); |
|
if (file1 == NULL || stat(file1, &stb1) < 0) { |
|
warn("%s", file1); |
|
status |= 2; |
|
goto closem; |
|
} |
|
} |
|
f1 = fopen(file1, "r"); |
} |
} |
if (S_ISDIR(stb2.st_mode)) { |
if (f1 == NULL) { |
file2 = splice(file2, file1); |
warn("%s", file1); |
if (stat(file2, &stb2) < 0) |
status |= 2; |
error("%s", file2); |
goto closem; |
} else if (strcmp(file2, "-") == 0 || |
|
(!S_ISREG(stb2.st_mode) && strcmp(file2, _PATH_DEVNULL) != 0)) { |
|
file2 = copytemp(file2, 2); |
|
if (stat(file2, &stb2) < 0) |
|
error("%s", file2); |
|
} |
} |
if ((f1 = fopen(file1, "r")) == NULL) |
|
error("%s", file1); |
if (flags & D_EMPTY2) |
if ((f2 = fopen(file2, "r")) == NULL) |
f2 = fopen(_PATH_DEVNULL, "r"); |
error("%s", file2); |
else { |
if ((stb1.st_mode & S_IFMT) != (stb2.st_mode & S_IFMT) || |
if (S_ISDIR(stb2.st_mode)) { |
stb1.st_size != stb2.st_size) |
file2 = splice(file2, file1); |
goto notsame; |
if (stat(file2, &stb2) < 0) { |
for (;;) { |
warn("%s", file2); |
i = fread(buf1, 1, BUFSIZ, f1); |
status |= 2; |
j = fread(buf2, 1, BUFSIZ, f2); |
goto closem; |
if (i < 0 || j < 0 || i != j) |
} |
goto notsame; |
} else if (strcmp(file2, "-") == 0 || !S_ISREG(stb2.st_mode)) { |
if (i == 0 && j == 0) { |
file2 = copytemp(file2, 2); |
fclose(f1); |
if (file2 == NULL || stat(file2, &stb2) < 0) { |
fclose(f2); |
warn("%s", file2); |
status = 0; /* files don't differ */ |
status |= 2; |
goto same; |
goto closem; |
|
} |
} |
} |
for (j = 0; j < i; j++) |
f2 = fopen(file2, "r"); |
if (buf1[j] != buf2[j]) |
|
goto notsame; |
|
} |
} |
|
if (f2 == NULL) { |
|
warn("%s", file2); |
|
status |= 2; |
|
goto closem; |
|
} |
|
|
|
switch (files_differ(f1, f2, flags)) { |
|
case 0: |
|
goto same; |
|
case 1: |
|
break; |
|
default: |
|
/* error */ |
|
status |= 2; |
|
goto closem; |
|
} |
|
|
notsame: |
notsame: |
/* |
/* |
* Files certainly differ at this point; set status accordingly |
* Files certainly differ at this point; set status accordingly |
*/ |
*/ |
status = 1; |
status |= 1; |
|
if (flags & D_HEADER) { |
|
if (format == D_EDIT) |
|
printf("ed - %s << '-*-END-*-'\n", basename(file1)); |
|
else |
|
printf("%s %s %s\n", diffargs, file1, file2); |
|
} |
if (!asciifile(f1) || !asciifile(f2)) { |
if (!asciifile(f1) || !asciifile(f2)) { |
printf("Binary files %s and %s differ\n", file1, file2); |
printf("Binary files %s and %s differ\n", file1, file2); |
exit(status); |
goto closem; |
} |
} |
prepare(0, f1); |
prepare(0, f1); |
prepare(1, f2); |
prepare(1, f2); |
fclose(f1); |
|
fclose(f2); |
|
prune(); |
prune(); |
sort(sfile[0], slen[0]); |
sort(sfile[0], slen[0]); |
sort(sfile[1], slen[1]); |
sort(sfile[1], slen[1]); |
|
|
free(member); |
free(member); |
free(class); |
free(class); |
|
|
J = emalloc((len[0] + 2) * sizeof(int)); |
J = erealloc(J, (len[0] + 2) * sizeof(int)); |
unravel(klist[i]); |
unravel(klist[i]); |
free(clist); |
free(clist); |
free(klist); |
free(klist); |
|
|
ixold = emalloc((len[0] + 2) * sizeof(long)); |
ixold = erealloc(ixold, (len[0] + 2) * sizeof(long)); |
ixnew = emalloc((len[1] + 2) * sizeof(long)); |
ixnew = erealloc(ixnew, (len[1] + 2) * sizeof(long)); |
check(); |
check(file1, f1, file2, f2); |
output(); |
output(file1, f1, file2, f2); |
status = anychange; |
if ((flags & D_HEADER) && format == D_EDIT) |
|
printf("w\nq\n-*-END-*-\n"); |
same: |
same: |
if (anychange == 0 && (opt == D_CONTEXT || opt == D_UNIFIED)) |
if (anychange == 0 && sflag != 0) |
printf("No differences encountered\n"); |
printf("Files %s and %s are identical\n", file1, file2); |
|
|
|
closem: |
|
if (f1 != NULL) |
|
fclose(f1); |
|
if (f2 != NULL) |
|
fclose(f2); |
|
if (tempfiles[0] != NULL) { |
|
unlink(tempfiles[0]); |
|
free(tempfiles[0]); |
|
tempfiles[0] = NULL; |
|
} |
|
if (tempfiles[1] != NULL) { |
|
unlink(tempfiles[1]); |
|
free(tempfiles[1]); |
|
tempfiles[1] = NULL; |
|
} |
|
if (file1 != ofile1) |
|
free(file1); |
|
if (file2 != ofile2) |
|
free(file2); |
} |
} |
|
|
|
/* |
|
* Check to see if the given files differ. |
|
* Returns 0 if they are the same, 1 if different, and -1 on error. |
|
* XXX - could use code from cmp(1) [faster] |
|
*/ |
|
static int |
|
files_differ(FILE *f1, FILE *f2, int flags) |
|
{ |
|
char buf1[BUFSIZ], buf2[BUFSIZ]; |
|
size_t i, j; |
|
|
|
if ((flags & (D_EMPTY1|D_EMPTY2)) || stb1.st_size != stb2.st_size || |
|
(stb1.st_mode & S_IFMT) != (stb2.st_mode & S_IFMT)) |
|
return (1); |
|
for (;;) { |
|
i = fread(buf1, 1, sizeof(buf1), f1); |
|
j = fread(buf2, 1, sizeof(buf2), f2); |
|
if (i != j) |
|
return (1); |
|
if (i == 0 && j == 0) { |
|
if (ferror(f1) || ferror(f2)) |
|
return (1); |
|
return (0); |
|
} |
|
if (memcmp(buf1, buf2, i) != 0) |
|
return (1); |
|
} |
|
} |
|
|
char *tempfiles[2]; |
char *tempfiles[2]; |
|
|
|
/* XXX - pass back a FILE * too (millert) */ |
char * |
char * |
copytemp(const char *file, int n) |
copytemp(const char *file, int n) |
{ |
{ |
|
|
if (strcmp(file, "-") == 0) |
if (strcmp(file, "-") == 0) |
ifd = STDIN_FILENO; |
ifd = STDIN_FILENO; |
else if ((ifd = open(file, O_RDONLY, 0644)) < 0) |
else if ((ifd = open(file, O_RDONLY, 0644)) < 0) |
error("%s", file); |
return (NULL); |
|
|
if ((tempdir = getenv("TMPDIR")) == NULL) |
if ((tempdir = getenv("TMPDIR")) == NULL) |
tempdir = _PATH_TMP; |
tempdir = _PATH_TMP; |
if (asprintf(&tempfile, "%s/diff%d.XXXXXXXX", tempdir, n) == -1) |
if (asprintf(&tempfile, "%s/diff%d.XXXXXXXX", tempdir, n) == -1) |
error(NULL); |
return (NULL); |
tempfiles[n - 1] = tempfile; |
tempfiles[n - 1] = tempfile; |
|
|
signal(SIGHUP, done); |
signal(SIGHUP, quit); |
signal(SIGINT, done); |
signal(SIGINT, quit); |
signal(SIGPIPE, done); |
signal(SIGPIPE, quit); |
signal(SIGTERM, done); |
signal(SIGTERM, quit); |
ofd = mkstemp(tempfile); |
ofd = mkstemp(tempfile); |
if (ofd < 0) |
if (ofd < 0) |
error("%s", tempfile); |
return (NULL); |
while ((i = read(ifd, buf, BUFSIZ)) > 0) { |
while ((i = read(ifd, buf, BUFSIZ)) > 0) { |
if (write(ofd, buf, i) != i) |
if (write(ofd, buf, i) != i) |
error("%s", tempfile); |
return (NULL); |
} |
} |
close(ifd); |
close(ifd); |
close(ofd); |
close(ofd); |
|
|
char *tail, *buf; |
char *tail, *buf; |
size_t len; |
size_t len; |
|
|
if (!strcmp(file, "-")) |
|
errorx("can't specify - with other arg directory"); |
|
tail = strrchr(file, '/'); |
tail = strrchr(file, '/'); |
if (tail == NULL) |
if (tail == NULL) |
tail = file; |
tail = file; |
|
|
struct line *p; |
struct line *p; |
int j, h; |
int j, h; |
|
|
fseek(fd, 0L, SEEK_SET); |
rewind(fd); |
p = emalloc(3 * sizeof(struct line)); |
p = emalloc(3 * sizeof(struct line)); |
for (j = 0; (h = readhash(fd));) { |
for (j = 0; (h = readhash(fd));) { |
p = erealloc(p, (++j + 3) * sizeof(struct line)); |
p = erealloc(p, (++j + 3) * sizeof(struct line)); |
|
|
* 2. collect random access indexes to the two files |
* 2. collect random access indexes to the two files |
*/ |
*/ |
static void |
static void |
check(void) |
check(char *file1, FILE *f1, char *file2, FILE *f2) |
{ |
{ |
int i, j, jackpot, c, d; |
int i, j, jackpot, c, d; |
long ctold, ctnew; |
long ctold, ctnew; |
|
|
if ((input[0] = fopen(file1, "r")) == NULL) |
rewind(f1); |
error("%s", file1); |
rewind(f2); |
if ((input[1] = fopen(file2, "r")) == NULL) |
|
error("%s", file2); |
|
j = 1; |
j = 1; |
ixold[0] = ixnew[0] = 0; |
ixold[0] = ixnew[0] = 0; |
jackpot = 0; |
jackpot = 0; |
ctold = ctnew = 0; |
ctold = ctnew = 0; |
for (i = 1; i <= len[0]; i++) { |
for (i = 1; i <= len[0]; i++) { |
if (J[i] == 0) { |
if (J[i] == 0) { |
ixold[i] = ctold += skipline(0); |
ixold[i] = ctold += skipline(f1); |
continue; |
continue; |
} |
} |
while (j < J[i]) { |
while (j < J[i]) { |
ixnew[j] = ctnew += skipline(1); |
ixnew[j] = ctnew += skipline(f2); |
j++; |
j++; |
} |
} |
if (bflag || wflag || iflag) { |
if (bflag || wflag || iflag) { |
for (;;) { |
for (;;) { |
c = getc(input[0]); |
c = getc(f1); |
d = getc(input[1]); |
d = getc(f2); |
ctold++; |
ctold++; |
ctnew++; |
ctnew++; |
if (bflag && isspace(c) && isspace(d)) { |
if (bflag && isspace(c) && isspace(d)) { |
|
|
if (c == '\n') |
if (c == '\n') |
break; |
break; |
ctold++; |
ctold++; |
} while (isspace(c = getc(input[0]))); |
} while (isspace(c = getc(f1))); |
do { |
do { |
if (d == '\n') |
if (d == '\n') |
break; |
break; |
ctnew++; |
ctnew++; |
} while (isspace(d = getc(input[1]))); |
} while (isspace(d = getc(f2))); |
} else if (wflag) { |
} else if (wflag) { |
while (isspace(c) && c != '\n') { |
while (isspace(c) && c != '\n') { |
c = getc(input[0]); |
c = getc(f1); |
ctold++; |
ctold++; |
} |
} |
while (isspace(d) && d != '\n') { |
while (isspace(d) && d != '\n') { |
d = getc(input[1]); |
d = getc(f2); |
ctnew++; |
ctnew++; |
} |
} |
} |
} |
|
|
jackpot++; |
jackpot++; |
J[i] = 0; |
J[i] = 0; |
if (c != '\n') |
if (c != '\n') |
ctold += skipline(0); |
ctold += skipline(f1); |
if (d != '\n') |
if (d != '\n') |
ctnew += skipline(1); |
ctnew += skipline(f2); |
break; |
break; |
} |
} |
if (c == '\n') |
if (c == '\n') |
|
|
for (;;) { |
for (;;) { |
ctold++; |
ctold++; |
ctnew++; |
ctnew++; |
if ((c = getc(input[0])) != (d = getc(input[1]))) { |
if ((c = getc(f1)) != (d = getc(f2))) { |
/* jackpot++; */ |
/* jackpot++; */ |
J[i] = 0; |
J[i] = 0; |
if (c != '\n') |
if (c != '\n') |
ctold += skipline(0); |
ctold += skipline(f1); |
if (d != '\n') |
if (d != '\n') |
ctnew += skipline(1); |
ctnew += skipline(f2); |
break; |
break; |
} |
} |
if (c == '\n') |
if (c == '\n') |
|
|
ixnew[j] = ctnew; |
ixnew[j] = ctnew; |
j++; |
j++; |
} |
} |
for (; j <= len[1]; j++) { |
for (; j <= len[1]; j++) |
ixnew[j] = ctnew += skipline(1); |
ixnew[j] = ctnew += skipline(f2); |
} |
|
fclose(input[0]); |
|
fclose(input[1]); |
|
/* |
/* |
* if (jackpot) |
* if (jackpot) |
* fprintf(stderr, "jackpot\n"); |
* fprintf(stderr, "jackpot\n"); |
|
|
} |
} |
|
|
static int |
static int |
skipline(int f) |
skipline(FILE *f) |
{ |
{ |
int i, c; |
int i, c; |
|
|
for (i = 1; (c = getc(input[f])) != '\n'; i++) |
for (i = 1; (c = getc(f)) != '\n'; i++) |
if (c < 0) |
if (c < 0) |
return (i); |
return (i); |
return (i); |
return (i); |
} |
} |
|
|
static void |
static void |
output(void) |
output(char *file1, FILE *f1, char *file2, FILE *f2) |
{ |
{ |
int m, i0, i1, j0, j1; |
int m, i0, i1, j0, j1; |
|
|
input[0] = fopen(file1, "r"); |
rewind(f1); |
input[1] = fopen(file2, "r"); |
rewind(f2); |
m = len[0]; |
m = len[0]; |
J[0] = 0; |
J[0] = 0; |
J[m + 1] = len[1] + 1; |
J[m + 1] = len[1] + 1; |
if (opt != D_EDIT) { |
if (format != D_EDIT) { |
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++; |
|
|
i1++; |
i1++; |
j1 = J[i1 + 1] - 1; |
j1 = J[i1 + 1] - 1; |
J[i1] = j1; |
J[i1] = j1; |
change(i0, i1, j0, j1); |
change(file1, f1, file2, f2, i0, i1, j0, j1); |
} |
} |
} else { |
} else { |
for (i0 = m; i0 >= 1; i0 = i1 - 1) { |
for (i0 = m; i0 >= 1; i0 = i1 - 1) { |
|
|
i1--; |
i1--; |
j1 = J[i1 - 1] + 1; |
j1 = J[i1 - 1] + 1; |
J[i1] = j1; |
J[i1] = j1; |
change(i1, i0, j1, j0); |
change(file1, f1, file2, f2, i1, i0, j1, j0); |
} |
} |
} |
} |
if (m == 0) |
if (m == 0) |
change(1, 0, 1, len[1]); |
change(file1, f1, file2, f2, 1, 0, 1, len[1]); |
if (opt == D_IFDEF) { |
if (format == D_IFDEF) { |
for (;;) { |
for (;;) { |
#define c i0 |
#define c i0 |
c = getc(input[0]); |
c = getc(f1); |
if (c < 0) |
if (c < 0) |
return; |
return; |
putchar(c); |
putchar(c); |
|
|
#undef c |
#undef c |
} |
} |
if (anychange != 0) { |
if (anychange != 0) { |
if (opt == D_CONTEXT) |
if (format == D_CONTEXT) |
dump_context_vec(); |
dump_context_vec(f1, f2); |
else if (opt == D_UNIFIED) |
else if (format == D_UNIFIED) |
dump_unified_vec(); |
dump_unified_vec(f1, f2); |
} |
} |
} |
} |
|
|
/* |
/* |
* The following struct is used to record change information when |
* The following struct is used to record change information when |
* doing a "context" diff. (see routine "change" to understand the |
* doing a "context" or "unified" diff. (see routine "change" to |
* highly mneumonic field names) |
* understand the highly mnemonic field names) |
*/ |
*/ |
struct context_vec { |
struct context_vec { |
int a; /* start line in old file */ |
int a; /* start line in old file */ |
|
|
#define MAX_CONTEXT 128 |
#define MAX_CONTEXT 128 |
|
|
/* |
/* |
* 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 then b then there |
* to get to lines c to d of the to file. If a is greater then b then there |
* are no lines in the from file involved and this means that there were |
* are no lines in the from file involved and this means that there were |
* 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. |
*/ |
*/ |
static void |
static void |
change(int a, int b, int c, int d) |
change(char *file1, FILE *f1, char *file2, FILE *f2, int a, int b, int c, int d) |
{ |
{ |
struct stat stbuf; |
if (format != D_IFDEF && a > b && c > d) |
|
|
if (opt != D_IFDEF && a > b && c > d) |
|
return; |
return; |
if (anychange == 0) { |
if (anychange == 0) { |
anychange = 1; |
anychange = 1; |
if (opt == D_CONTEXT || opt == D_UNIFIED) { |
if (format == D_CONTEXT || format == D_UNIFIED) { |
stat(file1, &stbuf); |
printf("%s %s %s", format == D_CONTEXT ? "***" : "---", |
printf("%s %s %s", opt == D_CONTEXT ? "***" : "---", |
file1, ctime(&stb1.st_mtime)); |
file1, ctime(&stbuf.st_mtime)); |
printf("%s %s %s", format == D_CONTEXT ? "---" : "+++", |
stat(file2, &stbuf); |
file2, ctime(&stb2.st_mtime)); |
printf("%s %s %s", opt == D_CONTEXT ? "---" : "+++", |
if (context_vec_start == NULL) |
file2, ctime(&stbuf.st_mtime)); |
context_vec_start = emalloc(MAX_CONTEXT * |
context_vec_start = emalloc(MAX_CONTEXT * |
sizeof(struct context_vec)); |
sizeof(struct context_vec)); |
|
context_vec_end = context_vec_start + MAX_CONTEXT; |
context_vec_end = context_vec_start + MAX_CONTEXT; |
context_vec_ptr = context_vec_start - 1; |
context_vec_ptr = context_vec_start - 1; |
} |
} |
} |
} |
if (opt == D_CONTEXT || opt == D_UNIFIED) { |
if (format == D_CONTEXT || format == D_UNIFIED) { |
/* |
/* |
* If this new change is within 'context' lines of |
* If this new change is within 'context' lines of |
* the previous change, just add it to the change |
* the previous change, just add it to the change |
|
|
(context_vec_ptr >= context_vec_start && |
(context_vec_ptr >= context_vec_start && |
a > (context_vec_ptr->b + 2 * context) && |
a > (context_vec_ptr->b + 2 * context) && |
c > (context_vec_ptr->d + 2 * context))) { |
c > (context_vec_ptr->d + 2 * context))) { |
if (opt == D_CONTEXT) |
if (format == D_CONTEXT) |
dump_context_vec(); |
dump_context_vec(f1, f2); |
else |
else |
dump_unified_vec(); |
dump_unified_vec(f1, f2); |
} |
} |
context_vec_ptr++; |
context_vec_ptr++; |
context_vec_ptr->a = a; |
context_vec_ptr->a = a; |
|
|
context_vec_ptr->d = d; |
context_vec_ptr->d = d; |
return; |
return; |
} |
} |
switch (opt) { |
switch (format) { |
|
|
case D_NORMAL: |
case D_NORMAL: |
case D_EDIT: |
case D_EDIT: |
range(a, b, ","); |
range(a, b, ","); |
putchar(a > b ? 'a' : c > d ? 'd' : 'c'); |
putchar(a > b ? 'a' : c > d ? 'd' : 'c'); |
if (opt == D_NORMAL) |
if (format == D_NORMAL) |
range(c, d, ","); |
range(c, d, ","); |
putchar('\n'); |
putchar('\n'); |
break; |
break; |
|
|
} |
} |
break; |
break; |
} |
} |
if (opt == D_NORMAL || opt == D_IFDEF) { |
if (format == D_NORMAL || format == D_IFDEF) { |
fetch(ixold, a, b, input[0], "< ", 1); |
fetch(ixold, a, b, f1, "< ", 1); |
if (a <= b && c <= d && opt == D_NORMAL) |
if (a <= b && c <= d && format == D_NORMAL) |
prints("---\n"); |
puts("---"); |
} |
} |
fetch(ixnew, c, d, input[1], opt == D_NORMAL ? "> " : "", 0); |
fetch(ixnew, c, d, f2, format == D_NORMAL ? "> " : "", 0); |
if ((opt == D_EDIT || opt == D_REVERSE) && c <= d) |
if ((format == D_EDIT || format == D_REVERSE) && c <= d) |
prints(".\n"); |
puts("."); |
if (inifdef) { |
if (inifdef) { |
fprintf(stdout, "#endif /* %s */\n", ifdefname); |
fprintf(stdout, "#endif /* %s */\n", ifdefname); |
inifdef = 0; |
inifdef = 0; |
|
|
* When doing #ifdef's, copy down to current line |
* When doing #ifdef's, copy down to current line |
* if this is the first file, so that stuff makes it to output. |
* if this is the first file, so that stuff makes it to output. |
*/ |
*/ |
if (opt == D_IFDEF && oldfile) { |
if (format == D_IFDEF && oldfile) { |
long curpos = ftell(lb); |
long curpos = ftell(lb); |
/* print through if append (a>b), else to (nb: 0 vs 1 orig) */ |
/* print through if append (a>b), else to (nb: 0 vs 1 orig) */ |
nc = f[a > b ? b : a - 1] - curpos; |
nc = f[a > b ? b : a - 1] - curpos; |
|
|
} |
} |
if (a > b) |
if (a > b) |
return; |
return; |
if (opt == D_IFDEF) { |
if (format == D_IFDEF) { |
if (inifdef) { |
if (inifdef) { |
fprintf(stdout, "#else /* %s%s */\n", |
fprintf(stdout, "#else /* %s%s */\n", |
oldfile == 1 ? "!" : "", ifdefname); |
oldfile == 1 ? "!" : "", ifdefname); |
|
|
for (i = a; i <= b; i++) { |
for (i = a; i <= b; i++) { |
fseek(lb, f[i - 1], SEEK_SET); |
fseek(lb, f[i - 1], SEEK_SET); |
nc = f[i] - f[i - 1]; |
nc = f[i] - f[i - 1]; |
if (opt != D_IFDEF) |
if (format != D_IFDEF) |
prints(s); |
fputs(s, stdout); |
col = 0; |
col = 0; |
for (j = 0; j < nc; j++) { |
for (j = 0; j < nc; j++) { |
c = getc(lb); |
c = getc(lb); |
|
|
return ((short) low(sum) + (short) high(sum)); |
return ((short) low(sum) + (short) high(sum)); |
} |
} |
|
|
static int |
int |
asciifile(FILE *f) |
asciifile(FILE *f) |
{ |
{ |
char buf[BUFSIZ], *cp; |
char buf[BUFSIZ], *cp; |
int cnt; |
int cnt; |
|
|
if (aflag) |
if (aflag || f == NULL) |
return (1); |
return (1); |
|
|
fseek(f, 0L, SEEK_SET); |
rewind(f); |
cnt = fread(buf, 1, BUFSIZ, f); |
cnt = fread(buf, 1, sizeof(buf), f); |
cp = buf; |
cp = buf; |
while (--cnt >= 0) |
while (--cnt >= 0) |
if (*cp++ & 0200) |
if (*cp++ & 0200) |
|
|
return (1); |
return (1); |
} |
} |
|
|
|
static __inline int min(int a, int b) |
|
{ |
|
return (a < b ? a : b); |
|
} |
|
|
|
static __inline int max(int a, int b) |
|
{ |
|
return (a > b ? a : b); |
|
} |
|
|
/* dump accumulated "context" diff changes */ |
/* dump accumulated "context" diff changes */ |
static void |
static void |
dump_context_vec(void) |
dump_context_vec(FILE *f1, FILE *f2) |
{ |
{ |
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; |
|
|
printf(" ****\n"); |
printf(" ****\n"); |
|
|
/* |
/* |
* output changes to the "old" file. The first loop suppresses |
* Output changes to the "old" file. The first loop suppresses |
* output if there were no changes to the "old" file (we'll see |
* output if there were no changes to the "old" file (we'll see |
* the "old" lines as context in the "new" list). |
* the "old" lines as context in the "new" list). |
*/ |
*/ |
|
|
ch = (a <= b) ? 'd' : 'a'; |
ch = (a <= b) ? 'd' : 'a'; |
|
|
if (ch == 'a') |
if (ch == 'a') |
fetch(ixold, lowa, b, input[0], " ", 0); |
fetch(ixold, lowa, b, f1, " ", 0); |
else { |
else { |
fetch(ixold, lowa, a - 1, input[0], " ", 0); |
fetch(ixold, lowa, a - 1, f1, " ", 0); |
fetch(ixold, a, b, input[0], |
fetch(ixold, a, b, f1, |
ch == 'c' ? "! " : "- ", 0); |
ch == 'c' ? "! " : "- ", 0); |
} |
} |
lowa = b + 1; |
lowa = b + 1; |
cvp++; |
cvp++; |
} |
} |
fetch(ixold, b + 1, upb, input[0], " ", 0); |
fetch(ixold, b + 1, upb, f1, " ", 0); |
} |
} |
/* 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, input[1], " ", 0); |
fetch(ixnew, lowc, d, f2, " ", 0); |
else { |
else { |
fetch(ixnew, lowc, c - 1, input[1], " ", 0); |
fetch(ixnew, lowc, c - 1, f2, " ", 0); |
fetch(ixnew, c, d, input[1], |
fetch(ixnew, c, d, f2, |
ch == 'c' ? "! " : "+ ", 0); |
ch == 'c' ? "! " : "+ ", 0); |
} |
} |
lowc = d + 1; |
lowc = d + 1; |
cvp++; |
cvp++; |
} |
} |
fetch(ixnew, d + 1, upd, input[1], " ", 0); |
fetch(ixnew, d + 1, upd, f2, " ", 0); |
} |
} |
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(void) |
dump_unified_vec(FILE *f1, FILE *f2) |
{ |
{ |
struct context_vec *cvp = context_vec_start; |
struct context_vec *cvp = context_vec_start; |
int lowa, upb, lowc, upd; |
int lowa, upb, lowc, upd; |
|
|
|
|
switch (ch) { |
switch (ch) { |
case 'c': |
case 'c': |
fetch(ixold, lowa, a - 1, input[0], " ", 0); |
fetch(ixold, lowa, a - 1, f1, " ", 0); |
fetch(ixold, a, b, input[0], "-", 0); |
fetch(ixold, a, b, f1, "-", 0); |
fetch(ixnew, c, d, input[1], "+", 0); |
fetch(ixnew, c, d, f2, "+", 0); |
break; |
break; |
case 'd': |
case 'd': |
fetch(ixold, lowa, a - 1, input[0], " ", 0); |
fetch(ixold, lowa, a - 1, f1, " ", 0); |
fetch(ixold, a, b, input[0], "-", 0); |
fetch(ixold, a, b, f1, "-", 0); |
break; |
break; |
case 'a': |
case 'a': |
fetch(ixnew, lowc, c - 1, input[1], " ", 0); |
fetch(ixnew, lowc, c - 1, f2, " ", 0); |
fetch(ixnew, c, d, input[1], "+", 0); |
fetch(ixnew, c, d, f2, "+", 0); |
break; |
break; |
} |
} |
lowa = b + 1; |
lowa = b + 1; |
lowc = d + 1; |
lowc = d + 1; |
} |
} |
fetch(ixnew, d + 1, upd, input[1], " ", 0); |
fetch(ixnew, d + 1, upd, f2, " ", 0); |
|
|
context_vec_ptr = context_vec_start - 1; |
context_vec_ptr = context_vec_start - 1; |
} |
} |