diff options
author | Todd C. Miller <millert@cvs.openbsd.org> | 2003-07-09 00:07:45 +0000 |
---|---|---|
committer | Todd C. Miller <millert@cvs.openbsd.org> | 2003-07-09 00:07:45 +0000 |
commit | 553e0315fd0d1bd47119cb903dd1783a20954223 (patch) | |
tree | 4e7cd0c6f736e7c6bf30901de162ebfef9530d56 | |
parent | 95267cf7b08e0e2cb162032efcf164ea19baf730 (diff) |
Re-implement -l flag; diff -l now works correctly in non-directory
mode (like GNU diff).
-rw-r--r-- | usr.bin/diff/diff.1 | 21 | ||||
-rw-r--r-- | usr.bin/diff/diff.c | 65 | ||||
-rw-r--r-- | usr.bin/diff/diff.h | 19 | ||||
-rw-r--r-- | usr.bin/diff/diffdir.c | 31 | ||||
-rw-r--r-- | usr.bin/diff/diffreg.c | 107 | ||||
-rw-r--r-- | usr.bin/diff/pathnames.h | 25 |
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" |