280 lines
4.6 KiB
C
280 lines
4.6 KiB
C
static char sccsid[] = "@(#)diff.c 4.6 4/3/86";
|
|
|
|
#include "diff.h"
|
|
/*
|
|
* diff - driver and subroutines
|
|
*/
|
|
|
|
char diff[] = DIFF;
|
|
char diffh[] = DIFFH;
|
|
char pr[] = PR;
|
|
|
|
/*
|
|
* Output format options
|
|
*/
|
|
int opt;
|
|
|
|
int tflag; /* expand tabs on output */
|
|
|
|
/*
|
|
* Algorithm related options
|
|
*/
|
|
int hflag; /* -h, use halfhearted DIFFH */
|
|
int bflag; /* ignore blanks in comparisons */
|
|
int wflag; /* totally ignore blanks in comparisons */
|
|
int iflag; /* ignore case in comparisons */
|
|
|
|
/*
|
|
* Options on hierarchical diffs.
|
|
*/
|
|
int lflag; /* long output format with header */
|
|
int rflag; /* recursively trace directories */
|
|
int sflag; /* announce files which are same */
|
|
char *start; /* do file only if name >= this */
|
|
|
|
/*
|
|
* Variables for -I D_IFDEF option.
|
|
*/
|
|
int wantelses; /* -E */
|
|
char *ifdef1; /* String for -1 */
|
|
char *ifdef2; /* String for -2 */
|
|
char *endifname; /* What we will print on next #endif */
|
|
int inifdef;
|
|
|
|
/*
|
|
* Variables for -c context option.
|
|
*/
|
|
int context; /* lines of context to be printed */
|
|
|
|
/*
|
|
* State for exit status.
|
|
*/
|
|
int status;
|
|
int anychange;
|
|
char *tempfile; /* used when comparing against std input */
|
|
|
|
/*
|
|
* Variables for diffdir.
|
|
*/
|
|
char **diffargv; /* option list to pass to recursive diffs */
|
|
|
|
/*
|
|
* Input file names.
|
|
* With diffdir, file1 and file2 are allocated BUFSIZ space,
|
|
* and padded with a '/', and then efile0 and efile1 point after
|
|
* the '/'.
|
|
*/
|
|
char *file1, *file2, *efile1, *efile2;
|
|
struct stat64 stb1, stb2;
|
|
|
|
main(argc, argv)
|
|
int argc;
|
|
char **argv;
|
|
{
|
|
register char *argp;
|
|
|
|
ifdef1 = "FILE1"; ifdef2 = "FILE2";
|
|
status = 2;
|
|
diffargv = argv;
|
|
argc--, argv++;
|
|
while (argc > 2 && argv[0][0] == '-') {
|
|
argp = &argv[0][1];
|
|
argv++, argc--;
|
|
while (*argp) switch(*argp++) {
|
|
|
|
#ifdef notdef
|
|
case 'I':
|
|
opt = D_IFDEF;
|
|
wantelses = 0;
|
|
continue;
|
|
case 'E':
|
|
opt = D_IFDEF;
|
|
wantelses = 1;
|
|
continue;
|
|
case '1':
|
|
opt = D_IFDEF;
|
|
ifdef1 = argp;
|
|
*--argp = 0;
|
|
continue;
|
|
#endif
|
|
case 'D':
|
|
/* -Dfoo = -E -1 -2foo */
|
|
wantelses = 1;
|
|
ifdef1 = "";
|
|
/* fall through */
|
|
#ifdef notdef
|
|
case '2':
|
|
#endif
|
|
opt = D_IFDEF;
|
|
ifdef2 = argp;
|
|
*--argp = 0;
|
|
continue;
|
|
case 'e':
|
|
opt = D_EDIT;
|
|
continue;
|
|
case 'f':
|
|
opt = D_REVERSE;
|
|
continue;
|
|
case 'n':
|
|
opt = D_NREVERSE;
|
|
continue;
|
|
case 'b':
|
|
bflag = 1;
|
|
continue;
|
|
case 'w':
|
|
wflag = 1;
|
|
continue;
|
|
case 'i':
|
|
iflag = 1;
|
|
continue;
|
|
case 't':
|
|
tflag = 1;
|
|
continue;
|
|
case 'c':
|
|
opt = D_CONTEXT;
|
|
if (isdigit(*argp)) {
|
|
context = atoi(argp);
|
|
while (isdigit(*argp))
|
|
argp++;
|
|
if (*argp) {
|
|
fprintf(stderr,
|
|
"diff: -c: bad count\n");
|
|
done();
|
|
}
|
|
argp = "";
|
|
} else
|
|
context = 3;
|
|
continue;
|
|
case 'h':
|
|
hflag++;
|
|
continue;
|
|
case 'S':
|
|
if (*argp == 0) {
|
|
fprintf(stderr, "diff: use -Sstart\n");
|
|
done();
|
|
}
|
|
start = argp;
|
|
*--argp = 0; /* don't pass it on */
|
|
continue;
|
|
case 'r':
|
|
rflag++;
|
|
continue;
|
|
case 's':
|
|
sflag++;
|
|
continue;
|
|
case 'l':
|
|
lflag++;
|
|
continue;
|
|
case 'x':
|
|
/* XXX all of this should use getopt() */
|
|
if (*argp ==0) {
|
|
fprintf(stderr, "diff: use -xpattern\n");
|
|
done();
|
|
}
|
|
if (0 > setxpat(argp))
|
|
done();
|
|
argp = "";
|
|
continue;
|
|
default:
|
|
fprintf(stderr, "diff: -%s: unknown option\n",
|
|
--argp);
|
|
done();
|
|
}
|
|
}
|
|
if (argc != 2) {
|
|
fprintf(stderr, "diff: two filename arguments required\n");
|
|
done();
|
|
}
|
|
file1 = argv[0];
|
|
file2 = argv[1];
|
|
if (hflag && opt) {
|
|
fprintf(stderr,
|
|
"diff: -h doesn't support -e, -f, -n, -c, or -I\n");
|
|
done();
|
|
}
|
|
if (!strcmp(file1, "-"))
|
|
stb1.st_mode = S_IFREG;
|
|
else if (stat64(file1, &stb1) < 0) {
|
|
fprintf(stderr, "diff: ");
|
|
perror(file1);
|
|
done();
|
|
}
|
|
if (!strcmp(file2, "-"))
|
|
stb2.st_mode = S_IFREG;
|
|
else if (stat64(file2, &stb2) < 0) {
|
|
fprintf(stderr, "diff: ");
|
|
perror(file2);
|
|
done();
|
|
}
|
|
if ((stb1.st_mode & S_IFMT) == S_IFDIR &&
|
|
(stb2.st_mode & S_IFMT) == S_IFDIR) {
|
|
diffdir(argv);
|
|
} else
|
|
diffreg();
|
|
done();
|
|
}
|
|
|
|
char *
|
|
savestr(cp)
|
|
register char *cp;
|
|
{
|
|
register char *dp = malloc(strlen(cp)+1);
|
|
|
|
if (dp == 0) {
|
|
fprintf(stderr, "diff: ran out of memory\n");
|
|
done();
|
|
}
|
|
strcpy(dp, cp);
|
|
return (dp);
|
|
}
|
|
|
|
min(a,b)
|
|
int a,b;
|
|
{
|
|
|
|
return (a < b ? a : b);
|
|
}
|
|
|
|
max(a,b)
|
|
int a,b;
|
|
{
|
|
|
|
return (a > b ? a : b);
|
|
}
|
|
|
|
void
|
|
done()
|
|
{
|
|
if (tempfile)
|
|
unlink(tempfile);
|
|
exit(status);
|
|
}
|
|
|
|
char *
|
|
talloc(n)
|
|
{
|
|
register char *p;
|
|
|
|
if ((p = malloc((unsigned)n)) != NULL)
|
|
return(p);
|
|
noroom();
|
|
}
|
|
|
|
char *
|
|
ralloc(p,n)
|
|
char *p;
|
|
{
|
|
register char *q;
|
|
char *realloc();
|
|
|
|
if ((q = realloc(p, (unsigned)n)) == NULL)
|
|
noroom();
|
|
return(q);
|
|
}
|
|
|
|
noroom()
|
|
{
|
|
fprintf(stderr, "diff: files too big, try -h\n");
|
|
done();
|
|
}
|