=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/diff/diff.c,v retrieving revision 1.22 retrieving revision 1.23 diff -u -r1.22 -r1.23 --- src/usr.bin/diff/diff.c 2003/07/04 17:52:35 1.22 +++ src/usr.bin/diff/diff.c 2003/07/06 20:48:59 1.23 @@ -1,157 +1,158 @@ -/* $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 * - * 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 +#include + +#include #include +#include #include +#include #include #include #include #include "diff.h" -#include "pathnames.h" -#if 0 -static char const sccsid[] = "@(#)diff.c 4.7 5/11/89"; -#endif +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; -/* - * 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 */ +#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' }, +}; -/* - * 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; - __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(); break; @@ -160,49 +161,42 @@ 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); + 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); } -int -min(int a, int b) +void +quit(int signo) { - - return (a < b ? a : b); -} - -int -max(int a, int b) -{ - - return (a > b ? a : b); -} - -__dead void -done(int sig) -{ 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 @@ unlink(tempfiles[1]); errno = sverrno; va_start(ap, fmt); - verr(status, fmt, ap); + verr(2, fmt, ap); va_end(ap); } @@ -251,10 +245,67 @@ 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 @@ " 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); }