summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTodd C. Miller <millert@cvs.openbsd.org>2003-07-09 00:07:45 +0000
committerTodd C. Miller <millert@cvs.openbsd.org>2003-07-09 00:07:45 +0000
commit553e0315fd0d1bd47119cb903dd1783a20954223 (patch)
tree4e7cd0c6f736e7c6bf30901de162ebfef9530d56
parent95267cf7b08e0e2cb162032efcf164ea19baf730 (diff)
Re-implement -l flag; diff -l now works correctly in non-directory
mode (like GNU diff).
-rw-r--r--usr.bin/diff/diff.121
-rw-r--r--usr.bin/diff/diff.c65
-rw-r--r--usr.bin/diff/diff.h19
-rw-r--r--usr.bin/diff/diffdir.c31
-rw-r--r--usr.bin/diff/diffreg.c107
-rw-r--r--usr.bin/diff/pathnames.h25
6 files changed, 219 insertions, 49 deletions
diff --git a/usr.bin/diff/diff.1 b/usr.bin/diff/diff.1
index feb5d67efb1..0959cd040f9 100644
--- a/usr.bin/diff/diff.1
+++ b/usr.bin/diff/diff.1
@@ -1,4 +1,4 @@
-.\" $OpenBSD: diff.1,v 1.13 2003/07/06 22:17:21 millert Exp $
+.\" $OpenBSD: diff.1,v 1.14 2003/07/09 00:07:44 millert Exp $
.\"
.\" Copyright (c) 1980, 1990, 1993
.\" The Regents of the University of California. All rights reserved.
@@ -37,26 +37,26 @@
.Nd differential file and directory comparator
.Sh SYNOPSIS
.Nm diff
-.Op Fl abiqtw
+.Op Fl abilqtw
.Oo
.Fl c | Fl e | Fl f |
.Fl n | Fl u
.Oc
.Ar file1 file2
.Nm diff
-.Op Fl abiqtw
+.Op Fl abilqtw
.Op Fl C Ar number
.Ar file1 file2
.Nm diff
-.Op Fl abiqtw
+.Op Fl abilqtw
.Op Fl D Ar string
.Ar file1 file2
.Nm diff
-.Op Fl abiqtw
+.Op Fl abilqtw
.Op Fl U Ar number
.Ar file1 file2
.Nm diff
-.Op Fl abiNqtw
+.Op Fl abilNqtw
.Oo
.Fl c | Fl e | Fl f |
.Fl n | Fl u
@@ -178,6 +178,14 @@ 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.
+.It Fl l
+Long output format; each text file
+.Nm diff Ns \'d
+is piped through
+.Xr pr 1
+to paginate it;
+other differences are remembered and summarized
+after all text file differences are reported.
.It Fl i
Ignores the case of letters.
E.g.,
@@ -413,6 +421,7 @@ An error occurred.
.Xr comm 1 ,
.Xr diff3 1 ,
.Xr ed 1 ,
+.Xr pr 1 ,
.Xr fnmatch 3
.Sh HISTORY
A
diff --git a/usr.bin/diff/diff.c b/usr.bin/diff/diff.c
index 6d497053d6c..ef929d1ff3b 100644
--- a/usr.bin/diff/diff.c
+++ b/usr.bin/diff/diff.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: diff.c,v 1.26 2003/07/08 04:45:32 millert Exp $ */
+/* $OpenBSD: diff.c,v 1.27 2003/07/09 00:07:44 millert Exp $ */
/*
* Copyright (c) 2003 Todd C. Miller <Todd.Miller@courtesan.com>
@@ -21,7 +21,7 @@
*/
#ifndef lint
-static const char rcsid[] = "$OpenBSD: diff.c,v 1.26 2003/07/08 04:45:32 millert Exp $";
+static const char rcsid[] = "$OpenBSD: diff.c,v 1.27 2003/07/09 00:07:44 millert Exp $";
#endif /* not lint */
#include <sys/param.h>
@@ -38,13 +38,13 @@ static const char rcsid[] = "$OpenBSD: diff.c,v 1.26 2003/07/08 04:45:32 millert
#include "diff.h"
-int aflag, bflag, iflag, Nflag, Pflag, rflag, sflag, tflag, wflag;
+int aflag, bflag, iflag, lflag, Nflag, Pflag, rflag, sflag, tflag, wflag;
int format, context, status;
char *start, *ifdefname, *diffargs;
struct stat stb1, stb2;
struct excludes *excludes_list;
-#define OPTIONS "abC:cD:efhinNPqrS:stU:uwX:x:"
+#define OPTIONS "abC:cD:efhilnNPqrS:stU:uwX:x:"
static struct option longopts[] = {
{ "text", no_argument, 0, 'a' },
{ "ignore-space-change", no_argument, 0, 'b' },
@@ -53,6 +53,7 @@ static struct option longopts[] = {
{ "ed", no_argument, 0, 'e' },
{ "forward-ed", no_argument, 0, 'f' },
{ "ignore-case", no_argument, 0, 'i' },
+ { "paginate", no_argument, 0, 'l' },
{ "new-file", no_argument, 0, 'N' },
{ "rcs", no_argument, 0, 'n' },
{ "unidirectional-new-file", no_argument, 0, 'P' },
@@ -117,6 +118,9 @@ main(int argc, char **argv)
case 'i':
iflag = 1;
break;
+ case 'l':
+ lflag = 1;
+ break;
case 'N':
Nflag = 1;
break;
@@ -187,13 +191,15 @@ main(int argc, char **argv)
error("%s", argv[1]);
if (gotstdin && (S_ISDIR(stb1.st_mode) || S_ISDIR(stb2.st_mode)))
errorx("can't compare - to a directory");
+ set_argstr(oargv, argv);
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);
+ } else {
+ print_status(diffreg(argv[0], argv[1], 0), argv[0], argv[1],
+ NULL);
+ }
exit(status);
}
@@ -227,6 +233,21 @@ erealloc(void *p, size_t n)
return (q);
}
+int
+easprintf(char **ret, const char *fmt, ...)
+{
+ int len;
+ va_list ap;
+
+ va_start(ap, fmt);
+ len = vasprintf(ret, fmt, ap);
+ va_end(ap);
+
+ if (len == -1)
+ error(NULL);
+ return(len);
+}
+
__dead void
error(const char *fmt, ...)
{
@@ -314,6 +335,36 @@ push_excludes(char *pattern)
excludes_list = entry;
}
+void
+print_status(int val, char *path1, char *path2, char *entry)
+{
+ switch (val) {
+ case D_ONLY:
+ printf("Only in %s: %s\n", path1, entry);
+ break;
+ case D_COMMON:
+ printf("Common subdirectories: %s%s and %s%s\n",
+ path1, entry ? entry : "", path2, entry ? entry : "");
+ break;
+ case D_BINARY:
+ printf("Binary files %s%s and %s%s differ\n",
+ path1, entry ? entry : "", path2, entry ? entry : "");
+ break;
+ case D_DIFFER:
+ if (format == D_BRIEF)
+ printf("Files %s%s and %s%s differ\n",
+ path1, entry ? entry : "",
+ path2, entry ? entry : "");
+ break;
+ case D_SAME:
+ if (sflag)
+ printf("Files %s%s and %s%s are identical\n",
+ path1, entry ? entry : "",
+ path2, entry ? entry : "");
+ break;
+ }
+}
+
__dead void
usage(void)
{
diff --git a/usr.bin/diff/diff.h b/usr.bin/diff/diff.h
index a2f63cc8d48..b08f10120f2 100644
--- a/usr.bin/diff/diff.h
+++ b/usr.bin/diff/diff.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: diff.h,v 1.17 2003/07/06 22:17:21 millert Exp $ */
+/* $OpenBSD: diff.h,v 1.18 2003/07/09 00:07:44 millert Exp $ */
/*-
* Copyright (c) 1991, 1993
@@ -51,12 +51,23 @@
#define D_EMPTY1 2 /* Treat first file as empty (/dev/null) */
#define D_EMPTY2 4 /* Treat second file as empty (/dev/null) */
+/*
+ * Status values for print_status() and diffreg() return values
+ */
+#define D_SAME 0 /* Files are the same */
+#define D_DIFFER 1 /* Files are different */
+#define D_BINARY 2 /* Binary files are different */
+#define D_COMMON 3 /* Subdirectory common to both dirs */
+#define D_ONLY 4 /* Only exists in one directory */
+#define D_ERROR 5 /* An error ocurred */
+
struct excludes {
char *pattern;
struct excludes *next;
};
-extern int aflag, bflag, iflag, Nflag, Pflag, rflag, sflag, tflag, wflag;
+extern int aflag, bflag, iflag, lflag, Nflag, Pflag, rflag, sflag,
+ tflag, wflag;
extern char *start, *ifdefname;
extern int format, context, status, anychange;
extern char *tempfiles[], *diffargs;
@@ -65,10 +76,12 @@ extern struct excludes *excludes_list;
char *copytemp(const char *, int);
char *splice(char *, char *);
+int diffreg(char *, char *, int);
+int easprintf(char **, const char *, ...);
void *emalloc(size_t);
void *erealloc(void *, size_t);
void diffdir(char *, char *);
-void diffreg(char *, char *, int);
+void print_status(int, char *, char *, char *);
void quit(int);
__dead void error(const char *, ...);
__dead void errorx(const char *, ...);
diff --git a/usr.bin/diff/diffdir.c b/usr.bin/diff/diffdir.c
index 0907e3bc86a..63f555db984 100644
--- a/usr.bin/diff/diffdir.c
+++ b/usr.bin/diff/diffdir.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: diffdir.c,v 1.21 2003/07/06 22:17:21 millert Exp $ */
+/* $OpenBSD: diffdir.c,v 1.22 2003/07/09 00:07:44 millert Exp $ */
/*
* Copyright (c) 2003 Todd C. Miller <Todd.Miller@courtesan.com>
@@ -21,7 +21,7 @@
*/
#ifndef lint
-static const char rcsid[] = "$OpenBSD: diffdir.c,v 1.21 2003/07/06 22:17:21 millert Exp $";
+static const char rcsid[] = "$OpenBSD: diffdir.c,v 1.22 2003/07/09 00:07:44 millert Exp $";
#endif /* not lint */
#include <sys/param.h>
@@ -45,6 +45,8 @@ static int excluded(const char *);
static struct dirent **slurpdir(char *, char **, int);
static void diffit(struct dirent *, char *, size_t, char *, size_t);
+#define d_status d_type /* we need to store status for -l */
+
/*
* Diff directory traveral. Will be called recursively if -r was specified.
*/
@@ -113,6 +115,8 @@ diffdir(char *p1, char *p2)
/* file only in first dir, only diff if -N */
if (Nflag)
diffit(dent1, path1, dirlen1, path2, dirlen2);
+ else if (lflag)
+ dent1->d_status |= D_ONLY;
else if (format == D_NORMAL || format == D_CONTEXT ||
format == D_UNIFIED || format == D_BRIEF)
/* XXX GNU diff always prints this XXX */
@@ -123,6 +127,8 @@ diffdir(char *p1, char *p2)
/* file only in second dir, only diff if -N or -P */
if (Nflag || Pflag)
diffit(dent2, path1, dirlen1, path2, dirlen2);
+ else if (lflag)
+ dent2->d_status |= D_ONLY;
else if (format == D_NORMAL || format == D_CONTEXT ||
format == D_UNIFIED || format == D_BRIEF)
/* XXX GNU diff always prints this XXX */
@@ -131,6 +137,19 @@ diffdir(char *p1, char *p2)
dp2++;
}
}
+ if (lflag) {
+ path1[dirlen1 - 1] = '\0';
+ path2[dirlen2 - 1] = '\0';
+ for (dp1 = dirp1; (dent1 = *dp1) != NULL; dp1++) {
+ print_status(dent1->d_status, path1, path2,
+ dent1->d_name);
+ }
+ for (dp2 = dirp2; (dent2 = *dp2) != NULL; dp2++) {
+ if (dent2->d_status == D_ONLY)
+ print_status(dent2->d_status, path2, NULL,
+ dent2->d_name);
+ }
+ }
if (dirbuf1 != NULL) {
free(dirp1);
@@ -201,8 +220,10 @@ slurpdir(char *path, char **bufp, int enoentok)
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))
+ !excluded(dp->d_name)) {
+ dp->d_status = 0;
dirlist[entries++] = dp;
+ }
if (dp->d_reclen <= 0)
break;
cp += dp->d_reclen;
@@ -261,13 +282,15 @@ diffit(struct dirent *dp, char *path1, size_t plen1, char *path2, size_t plen2)
if (S_ISDIR(stb1.st_mode) && S_ISDIR(stb2.st_mode)) {
if (rflag)
diffdir(path1, path2);
+ else if (lflag)
+ dp->d_status |= D_COMMON;
else if (format != D_EDIT)
/* XXX GNU diff always prints this for dirs XXX */
printf("Common subdirectories: %s and %s\n",
path1, path2);
return;
}
- diffreg(path1, path2, flags);
+ dp->d_status = diffreg(path1, path2, flags);
}
/*
diff --git a/usr.bin/diff/diffreg.c b/usr.bin/diff/diffreg.c
index 69c6dd9a511..e8b14d785e5 100644
--- a/usr.bin/diff/diffreg.c
+++ b/usr.bin/diff/diffreg.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: diffreg.c,v 1.30 2003/07/08 04:51:30 millert Exp $ */
+/* $OpenBSD: diffreg.c,v 1.31 2003/07/09 00:07:44 millert Exp $ */
/*
* Copyright (C) Caldera International Inc. 2001-2002.
@@ -65,17 +65,17 @@
*/
#ifndef lint
-static const char rcsid[] = "$OpenBSD: diffreg.c,v 1.30 2003/07/08 04:51:30 millert Exp $";
+static const char rcsid[] = "$OpenBSD: diffreg.c,v 1.31 2003/07/09 00:07:44 millert Exp $";
#endif /* not lint */
#include <sys/types.h>
#include <sys/stat.h>
+#include <sys/wait.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>
@@ -83,6 +83,7 @@ static const char rcsid[] = "$OpenBSD: diffreg.c,v 1.30 2003/07/08 04:51:30 mill
#include <unistd.h>
#include "diff.h"
+#include "pathnames.h"
/*
* diff - compare two files.
@@ -257,14 +258,16 @@ u_char cup2low[256] = {
0xfd, 0xfe, 0xff
};
-void
+int
diffreg(char *ofile1, char *ofile2, int flags)
{
char *file1 = ofile1;
char *file2 = ofile2;
FILE *f1 = NULL;
FILE *f2 = NULL;
- int i;
+ int rval = D_SAME;
+ int i, ostdout = -1;
+ pid_t pid = -1;
anychange = 0;
chrtran = (iflag ? cup2low : clow2low);
@@ -332,7 +335,7 @@ diffreg(char *ofile1, char *ofile2, int flags)
switch (files_differ(f1, f2, flags)) {
case 0:
- goto same;
+ goto closem;
case 1:
break;
default:
@@ -346,19 +349,58 @@ notsame:
* Files certainly differ at this point; set status accordingly
*/
status |= 1;
- if (format == D_BRIEF) {
- printf("Files %s and %s differ\n", file1, file2);
+ rval = D_DIFFER;
+ if (!asciifile(f1) || !asciifile(f2)) {
+ rval = D_BINARY;
goto closem;
}
- 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);
+ if (format == D_BRIEF)
goto closem;
+ if (lflag) {
+ /* redirect stdout to pr */
+ int pfd[2];
+ char *header;
+ char *prargv[] = { "pr", "-h", NULL, "-f", NULL };
+
+ easprintf(&header, "%s %s %s", diffargs, file1, file2);
+ prargv[2] = header;
+ fflush(stdout);
+ rewind(stdout);
+ pipe(pfd);
+ switch ((pid = fork())) {
+ case -1:
+ warnx("No more processes");
+ status |= 2;
+ free(header);
+ return (D_ERROR);
+ case 0:
+ /* child */
+ if (pfd[0] != STDIN_FILENO) {
+ dup2(pfd[0], STDIN_FILENO);
+ close(pfd[0]);
+ }
+ close(pfd[1]);
+ execv(_PATH_PR, prargv);
+ _exit(127);
+ default:
+ /* parent */
+ if (pfd[1] != STDOUT_FILENO) {
+ ostdout = dup(STDOUT_FILENO);
+ dup2(pfd[1], STDOUT_FILENO);
+ close(pfd[1]);
+ }
+ close(pfd[0]);
+ rewind(stdout);
+ free(header);
+ }
+ } else {
+ if (flags & D_HEADER) {
+ if (format == D_EDIT)
+ printf("ed - %s << '-*-END-*-'\n",
+ basename(file1));
+ else
+ printf("%s %s %s\n", diffargs, file1, file2);
+ }
}
prepare(0, f1);
prepare(1, f2);
@@ -389,12 +431,20 @@ notsame:
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)
+ if (ostdout != -1) {
+ int wstatus;
+
+ /* close the pipe to pr and restore stdout */
+ fflush(stdout);
+ rewind(stdout);
+ if (ostdout != STDOUT_FILENO) {
+ close(STDOUT_FILENO);
+ dup2(ostdout, STDOUT_FILENO);
+ close(ostdout);
+ }
+ waitpid(pid, &wstatus, 0);
+ } else if ((flags & D_HEADER) && format == D_EDIT)
printf("w\nq\n-*-END-*-\n");
-same:
- if (anychange == 0 && sflag != 0)
- printf("Files %s and %s are identical\n", file1, file2);
-
closem:
if (f1 != NULL)
fclose(f1);
@@ -412,6 +462,7 @@ closem:
tempfiles[1] = NULL;
} else if (file2 != ofile2)
free(file2);
+ return (rval);
}
/*
@@ -470,6 +521,7 @@ copytemp(const char *file, int n)
signal(SIGINT, quit);
signal(SIGPIPE, quit);
signal(SIGTERM, quit);
+ signal(SIGPIPE, SIG_IGN);
ofd = mkstemp(tempfile);
if (ofd < 0)
return (NULL);
@@ -486,16 +538,13 @@ char *
splice(char *dir, char *file)
{
char *tail, *buf;
- size_t len;
tail = strrchr(file, '/');
if (tail == NULL)
tail = file;
else
tail++;
- len = strlen(dir) + 1 + strlen(tail) + 1;
- buf = emalloc(len);
- snprintf(buf, len, "%s/%s", dir, tail);
+ easprintf(&buf, "%s/%s", dir, tail);
return (buf);
}
@@ -960,7 +1009,7 @@ change(char *file1, FILE *f1, char *file2, FILE *f2, int a, int b, int c, int d)
if ((format == D_EDIT || format == D_REVERSE) && c <= d)
puts(".");
if (inifdef) {
- fprintf(stdout, "#endif /* %s */\n", ifdefname);
+ printf("#endif /* %s */\n", ifdefname);
inifdef = 0;
}
}
@@ -993,13 +1042,13 @@ fetch(long *f, int a, int b, FILE *lb, char *s, int oldfile)
return;
if (format == D_IFDEF) {
if (inifdef) {
- fprintf(stdout, "#else /* %s%s */\n",
+ printf("#else /* %s%s */\n",
oldfile == 1 ? "!" : "", ifdefname);
} else {
if (oldfile)
- fprintf(stdout, "#ifndef %s\n", ifdefname);
+ printf("#ifndef %s\n", ifdefname);
else
- fprintf(stdout, "#ifdef %s\n", ifdefname);
+ printf("#ifdef %s\n", ifdefname);
}
inifdef = 1 + oldfile;
}
diff --git a/usr.bin/diff/pathnames.h b/usr.bin/diff/pathnames.h
new file mode 100644
index 00000000000..ab79dca284d
--- /dev/null
+++ b/usr.bin/diff/pathnames.h
@@ -0,0 +1,25 @@
+/* $OpenBSD: pathnames.h,v 1.10 2003/07/09 00:07:44 millert Exp $ */
+
+/*
+ * Copyright (c) 2003 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * 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.
+ *
+ * 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 <paths.h>
+
+#define _PATH_PR "/usr/bin/pr"