1*66e5764eSmillert /* $OpenBSD: diff.c,v 1.15 2003/06/26 18:19:29 millert 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 37*66e5764eSmillert #include <errno.h> 3826da422aStedu #include <stdlib.h> 39*66e5764eSmillert #include <stdarg.h> 4026da422aStedu #include <unistd.h> 41ae8d569bSderaadt 42ae8d569bSderaadt #include "diff.h" 43ae8d569bSderaadt #include "pathnames.h" 44ae8d569bSderaadt 4526da422aStedu #if 0 4626da422aStedu static char const sccsid[] = "@(#)diff.c 4.7 5/11/89"; 4726da422aStedu #endif 4826da422aStedu 49ae8d569bSderaadt /* 50ae8d569bSderaadt * diff - driver and subroutines 51ae8d569bSderaadt */ 52d5d5ac6cStedu int opt; 53d5d5ac6cStedu int aflag; /* treat all files as text */ 54d5d5ac6cStedu int tflag; /* expand tabs on output */ 55d5d5ac6cStedu /* Algorithm related options. */ 56d5d5ac6cStedu int hflag; /* -h, use halfhearted DIFFH */ 57d5d5ac6cStedu int bflag; /* ignore blanks in comparisons */ 58d5d5ac6cStedu int wflag; /* totally ignore blanks in comparisons */ 59d5d5ac6cStedu int iflag; /* ignore case in comparisons */ 60d5d5ac6cStedu /* Options on hierarchical diffs. */ 61d5d5ac6cStedu int lflag; /* long output format with header */ 62d5d5ac6cStedu int rflag; /* recursively trace directories */ 63d5d5ac6cStedu int sflag; /* announce files which are same */ 64d5d5ac6cStedu char *start; /* do file only if name >= this */ 65d5d5ac6cStedu /* Variables for -I D_IFDEF option. */ 66d5d5ac6cStedu int wantelses; /* -E */ 67d5d5ac6cStedu char *ifdef1; /* String for -1 */ 68d5d5ac6cStedu char *ifdef2; /* String for -2 */ 69d5d5ac6cStedu char *endifname; /* What we will print on next #endif */ 70d5d5ac6cStedu int inifdef; 71d5d5ac6cStedu /* Variables for -c and -u context option. */ 72d5d5ac6cStedu int context; /* lines of context to be printed */ 73d5d5ac6cStedu /* State for exit status. */ 74d5d5ac6cStedu int status; 75d5d5ac6cStedu int anychange; 76d5d5ac6cStedu char *tempfile; /* used when comparing against std input */ 77d5d5ac6cStedu /* Variables for diffdir. */ 78d5d5ac6cStedu char **diffargv; /* option list to pass to recursive diffs */ 79d5d5ac6cStedu 80d5d5ac6cStedu /* 81d5d5ac6cStedu * Input file names. 82d5d5ac6cStedu * With diffdir, file1 and file2 are allocated BUFSIZ space, 83d5d5ac6cStedu * and padded with a '/', and then efile0 and efile1 point after 84d5d5ac6cStedu * the '/'. 85d5d5ac6cStedu */ 86d5d5ac6cStedu char *file1, *file2, *efile1, *efile2; 87d5d5ac6cStedu struct stat stb1, stb2; 88ae8d569bSderaadt 8948b947b7Smillert const char *diff = _PATH_DIFF; 9048b947b7Smillert const char *diffh = _PATH_DIFFH; 9148b947b7Smillert const char *pr = _PATH_PR; 92ae8d569bSderaadt 93c42aed39Smillert __dead void usage(void); 94ae8d569bSderaadt 9526da422aStedu int 9626da422aStedu main(int argc, char **argv) 9726da422aStedu { 98c42aed39Smillert int ch; 9926da422aStedu 10026da422aStedu ifdef1 = "FILE1"; 10126da422aStedu ifdef2 = "FILE2"; 102ae8d569bSderaadt status = 2; 103ae8d569bSderaadt diffargv = argv; 104c42aed39Smillert 105d5d5ac6cStedu while ((ch = getopt(argc, argv, "abC:cD:efhilnrS:stU:uw")) != -1) { 106c42aed39Smillert switch (ch) { 107d5d5ac6cStedu case 'a': 108d5d5ac6cStedu aflag++; 109d5d5ac6cStedu break; 110ae8d569bSderaadt case 'b': 111c42aed39Smillert bflag++; 112c42aed39Smillert break; 113c42aed39Smillert case 'C': 114c42aed39Smillert opt = D_CONTEXT; 115c42aed39Smillert if (!isdigit(*optarg)) 116c42aed39Smillert usage(); 117c42aed39Smillert context = atoi(optarg); /* XXX - use strtol */ 118c42aed39Smillert break; 119ae8d569bSderaadt case 'c': 120ae8d569bSderaadt opt = D_CONTEXT; 121ae8d569bSderaadt context = 3; 122c42aed39Smillert break; 123c42aed39Smillert case 'D': 124c42aed39Smillert /* -Dfoo = -E -1 -2foo */ 125c42aed39Smillert opt = D_IFDEF; 126c42aed39Smillert ifdef1 = ""; 127c42aed39Smillert ifdef2 = optarg; 128c42aed39Smillert wantelses++; 129c42aed39Smillert break; 130c42aed39Smillert case 'e': 131c42aed39Smillert opt = D_EDIT; 132c42aed39Smillert break; 133c42aed39Smillert case 'f': 134c42aed39Smillert opt = D_REVERSE; 135c42aed39Smillert break; 136ae8d569bSderaadt case 'h': 137ae8d569bSderaadt hflag++; 138c42aed39Smillert break; 139c42aed39Smillert case 'i': 140c42aed39Smillert iflag++; 141c42aed39Smillert break; 142ae8d569bSderaadt case 'l': 143ae8d569bSderaadt lflag++; 144c42aed39Smillert break; 145c42aed39Smillert case 'n': 146c42aed39Smillert opt = D_NREVERSE; 147c42aed39Smillert break; 148c42aed39Smillert case 'r': 149c42aed39Smillert opt = D_REVERSE; 150c42aed39Smillert break; 151c42aed39Smillert case 'S': 152c42aed39Smillert start = optarg; 153c42aed39Smillert break; 154c42aed39Smillert case 's': 155c42aed39Smillert sflag++; 156c42aed39Smillert break; 157c42aed39Smillert case 't': 158c42aed39Smillert tflag++; 159c42aed39Smillert break; 1609de32c1bSmillert case 'U': 1619de32c1bSmillert opt = D_UNIFIED; 1629de32c1bSmillert if (!isdigit(*optarg)) 1639de32c1bSmillert usage(); 1649de32c1bSmillert context = atoi(optarg); /* XXX - use strtol */ 1659de32c1bSmillert break; 1669de32c1bSmillert case 'u': 1679de32c1bSmillert opt = D_UNIFIED; 1689de32c1bSmillert context = 3; 1699de32c1bSmillert break; 170c42aed39Smillert case 'w': 171c42aed39Smillert wflag++; 172c42aed39Smillert break; 173ae8d569bSderaadt default: 174c42aed39Smillert usage(); 175c42aed39Smillert break; 176ae8d569bSderaadt } 177ae8d569bSderaadt } 178c42aed39Smillert argc -= optind; 179c42aed39Smillert argv += optind; 180c42aed39Smillert 181c42aed39Smillert if (argc != 2) 182*66e5764eSmillert errorx("two filename arguments required"); 183ae8d569bSderaadt file1 = argv[0]; 184ae8d569bSderaadt file2 = argv[1]; 185c42aed39Smillert if (hflag && opt) 186*66e5764eSmillert errorx("-h doesn't support -D, -c, -C, -e, -f, -I, -n, -u or -U"); 187ae8d569bSderaadt if (!strcmp(file1, "-")) 188ae8d569bSderaadt stb1.st_mode = S_IFREG; 189c42aed39Smillert else if (stat(file1, &stb1) < 0) 190*66e5764eSmillert error("%s", file1); 191ae8d569bSderaadt if (!strcmp(file2, "-")) 192ae8d569bSderaadt stb2.st_mode = S_IFREG; 193c42aed39Smillert else if (stat(file2, &stb2) < 0) 194*66e5764eSmillert error("%s", file2); 19549dffe13Smillert if (S_ISDIR(stb1.st_mode) && S_ISDIR(stb2.st_mode)) 196ae8d569bSderaadt diffdir(argv); 19749dffe13Smillert else 198ae8d569bSderaadt diffreg(); 199a6a14831Sderaadt done(0); 200ae8d569bSderaadt } 201ae8d569bSderaadt 20226da422aStedu int 20326da422aStedu min(int a, int b) 204ae8d569bSderaadt { 205ae8d569bSderaadt 206ae8d569bSderaadt return (a < b ? a : b); 207ae8d569bSderaadt } 208ae8d569bSderaadt 20926da422aStedu int 21026da422aStedu max(int a, int b) 211ae8d569bSderaadt { 212ae8d569bSderaadt 213ae8d569bSderaadt return (a > b ? a : b); 214ae8d569bSderaadt } 215ae8d569bSderaadt 216c42aed39Smillert __dead void 217a6a14831Sderaadt done(int sig) 218ae8d569bSderaadt { 219*66e5764eSmillert if (tempfiles[0] != NULL) 22048b947b7Smillert unlink(tempfiles[0]); 221*66e5764eSmillert if (tempfiles[1] != NULL) 22248b947b7Smillert unlink(tempfiles[1]); 223a6a14831Sderaadt if (sig) 224a6a14831Sderaadt _exit(status); 225ae8d569bSderaadt exit(status); 226ae8d569bSderaadt } 227ae8d569bSderaadt 22826da422aStedu void * 22949dffe13Smillert emalloc(size_t n) 230ae8d569bSderaadt { 23126da422aStedu void *p; 232ae8d569bSderaadt 23326da422aStedu if ((p = malloc(n)) == NULL) 234*66e5764eSmillert error("files too big, try -h"); 23526da422aStedu return (p); 23626da422aStedu } 23726da422aStedu 23826da422aStedu void * 23949dffe13Smillert erealloc(void *p, size_t n) 24026da422aStedu { 24126da422aStedu void *q; 24226da422aStedu 24326da422aStedu if ((q = realloc(p, n)) == NULL) 244*66e5764eSmillert error("files too big, try -h"); 245ae8d569bSderaadt return (q); 246ae8d569bSderaadt } 247ae8d569bSderaadt 248*66e5764eSmillert __dead void 249*66e5764eSmillert error(const char *fmt, ...) 250ae8d569bSderaadt { 251*66e5764eSmillert va_list ap; 252*66e5764eSmillert int sverrno = errno; 253*66e5764eSmillert 254*66e5764eSmillert if (tempfiles[0] != NULL) 255*66e5764eSmillert unlink(tempfiles[0]); 256*66e5764eSmillert if (tempfiles[1] != NULL) 257*66e5764eSmillert unlink(tempfiles[1]); 258*66e5764eSmillert errno = sverrno; 259*66e5764eSmillert va_start(ap, fmt); 260*66e5764eSmillert verr(status, fmt, ap); 261*66e5764eSmillert va_end(ap); 262*66e5764eSmillert } 263*66e5764eSmillert 264*66e5764eSmillert __dead void 265*66e5764eSmillert errorx(const char *fmt, ...) 266*66e5764eSmillert { 267*66e5764eSmillert va_list ap; 268*66e5764eSmillert 269*66e5764eSmillert if (tempfiles[0] != NULL) 270*66e5764eSmillert unlink(tempfiles[0]); 271*66e5764eSmillert if (tempfiles[1] != NULL) 272*66e5764eSmillert unlink(tempfiles[1]); 273*66e5764eSmillert va_start(ap, fmt); 274*66e5764eSmillert verrx(status, fmt, ap); 275*66e5764eSmillert va_end(ap); 276ae8d569bSderaadt } 277c42aed39Smillert 278c42aed39Smillert __dead void 279c42aed39Smillert usage(void) 280c42aed39Smillert { 281c012fe98Sderaadt (void)fprintf(stderr, 282c012fe98Sderaadt "usage: diff [-bitw] [-c | -e | -f | -h | -n | -u ] file1 file2\n" 2838dd7bf08Smillert " diff [-bitw] -C number file1 file2\n" 2848dd7bf08Smillert " diff [-bitw] -D string file1 file2\n" 2858dd7bf08Smillert " diff [-bitw] -U number file1 file2\n" 286c012fe98Sderaadt " diff [-biwt] [-c | -e | -f | -h | -n | -u ] " 287c012fe98Sderaadt "[-l] [-r] [-s] [-S name]\n dir1 dir2\n"); 288c42aed39Smillert 289*66e5764eSmillert exit(2); 290c42aed39Smillert } 291