1*e582024bSdavid /* $OpenBSD: diff.c,v 1.18 2003/06/27 17:08:45 david Exp $ */ 2d0c3f575Sderaadt 3d0c3f575Sderaadt /* 4d0c3f575Sderaadt * Copyright (C) Caldera International Inc. 2001-2002. 5d0c3f575Sderaadt * All rights reserved. 6d0c3f575Sderaadt * 7d0c3f575Sderaadt * Redistribution and use in source and binary forms, with or without 8d0c3f575Sderaadt * modification, are permitted provided that the following conditions 9d0c3f575Sderaadt * are met: 10d0c3f575Sderaadt * 1. Redistributions of source code and documentation must retain the above 11d0c3f575Sderaadt * copyright notice, this list of conditions and the following disclaimer. 12d0c3f575Sderaadt * 2. Redistributions in binary form must reproduce the above copyright 13d0c3f575Sderaadt * notice, this list of conditions and the following disclaimer in the 14d0c3f575Sderaadt * documentation and/or other materials provided with the distribution. 15d0c3f575Sderaadt * 3. All advertising materials mentioning features or use of this software 16d0c3f575Sderaadt * must display the following acknowledgement: 17d0c3f575Sderaadt * This product includes software developed or owned by Caldera 18d0c3f575Sderaadt * International, Inc. 19d0c3f575Sderaadt * 4. Neither the name of Caldera International, Inc. nor the names of other 20d0c3f575Sderaadt * contributors may be used to endorse or promote products derived from 21d0c3f575Sderaadt * this software without specific prior written permission. 22d0c3f575Sderaadt * 23d0c3f575Sderaadt * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA 24d0c3f575Sderaadt * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR 25d0c3f575Sderaadt * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 26d0c3f575Sderaadt * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 27d0c3f575Sderaadt * IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT, 28d0c3f575Sderaadt * INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 29d0c3f575Sderaadt * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 30d0c3f575Sderaadt * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31d0c3f575Sderaadt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 32d0c3f575Sderaadt * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 33d0c3f575Sderaadt * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34d0c3f575Sderaadt * POSSIBILITY OF SUCH DAMAGE. 35d0c3f575Sderaadt */ 36d0c3f575Sderaadt 3766e5764eSmillert #include <errno.h> 3826da422aStedu #include <stdlib.h> 3966e5764eSmillert #include <stdarg.h> 40*e582024bSdavid #include <string.h> 4126da422aStedu #include <unistd.h> 42ae8d569bSderaadt 43ae8d569bSderaadt #include "diff.h" 44ae8d569bSderaadt #include "pathnames.h" 45ae8d569bSderaadt 4626da422aStedu #if 0 4726da422aStedu static char const sccsid[] = "@(#)diff.c 4.7 5/11/89"; 4826da422aStedu #endif 4926da422aStedu 50ae8d569bSderaadt /* 51ae8d569bSderaadt * diff - driver and subroutines 52ae8d569bSderaadt */ 53d5d5ac6cStedu int opt; 54d5d5ac6cStedu int aflag; /* treat all files as text */ 55d5d5ac6cStedu int tflag; /* expand tabs on output */ 56d5d5ac6cStedu /* Algorithm related options. */ 57d5d5ac6cStedu int hflag; /* -h, use halfhearted DIFFH */ 58d5d5ac6cStedu int bflag; /* ignore blanks in comparisons */ 59d5d5ac6cStedu int wflag; /* totally ignore blanks in comparisons */ 60d5d5ac6cStedu int iflag; /* ignore case in comparisons */ 61d5d5ac6cStedu /* Options on hierarchical diffs. */ 62d5d5ac6cStedu int lflag; /* long output format with header */ 63d5d5ac6cStedu int rflag; /* recursively trace directories */ 64d5d5ac6cStedu int sflag; /* announce files which are same */ 65d5d5ac6cStedu char *start; /* do file only if name >= this */ 6690f56ad8Smillert /* Variables for -D D_IFDEF option. */ 6790f56ad8Smillert char *ifdefname; /* What we will print for #ifdef/#endif */ 68d5d5ac6cStedu int inifdef; 69d5d5ac6cStedu /* Variables for -c and -u context option. */ 70d5d5ac6cStedu int context; /* lines of context to be printed */ 71d5d5ac6cStedu /* State for exit status. */ 72d5d5ac6cStedu int status; 73d5d5ac6cStedu int anychange; 74d5d5ac6cStedu char *tempfile; /* used when comparing against std input */ 75d5d5ac6cStedu /* Variables for diffdir. */ 76d5d5ac6cStedu char **diffargv; /* option list to pass to recursive diffs */ 77d5d5ac6cStedu 78d5d5ac6cStedu /* 79d5d5ac6cStedu * Input file names. 80d5d5ac6cStedu * With diffdir, file1 and file2 are allocated BUFSIZ space, 81d5d5ac6cStedu * and padded with a '/', and then efile0 and efile1 point after 82d5d5ac6cStedu * the '/'. 83d5d5ac6cStedu */ 84d5d5ac6cStedu char *file1, *file2, *efile1, *efile2; 85d5d5ac6cStedu struct stat stb1, stb2; 86ae8d569bSderaadt 8748b947b7Smillert const char *diff = _PATH_DIFF; 8848b947b7Smillert const char *diffh = _PATH_DIFFH; 8948b947b7Smillert const char *pr = _PATH_PR; 90ae8d569bSderaadt 91c42aed39Smillert __dead void usage(void); 92ae8d569bSderaadt 9326da422aStedu int 9426da422aStedu main(int argc, char **argv) 9526da422aStedu { 96c42aed39Smillert int ch; 9726da422aStedu 98ae8d569bSderaadt status = 2; 99ae8d569bSderaadt diffargv = argv; 100c42aed39Smillert 101d5d5ac6cStedu while ((ch = getopt(argc, argv, "abC:cD:efhilnrS:stU:uw")) != -1) { 102c42aed39Smillert switch (ch) { 103d5d5ac6cStedu case 'a': 104d5d5ac6cStedu aflag++; 105d5d5ac6cStedu break; 106ae8d569bSderaadt case 'b': 107c42aed39Smillert bflag++; 108c42aed39Smillert break; 109c42aed39Smillert case 'C': 110c42aed39Smillert opt = D_CONTEXT; 111c42aed39Smillert if (!isdigit(*optarg)) 112c42aed39Smillert usage(); 113c42aed39Smillert context = atoi(optarg); /* XXX - use strtol */ 114c42aed39Smillert break; 115ae8d569bSderaadt case 'c': 116ae8d569bSderaadt opt = D_CONTEXT; 117ae8d569bSderaadt context = 3; 118c42aed39Smillert break; 119c42aed39Smillert case 'D': 120c42aed39Smillert opt = D_IFDEF; 12190f56ad8Smillert ifdefname = optarg; 122c42aed39Smillert break; 123c42aed39Smillert case 'e': 124c42aed39Smillert opt = D_EDIT; 125c42aed39Smillert break; 126c42aed39Smillert case 'f': 127c42aed39Smillert opt = D_REVERSE; 128c42aed39Smillert break; 129ae8d569bSderaadt case 'h': 130ae8d569bSderaadt hflag++; 131c42aed39Smillert break; 132c42aed39Smillert case 'i': 133c42aed39Smillert iflag++; 134c42aed39Smillert break; 135ae8d569bSderaadt case 'l': 136ae8d569bSderaadt lflag++; 137c42aed39Smillert break; 138c42aed39Smillert case 'n': 139c42aed39Smillert opt = D_NREVERSE; 140c42aed39Smillert break; 141c42aed39Smillert case 'r': 142d0c85965Smillert rflag++; 143c42aed39Smillert break; 144c42aed39Smillert case 'S': 145c42aed39Smillert start = optarg; 146c42aed39Smillert break; 147c42aed39Smillert case 's': 148c42aed39Smillert sflag++; 149c42aed39Smillert break; 150c42aed39Smillert case 't': 151c42aed39Smillert tflag++; 152c42aed39Smillert break; 1539de32c1bSmillert case 'U': 1549de32c1bSmillert opt = D_UNIFIED; 1559de32c1bSmillert if (!isdigit(*optarg)) 1569de32c1bSmillert usage(); 1579de32c1bSmillert context = atoi(optarg); /* XXX - use strtol */ 1589de32c1bSmillert break; 1599de32c1bSmillert case 'u': 1609de32c1bSmillert opt = D_UNIFIED; 1619de32c1bSmillert context = 3; 1629de32c1bSmillert break; 163c42aed39Smillert case 'w': 164c42aed39Smillert wflag++; 165c42aed39Smillert break; 166ae8d569bSderaadt default: 167c42aed39Smillert usage(); 168c42aed39Smillert break; 169ae8d569bSderaadt } 170ae8d569bSderaadt } 171c42aed39Smillert argc -= optind; 172c42aed39Smillert argv += optind; 173c42aed39Smillert 174c42aed39Smillert if (argc != 2) 17566e5764eSmillert errorx("two filename arguments required"); 176ae8d569bSderaadt file1 = argv[0]; 177ae8d569bSderaadt file2 = argv[1]; 178c42aed39Smillert if (hflag && opt) 17966e5764eSmillert errorx("-h doesn't support -D, -c, -C, -e, -f, -I, -n, -u or -U"); 180ae8d569bSderaadt if (!strcmp(file1, "-")) 181ae8d569bSderaadt stb1.st_mode = S_IFREG; 182c42aed39Smillert else if (stat(file1, &stb1) < 0) 18366e5764eSmillert error("%s", file1); 184ae8d569bSderaadt if (!strcmp(file2, "-")) 185ae8d569bSderaadt stb2.st_mode = S_IFREG; 186c42aed39Smillert else if (stat(file2, &stb2) < 0) 18766e5764eSmillert error("%s", file2); 18849dffe13Smillert if (S_ISDIR(stb1.st_mode) && S_ISDIR(stb2.st_mode)) 189ae8d569bSderaadt diffdir(argv); 19049dffe13Smillert else 191ae8d569bSderaadt diffreg(); 192a6a14831Sderaadt done(0); 193ae8d569bSderaadt } 194ae8d569bSderaadt 19526da422aStedu int 19626da422aStedu min(int a, int b) 197ae8d569bSderaadt { 198ae8d569bSderaadt 199ae8d569bSderaadt return (a < b ? a : b); 200ae8d569bSderaadt } 201ae8d569bSderaadt 20226da422aStedu int 20326da422aStedu max(int a, int b) 204ae8d569bSderaadt { 205ae8d569bSderaadt 206ae8d569bSderaadt return (a > b ? a : b); 207ae8d569bSderaadt } 208ae8d569bSderaadt 209c42aed39Smillert __dead void 210a6a14831Sderaadt done(int sig) 211ae8d569bSderaadt { 21266e5764eSmillert if (tempfiles[0] != NULL) 21348b947b7Smillert unlink(tempfiles[0]); 21466e5764eSmillert if (tempfiles[1] != NULL) 21548b947b7Smillert unlink(tempfiles[1]); 216a6a14831Sderaadt if (sig) 217a6a14831Sderaadt _exit(status); 218ae8d569bSderaadt exit(status); 219ae8d569bSderaadt } 220ae8d569bSderaadt 22126da422aStedu void * 22249dffe13Smillert emalloc(size_t n) 223ae8d569bSderaadt { 22426da422aStedu void *p; 225ae8d569bSderaadt 22626da422aStedu if ((p = malloc(n)) == NULL) 22766e5764eSmillert error("files too big, try -h"); 22826da422aStedu return (p); 22926da422aStedu } 23026da422aStedu 23126da422aStedu void * 23249dffe13Smillert erealloc(void *p, size_t n) 23326da422aStedu { 23426da422aStedu void *q; 23526da422aStedu 23626da422aStedu if ((q = realloc(p, n)) == NULL) 23766e5764eSmillert error("files too big, try -h"); 238ae8d569bSderaadt return (q); 239ae8d569bSderaadt } 240ae8d569bSderaadt 24166e5764eSmillert __dead void 24266e5764eSmillert error(const char *fmt, ...) 243ae8d569bSderaadt { 24466e5764eSmillert va_list ap; 24566e5764eSmillert int sverrno = errno; 24666e5764eSmillert 24766e5764eSmillert if (tempfiles[0] != NULL) 24866e5764eSmillert unlink(tempfiles[0]); 24966e5764eSmillert if (tempfiles[1] != NULL) 25066e5764eSmillert unlink(tempfiles[1]); 25166e5764eSmillert errno = sverrno; 25266e5764eSmillert va_start(ap, fmt); 25366e5764eSmillert verr(status, fmt, ap); 25466e5764eSmillert va_end(ap); 25566e5764eSmillert } 25666e5764eSmillert 25766e5764eSmillert __dead void 25866e5764eSmillert errorx(const char *fmt, ...) 25966e5764eSmillert { 26066e5764eSmillert va_list ap; 26166e5764eSmillert 26266e5764eSmillert if (tempfiles[0] != NULL) 26366e5764eSmillert unlink(tempfiles[0]); 26466e5764eSmillert if (tempfiles[1] != NULL) 26566e5764eSmillert unlink(tempfiles[1]); 26666e5764eSmillert va_start(ap, fmt); 26766e5764eSmillert verrx(status, fmt, ap); 26866e5764eSmillert va_end(ap); 269ae8d569bSderaadt } 270c42aed39Smillert 271c42aed39Smillert __dead void 272c42aed39Smillert usage(void) 273c42aed39Smillert { 274c012fe98Sderaadt (void)fprintf(stderr, 275c012fe98Sderaadt "usage: diff [-bitw] [-c | -e | -f | -h | -n | -u ] file1 file2\n" 2768dd7bf08Smillert " diff [-bitw] -C number file1 file2\n" 2778dd7bf08Smillert " diff [-bitw] -D string file1 file2\n" 2788dd7bf08Smillert " diff [-bitw] -U number file1 file2\n" 279c012fe98Sderaadt " diff [-biwt] [-c | -e | -f | -h | -n | -u ] " 280c012fe98Sderaadt "[-l] [-r] [-s] [-S name]\n dir1 dir2\n"); 281c42aed39Smillert 28266e5764eSmillert exit(2); 283c42aed39Smillert } 284