summaryrefslogtreecommitdiff
path: root/usr.bin
diff options
context:
space:
mode:
authorTodd C. Miller <millert@cvs.openbsd.org>2003-07-06 20:49:00 +0000
committerTodd C. Miller <millert@cvs.openbsd.org>2003-07-06 20:49:00 +0000
commit737cbdaa54f6fa925621ca719208c6d5c8ab77fe (patch)
treec8048f62eadf7de70c0c27894f168dda8ff12a7e /usr.bin
parentfb77cb0f007d25ab8a99b64eb77a2c87f0f2716b (diff)
Some fairly major changes:
o -N is implemented o -X is implemented o -x is implemented o diff.c has been rewritten and GNU long options are now supported o diffdir.c has been rewritten + no longer does fork + exec of /usr/bin/diff + can be called recursively (and will be for -r) o diff.h + don't include any .h files here any more, do it in the .c files + no Bell Labs code in this, gets a UCB copyright (the 32v sources only have a diff.c and there is nothing in common). o diffreg.c + most all remaining globals are now private to diffreg.c + files are only opened once + dynamically allocated objects are either freed or realloced + added missing UCB copyright (there were lots of UCB changes) + print correct thing when -s is specified OK deraadt@
Diffstat (limited to 'usr.bin')
-rw-r--r--usr.bin/diff/diff.133
-rw-r--r--usr.bin/diff/diff.c315
-rw-r--r--usr.bin/diff/diff.h93
-rw-r--r--usr.bin/diff/diffdir.c533
-rw-r--r--usr.bin/diff/diffreg.c513
-rw-r--r--usr.bin/diff/pathnames.h34
6 files changed, 798 insertions, 723 deletions
diff --git a/usr.bin/diff/diff.1 b/usr.bin/diff/diff.1
index 3518ca11573..c555da5ddd0 100644
--- a/usr.bin/diff/diff.1
+++ b/usr.bin/diff/diff.1
@@ -1,4 +1,4 @@
-.\" $OpenBSD: diff.1,v 1.10 2003/07/04 17:50:24 millert Exp $
+.\" $OpenBSD: diff.1,v 1.11 2003/07/06 20:48:59 millert Exp $
.\"
.\" Copyright (c) 1980, 1990, 1993
.\" The Regents of the University of California. All rights reserved.
@@ -56,14 +56,18 @@
.Op Fl U Ar number
.Ar file1 file2
.Nm diff
-.Op Fl abitw
+.Op Fl abiNtw
.Oo
.Fl c | Fl e | Fl f |
.Fl n | Fl u
.Oc
+.Bk -words
.Op Fl r
.Op Fl s
.Op Fl S Ar name
+.Op Fl X Ar file
+.Op Fl x Ar pattern
+.Ek
.Ar dir1 dir2
.Sh DESCRIPTION
The
@@ -78,8 +82,6 @@ No output is produced if the files are identical.
.Pp
Output options (mutually exclusive):
.Bl -tag -width Ds
-.It Fl a
-Treat all files as ASCII.
.It Fl c
Produces a diff with 3 lines of context.
With
@@ -168,6 +170,8 @@ lines of context.
.Pp
Comparison options:
.Bl -tag -width Ds
+.It Fl a
+Treat all files as ASCII.
.It Fl b
Causes trailing blanks (spaces and tabs) to be ignored, and other
strings of blanks to compare equal.
@@ -197,6 +201,9 @@ will compare equal to
.Pp
Directory comparison options:
.Bl -tag -width Ds
+.It Fl N
+If a file is found in only one directory, act as if it was found in the
+other directory too but was of zero size.
.It Fl r
Causes application of
.Nm
@@ -210,6 +217,21 @@ Re-starts a directory
.Nm
in the middle, beginning with file
.Ar name .
+.It Fl X Ar file
+Exclude files and subdirectories from comparison whose basenames match
+lines in
+.Ar file .
+Multiple
+.Fl X
+options may be specified.
+.It Fl x Ar pattern
+Exclude files and subdirectories from comparison whose basenames match
+.Ar pattern .
+Patterns are matched using shell-style globbing via
+.Xr fnmatch 3 .
+Multiple
+.Fl x
+options may be specified.
.El
.Pp
If both arguments are directories,
@@ -381,7 +403,8 @@ An error occurred.
.Xr cmp 1 ,
.Xr comm 1 ,
.Xr diff3 1 ,
-.Xr ed 1
+.Xr ed 1 ,
+.Xr fnmatch 3
.Sh HISTORY
A
.Nm
diff --git a/usr.bin/diff/diff.c b/usr.bin/diff/diff.c
index 9a6ad78dc5b..6c570cc98e4 100644
--- a/usr.bin/diff/diff.c
+++ b/usr.bin/diff/diff.c
@@ -1,156 +1,157 @@
-/* $OpenBSD: diff.c,v 1.22 2003/07/04 17:52:35 millert Exp $ */
+/* $OpenBSD: diff.c,v 1.23 2003/07/06 20:48:59 millert Exp $ */
/*
- * Copyright (C) Caldera International Inc. 2001-2002.
- * All rights reserved.
+ * Copyright (c) 2003 Todd C. Miller <Todd.Miller@courtesan.com>
*
- * 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 and documentation 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. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed or owned by Caldera
- * International, Inc.
- * 4. Neither the name of Caldera International, Inc. nor the names of other
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
*
- * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
- * INTERNATIONAL, INC. 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 CALDERA INTERNATIONAL, INC. 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.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F39502-99-1-0512.
*/
+#ifndef lint
+static const char rcsid[] = "$OpenBSD: diff.c,v 1.23 2003/07/06 20:48:59 millert Exp $";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <err.h>
#include <errno.h>
+#include <getopt.h>
#include <stdlib.h>
+#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include "diff.h"
-#include "pathnames.h"
-#if 0
-static char const sccsid[] = "@(#)diff.c 4.7 5/11/89";
-#endif
-
-/*
- * diff - driver and subroutines
- */
-int opt;
-int aflag; /* treat all files as text */
-int tflag; /* expand tabs on output */
-/* Algorithm related options. */
-int bflag; /* ignore blanks in comparisons */
-int wflag; /* totally ignore blanks in comparisons */
-int iflag; /* ignore case in comparisons */
-/* Options on hierarchical diffs. */
-int rflag; /* recursively trace directories */
-int sflag; /* announce files which are same */
-char *start; /* do file only if name >= this */
-/* Variable for -D D_IFDEF option. */
-char *ifdefname; /* What we will print for #ifdef/#endif */
-/* Variables for -c and -u context option. */
-int context; /* lines of context to be printed */
-/* State for exit status. */
-int status;
-int anychange;
-/* Variables for diffdir. */
-char **diffargv; /* option list to pass to recursive diffs */
+int aflag, bflag, iflag, Nflag, rflag, sflag, tflag, wflag;
+int format, context, status;
+char *start, *ifdefname, *diffargs;
+struct stat stb1, stb2;
+struct excludes *excludes_list;
-/*
- * Input file names.
- * With diffdir, file1 and file2 are allocated MAXPATHLEN space,
- * and padded with a '/', and then efile1 and efile2 point after
- * the '/'.
- */
-char *file1, *file2, *efile1, *efile2;
-struct stat stb1, stb2;
+#define OPTIONS "abC:cD:efhinNrS:stU:uwX:x:"
+static struct option longopts[] = {
+ { "text", no_argument, 0, 'a' },
+ { "ignore-space-change", no_argument, 0, 'b' },
+ { "context", optional_argument, 0, 'C' },
+ { "ifdef", required_argument, 0, 'D' },
+ { "ed", no_argument, 0, 'e' },
+ { "forward-ed", no_argument, 0, 'f' },
+ { "ignore-case", no_argument, 0, 'i' },
+ { "new-file", no_argument, 0, 'N' },
+ { "rcs", no_argument, 0, 'n' },
+ { "recursive", no_argument, 0, 'r' },
+ { "report-identical-files", no_argument, 0, 's' },
+ { "starting-file", required_argument, 0, 'S' },
+ { "expand-tabs", no_argument, 0, 't' },
+ { "unified", optional_argument, 0, 'U' },
+ { "ignore-all-space", no_argument, 0, 'w' },
+ { "exclude", required_argument, 0, 'x' },
+ { "exclude-from", required_argument, 0, 'X' },
+};
__dead void usage(void);
+void push_excludes(char *);
+void read_excludes_file(char *file);
+void set_argstr(char **, char **);
int
main(int argc, char **argv)
{
- int ch;
+ char *ep, **oargv;
+ long l;
+ int ch, gotstdin;
- status = 2;
- diffargv = argv;
+ oargv = argv;
+ gotstdin = 0;
- while ((ch = getopt(argc, argv, "abC:cD:efhinrS:stU:uw")) != -1) {
+ while ((ch = getopt_long(argc, argv, OPTIONS, longopts, NULL)) != -1) {
switch (ch) {
case 'a':
- aflag++;
+ aflag = 1;
break;
case 'b':
- bflag++;
+ bflag = 1;
break;
case 'C':
- opt = D_CONTEXT;
- if (!isdigit(*optarg))
- usage();
- context = atoi(optarg); /* XXX - use strtol */
- break;
case 'c':
- opt = D_CONTEXT;
- context = 3;
+ format = D_CONTEXT;
+ if (optarg != NULL) {
+ l = strtol(optarg, &ep, 10);
+ if (*ep != '\0' || l < 0 || l >= INT_MAX)
+ usage();
+ context = (int)l;
+ } else
+ context = 3;
break;
case 'D':
- opt = D_IFDEF;
+ format = D_IFDEF;
ifdefname = optarg;
break;
case 'e':
- opt = D_EDIT;
+ format = D_EDIT;
break;
case 'f':
- opt = D_REVERSE;
+ format = D_REVERSE;
break;
case 'h':
/* silently ignore for backwards compatibility */
break;
case 'i':
- iflag++;
+ iflag = 1;
+ break;
+ case 'N':
+ Nflag = 1;
break;
case 'n':
- opt = D_NREVERSE;
+ format = D_NREVERSE;
break;
case 'r':
- rflag++;
+ rflag = 1;
break;
case 'S':
start = optarg;
break;
case 's':
- sflag++;
+ sflag = 1;
break;
case 't':
- tflag++;
+ tflag = 1;
break;
case 'U':
- opt = D_UNIFIED;
- if (!isdigit(*optarg))
- usage();
- context = atoi(optarg); /* XXX - use strtol */
- break;
case 'u':
- opt = D_UNIFIED;
- context = 3;
+ format = D_UNIFIED;
+ if (optarg != NULL) {
+ l = strtol(optarg, &ep, 10);
+ if (*ep != '\0' || l < 0 || l >= INT_MAX)
+ usage();
+ context = (int)l;
+ } else
+ context = 3;
break;
case 'w':
- wflag++;
+ wflag = 1;
+ break;
+ case 'X':
+ read_excludes_file(optarg);
+ break;
+ case 'x':
+ push_excludes(optarg);
break;
default:
usage();
@@ -160,49 +161,42 @@ main(int argc, char **argv)
argc -= optind;
argv += optind;
+ /*
+ * Do sanity checks, fill in stb1 and stb2 and call the appropriate
+ * driver routine. Both drivers use the contents of stb1 and stb2.
+ */
if (argc != 2)
- errorx("two filename arguments required");
- file1 = argv[0];
- file2 = argv[1];
- if (!strcmp(file1, "-"))
+ usage();
+ if (strcmp(argv[0], "-") == 0) {
stb1.st_mode = S_IFREG;
- else if (stat(file1, &stb1) < 0)
- error("%s", file1);
- if (!strcmp(file2, "-"))
+ gotstdin = 1;
+ } else if (stat(argv[0], &stb1) != 0)
+ error("%s", argv[0]);
+ if (strcmp(argv[1], "-") == 0) {
stb2.st_mode = S_IFREG;
- else if (stat(file2, &stb2) < 0)
- error("%s", file2);
- if (S_ISDIR(stb1.st_mode) && S_ISDIR(stb2.st_mode))
- diffdir(argv);
- else
- diffreg();
- done(0);
-}
-
-int
-min(int a, int b)
-{
-
- return (a < b ? a : b);
-}
-
-int
-max(int a, int b)
-{
-
- return (a > b ? a : b);
+ gotstdin = 1;
+ } else if (stat(argv[1], &stb2) != 0)
+ error("%s", argv[1]);
+ if (gotstdin && (S_ISDIR(stb1.st_mode) || S_ISDIR(stb2.st_mode)))
+ errorx("can't compare - to a directory");
+ if (S_ISDIR(stb1.st_mode) && S_ISDIR(stb2.st_mode)) {
+ if (format == D_IFDEF)
+ errorx("-D option not supported with directories");
+ set_argstr(oargv, argv);
+ diffdir(argv[0], argv[1]);
+ } else
+ diffreg(argv[0], argv[1], 0);
+ exit(status);
}
-__dead void
-done(int sig)
+void
+quit(int signo)
{
if (tempfiles[0] != NULL)
unlink(tempfiles[0]);
if (tempfiles[1] != NULL)
unlink(tempfiles[1]);
- if (sig)
- _exit(status);
- exit(status);
+ _exit(status);
}
void *
@@ -237,7 +231,7 @@ error(const char *fmt, ...)
unlink(tempfiles[1]);
errno = sverrno;
va_start(ap, fmt);
- verr(status, fmt, ap);
+ verr(2, fmt, ap);
va_end(ap);
}
@@ -251,10 +245,67 @@ errorx(const char *fmt, ...)
if (tempfiles[1] != NULL)
unlink(tempfiles[1]);
va_start(ap, fmt);
- verrx(status, fmt, ap);
+ verrx(2, fmt, ap);
va_end(ap);
}
+void
+set_argstr(char **av, char **ave)
+{
+ size_t argsize;
+ char **ap;
+
+ argsize = 4 + (char *)ave - (char *)av + 1;
+ diffargs = emalloc(argsize);
+ strlcpy(diffargs, "diff", argsize);
+ for (ap = av + 1; ap < ave; ap++) {
+ if (strcmp(*ap, "--") != 0) {
+ strlcat(diffargs, " ", argsize);
+ strlcat(diffargs, *ap, argsize);
+ }
+ }
+}
+
+/*
+ * Read in an excludes file and push each line.
+ */
+void
+read_excludes_file(char *file)
+{
+ FILE *fp;
+ char *buf, *pattern;
+ size_t len;
+
+ if (strcmp(file, "-") == 0)
+ fp = stdin;
+ else if ((fp = fopen(file, "r")) == NULL)
+ error("%s", file);
+ while ((buf = fgetln(fp, &len)) != NULL) {
+ if (buf[len - 1] == '\n')
+ len--;
+ pattern = emalloc(len + 1);
+ memcpy(pattern, buf, len);
+ pattern[len] = '\0';
+ push_excludes(pattern);
+ }
+ if (strcmp(file, "-") != 0)
+ fclose(fp);
+}
+
+/*
+ * Push a pattern onto the excludes list.
+ */
+void
+push_excludes(char *pattern)
+{
+ struct excludes *entry;
+
+ entry = emalloc(sizeof(*entry));
+ entry->pattern = pattern;
+ entry->next = excludes_list;
+ excludes_list = entry;
+}
+
__dead void
usage(void)
{
@@ -263,8 +314,8 @@ usage(void)
" diff [-bitw] -C number file1 file2\n"
" diff [-bitw] -D string file1 file2\n"
" diff [-bitw] -U number file1 file2\n"
- " diff [-biwt] [-c | -e | -f | -n | -u ] "
- "[-r] [-s] [-S name]\n dir1 dir2\n");
+ " diff [-biNwt] [-c | -e | -f | -n | -u ] [-r] [-s] [-S name]"
+ " [-X file]\n [-x pattern] dir1 dir2\n");
exit(2);
}
diff --git a/usr.bin/diff/diff.h b/usr.bin/diff/diff.h
index 971c9b3269a..276660f5954 100644
--- a/usr.bin/diff/diff.h
+++ b/usr.bin/diff/diff.h
@@ -1,53 +1,36 @@
-/* $OpenBSD: diff.h,v 1.14 2003/07/04 17:50:24 millert Exp $ */
+/* $OpenBSD: diff.h,v 1.15 2003/07/06 20:48:59 millert Exp $ */
-/*
- * Copyright (C) Caldera International Inc. 2001-2002.
- * All rights reserved.
+/*-
+ * 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 and documentation must retain the above
- * copyright notice, this list of conditions and the following disclaimer.
+ * 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. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed or owned by Caldera
- * International, Inc.
- * 4. Neither the name of Caldera International, Inc. nor the names of other
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
+ * 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.
*
- * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
- * INTERNATIONAL, INC. 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 CALDERA INTERNATIONAL, INC. 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.
- */
-
-/* diff.h 4.7 85/08/16 */
-
-/*
- * diff - common declarations
+ * 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.
+ *
+ * @(#)diff.h 8.1 (Berkeley) 6/6/93
*/
-#include <sys/param.h>
-#include <sys/stat.h>
-
-#include <ctype.h>
-#include <err.h>
-#include <signal.h>
-#include <stdio.h>
-
/*
* Output format options
*/
@@ -60,21 +43,31 @@
#define D_NREVERSE 5 /* Reverse ed script with numbered
lines and no trailing . */
-extern int aflag, bflag, iflag, rflag, sflag, tflag, wflag;
+/*
+ * Output flags
+ */
+#define D_HEADER 1 /* Print a header/footer between files */
+#define D_EMPTY1 2 /* Treat first file as empty (/dev/null) */
+#define D_EMPTY2 4 /* Treat second file as empty (/dev/null) */
+
+struct excludes {
+ char *pattern;
+ struct excludes *next;
+};
+
+extern int aflag, bflag, iflag, Nflag, rflag, sflag, tflag, wflag;
extern char *start, *ifdefname;
-extern int opt, wantelses, context, status, anychange;
-extern char *tempfiles[], **diffargv;
-extern char *file1, *file2, *efile1, *efile2;
+extern int format, context, status, anychange;
+extern char *tempfiles[], *diffargs;
extern struct stat stb1, stb2;
+extern struct excludes *excludes_list;
+char *copytemp(const char *, int);
+char *splice(char *, char *);
void *emalloc(size_t);
void *erealloc(void *, size_t);
-char *splice(char *, char *);
-char *copytemp(const char *, int);
-void diffdir(char **);
-void diffreg(void);
-int max(int, int);
-int min(int, int);
+void diffdir(char *, char *);
+void diffreg(char *, char *, int);
+void quit(int);
__dead void error(const char *, ...);
__dead void errorx(const char *, ...);
-__dead void done(int);
diff --git a/usr.bin/diff/diffdir.c b/usr.bin/diff/diffdir.c
index a197b3e357d..6b3ebd01864 100644
--- a/usr.bin/diff/diffdir.c
+++ b/usr.bin/diff/diffdir.c
@@ -1,365 +1,292 @@
-/* $OpenBSD: diffdir.c,v 1.18 2003/07/06 02:11:12 millert Exp $ */
+/* $OpenBSD: diffdir.c,v 1.19 2003/07/06 20:48:59 millert Exp $ */
/*
- * Copyright (C) Caldera International Inc. 2001-2002.
- * All rights reserved.
+ * Copyright (c) 2003 Todd C. Miller <Todd.Miller@courtesan.com>
*
- * 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 and documentation 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. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed or owned by Caldera
- * International, Inc.
- * 4. Neither the name of Caldera International, Inc. nor the names of other
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
*
- * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
- * INTERNATIONAL, INC. 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 CALDERA INTERNATIONAL, INC. 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.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F39502-99-1-0512.
*/
-#include <sys/types.h>
-#include <sys/wait.h>
+#ifndef lint
+static const char rcsid[] = "$OpenBSD: diffdir.c,v 1.19 2003/07/06 20:48:59 millert Exp $";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
#include <dirent.h>
+#include <err.h>
#include <errno.h>
#include <fcntl.h>
+#include <fnmatch.h>
+#include <paths.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "diff.h"
-#include "pathnames.h"
-#if 0
-static const char sccsid[] = "@(#)diffdir.c 4.12 (Berkeley) 4/30/89";
-#endif
+static int dircompare(const void *, const void *);
+static int excluded(const char *);
+static struct dirent **slurpdir(char *, char **);
+static void diffit(struct dirent *, char *, size_t, char *, size_t);
/*
- * diff - directory comparison
+ * Diff directory traveral. Will be called recursively if -r was specified.
*/
-#define d_flags d_ino
-
-#define DIRECT 1 /* Directory */
-
-struct dir {
- u_long d_ino;
- short d_reclen;
- short d_namlen;
- char *d_entry;
-};
+void
+diffdir(char *p1, char *p2)
+{
+ struct dirent **dirp1, **dirp2, **dp1, **dp2;
+ struct dirent *dent1, *dent2;
+ size_t dirlen1, dirlen2;
+ char path1[MAXPATHLEN], path2[MAXPATHLEN];
+ char *dirbuf1, *dirbuf2;
+ int pos;
-static int dirstatus; /* exit status from diffdir */
-static char title[2 * BUFSIZ];
+ dirlen1 = strlcpy(path1, *p1 ? p1 : ".", sizeof(path1));
+ if (dirlen1 >= sizeof(path1) - 1) {
+ warnx("%s: %s", p1, strerror(ENAMETOOLONG));
+ status = 2;
+ return;
+ }
+ if (path1[dirlen1 - 1] != '/') {
+ path1[dirlen1++] = '/';
+ path1[dirlen1] = '\0';
+ }
+ dirlen2 = strlcpy(path2, *p2 ? p2 : ".", sizeof(path2));
+ if (dirlen2 >= sizeof(path2) - 1) {
+ warnx("%s: %s", p2, strerror(ENAMETOOLONG));
+ status = 2;
+ return;
+ }
+ if (path2[dirlen2 - 1] != '/') {
+ path2[dirlen2++] = '/';
+ path2[dirlen2] = '\0';
+ }
+ /* get a list of the entries in each directory */
+ dp1 = dirp1 = slurpdir(path1, &dirbuf1);
+ dp2 = dirp2 = slurpdir(path2, &dirbuf2);
+ if (dirp1 == NULL || dirp2 == NULL)
+ return;
-static struct dir *setupdir(char *);
-static int ascii(int);
-static void compare(struct dir *);
-static void calldiff(void);
-static void setfile(char **fpp, char **epp, char *file);
-static int useless(char *);
-static void only(struct dir *dp, int which);
-static int entcmp(const void *, const void *);
+ /*
+ * If we were given a starting point, find it.
+ */
+ if (start != NULL) {
+ while (*dp1 != NULL && strcmp((*dp1)->d_name, start) < 0)
+ dp1++;
+ while (*dp2 != NULL && strcmp((*dp2)->d_name, start) < 0)
+ dp2++;
+ }
-void
-diffdir(char **argv)
-{
- struct dir *dir1, *dir2;
- struct dir *d1, *d2;
- int i, cmp;
+ /*
+ * Iterate through the two directory lists, diffing as we go.
+ */
+ while (*dp1 != NULL || *dp2 != NULL) {
+ dent1 = *dp1;
+ dent2 = *dp2;
- if (opt == D_IFDEF)
- warnx("can't specify -I with directories");
- if (opt == D_EDIT && sflag)
- warnx("warning: shouldn't give -s with -e");
- strlcpy(title, "diff ", sizeof title);
- for (i = 1; diffargv[i + 2]; i++) {
- if (!strcmp(diffargv[i], "-"))
- continue; /* was -S, dont look silly */
- strlcat(title, diffargv[i], sizeof title);
- strlcat(title, " ", sizeof title);
- }
- 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 (opt == D_NORMAL || opt == D_CONTEXT ||
- opt == D_UNIFIED)
- only(d1, 1);
- d1++;
- dirstatus |= 1;
- } else if (cmp == 0) {
- compare(d1);
- d1++;
- d2++;
+ pos = dent1 == NULL ? 1 : dent2 == NULL ? -1 :
+ strcmp(dent1->d_name, dent2->d_name);
+ if (pos == 0) {
+ /* file exists in both dirs, diff it */
+ diffit(dent1, path1, dirlen1, path2, dirlen2);
+ dp1++;
+ dp2++;
+ } else if (pos < 0) {
+ /* file only in first dir, only diff if -N */
+ if (Nflag)
+ diffit(dent1, path1, dirlen1, path2, dirlen2);
+ else if (format == D_NORMAL || format == D_CONTEXT ||
+ format == D_UNIFIED)
+ /* XXX GNU diff always prints this XXX */
+ printf("Only in %.*s: %s\n", (int)(dirlen1 - 1),
+ path1, dent1->d_name);
+ dp1++;
} else {
- if (opt == D_NORMAL || opt == D_CONTEXT ||
- opt == D_UNIFIED)
- only(d2, 2);
- d2++;
- dirstatus |= 1;
+ /* file only in second dir, only diff if -N */
+ if (Nflag)
+ diffit(dent2, path1, dirlen1, path2, dirlen2);
+ else if (format == D_NORMAL || format == D_CONTEXT ||
+ format == D_UNIFIED)
+ /* XXX GNU diff always prints this XXX */
+ printf("Only in %.*s: %s\n", (int)(dirlen2 - 1),
+ path2, dent2->d_name);
+ dp2++;
}
}
- if (rflag) {
- for (d1 = dir1; d1->d_entry; d1++) {
- if ((d1->d_flags & DIRECT) == 0)
- continue;
- strlcpy(efile1, d1->d_entry,
- file1 + MAXPATHLEN - efile1);
- strlcpy(efile2, d1->d_entry,
- file2 + MAXPATHLEN - efile2);
- calldiff();
- }
+
+ if (dirbuf1 != NULL) {
+ free(dirp1);
+ free(dirbuf1);
+ }
+ if (dirbuf2 != NULL) {
+ free(dirp2);
+ free(dirbuf2);
}
- status = dirstatus;
}
-void
-setfile(char **fpp, char **epp, char *file)
+/*
+ * Read in a whole directory's worth of struct dirents, culling
+ * out the "excluded" ones.
+ * Returns an array of struct dirent *'s that point into the buffer
+ * returned via bufp. Caller is responsible for free()ing both of these.
+ */
+static struct dirent **
+slurpdir(char *path, char **bufp)
{
- char *cp;
- size_t len;
+ char *buf, *ebuf, *cp;
+ size_t bufsize;
+ long base;
+ int fd, nbytes, entries;
+ struct stat sb;
+ struct dirent **dirlist, *dp;
- if (*file == '\0')
- file = ".";
- *fpp = emalloc(MAXPATHLEN);
- len = strlcpy(*fpp, file, MAXPATHLEN);
- if (len >= MAXPATHLEN - 1)
- errorx("%s: %s", file, strerror(ENAMETOOLONG));
- cp = *fpp + len - 1;
- if (*cp == '/')
- ++cp;
- else {
- *++cp = '/';
- *++cp = '\0';
- }
- *epp = cp;
-}
+ *bufp = NULL;
+ if ((fd = open(path, O_RDONLY, 0644)) == -1) {
+ static struct dirent *dummy;
-void
-only(struct dir *dp, int which)
-{
- char *file = which == 1 ? file1 : file2;
- char *efile = which == 1 ? efile1 : efile2;
+ if (!Nflag) {
+ warn("%s", path);
+ return (NULL);
+ }
+ return (&dummy);
+ }
+ fstat(fd, &sb);
- printf("Only in %.*s: %s\n", (int)(efile - file - 1), file, dp->d_entry);
-}
+ bufsize = sb.st_size;
+ if (bufsize < sb.st_blksize)
+ bufsize = sb.st_blksize;
+ buf = emalloc(bufsize);
-struct dir *
-setupdir(char *cp)
-{
- struct dir *dp, *ep;
- struct dirent *rp;
- int nitems;
- DIR *dirp;
+ nbytes = getdirentries(fd, buf, bufsize, &base);
+ if (nbytes <= 0) {
+ free(buf);
+ warn("%s", path);
+ return (NULL);
+ }
+ ebuf = buf + nbytes;
+ close(fd);
- dirp = opendir(cp);
- if (dirp == NULL)
- error("%s", cp);
- nitems = 0;
- dp = emalloc(sizeof(struct dir));
- 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 = emalloc(ep->d_namlen + 1);
- strlcpy(ep->d_entry, rp->d_name, ep->d_namlen + 1);
- }
- dp = erealloc(dp, (nitems + 1) * sizeof(struct dir));
+ /*
+ * We now have all the directory entries in our buffer.
+ * However, in order to easily sort them we need to convert
+ * the buffer into an array.
+ */
+ for (entries = 0, cp = buf; cp < ebuf; ) {
+ dp = (struct dirent *)cp;
+ if (dp->d_fileno != 0 && dp->d_type != DT_WHT)
+ entries++;
+ if (dp->d_reclen <= 0)
+ break;
+ cp += dp->d_reclen;
+ }
+ dirlist = emalloc(sizeof(struct dirent *) * (entries + 1));
+ for (entries = 0, cp = buf; cp < ebuf; ) {
+ dp = (struct dirent *)cp;
+ if (dp->d_fileno != 0 && dp->d_type != DT_WHT &&
+ !excluded(dp->d_name))
+ dirlist[entries++] = dp;
+ if (dp->d_reclen <= 0)
+ break;
+ cp += dp->d_reclen;
}
- dp[nitems].d_entry = 0; /* delimiter */
- closedir(dirp);
- qsort(dp, nitems, sizeof(struct dir), entcmp);
- return (dp);
+ dirlist[entries] = NULL;
+
+ qsort(dirlist, entries, sizeof(struct dir *), dircompare);
+
+ *bufp = buf;
+ return (dirlist);
}
+/*
+ * Compare d_name in two dirent structures; for qsort(3).
+ */
static int
-entcmp(const void *v1, const void *v2)
+dircompare(const void *vp1, const void *vp2)
{
- const struct dir *d1, *d2;
+ struct dirent *dp1 = *((struct dirent **) vp1);
+ struct dirent *dp2 = *((struct dirent **) vp2);
- d1 = v1;
- d2 = v2;
- return (strcmp(d1->d_entry, d2->d_entry));
+ return (strcmp(dp1->d_name, dp2->d_name));
}
+/*
+ * Do the actual diff by calling either diffreg() or diffdir().
+ */
static void
-compare(struct dir *dp)
+diffit(struct dirent *dp, char *path1, size_t plen1, char *path2, size_t plen2)
{
- char buf1[BUFSIZ], buf2[BUFSIZ];
- int i, j, f1, f2, fmt1, fmt2;
- struct stat stb1, stb2;
+ int flags = D_HEADER;
- strlcpy(efile1, dp->d_entry, file1 + MAXPATHLEN - efile1);
- strlcpy(efile2, dp->d_entry, file2 + MAXPATHLEN - efile2);
- f1 = open(file1, 0);
- if (f1 < 0) {
- warn("%s", file1);
- return;
- }
- f2 = open(file2, 0);
- if (f2 < 0) {
- warn("%s", 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 (opt == D_EDIT)
- goto closem;
- printf("Common subdirectories: %s and %s\n",
- file1, file2);
- goto closem;
- }
+ strlcpy(path1 + plen1, dp->d_name, MAXPATHLEN - plen1);
+ if (stat(path1, &stb1) != 0) {
+ if (!Nflag || errno != ENOENT) {
+ warn("%s", path1);
+ return;
}
- 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)
- printf("Files %s and %s are identical\n", file1, file2);
- goto closem;
-notsame:
- dirstatus |= 1;
- if (!ascii(f1) || !ascii(f2)) {
- if (opt == D_NORMAL || opt == D_CONTEXT || opt == D_UNIFIED)
- printf("Binary files %s and %s differ\n",
- file1, file2);
- goto closem;
+ flags |= D_EMPTY1;
+ memset(&stb1, 0, sizeof(stb1));
}
- close(f1);
- close(f2);
- anychange = 1;
- if (opt == D_EDIT) {
- printf("ed - %s << '-*-END-*-'\n", dp->d_entry);
- calldiff();
- } else {
- printf("%s%s %s\n", title, file1, file2);
- calldiff();
- }
- if (opt == D_EDIT)
- printf("w\nq\n-*-END-*-\n");
- return;
-closem:
- close(f1);
- close(f2);
-}
-static void
-calldiff(void)
-{
- int lstatus;
- pid_t pid;
+ strlcpy(path2 + plen2, dp->d_name, MAXPATHLEN - plen2);
+ if (stat(path2, &stb2) != 0) {
+ if (!Nflag || errno != ENOENT) {
+ warn("%s", path2);
+ return;
+ }
+ flags |= D_EMPTY2;
+ memset(&stb2, 0, sizeof(stb2));
+ stb2.st_mode = stb1.st_mode;
+ }
+ if (stb1.st_mode == 0)
+ stb1.st_mode = stb2.st_mode;
- fflush(stdout);
- pid = fork();
- if (pid == -1)
- errorx("No more processes");
- if (pid == 0) {
- execv(_PATH_DIFF, diffargv);
- error("%s", _PATH_DIFF);
+ if (S_ISDIR(stb1.st_mode) && S_ISDIR(stb2.st_mode)) {
+ /* XXX GNU diff always prints this for dirs XXX */
+ if (format != D_EDIT)
+ printf("Common subdirectories: %s and %s\n",
+ path1, path2);
+ if (rflag)
+ diffdir(path1, path2);
+ return;
}
- while (wait(&lstatus) != pid)
- continue;
- /*
- if ((lstatus >> 8) >= 2)
- done(0);
- */
- dirstatus |= lstatus >> 8;
+ diffreg(path1, path2, flags);
}
-int
-ascii(int f)
+/*
+ * Exclude the given directory entry?
+ */
+static int
+excluded(const char *entry)
{
- char buf[BUFSIZ], *cp;
- int cnt;
+ struct excludes *excl;
- if (aflag)
+ /* always skip "." and ".." */
+ if (entry[0] == '.' &&
+ (entry[1] == '\0' || (entry[1] == '.' && entry[2] == '\0')))
return (1);
- lseek(f, (off_t)0, SEEK_SET);
- cnt = read(f, buf, BUFSIZ);
- cp = buf;
- while (--cnt >= 0)
- if (*cp++ & 0200)
- return (0);
- return (1);
-}
+ /* check excludes list */
+ for (excl = excludes_list; excl != NULL; excl = excl->next)
+ if (fnmatch(excl->pattern, entry, FNM_PATHNAME) == 0)
+ return (1);
-/*
- * THIS IS CRUDE.
- */
-int
-useless(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
index c8dbc50c5d5..3a5852125e5 100644
--- a/usr.bin/diff/diffreg.c
+++ b/usr.bin/diff/diffreg.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: diffreg.c,v 1.26 2003/07/04 17:37:07 millert Exp $ */
+/* $OpenBSD: diffreg.c,v 1.27 2003/07/06 20:48:59 millert Exp $ */
/*
* Copyright (C) Caldera International Inc. 2001-2002.
@@ -33,20 +33,56 @@
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* 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: diffreg.c,v 1.27 2003/07/06 20:48:59 millert Exp $";
+#endif /* not lint */
#include <sys/types.h>
+#include <sys/stat.h>
-#include <stdlib.h>
-#include <unistd.h>
+#include <ctype.h>
+#include <err.h>
#include <fcntl.h>
+#include <libgen.h>
+#include <paths.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
+#include <unistd.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.
@@ -115,10 +151,6 @@ static char const sccsid[] = "@(#)diffreg.c 4.21 4/6/90";
* 6n words for files of length n.
*/
-#define prints(s) fputs(s,stdout)
-
-FILE *input[2];
-
struct cand {
int x;
int y;
@@ -130,40 +162,42 @@ struct line {
int value;
} *file[2];
-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 inifdef; /* whether or not we are in a #ifdef block */
-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] */
-u_char *chrtran; /* translation table for case-folding */
+static int *J; /* will be overlaid on class */
+static int *class; /* will be overlaid on file[0] */
+static int *klist; /* will be overlaid on file[0] after class */
+static int *member; /* will be overlaid on file[1] */
+static int clen;
+static int inifdef; /* whether or not we are in a #ifdef block */
+static int len[2];
+static int pref, suff; /* length of prefix and suffix */
+static int slen[2];
+static int anychange;
+static long *ixnew; /* will be overlaid on file[1] */
+static long *ixold; /* will be overlaid on klist */
+static struct cand *clist; /* merely a free storage pot for candidates */
+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 output(void);
-static void check(void);
+static void output(char *, FILE *, char *, FILE *);
+static void check(char *, FILE *, char *, FILE *);
static void range(int, int, char *);
-static void dump_context_vec(void);
-static void dump_unified_vec(void);
+static void dump_context_vec(FILE *, FILE *);
+static void dump_unified_vec(FILE *, FILE *);
static void prepare(int, FILE *);
static void prune(void);
static void equiv(struct line *, int, struct line *, int, int *);
static void unravel(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 int newcand(int, int, int);
-static int search(int *, int, int);
-static int skipline(int);
-static int asciifile(FILE *);
-static int stone(int *, int, int *, int *);
-static int readhash(FILE *);
+static int asciifile(FILE *);
+static int newcand(int, int, int);
+static int search(int *, int, int);
+static int skipline(FILE *);
+static int stone(int *, int, int *, int *);
+static int readhash(FILE *);
+static int files_differ(FILE *, FILE *, int);
/*
* chrtran points to one of 2 translation tables: cup2low if folding upper to
@@ -224,70 +258,100 @@ u_char cup2low[256] = {
};
void
-diffreg(void)
+diffreg(char *ofile1, char *ofile2, int flags)
{
- char buf1[BUFSIZ], buf2[BUFSIZ];
- FILE *f1, *f2;
- int i, j;
+ char *file1 = ofile1;
+ char *file2 = ofile2;
+ FILE *f1 = NULL;
+ FILE *f2 = NULL;
+ int i;
+ anychange = 0;
chrtran = (iflag ? cup2low : clow2low);
if (strcmp(file1, "-") == 0 && strcmp(file2, "-") == 0)
- errorx("can't specify - -");
- if (S_ISDIR(stb1.st_mode)) {
- file1 = splice(file1, file2);
- if (stat(file1, &stb1) < 0)
- error("%s", file1);
- } else if (strcmp(file1, "-") == 0 ||
- (!S_ISREG(stb1.st_mode) && strcmp(file1, _PATH_DEVNULL) != 0)) {
- file1 = copytemp(file1, 1);
- if (stat(file1, &stb1) < 0)
- error("%s", file1);
+ goto notsame;
+
+ /* XXX - only make temp file for stdin if not seekable? (millert) */
+ if (flags & D_EMPTY1)
+ f1 = fopen(_PATH_DEVNULL, "r");
+ else {
+ if (S_ISDIR(stb1.st_mode)) {
+ file1 = splice(file1, file2);
+ if (stat(file1, &stb1) < 0) {
+ 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)) {
- file2 = splice(file2, file1);
- if (stat(file2, &stb2) < 0)
- error("%s", file2);
- } 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 == NULL) {
+ warn("%s", file1);
+ status |= 2;
+ goto closem;
}
- if ((f1 = fopen(file1, "r")) == NULL)
- error("%s", file1);
- if ((f2 = fopen(file2, "r")) == NULL)
- error("%s", file2);
- if ((stb1.st_mode & S_IFMT) != (stb2.st_mode & S_IFMT) ||
- 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;
+
+ if (flags & D_EMPTY2)
+ f2 = fopen(_PATH_DEVNULL, "r");
+ else {
+ if (S_ISDIR(stb2.st_mode)) {
+ file2 = splice(file2, file1);
+ if (stat(file2, &stb2) < 0) {
+ warn("%s", file2);
+ status |= 2;
+ goto closem;
+ }
+ } else if (strcmp(file2, "-") == 0 || !S_ISREG(stb2.st_mode)) {
+ file2 = copytemp(file2, 2);
+ if (file2 == NULL || stat(file2, &stb2) < 0) {
+ warn("%s", file2);
+ status |= 2;
+ goto closem;
+ }
}
- for (j = 0; j < i; j++)
- if (buf1[j] != buf2[j])
- goto notsame;
+ f2 = fopen(file2, "r");
+ }
+ 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:
/*
* 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)) {
printf("Binary files %s and %s differ\n", file1, file2);
- exit(status);
+ goto closem;
}
prepare(0, f1);
prepare(1, f2);
- fclose(f1);
- fclose(f2);
prune();
sort(sfile[0], slen[0]);
sort(sfile[1], slen[1]);
@@ -306,23 +370,74 @@ notsame:
free(member);
free(class);
- J = emalloc((len[0] + 2) * sizeof(int));
+ J = erealloc(J, (len[0] + 2) * sizeof(int));
unravel(klist[i]);
free(clist);
free(klist);
- ixold = emalloc((len[0] + 2) * sizeof(long));
- ixnew = emalloc((len[1] + 2) * sizeof(long));
- check();
- output();
- status = anychange;
+ ixold = erealloc(ixold, (len[0] + 2) * sizeof(long));
+ ixnew = erealloc(ixnew, (len[1] + 2) * sizeof(long));
+ check(file1, f1, file2, f2);
+ output(file1, f1, file2, f2);
+ if ((flags & D_HEADER) && format == D_EDIT)
+ printf("w\nq\n-*-END-*-\n");
same:
- if (anychange == 0 && (opt == D_CONTEXT || opt == D_UNIFIED))
- printf("No differences encountered\n");
+ if (anychange == 0 && sflag != 0)
+ 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];
+/* XXX - pass back a FILE * too (millert) */
char *
copytemp(const char *file, int n)
{
@@ -335,24 +450,24 @@ copytemp(const char *file, int n)
if (strcmp(file, "-") == 0)
ifd = STDIN_FILENO;
else if ((ifd = open(file, O_RDONLY, 0644)) < 0)
- error("%s", file);
+ return (NULL);
if ((tempdir = getenv("TMPDIR")) == NULL)
tempdir = _PATH_TMP;
if (asprintf(&tempfile, "%s/diff%d.XXXXXXXX", tempdir, n) == -1)
- error(NULL);
+ return (NULL);
tempfiles[n - 1] = tempfile;
- signal(SIGHUP, done);
- signal(SIGINT, done);
- signal(SIGPIPE, done);
- signal(SIGTERM, done);
+ signal(SIGHUP, quit);
+ signal(SIGINT, quit);
+ signal(SIGPIPE, quit);
+ signal(SIGTERM, quit);
ofd = mkstemp(tempfile);
if (ofd < 0)
- error("%s", tempfile);
+ return (NULL);
while ((i = read(ifd, buf, BUFSIZ)) > 0) {
if (write(ofd, buf, i) != i)
- error("%s", tempfile);
+ return (NULL);
}
close(ifd);
close(ofd);
@@ -365,8 +480,6 @@ splice(char *dir, char *file)
char *tail, *buf;
size_t len;
- if (!strcmp(file, "-"))
- errorx("can't specify - with other arg directory");
tail = strrchr(file, '/');
if (tail == NULL)
tail = file;
@@ -384,7 +497,7 @@ prepare(int i, FILE *fd)
struct line *p;
int j, h;
- fseek(fd, 0L, SEEK_SET);
+ rewind(fd);
p = emalloc(3 * sizeof(struct line));
for (j = 0; (h = readhash(fd));) {
p = erealloc(p, (++j + 3) * sizeof(struct line));
@@ -538,32 +651,30 @@ unravel(int p)
* 2. collect random access indexes to the two files
*/
static void
-check(void)
+check(char *file1, FILE *f1, char *file2, FILE *f2)
{
int i, j, jackpot, c, d;
long ctold, ctnew;
- if ((input[0] = fopen(file1, "r")) == NULL)
- error("%s", file1);
- if ((input[1] = fopen(file2, "r")) == NULL)
- error("%s", file2);
+ rewind(f1);
+ rewind(f2);
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);
+ ixold[i] = ctold += skipline(f1);
continue;
}
while (j < J[i]) {
- ixnew[j] = ctnew += skipline(1);
+ ixnew[j] = ctnew += skipline(f2);
j++;
}
if (bflag || wflag || iflag) {
for (;;) {
- c = getc(input[0]);
- d = getc(input[1]);
+ c = getc(f1);
+ d = getc(f2);
ctold++;
ctnew++;
if (bflag && isspace(c) && isspace(d)) {
@@ -571,19 +682,19 @@ check(void)
if (c == '\n')
break;
ctold++;
- } while (isspace(c = getc(input[0])));
+ } while (isspace(c = getc(f1)));
do {
if (d == '\n')
break;
ctnew++;
- } while (isspace(d = getc(input[1])));
+ } while (isspace(d = getc(f2)));
} else if (wflag) {
while (isspace(c) && c != '\n') {
- c = getc(input[0]);
+ c = getc(f1);
ctold++;
}
while (isspace(d) && d != '\n') {
- d = getc(input[1]);
+ d = getc(f2);
ctnew++;
}
}
@@ -591,9 +702,9 @@ check(void)
jackpot++;
J[i] = 0;
if (c != '\n')
- ctold += skipline(0);
+ ctold += skipline(f1);
if (d != '\n')
- ctnew += skipline(1);
+ ctnew += skipline(f2);
break;
}
if (c == '\n')
@@ -603,13 +714,13 @@ check(void)
for (;;) {
ctold++;
ctnew++;
- if ((c = getc(input[0])) != (d = getc(input[1]))) {
+ if ((c = getc(f1)) != (d = getc(f2))) {
/* jackpot++; */
J[i] = 0;
if (c != '\n')
- ctold += skipline(0);
+ ctold += skipline(f1);
if (d != '\n')
- ctnew += skipline(1);
+ ctnew += skipline(f2);
break;
}
if (c == '\n')
@@ -620,11 +731,8 @@ check(void)
ixnew[j] = ctnew;
j++;
}
- for (; j <= len[1]; j++) {
- ixnew[j] = ctnew += skipline(1);
- }
- fclose(input[0]);
- fclose(input[1]);
+ for (; j <= len[1]; j++)
+ ixnew[j] = ctnew += skipline(f2);
/*
* if (jackpot)
* fprintf(stderr, "jackpot\n");
@@ -678,27 +786,27 @@ unsort(struct line *f, int l, int *b)
}
static int
-skipline(int f)
+skipline(FILE *f)
{
int i, c;
- for (i = 1; (c = getc(input[f])) != '\n'; i++)
+ for (i = 1; (c = getc(f)) != '\n'; i++)
if (c < 0)
return (i);
return (i);
}
static void
-output(void)
+output(char *file1, FILE *f1, char *file2, FILE *f2)
{
int m, i0, i1, j0, j1;
- input[0] = fopen(file1, "r");
- input[1] = fopen(file2, "r");
+ rewind(f1);
+ rewind(f2);
m = len[0];
J[0] = 0;
J[m + 1] = len[1] + 1;
- if (opt != D_EDIT) {
+ if (format != D_EDIT) {
for (i0 = 1; i0 <= m; i0 = i1 + 1) {
while (i0 <= m && J[i0] == J[i0 - 1] + 1)
i0++;
@@ -708,7 +816,7 @@ output(void)
i1++;
j1 = J[i1 + 1] - 1;
J[i1] = j1;
- change(i0, i1, j0, j1);
+ change(file1, f1, file2, f2, i0, i1, j0, j1);
}
} else {
for (i0 = m; i0 >= 1; i0 = i1 - 1) {
@@ -720,15 +828,15 @@ output(void)
i1--;
j1 = J[i1 - 1] + 1;
J[i1] = j1;
- change(i1, i0, j1, j0);
+ change(file1, f1, file2, f2, i1, i0, j1, j0);
}
}
if (m == 0)
- change(1, 0, 1, len[1]);
- if (opt == D_IFDEF) {
+ change(file1, f1, file2, f2, 1, 0, 1, len[1]);
+ if (format == D_IFDEF) {
for (;;) {
#define c i0
- c = getc(input[0]);
+ c = getc(f1);
if (c < 0)
return;
putchar(c);
@@ -736,17 +844,17 @@ output(void)
#undef c
}
if (anychange != 0) {
- if (opt == D_CONTEXT)
- dump_context_vec();
- else if (opt == D_UNIFIED)
- dump_unified_vec();
+ if (format == D_CONTEXT)
+ dump_context_vec(f1, f2);
+ else if (format == D_UNIFIED)
+ dump_unified_vec(f1, f2);
}
}
/*
* The following struct is used to record change information when
- * doing a "context" diff. (see routine "change" to understand the
- * highly mneumonic field names)
+ * doing a "context" or "unified" diff. (see routine "change" to
+ * understand the highly mnemonic field names)
*/
struct context_vec {
int a; /* start line in old file */
@@ -760,35 +868,32 @@ 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
+ * 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 appended (beginning at b). If c is greater than d then there are
* lines missing from the to file.
*/
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 (opt != D_IFDEF && a > b && c > d)
+ if (format != D_IFDEF && a > b && c > d)
return;
if (anychange == 0) {
anychange = 1;
- if (opt == D_CONTEXT || opt == D_UNIFIED) {
- stat(file1, &stbuf);
- printf("%s %s %s", opt == D_CONTEXT ? "***" : "---",
- file1, ctime(&stbuf.st_mtime));
- stat(file2, &stbuf);
- printf("%s %s %s", opt == D_CONTEXT ? "---" : "+++",
- file2, ctime(&stbuf.st_mtime));
- context_vec_start = emalloc(MAX_CONTEXT *
- sizeof(struct context_vec));
+ if (format == D_CONTEXT || format == D_UNIFIED) {
+ printf("%s %s %s", format == D_CONTEXT ? "***" : "---",
+ file1, ctime(&stb1.st_mtime));
+ printf("%s %s %s", format == D_CONTEXT ? "---" : "+++",
+ file2, ctime(&stb2.st_mtime));
+ if (context_vec_start == NULL)
+ context_vec_start = emalloc(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 || opt == D_UNIFIED) {
+ if (format == D_CONTEXT || format == D_UNIFIED) {
/*
* If this new change is within 'context' lines of
* the previous change, just add it to the change
@@ -800,10 +905,10 @@ change(int a, int b, int c, int d)
(context_vec_ptr >= context_vec_start &&
a > (context_vec_ptr->b + 2 * context) &&
c > (context_vec_ptr->d + 2 * context))) {
- if (opt == D_CONTEXT)
- dump_context_vec();
+ if (format == D_CONTEXT)
+ dump_context_vec(f1, f2);
else
- dump_unified_vec();
+ dump_unified_vec(f1, f2);
}
context_vec_ptr++;
context_vec_ptr->a = a;
@@ -812,13 +917,13 @@ change(int a, int b, int c, int d)
context_vec_ptr->d = d;
return;
}
- switch (opt) {
+ switch (format) {
case D_NORMAL:
case D_EDIT:
range(a, b, ",");
putchar(a > b ? 'a' : c > d ? 'd' : 'c');
- if (opt == D_NORMAL)
+ if (format == D_NORMAL)
range(c, d, ",");
putchar('\n');
break;
@@ -838,14 +943,14 @@ change(int a, int b, int c, int d)
}
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");
+ if (format == D_NORMAL || format == D_IFDEF) {
+ fetch(ixold, a, b, f1, "< ", 1);
+ if (a <= b && c <= d && format == D_NORMAL)
+ puts("---");
}
- fetch(ixnew, c, d, input[1], opt == D_NORMAL ? "> " : "", 0);
- if ((opt == D_EDIT || opt == D_REVERSE) && c <= d)
- prints(".\n");
+ fetch(ixnew, c, d, f2, format == D_NORMAL ? "> " : "", 0);
+ if ((format == D_EDIT || format == D_REVERSE) && c <= d)
+ puts(".");
if (inifdef) {
fprintf(stdout, "#endif /* %s */\n", ifdefname);
inifdef = 0;
@@ -869,7 +974,7 @@ fetch(long *f, int a, int b, FILE *lb, char *s, int oldfile)
* 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) {
+ if (format == 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;
@@ -878,7 +983,7 @@ fetch(long *f, int a, int b, FILE *lb, char *s, int oldfile)
}
if (a > b)
return;
- if (opt == D_IFDEF) {
+ if (format == D_IFDEF) {
if (inifdef) {
fprintf(stdout, "#else /* %s%s */\n",
oldfile == 1 ? "!" : "", ifdefname);
@@ -893,8 +998,8 @@ fetch(long *f, int a, int b, FILE *lb, char *s, int oldfile)
for (i = a; i <= b; i++) {
fseek(lb, f[i - 1], SEEK_SET);
nc = f[i] - f[i - 1];
- if (opt != D_IFDEF)
- prints(s);
+ if (format != D_IFDEF)
+ fputs(s, stdout);
col = 0;
for (j = 0; j < nc; j++) {
c = getc(lb);
@@ -984,17 +1089,17 @@ readhash(FILE *f)
return ((short) low(sum) + (short) high(sum));
}
-static int
+int
asciifile(FILE *f)
{
char buf[BUFSIZ], *cp;
int cnt;
- if (aflag)
+ if (aflag || f == NULL)
return (1);
- fseek(f, 0L, SEEK_SET);
- cnt = fread(buf, 1, BUFSIZ, f);
+ rewind(f);
+ cnt = fread(buf, 1, sizeof(buf), f);
cp = buf;
while (--cnt >= 0)
if (*cp++ & 0200)
@@ -1002,9 +1107,19 @@ asciifile(FILE *f)
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 */
static void
-dump_context_vec(void)
+dump_context_vec(FILE *f1, FILE *f2)
{
struct context_vec *cvp = context_vec_start;
int lowa, upb, lowc, upd, do_output;
@@ -1025,7 +1140,7 @@ dump_context_vec(void)
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
* the "old" lines as context in the "new" list).
*/
@@ -1049,16 +1164,16 @@ dump_context_vec(void)
ch = (a <= b) ? 'd' : 'a';
if (ch == 'a')
- fetch(ixold, lowa, b, input[0], " ", 0);
+ fetch(ixold, lowa, b, f1, " ", 0);
else {
- fetch(ixold, lowa, a - 1, input[0], " ", 0);
- fetch(ixold, a, b, input[0],
+ fetch(ixold, lowa, a - 1, f1, " ", 0);
+ fetch(ixold, a, b, f1,
ch == 'c' ? "! " : "- ", 0);
}
lowa = b + 1;
cvp++;
}
- fetch(ixold, b + 1, upb, input[0], " ", 0);
+ fetch(ixold, b + 1, upb, f1, " ", 0);
}
/* output changes to the "new" file */
printf("--- ");
@@ -1085,23 +1200,23 @@ dump_context_vec(void)
ch = (a <= b) ? 'd' : 'a';
if (ch == 'd')
- fetch(ixnew, lowc, d, input[1], " ", 0);
+ fetch(ixnew, lowc, d, f2, " ", 0);
else {
- fetch(ixnew, lowc, c - 1, input[1], " ", 0);
- fetch(ixnew, c, d, input[1],
+ fetch(ixnew, lowc, c - 1, f2, " ", 0);
+ fetch(ixnew, c, d, f2,
ch == 'c' ? "! " : "+ ", 0);
}
lowc = d + 1;
cvp++;
}
- fetch(ixnew, d + 1, upd, input[1], " ", 0);
+ fetch(ixnew, d + 1, upd, f2, " ", 0);
}
context_vec_ptr = context_vec_start - 1;
}
/* dump accumulated "unified" diff changes */
static void
-dump_unified_vec(void)
+dump_unified_vec(FILE *f1, FILE *f2)
{
struct context_vec *cvp = context_vec_start;
int lowa, upb, lowc, upd;
@@ -1142,23 +1257,23 @@ dump_unified_vec(void)
switch (ch) {
case 'c':
- fetch(ixold, lowa, a - 1, input[0], " ", 0);
- fetch(ixold, a, b, input[0], "-", 0);
- fetch(ixnew, c, d, input[1], "+", 0);
+ fetch(ixold, lowa, a - 1, f1, " ", 0);
+ fetch(ixold, a, b, f1, "-", 0);
+ fetch(ixnew, c, d, f2, "+", 0);
break;
case 'd':
- fetch(ixold, lowa, a - 1, input[0], " ", 0);
- fetch(ixold, a, b, input[0], "-", 0);
+ fetch(ixold, lowa, a - 1, f1, " ", 0);
+ fetch(ixold, a, b, f1, "-", 0);
break;
case 'a':
- fetch(ixnew, lowc, c - 1, input[1], " ", 0);
- fetch(ixnew, c, d, input[1], "+", 0);
+ fetch(ixnew, lowc, c - 1, f2, " ", 0);
+ fetch(ixnew, c, d, f2, "+", 0);
break;
}
lowa = b + 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;
}
diff --git a/usr.bin/diff/pathnames.h b/usr.bin/diff/pathnames.h
deleted file mode 100644
index 83b4235e923..00000000000
--- a/usr.bin/diff/pathnames.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*-
- * Copyright (c) 1989, 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.
- *
- * @(#)pathnames.h 8.1 (Berkeley) 6/6/93
- */
-
-#include <paths.h>
-
-#define _PATH_DIFF "/usr/bin/diff"