diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 2003-06-25 01:20:53 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 2003-06-25 01:20:53 +0000 |
commit | e05edc6c22b8df9867ca93031a94a18910e2bfbf (patch) | |
tree | 2f05c40bd06943ff93f46c8156c842e9e45f4962 | |
parent | 87fbad9497b86c2a8876f24bbdddaa18deec5376 (diff) |
4.3reno diff. This is free because of the Caldera license. Nasty, but a
place to start.
-rw-r--r-- | usr.bin/diff/diff.1 | 402 | ||||
-rw-r--r-- | usr.bin/diff/diff.c | 212 | ||||
-rw-r--r-- | usr.bin/diff/diff.h | 85 | ||||
-rw-r--r-- | usr.bin/diff/diffdir.c | 419 | ||||
-rw-r--r-- | usr.bin/diff/diffreg.c | 1048 | ||||
-rw-r--r-- | usr.bin/diff/pathnames.h | 24 |
6 files changed, 2190 insertions, 0 deletions
diff --git a/usr.bin/diff/diff.1 b/usr.bin/diff/diff.1 new file mode 100644 index 00000000000..e570bcf9c03 --- /dev/null +++ b/usr.bin/diff/diff.1 @@ -0,0 +1,402 @@ +.\" Copyright (c) 1980, 1990 The Regents of the University of California. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms are permitted provided +.\" that: (1) source distributions retain this entire copyright notice and +.\" comment, and (2) distributions including binaries display the following +.\" acknowledgement: ``This product includes software developed by the +.\" University of California, Berkeley and its contributors'' in the +.\" documentation or other materials provided with the distribution and in +.\" all advertising materials mentioning features or use of this software. +.\" 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.\" @(#)diff.1 6.6 (Berkeley) 7/24/90 +.\" +.Dd July 24, 1990 +.Dt DIFF 1 +.Os BSD 4 +.Sh NAME +.Nm diff +.Nd differential file and directory comparator +.Sh SYNOPSIS +.Nm diff +.Op Fl cefhn +.Op Fl biwt +.Ar file1 file2 +.Nm diff +.Op Fl D Ar string +.Op Fl biw +.Ar file1 file2 +.Nm diff +.Op Fl l +.Op Fl r +.Op Fl s +.Op Fl cefhn +.Op Fl biwt +.Ar dir1 dir2 +.Sh DESCRIPTION +The +.Nm diff +utility compares the contents of +.Ar file1 +and +.Ar file2 +and writes to the standard output the list of changes necessary to +convert one file into the other. +No output is produced if the files are identical. +.Pp +Output options (mutually exclusive): +.Tw Fl +.Tp Fl c +produces a diff with lines of context. +The default is to present 3 lines of context and may be changed, e.g to 10, by +.Fl c10 . +With +.Fl c +the output format is modified slightly: +the output beginning with identification of the files involved and +their creation dates and then each change is separated +by a line with a dozen *'s. +The lines removed from +.Ar file1 +are marked with `\(mi '; those added to +.Ar file2 +are marked `+ '. Lines which are changed from one +file to the other are marked in both files with with `! '. +Changes which lie within <context> lines of each other are grouped +together on output. (This is a change from the previous ``diff -c'' +but the resulting output is usually much easier to interpret.) +.Tp Fl e +produces output in a form suitable as input for the editor utility, +.Xr ed 1 , +which can then be used to convert file1 into file2. +.Pp +Extra commands are added to the output when comparing directories with +.Fl e , +so that the result is a +.Xr sh 1 +script for converting text files which are common to the two directories +from their state in +.Ar dir1 +to their state in +.Ar dir2 . +.Tp Fl f +identical output of the +.Fl e +flag, but in reverse order. It cannot +be digested by +.Xr ed 1 . +.Tp Fl h +Invokes an alternate algorithm which can handle files of very long lengths. +There is a trade off. The algorithm can only deal with changes which are +clearly delimited and brief. Long sections of changes and overlaps will +confuse it. +.Tp Fl n +produces a script similar to that of +.Fl e , +but in the opposite order and with a count of changed lines on each +insert or delete command. This is the form used by +.Xr rcsdiff 1 . +.Tc Fl D +.Ar string +.Cx +creates a merged version of +.Ar file1 +and +.Ar file2 +on the standard output, with C preprocessor controls included so that +a compilation of the result without defining +.Ar string +is equivalent +to compiling +.Ar file1 , +while defining +.Ar string +will yield +.Ar file2 . +.Tp +.Pp +Comparison options: +.Tp Fl b +causes trailing blanks (spaces and tabs) to be ignored, and other +strings of blanks to compare equal. +.Tp Fl i +ignores the case of letters. E.g., ``A'' will compare equal to ``a''. +.Tp Fl t +will expand tabs in output lines. Normal or +.Fl c +output adds character(s) to the front of each line which may screw up +the indentation of the original source lines and make the output listing +difficult to interpret. This option will preserve the original source's +indentation. +.Tp Fl w +is similar to +.Fl b +but causes whitespace (blanks and tabs) to be totally ignored. E.g., +``if\ (\ a\ ==\ b\ )'' will compare equal to ``if(a==b)''. +.Tp +.Pp +Directory comparison options: +.Tw Fl +.Tp Fl l +long output format; each text file +.Sf Nm diff \'d +is piped through +.Xr pr 1 +to paginate it, +other differences are remembered and summarized +after all text file differences are reported. +.Tp Fl r +causes application of +.Nm diff +recursively to common subdirectories encountered. +.Tp Fl s +causes +.Nm diff +to report files which are the same, which are otherwise not mentioned. +.Tc Fl S +.Ar name +.Cx +re-starts a directory +.Nm diff +in the middle beginning with file +.Ar name . +.Tp +.Pp +If both arguments are directories, +.Nm diff +sorts the contents of the directories by name, and then runs the +regular file +.Nm diff +algorithm, producing a change list, +on text files which are different. +Binary files which differ, +common subdirectories, and files which appear in only one directory +are described as such. +.Pp +If only one of +.Ar file1 +and +.Ar file2 +is a directory, +.Nm diff +is applied to the non-directory file and the file contained in +the directory file with a filename that is the same as the +last component of the non-directory file. +.Pp +If either the +.Ar file1 +or +.Ar file2 +is +.Fl , +the standard input is +used in its place. +.Ss Output Style +The default (without +.Fl e , +.Fl c , +or +.Fl n +.\" -C +options) +output contains lines of these forms, where +.Va XX , YY , ZZ , QQ +are line numbers respective of file order. +.Pp +.Dp Cx Li XX +.Ic a +.Li YY +.Cx +At (the end of) line +.Va XX +of +.Ar file1 , +append the contents +of line +.Va YY +of +.Ar file2 +to make them equal. +.Dp Cx Li XX +.Ic a +.Li YY , +.Li ZZ +.Cx +Same as above, but append the range of lines, +.Va YY +through +.Va ZZ +of +.Ar file2 +to line +.Va XX +of file1. +.Dp Cx Li XX +.Ic d +.Li YY +.Cx +At line +.Va XX +delete +the line. The value +.Va YY +tells to which line the change +would bring +.Ar file1 +in line with +.Ar file1 . +.Dp Cx Li XX , +.Li YY +.Ic d +.Li ZZ +.Cx +Delete the range of lines +.Va XX +through +.Va YY +in +.Ar file1 . +.Dp Cx Li XX +.Ic c +.Li YY +.Cx +Change the line +.Va XX +in +.Ar file1 +to the line +.Va YY +in +.Ar file2. +.Dp Cx Li XX , +.Li YY +.Ic c +.Li ZZ +.Cx +Replace the range of specified lines with the line +.Va ZZ . +.Dp Cx Li XX , +.Li YY +.Ic c +.Li ZZ , +.Li QQ +.Cx +Replace the range +.Cx Va XX , +.Va YY +.Cx +from +.Ar file1 +with the range +.Cx Va ZZ , +.Va QQ +.Cx +from +.Ar file2 . +.Dp +.Pp +These lines resemble +.Xr ed 1 +subcommands to convert +.Ar file1 +into +.Ar file2 . +The line numbers before the action letters pertain to +.Ar file1 ; +those after pertain to +.Ar file2 . +Thus, by exchanging +.Ic a +for +.Ic d +and reading the line in reverse order, one can also +determine how to convert +.Ar file2 +into +.Ar file1 . +As in +.Xr ed 1 , +identical +pairs (where num1 = num2) are abbreviated as a single +number. +.Sh ENVIRONMENT +.Tw Fl +.Tp Ev TMPDIR +If the environment variable +.Ev TMPDIR +exists, +.Nm Diff +will use the name specified by +.Ev TMPDIR +as an alternate temporary directory. +.Tp +.Sh FILES +.Dw /usr/bin/diffh +.Di L +.Dp Pa /tmp/d????? +.br +.Dp Pa /usr/bin/diffh +Alternate algorithm version (used by option +.Fl h ) . +.Dp Pa /usr/bin/diff +for directory diffs +.Dp Pa /usr/bin/pr +used by the +.Fl l +option. +.Dp +.Sh SEE ALSO +.Xr cmp 1 , +.Xr cc 1 , +.Xr comm 1 , +.Xr ed 1 , +.Xr diff3 1 +.Sh HISTORY +.Nm Diff +appeared in Version 6 AT&T Unix. +.Sh DIAGNOSTICS +The +.Nm diff +utility exits with one of the following values: +.Dw Ds +.Dp \&0 +No differences were found. +.Dp \&1 +Differences were found. +.Dp \&>\&1 +An error occurred. +.Dp +.Sh BUGS +The +.Fl f +and +.Fl e +options +do not provide special handling for lines on which the +first and only character is +.Dq Li \&. . +This can cause problems for +.Xr ed 1 . +.Pp +When comparing directories with the +.Fl b , +.Fl w +or +.Fl i +options specified, +.Nm diff +first compares the files ala +.Ar cmp , +and then decides to run the +.Nm diff +algorithm if they are not equal. +This may cause a small amount of spurious output if the files +then turn out to be identical because the only differences are +insignificant white space or case differences. +.\" .Sh STANDARDS diff --git a/usr.bin/diff/diff.c b/usr.bin/diff/diff.c new file mode 100644 index 00000000000..ddab61fac1f --- /dev/null +++ b/usr.bin/diff/diff.c @@ -0,0 +1,212 @@ +static char sccsid[] = "@(#)diff.c 4.7 5/11/89"; + +#include "diff.h" +#include "pathnames.h" + +/* + * diff - driver and subroutines + */ + +char diff[] = _PATH_DIFF; +char diffh[] = _PATH_DIFFH; +char pr[] = _PATH_PR; + +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; + 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 (stat(file1, &stb1) < 0) { + fprintf(stderr, "diff: "); + perror(file1); + done(); + } + if (!strcmp(file2, "-")) + stb2.st_mode = S_IFREG; + else if (stat(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); +} + +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(); +} diff --git a/usr.bin/diff/diff.h b/usr.bin/diff/diff.h new file mode 100644 index 00000000000..7c11a5fb50d --- /dev/null +++ b/usr.bin/diff/diff.h @@ -0,0 +1,85 @@ +/* diff.h 4.7 85/08/16 */ + +/* + * diff - common declarations + */ + +#include <stdio.h> +#include <ctype.h> +#include <sys/param.h> +#include <sys/stat.h> +#include <sys/dir.h> +#include <signal.h> + +/* + * Output format options + */ +int opt; + +#define D_NORMAL 0 /* Normal output */ +#define D_EDIT -1 /* Editor script out */ +#define D_REVERSE 1 /* Reverse editor script */ +#define D_CONTEXT 2 /* Diff with context */ +#define D_IFDEF 3 /* Diff with merged #ifdef's */ +#define D_NREVERSE 4 /* Reverse ed script with numbered + lines and no trailing . */ + +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 stat stb1, stb2; + +char *malloc(), *talloc(), *ralloc(); +char *savestr(), *splice(), *splicen(); +char *mktemp(), *copytemp(), *rindex(); +int done(); + +extern char diffh[], diff[], pr[]; diff --git a/usr.bin/diff/diffdir.c b/usr.bin/diff/diffdir.c new file mode 100644 index 00000000000..7be6578da6f --- /dev/null +++ b/usr.bin/diff/diffdir.c @@ -0,0 +1,419 @@ +static char *sccsid = "@(#)diffdir.c 4.12 (Berkeley) 4/30/89"; + +#include "diff.h" +/* + * diff - directory comparison + */ +#define d_flags d_ino + +#define ONLY 1 /* Only in this directory */ +#define SAME 2 /* Both places and same */ +#define DIFFER 4 /* Both places and different */ +#define DIRECT 8 /* Directory */ + +struct dir { + u_long d_ino; + short d_reclen; + short d_namlen; + char *d_entry; +}; + +struct dir *setupdir(); +int header; +static int dirstatus; /* exit status from diffdir */ +extern int status; +char title[2*BUFSIZ], *etitle; + +diffdir(argv) + char **argv; +{ + register struct dir *d1, *d2; + struct dir *dir1, *dir2; + register int i; + int cmp; + + if (opt == D_IFDEF) { + fprintf(stderr, "diff: can't specify -I with directories\n"); + done(); + } + if (opt == D_EDIT && (sflag || lflag)) + fprintf(stderr, + "diff: warning: shouldn't give -s or -l with -e\n"); + title[0] = 0; + strcpy(title, "diff "); + for (i = 1; diffargv[i+2]; i++) { + if (!strcmp(diffargv[i], "-")) + continue; /* was -S, dont look silly */ + strcat(title, diffargv[i]); + strcat(title, " "); + } + for (etitle = title; *etitle; etitle++) + ; + setfile(&file1, &efile1, file1); + setfile(&file2, &efile2, file2); + argv[0] = file1; + argv[1] = file2; + dir1 = setupdir(file1); + dir2 = setupdir(file2); + d1 = dir1; d2 = dir2; + while (d1->d_entry != 0 || d2->d_entry != 0) { + if (d1->d_entry && useless(d1->d_entry)) { + d1++; + continue; + } + if (d2->d_entry && useless(d2->d_entry)) { + d2++; + continue; + } + if (d1->d_entry == 0) + cmp = 1; + else if (d2->d_entry == 0) + cmp = -1; + else + cmp = strcmp(d1->d_entry, d2->d_entry); + if (cmp < 0) { + if (lflag) + d1->d_flags |= ONLY; + else if (opt == 0 || opt == 2) + only(d1, 1); + d1++; + dirstatus |= 1; + } else if (cmp == 0) { + compare(d1); + d1++; + d2++; + } else { + if (lflag) + d2->d_flags |= ONLY; + else if (opt == 0 || opt == 2) + only(d2, 2); + d2++; + dirstatus |= 1; + } + } + if (lflag) { + scanpr(dir1, ONLY, "Only in %.*s", file1, efile1, 0, 0); + scanpr(dir2, ONLY, "Only in %.*s", file2, efile2, 0, 0); + scanpr(dir1, SAME, "Common identical files in %.*s and %.*s", + file1, efile1, file2, efile2); + scanpr(dir1, DIFFER, "Binary files which differ in %.*s and %.*s", + file1, efile1, file2, efile2); + scanpr(dir1, DIRECT, "Common subdirectories of %.*s and %.*s", + file1, efile1, file2, efile2); + } + if (rflag) { + if (header && lflag) + printf("\f"); + for (d1 = dir1; d1->d_entry; d1++) { + if ((d1->d_flags & DIRECT) == 0) + continue; + strcpy(efile1, d1->d_entry); + strcpy(efile2, d1->d_entry); + calldiff(0); + } + } + status = dirstatus; +} + +setfile(fpp, epp, file) + char **fpp, **epp; + char *file; +{ + register char *cp; + + *fpp = malloc(BUFSIZ); + if (*fpp == 0) { + fprintf(stderr, "diff: ran out of memory\n"); + exit(1); + } + strcpy(*fpp, file); + for (cp = *fpp; *cp; cp++) + continue; + *cp++ = '/'; + *epp = cp; +} + +scanpr(dp, test, title, file1, efile1, file2, efile2) + register struct dir *dp; + int test; + char *title, *file1, *efile1, *file2, *efile2; +{ + int titled = 0; + + for (; dp->d_entry; dp++) { + if ((dp->d_flags & test) == 0) + continue; + if (titled == 0) { + if (header == 0) + header = 1; + else + printf("\n"); + printf(title, + efile1 - file1 - 1, file1, + efile2 - file2 - 1, file2); + printf(":\n"); + titled = 1; + } + printf("\t%s\n", dp->d_entry); + } +} + +only(dp, which) + struct dir *dp; + int which; +{ + char *file = which == 1 ? file1 : file2; + char *efile = which == 1 ? efile1 : efile2; + + printf("Only in %.*s: %s\n", efile - file - 1, file, dp->d_entry); + +} + +int entcmp(); + +struct dir * +setupdir(cp) + char *cp; +{ + register struct dir *dp, *ep; + register struct direct *rp; + register int nitems, n; + DIR *dirp; + + dirp = opendir(cp); + if (dirp == NULL) { + fprintf(stderr, "diff: "); + perror(cp); + done(); + } + nitems = 0; + dp = (struct dir *)malloc(sizeof (struct dir)); + if (dp == 0) { + fprintf(stderr, "diff: ran out of memory\n"); + done(); + } + while (rp = readdir(dirp)) { + ep = &dp[nitems++]; + ep->d_reclen = rp->d_reclen; + ep->d_namlen = rp->d_namlen; + ep->d_entry = 0; + ep->d_flags = 0; + if (ep->d_namlen > 0) { + ep->d_entry = malloc(ep->d_namlen + 1); + if (ep->d_entry == 0) { + fprintf(stderr, "diff: out of memory\n"); + done(); + } + strcpy(ep->d_entry, rp->d_name); + } + dp = (struct dir *)realloc((char *)dp, + (nitems + 1) * sizeof (struct dir)); + if (dp == 0) { + fprintf(stderr, "diff: ran out of memory\n"); + done(); + } + } + dp[nitems].d_entry = 0; /* delimiter */ + closedir(dirp); + qsort(dp, nitems, sizeof (struct dir), entcmp); + return (dp); +} + +entcmp(d1, d2) + struct dir *d1, *d2; +{ + return (strcmp(d1->d_entry, d2->d_entry)); +} + +compare(dp) + register struct dir *dp; +{ + register int i, j; + int f1, f2, fmt1, fmt2; + struct stat stb1, stb2; + int flag = 0; + char buf1[BUFSIZ], buf2[BUFSIZ]; + + strcpy(efile1, dp->d_entry); + strcpy(efile2, dp->d_entry); + f1 = open(file1, 0); + if (f1 < 0) { + perror(file1); + return; + } + f2 = open(file2, 0); + if (f2 < 0) { + perror(file2); + close(f1); + return; + } + fstat(f1, &stb1); fstat(f2, &stb2); + fmt1 = stb1.st_mode & S_IFMT; + fmt2 = stb2.st_mode & S_IFMT; + if (fmt1 != S_IFREG || fmt2 != S_IFREG) { + if (fmt1 == fmt2) { + if (fmt1 != S_IFDIR && stb1.st_rdev == stb2.st_rdev) + goto same; + if (fmt1 == S_IFDIR) { + dp->d_flags = DIRECT; + if (lflag || opt == D_EDIT) + goto closem; + printf("Common subdirectories: %s and %s\n", + file1, file2); + goto closem; + } + } + goto notsame; + } + if (stb1.st_size != stb2.st_size) + goto notsame; + for (;;) { + i = read(f1, buf1, BUFSIZ); + j = read(f2, buf2, BUFSIZ); + if (i < 0 || j < 0 || i != j) + goto notsame; + if (i == 0 && j == 0) + goto same; + for (j = 0; j < i; j++) + if (buf1[j] != buf2[j]) + goto notsame; + } +same: + if (sflag == 0) + goto closem; + if (lflag) + dp->d_flags = SAME; + else + printf("Files %s and %s are identical\n", file1, file2); + goto closem; +notsame: + dirstatus |= 1; + if (!ascii(f1) || !ascii(f2)) { + if (lflag) + dp->d_flags |= DIFFER; + else if (opt == D_NORMAL || opt == D_CONTEXT) + printf("Binary files %s and %s differ\n", + file1, file2); + goto closem; + } + close(f1); close(f2); + anychange = 1; + if (lflag) + calldiff(title); + else { + if (opt == D_EDIT) { + printf("ed - %s << '-*-END-*-'\n", dp->d_entry); + calldiff(0); + } else { + printf("%s%s %s\n", title, file1, file2); + calldiff(0); + } + if (opt == D_EDIT) + printf("w\nq\n-*-END-*-\n"); + } + return; +closem: + close(f1); close(f2); +} + +char *prargs[] = { "pr", "-h", 0, "-f", 0, 0 }; + +calldiff(wantpr) + char *wantpr; +{ + int pid, lstatus, lstatus2, pv[2]; + + prargs[2] = wantpr; + fflush(stdout); + if (wantpr) { + (void)sprintf(etitle, "%s %s", file1, file2); + pipe(pv); + pid = fork(); + if (pid == -1) { + fprintf(stderr, "No more processes"); + done(); + } + if (pid == 0) { + close(0); + dup(pv[0]); + close(pv[0]); + close(pv[1]); + execv(pr+4, prargs); + execv(pr, prargs); + perror(pr); + done(); + } + } + pid = fork(); + if (pid == -1) { + fprintf(stderr, "diff: No more processes\n"); + done(); + } + if (pid == 0) { + if (wantpr) { + close(1); + dup(pv[1]); + close(pv[0]); + close(pv[1]); + } + execv(diff+4, diffargv); + execv(diff, diffargv); + perror(diff); + done(); + } + if (wantpr) { + close(pv[0]); + close(pv[1]); + } + while (wait(&lstatus) != pid) + continue; + while (wait(&lstatus2) != -1) + continue; +/* + if ((lstatus >> 8) >= 2) + done(); +*/ + dirstatus |= lstatus >> 8; +} + +#include <a.out.h> + +ascii(f) + int f; +{ + char buf[BUFSIZ]; + register int cnt; + register char *cp; + + lseek(f, (long)0, 0); + cnt = read(f, buf, BUFSIZ); + if (cnt >= sizeof (struct exec)) { + struct exec hdr; + hdr = *(struct exec *)buf; + if (!N_BADMAG(hdr)) + return (0); + } + cp = buf; + while (--cnt >= 0) + if (*cp++ & 0200) + return (0); + return (1); +} + +/* + * THIS IS CRUDE. + */ +useless(cp) +register char *cp; +{ + + if (cp[0] == '.') { + if (cp[1] == '\0') + return (1); /* directory "." */ + if (cp[1] == '.' && cp[2] == '\0') + return (1); /* directory ".." */ + } + if (start && strcmp(start, cp) > 0) + return (1); + return (0); +} diff --git a/usr.bin/diff/diffreg.c b/usr.bin/diff/diffreg.c new file mode 100644 index 00000000000..fc49f6e4a29 --- /dev/null +++ b/usr.bin/diff/diffreg.c @@ -0,0 +1,1048 @@ +static char sccsid[] = "@(#)diffreg.c 4.21 4/6/90"; + +#include "diff.h" +#include "pathnames.h" +/* + * diff - compare two files. + */ + +/* + * Uses an algorithm due to Harold Stone, which finds + * a pair of longest identical subsequences in the two + * files. + * + * The major goal is to generate the match vector J. + * J[i] is the index of the line in file1 corresponding + * to line i file0. J[i] = 0 if there is no + * such line in file1. + * + * Lines are hashed so as to work in core. All potential + * matches are located by sorting the lines of each file + * on the hash (called ``value''). In particular, this + * collects the equivalence classes in file1 together. + * Subroutine equiv replaces the value of each line in + * file0 by the index of the first element of its + * matching equivalence in (the reordered) file1. + * To save space equiv squeezes file1 into a single + * array member in which the equivalence classes + * are simply concatenated, except that their first + * members are flagged by changing sign. + * + * Next the indices that point into member are unsorted into + * array class according to the original order of file0. + * + * The cleverness lies in routine stone. This marches + * through the lines of file0, developing a vector klist + * of "k-candidates". At step i a k-candidate is a matched + * pair of lines x,y (x in file0 y in file1) such that + * there is a common subsequence of length k + * between the first i lines of file0 and the first y + * lines of file1, but there is no such subsequence for + * any smaller y. x is the earliest possible mate to y + * that occurs in such a subsequence. + * + * Whenever any of the members of the equivalence class of + * lines in file1 matable to a line in file0 has serial number + * less than the y of some k-candidate, that k-candidate + * with the smallest such y is replaced. The new + * k-candidate is chained (via pred) to the current + * k-1 candidate so that the actual subsequence can + * be recovered. When a member has serial number greater + * that the y of all k-candidates, the klist is extended. + * At the end, the longest subsequence is pulled out + * and placed in the array J by unravel + * + * With J in hand, the matches there recorded are + * check'ed against reality to assure that no spurious + * matches have crept in due to hashing. If they have, + * they are broken, and "jackpot" is recorded--a harmless + * matter except that a true match for a spuriously + * mated line may now be unnecessarily reported as a change. + * + * Much of the complexity of the program comes simply + * from trying to minimize core utilization and + * maximize the range of doable problems by dynamically + * allocating what is needed and reusing what is not. + * The core requirements for problems larger than somewhat + * are (in words) 2*length(file0) + length(file1) + + * 3*(number of k-candidates installed), typically about + * 6n words for files of length n. + */ + +#define prints(s) fputs(s,stdout) + +FILE *input[2]; +FILE *fopen(); + +struct cand { + int x; + int y; + int pred; +} cand; +struct line { + int serial; + int value; +} *file[2], line; +int len[2]; +struct line *sfile[2]; /* shortened by pruning common prefix and suffix */ +int slen[2]; +int pref, suff; /* length of prefix and suffix */ +int *class; /* will be overlaid on file[0] */ +int *member; /* will be overlaid on file[1] */ +int *klist; /* will be overlaid on file[0] after class */ +struct cand *clist; /* merely a free storage pot for candidates */ +int clen = 0; +int *J; /* will be overlaid on class */ +long *ixold; /* will be overlaid on klist */ +long *ixnew; /* will be overlaid on file[1] */ +char *chrtran; /* translation table for case-folding */ + +/* chrtran points to one of 2 translation tables: + * cup2low if folding upper to lower case + * clow2low if not folding case + */ +char clow2low[256] = { +0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, +0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f, +0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f, +0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, +0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f, +0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f, +0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f, +0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f, +0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f, +0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f, +0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf, +0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf, +0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf, +0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf, +0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef, +0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff +}; + +char cup2low[256] = { +0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, +0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f, +0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f, +0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, +0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f, +0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f, +0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f, +0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f, +0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f, +0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f, +0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf, +0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf, +0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf, +0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf, +0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef, +0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff +}; + +diffreg() +{ + register int i, j; + FILE *f1, *f2; + char buf1[BUFSIZ], buf2[BUFSIZ]; + + if (hflag) { + diffargv[0] = "diffh"; + execv(diffh, diffargv); + fprintf(stderr, "diff: "); + perror(diffh); + done(); + } + chrtran = (iflag? cup2low : clow2low); + if ((stb1.st_mode & S_IFMT) == S_IFDIR) { + file1 = splice(file1, file2); + if (stat(file1, &stb1) < 0) { + fprintf(stderr, "diff: "); + perror(file1); + done(); + } + } else if ((stb2.st_mode & S_IFMT) == S_IFDIR) { + file2 = splice(file2, file1); + if (stat(file2, &stb2) < 0) { + fprintf(stderr, "diff: "); + perror(file2); + done(); + } + } else if ((stb1.st_mode & S_IFMT) != S_IFREG || !strcmp(file1, "-")) { + if (!strcmp(file2, "-")) { + fprintf(stderr, "diff: can't specify - -\n"); + done(); + } + file1 = copytemp(); + if (stat(file1, &stb1) < 0) { + fprintf(stderr, "diff: "); + perror(file1); + done(); + } + } else if ((stb2.st_mode & S_IFMT) != S_IFREG || !strcmp(file2, "-")) { + file2 = copytemp(); + if (stat(file2, &stb2) < 0) { + fprintf(stderr, "diff: "); + perror(file2); + done(); + } + } + if ((f1 = fopen(file1, "r")) == NULL) { + fprintf(stderr, "diff: "); + perror(file1); + done(); + } + if ((f2 = fopen(file2, "r")) == NULL) { + fprintf(stderr, "diff: "); + perror(file2); + fclose(f1); + done(); + } + if (stb1.st_size != stb2.st_size) + goto notsame; + for (;;) { + i = fread(buf1, 1, BUFSIZ, f1); + j = fread(buf2, 1, BUFSIZ, f2); + if (i < 0 || j < 0 || i != j) + goto notsame; + if (i == 0 && j == 0) { + fclose(f1); + fclose(f2); + status = 0; /* files don't differ */ + goto same; + } + for (j = 0; j < i; j++) + if (buf1[j] != buf2[j]) + goto notsame; + } +notsame: + /* + * Files certainly differ at this point; set status accordingly + */ + status = 1; + if (!asciifile(f1) || !asciifile(f2)) { + printf("Binary files %s and %s differ\n", file1, file2); + fclose(f1); + fclose(f2); + done(); + } + prepare(0, f1); + prepare(1, f2); + fclose(f1); + fclose(f2); + prune(); + sort(sfile[0],slen[0]); + sort(sfile[1],slen[1]); + + member = (int *)file[1]; + equiv(sfile[0], slen[0], sfile[1], slen[1], member); + member = (int *)ralloc((char *)member,(slen[1]+2)*sizeof(int)); + + class = (int *)file[0]; + unsort(sfile[0], slen[0], class); + class = (int *)ralloc((char *)class,(slen[0]+2)*sizeof(int)); + + klist = (int *)talloc((slen[0]+2)*sizeof(int)); + clist = (struct cand *)talloc(sizeof(cand)); + i = stone(class, slen[0], member, klist); + free((char *)member); + free((char *)class); + + J = (int *)talloc((len[0]+2)*sizeof(int)); + unravel(klist[i]); + free((char *)clist); + free((char *)klist); + + ixold = (long *)talloc((len[0]+2)*sizeof(long)); + ixnew = (long *)talloc((len[1]+2)*sizeof(long)); + check(); + output(); + status = anychange; +same: + if (opt == D_CONTEXT && anychange == 0) + printf("No differences encountered\n"); + done(); +} + +char *tempfile = _PATH_TMP; + +char * +copytemp() +{ + char buf[BUFSIZ]; + register int i, f; + + signal(SIGHUP,done); + signal(SIGINT,done); + signal(SIGPIPE,done); + signal(SIGTERM,done); + mktemp(tempfile); + f = creat(tempfile,0600); + if (f < 0) { + fprintf(stderr, "diff: "); + perror(tempfile); + done(); + } + while ((i = read(0,buf,BUFSIZ)) > 0) + if (write(f,buf,i) != i) { + fprintf(stderr, "diff: "); + perror(tempfile); + done(); + } + close(f); + return (tempfile); +} + +char * +splice(dir, file) + char *dir, *file; +{ + char *tail; + char buf[BUFSIZ]; + + if (!strcmp(file, "-")) { + fprintf(stderr, "diff: can't specify - with other arg directory\n"); + done(); + } + tail = rindex(file, '/'); + if (tail == 0) + tail = file; + else + tail++; + (void)sprintf(buf, "%s/%s", dir, tail); + return (savestr(buf)); +} + +prepare(i, fd) + int i; + FILE *fd; +{ + register struct line *p; + register j,h; + + fseek(fd, (long)0, 0); + p = (struct line *)talloc(3*sizeof(line)); + for(j=0; h=readhash(fd);) { + p = (struct line *)ralloc((char *)p,(++j+3)*sizeof(line)); + p[j].value = h; + } + len[i] = j; + file[i] = p; +} + +prune() +{ + register i,j; + for(pref=0;pref<len[0]&&pref<len[1]&& + file[0][pref+1].value==file[1][pref+1].value; + pref++ ) ; + for(suff=0;suff<len[0]-pref&&suff<len[1]-pref&& + file[0][len[0]-suff].value==file[1][len[1]-suff].value; + suff++) ; + for(j=0;j<2;j++) { + sfile[j] = file[j]+pref; + slen[j] = len[j]-pref-suff; + for(i=0;i<=slen[j];i++) + sfile[j][i].serial = i; + } +} + +equiv(a,n,b,m,c) +struct line *a, *b; +int *c; +{ + register int i, j; + i = j = 1; + while(i<=n && j<=m) { + if(a[i].value <b[j].value) + a[i++].value = 0; + else if(a[i].value == b[j].value) + a[i++].value = j; + else + j++; + } + while(i <= n) + a[i++].value = 0; + b[m+1].value = 0; + j = 0; + while(++j <= m) { + c[j] = -b[j].serial; + while(b[j+1].value == b[j].value) { + j++; + c[j] = b[j].serial; + } + } + c[j] = -1; +} + +stone(a,n,b,c) +int *a; +int *b; +register int *c; +{ + register int i, k,y; + int j, l; + int oldc, tc; + int oldl; + k = 0; + c[0] = newcand(0,0,0); + for(i=1; i<=n; i++) { + j = a[i]; + if(j==0) + continue; + y = -b[j]; + oldl = 0; + oldc = c[0]; + do { + if(y <= clist[oldc].y) + continue; + l = search(c, k, y); + if(l!=oldl+1) + oldc = c[l-1]; + if(l<=k) { + if(clist[c[l]].y <= y) + continue; + tc = c[l]; + c[l] = newcand(i,y,oldc); + oldc = tc; + oldl = l; + } else { + c[l] = newcand(i,y,oldc); + k++; + break; + } + } while((y=b[++j]) > 0); + } + return(k); +} + +newcand(x,y,pred) +{ + register struct cand *q; + clist = (struct cand *)ralloc((char *)clist,++clen*sizeof(cand)); + q = clist + clen -1; + q->x = x; + q->y = y; + q->pred = pred; + return(clen-1); +} + +search(c, k, y) +int *c; +{ + register int i, j, l; + int t; + if(clist[c[k]].y<y) /*quick look for typical case*/ + return(k+1); + i = 0; + j = k+1; + while (1) { + l = i + j; + if ((l >>= 1) <= i) + break; + t = clist[c[l]].y; + if(t > y) + j = l; + else if(t < y) + i = l; + else + return(l); + } + return(l+1); +} + +unravel(p) +{ + register int i; + register struct cand *q; + for(i=0; i<=len[0]; i++) + J[i] = i<=pref ? i: + i>len[0]-suff ? i+len[1]-len[0]: + 0; + for(q=clist+p;q->y!=0;q=clist+q->pred) + J[q->x+pref] = q->y+pref; +} + +/* check does double duty: +1. ferret out any fortuitous correspondences due +to confounding by hashing (which result in "jackpot") +2. collect random access indexes to the two files */ + +check() +{ + register int i, j; + int jackpot; + long ctold, ctnew; + register int c,d; + + if ((input[0] = fopen(file1,"r")) == NULL) { + perror(file1); + done(); + } + if ((input[1] = fopen(file2,"r")) == NULL) { + perror(file2); + done(); + } + j = 1; + ixold[0] = ixnew[0] = 0; + jackpot = 0; + ctold = ctnew = 0; + for(i=1;i<=len[0];i++) { + if(J[i]==0) { + ixold[i] = ctold += skipline(0); + continue; + } + while(j<J[i]) { + ixnew[j] = ctnew += skipline(1); + j++; + } + if(bflag || wflag || iflag) { + for(;;) { + c = getc(input[0]); + d = getc(input[1]); + ctold++; + ctnew++; + if(bflag && isspace(c) && isspace(d)) { + do { + if(c=='\n') + break; + ctold++; + } while(isspace(c=getc(input[0]))); + do { + if(d=='\n') + break; + ctnew++; + } while(isspace(d=getc(input[1]))); + } else if ( wflag ) { + while( isspace(c) && c!='\n' ) { + c=getc(input[0]); + ctold++; + } + while( isspace(d) && d!='\n' ) { + d=getc(input[1]); + ctnew++; + } + } + if(chrtran[c] != chrtran[d]) { + jackpot++; + J[i] = 0; + if(c!='\n') + ctold += skipline(0); + if(d!='\n') + ctnew += skipline(1); + break; + } + if(c=='\n') + break; + } + } else { + for(;;) { + ctold++; + ctnew++; + if((c=getc(input[0])) != (d=getc(input[1]))) { + /* jackpot++; */ + J[i] = 0; + if(c!='\n') + ctold += skipline(0); + if(d!='\n') + ctnew += skipline(1); + break; + } + if(c=='\n') + break; + } + } + ixold[i] = ctold; + ixnew[j] = ctnew; + j++; + } + for(;j<=len[1];j++) { + ixnew[j] = ctnew += skipline(1); + } + fclose(input[0]); + fclose(input[1]); +/* + if(jackpot) + fprintf(stderr, "jackpot\n"); +*/ +} + +sort(a,n) /*shellsort CACM #201*/ +struct line *a; +{ + struct line w; + register int j,m; + struct line *ai; + register struct line *aim; + int k; + + if (n == 0) + return; + for(j=1;j<=n;j*= 2) + m = 2*j - 1; + for(m/=2;m!=0;m/=2) { + k = n-m; + for(j=1;j<=k;j++) { + for(ai = &a[j]; ai > a; ai -= m) { + aim = &ai[m]; + if(aim < ai) + break; /*wraparound*/ + if(aim->value > ai[0].value || + aim->value == ai[0].value && + aim->serial > ai[0].serial) + break; + w.value = ai[0].value; + ai[0].value = aim->value; + aim->value = w.value; + w.serial = ai[0].serial; + ai[0].serial = aim->serial; + aim->serial = w.serial; + } + } + } +} + +unsort(f, l, b) +struct line *f; +int *b; +{ + register int *a; + register int i; + a = (int *)talloc((l+1)*sizeof(int)); + for(i=1;i<=l;i++) + a[f[i].serial] = f[i].value; + for(i=1;i<=l;i++) + b[i] = a[i]; + free((char *)a); +} + +skipline(f) +{ + register i, c; + + for(i=1;(c=getc(input[f]))!='\n';i++) + if (c < 0) + return(i); + return(i); +} + +output() +{ + int m; + register int i0, i1, j1; + int j0; + input[0] = fopen(file1,"r"); + input[1] = fopen(file2,"r"); + m = len[0]; + J[0] = 0; + J[m+1] = len[1]+1; + if(opt!=D_EDIT) for(i0=1;i0<=m;i0=i1+1) { + while(i0<=m&&J[i0]==J[i0-1]+1) i0++; + j0 = J[i0-1]+1; + i1 = i0-1; + while(i1<m&&J[i1+1]==0) i1++; + j1 = J[i1+1]-1; + J[i1] = j1; + change(i0,i1,j0,j1); + } else for(i0=m;i0>=1;i0=i1-1) { + while(i0>=1&&J[i0]==J[i0+1]-1&&J[i0]!=0) i0--; + j0 = J[i0+1]-1; + i1 = i0+1; + while(i1>1&&J[i1-1]==0) i1--; + j1 = J[i1-1]+1; + J[i1] = j1; + change(i1,i0,j1,j0); + } + if(m==0) + change(1,0,1,len[1]); + if (opt==D_IFDEF) { + for (;;) { +#define c i0 + c = getc(input[0]); + if (c < 0) + return; + putchar(c); + } +#undef c + } + if (anychange && opt == D_CONTEXT) + dump_context_vec(); +} + +/* + * The following struct is used to record change information when + * doing a "context" diff. (see routine "change" to understand the + * highly mneumonic field names) + */ +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 */ +}; + +struct context_vec *context_vec_start, + *context_vec_end, + *context_vec_ptr; + +#define MAX_CONTEXT 128 + +/* 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 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 missing from the to file. +*/ +change(a,b,c,d) +{ + int lowa,upb,lowc,upd; + struct stat stbuf; + + if (opt != D_IFDEF && a>b && c>d) + return; + if (anychange == 0) { + anychange = 1; + if(opt == D_CONTEXT) { + printf("*** %s ", file1); + stat(file1, &stbuf); + printf("%s--- %s ", + ctime(&stbuf.st_mtime), file2); + stat(file2, &stbuf); + printf("%s", ctime(&stbuf.st_mtime)); + + context_vec_start = (struct context_vec *) + malloc(MAX_CONTEXT * + sizeof(struct context_vec)); + context_vec_end = context_vec_start + MAX_CONTEXT; + context_vec_ptr = context_vec_start - 1; + } + } + if(opt == D_CONTEXT) { + /* + * if this new change is within 'context' lines of + * the previous change, just add it to the change + * record. If the record is full or if this + * change is more than 'context' lines from the previous + * change, dump the record, reset it & add the new change. + */ + if ( context_vec_ptr >= context_vec_end || + ( context_vec_ptr >= context_vec_start && + a > (context_vec_ptr->b + 2*context) && + c > (context_vec_ptr->d + 2*context) ) ) + dump_context_vec(); + + context_vec_ptr++; + context_vec_ptr->a = a; + context_vec_ptr->b = b; + context_vec_ptr->c = c; + context_vec_ptr->d = d; + return; + } + switch (opt) { + + case D_NORMAL: + case D_EDIT: + range(a,b,","); + putchar(a>b?'a':c>d?'d':'c'); + if(opt==D_NORMAL) + range(c,d,","); + putchar('\n'); + break; + case D_REVERSE: + putchar(a>b?'a':c>d?'d':'c'); + range(a,b," "); + putchar('\n'); + break; + case D_NREVERSE: + if (a>b) + printf("a%d %d\n",b,d-c+1); + else { + printf("d%d %d\n",a,b-a+1); + if (!(c>d)) + /* add changed lines */ + printf("a%d %d\n",b, d-c+1); + } + break; + } + if(opt == D_NORMAL || opt == D_IFDEF) { + fetch(ixold,a,b,input[0],"< ", 1); + if(a<=b&&c<=d && opt == D_NORMAL) + prints("---\n"); + } + fetch(ixnew,c,d,input[1],opt==D_NORMAL?"> ":"", 0); + if ((opt ==D_EDIT || opt == D_REVERSE) && c<=d) + prints(".\n"); + if (inifdef) { + fprintf(stdout, "#endif /* %s */\n", endifname); + inifdef = 0; + } +} + +range(a,b,separator) +char *separator; +{ + printf("%d", a>b?b:a); + if(a<b) { + printf("%s%d", separator, b); + } +} + +fetch(f,a,b,lb,s,oldfile) +long *f; +FILE *lb; +char *s; +{ + register int i, j; + register int c; + register int col; + register int nc; + int oneflag = (*ifdef1!='\0') != (*ifdef2!='\0'); + + /* + * When doing #ifdef's, copy down to current line + * if this is the first file, so that stuff makes it to output. + */ + if (opt == D_IFDEF && oldfile){ + long curpos = ftell(lb); + /* print through if append (a>b), else to (nb: 0 vs 1 orig) */ + nc = f[a>b? b : a-1 ] - curpos; + for (i = 0; i < nc; i++) + putchar(getc(lb)); + } + if (a > b) + return; + if (opt == D_IFDEF) { + if (inifdef) + fprintf(stdout, "#else /* %s%s */\n", oneflag && oldfile==1 ? "!" : "", ifdef2); + else { + if (oneflag) { + /* There was only one ifdef given */ + endifname = ifdef2; + if (oldfile) + fprintf(stdout, "#ifndef %s\n", endifname); + else + fprintf(stdout, "#ifdef %s\n", endifname); + } + else { + endifname = oldfile ? ifdef1 : ifdef2; + fprintf(stdout, "#ifdef %s\n", endifname); + } + } + inifdef = 1+oldfile; + } + + for(i=a;i<=b;i++) { + fseek(lb,f[i-1],0); + nc = f[i]-f[i-1]; + if (opt != D_IFDEF) + prints(s); + col = 0; + for(j=0;j<nc;j++) { + c = getc(lb); + if (c == '\t' && tflag) + do + putchar(' '); + while (++col & 7); + else { + putchar(c); + col++; + } + } + } + + if (inifdef && !wantelses) { + fprintf(stdout, "#endif /* %s */\n", endifname); + inifdef = 0; + } +} + +#define POW2 /* define only if HALFLONG is 2**n */ +#define HALFLONG 16 +#define low(x) (x&((1L<<HALFLONG)-1)) +#define high(x) (x>>HALFLONG) + +/* + * hashing has the effect of + * arranging line in 7-bit bytes and then + * summing 1-s complement in 16-bit hunks + */ +readhash(f) +register FILE *f; +{ + register long sum; + register unsigned shift; + register t; + register space; + + sum = 1; + space = 0; + if(!bflag && !wflag) { + if(iflag) + for(shift=0;(t=getc(f))!='\n';shift+=7) { + if(t==-1) + return(0); + sum += (long)chrtran[t] << (shift +#ifdef POW2 + &= HALFLONG - 1); +#else + %= HALFLONG); +#endif + } + else + for(shift=0;(t=getc(f))!='\n';shift+=7) { + if(t==-1) + return(0); + sum += (long)t << (shift +#ifdef POW2 + &= HALFLONG - 1); +#else + %= HALFLONG); +#endif + } + } else { + for(shift=0;;) { + switch(t=getc(f)) { + case -1: + return(0); + case '\t': + case ' ': + space++; + continue; + default: + if(space && !wflag) { + shift += 7; + space = 0; + } + sum += (long)chrtran[t] << (shift +#ifdef POW2 + &= HALFLONG - 1); +#else + %= HALFLONG); +#endif + shift += 7; + continue; + case '\n': + break; + } + break; + } + } + sum = low(sum) + high(sum); + return((short)low(sum) + (short)high(sum)); +} + +#include <a.out.h> + +asciifile(f) + FILE *f; +{ + char buf[BUFSIZ]; + register int cnt; + register char *cp; + + fseek(f, (long)0, 0); + cnt = fread(buf, 1, BUFSIZ, f); + if (cnt >= sizeof (struct exec)) { + struct exec hdr; + hdr = *(struct exec *)buf; + if (!N_BADMAG(hdr)) + return (0); + } + cp = buf; + while (--cnt >= 0) + if (*cp++ & 0200) + return (0); + return (1); +} + + +/* dump accumulated "context" diff changes */ +dump_context_vec() +{ + register int a, b, c, d; + register char ch; + register struct context_vec *cvp = context_vec_start; + register int lowa, upb, lowc, upd; + register int do_output; + + if ( cvp > context_vec_ptr ) + return; + + lowa = max(1, cvp->a - context); + upb = min(len[0], context_vec_ptr->b + context); + lowc = max(1, cvp->c - context); + upd = min(len[1], context_vec_ptr->d + context); + + printf("***************\n*** "); + range(lowa,upb,","); + printf(" ****\n"); + + /* + * output changes to the "old" file. The first loop suppresses + * output if there were no changes to the "old" file (we'll see + * the "old" lines as context in the "new" list). + */ + do_output = 0; + for ( ; cvp <= context_vec_ptr; cvp++) + if (cvp->a <= cvp->b) { + cvp = context_vec_start; + do_output++; + break; + } + + if ( do_output ) { + while (cvp <= context_vec_ptr) { + a = cvp->a; b = cvp->b; c = cvp->c; d = cvp->d; + + if (a <= b && c <= d) + ch = 'c'; + else + ch = (a <= b) ? 'd' : 'a'; + + if (ch == 'a') + fetch(ixold,lowa,b,input[0]," "); + else { + fetch(ixold,lowa,a-1,input[0]," "); + fetch(ixold,a,b,input[0],ch == 'c' ? "! " : "- "); + } + lowa = b + 1; + cvp++; + } + fetch(ixold, b+1, upb, input[0], " "); + } + + /* output changes to the "new" file */ + printf("--- "); + range(lowc,upd,","); + printf(" ----\n"); + + do_output = 0; + for (cvp = context_vec_start; cvp <= context_vec_ptr; cvp++) + if (cvp->c <= cvp->d) { + cvp = context_vec_start; + do_output++; + break; + } + + if (do_output) { + while (cvp <= context_vec_ptr) { + a = cvp->a; b = cvp->b; c = cvp->c; d = cvp->d; + + if (a <= b && c <= d) + ch = 'c'; + else + ch = (a <= b) ? 'd' : 'a'; + + if (ch == 'd') + fetch(ixnew,lowc,d,input[1]," "); + else { + fetch(ixnew,lowc,c-1,input[1]," "); + fetch(ixnew,c,d,input[1],ch == 'c' ? "! " : "+ "); + } + lowc = d + 1; + cvp++; + } + fetch(ixnew, d+1, upd, input[1], " "); + } + + context_vec_ptr = context_vec_start - 1; +} diff --git a/usr.bin/diff/pathnames.h b/usr.bin/diff/pathnames.h new file mode 100644 index 00000000000..97b9ae9717c --- /dev/null +++ b/usr.bin/diff/pathnames.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * @(#)pathnames.h 5.1 (Berkeley) 5/11/89 + */ + +#define _PATH_DIFF "/usr/bin/diff" +#define _PATH_DIFFH "/usr/bin/diffh" +#define _PATH_PR "/usr/bin/pr" +#undef _PATH_TMP +#define _PATH_TMP "/tmp/dXXXXX" |