Annotation of src/usr.bin/diff/diff.c, Revision 1.23
1.23 ! millert 1: /* $OpenBSD: diff.c,v 1.22 2003/07/04 17:52:35 millert Exp $ */
1.2 deraadt 2:
3: /*
1.23 ! millert 4: * Copyright (c) 2003 Todd C. Miller <Todd.Miller@courtesan.com>
1.2 deraadt 5: *
1.23 ! millert 6: * Permission to use, copy, modify, and distribute this software for any
! 7: * purpose with or without fee is hereby granted, provided that the above
! 8: * copyright notice and this permission notice appear in all copies.
1.2 deraadt 9: *
1.23 ! millert 10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
! 11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
! 13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
! 15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
! 16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 17: *
! 18: * Sponsored in part by the Defense Advanced Research Projects
! 19: * Agency (DARPA) and Air Force Research Laboratory, Air Force
! 20: * Materiel Command, USAF, under agreement number F39502-99-1-0512.
1.2 deraadt 21: */
22:
1.23 ! millert 23: #ifndef lint
! 24: static const char rcsid[] = "$OpenBSD: diffdir.c,v 1.17 2003/07/04 17:50:24 millert Exp $";
! 25: #endif /* not lint */
! 26:
! 27: #include <sys/param.h>
! 28: #include <sys/stat.h>
! 29:
! 30: #include <err.h>
1.15 millert 31: #include <errno.h>
1.23 ! millert 32: #include <getopt.h>
1.3 tedu 33: #include <stdlib.h>
1.23 ! millert 34: #include <stdio.h>
1.15 millert 35: #include <stdarg.h>
1.18 david 36: #include <string.h>
1.3 tedu 37: #include <unistd.h>
1.1 deraadt 38:
39: #include "diff.h"
1.12 tedu 40:
1.23 ! millert 41: int aflag, bflag, iflag, Nflag, rflag, sflag, tflag, wflag;
! 42: int format, context, status;
! 43: char *start, *ifdefname, *diffargs;
! 44: struct stat stb1, stb2;
! 45: struct excludes *excludes_list;
! 46:
! 47: #define OPTIONS "abC:cD:efhinNrS:stU:uwX:x:"
! 48: static struct option longopts[] = {
! 49: { "text", no_argument, 0, 'a' },
! 50: { "ignore-space-change", no_argument, 0, 'b' },
! 51: { "context", optional_argument, 0, 'C' },
! 52: { "ifdef", required_argument, 0, 'D' },
! 53: { "ed", no_argument, 0, 'e' },
! 54: { "forward-ed", no_argument, 0, 'f' },
! 55: { "ignore-case", no_argument, 0, 'i' },
! 56: { "new-file", no_argument, 0, 'N' },
! 57: { "rcs", no_argument, 0, 'n' },
! 58: { "recursive", no_argument, 0, 'r' },
! 59: { "report-identical-files", no_argument, 0, 's' },
! 60: { "starting-file", required_argument, 0, 'S' },
! 61: { "expand-tabs", no_argument, 0, 't' },
! 62: { "unified", optional_argument, 0, 'U' },
! 63: { "ignore-all-space", no_argument, 0, 'w' },
! 64: { "exclude", required_argument, 0, 'x' },
! 65: { "exclude-from", required_argument, 0, 'X' },
! 66: };
1.1 deraadt 67:
1.6 millert 68: __dead void usage(void);
1.23 ! millert 69: void push_excludes(char *);
! 70: void read_excludes_file(char *file);
! 71: void set_argstr(char **, char **);
1.3 tedu 72:
73: int
74: main(int argc, char **argv)
1.1 deraadt 75: {
1.23 ! millert 76: char *ep, **oargv;
! 77: long l;
! 78: int ch, gotstdin;
1.1 deraadt 79:
1.23 ! millert 80: oargv = argv;
! 81: gotstdin = 0;
1.6 millert 82:
1.23 ! millert 83: while ((ch = getopt_long(argc, argv, OPTIONS, longopts, NULL)) != -1) {
1.6 millert 84: switch (ch) {
1.12 tedu 85: case 'a':
1.23 ! millert 86: aflag = 1;
1.12 tedu 87: break;
1.6 millert 88: case 'b':
1.23 ! millert 89: bflag = 1;
1.6 millert 90: break;
91: case 'C':
92: case 'c':
1.23 ! millert 93: format = D_CONTEXT;
! 94: if (optarg != NULL) {
! 95: l = strtol(optarg, &ep, 10);
! 96: if (*ep != '\0' || l < 0 || l >= INT_MAX)
! 97: usage();
! 98: context = (int)l;
! 99: } else
! 100: context = 3;
1.6 millert 101: break;
102: case 'D':
1.23 ! millert 103: format = D_IFDEF;
1.17 millert 104: ifdefname = optarg;
1.6 millert 105: break;
106: case 'e':
1.23 ! millert 107: format = D_EDIT;
1.6 millert 108: break;
109: case 'f':
1.23 ! millert 110: format = D_REVERSE;
1.6 millert 111: break;
1.22 millert 112: case 'h':
113: /* silently ignore for backwards compatibility */
114: break;
1.6 millert 115: case 'i':
1.23 ! millert 116: iflag = 1;
! 117: break;
! 118: case 'N':
! 119: Nflag = 1;
1.6 millert 120: break;
121: case 'n':
1.23 ! millert 122: format = D_NREVERSE;
1.6 millert 123: break;
124: case 'r':
1.23 ! millert 125: rflag = 1;
1.6 millert 126: break;
127: case 'S':
128: start = optarg;
129: break;
130: case 's':
1.23 ! millert 131: sflag = 1;
1.6 millert 132: break;
133: case 't':
1.23 ! millert 134: tflag = 1;
1.6 millert 135: break;
1.9 millert 136: case 'U':
137: case 'u':
1.23 ! millert 138: format = D_UNIFIED;
! 139: if (optarg != NULL) {
! 140: l = strtol(optarg, &ep, 10);
! 141: if (*ep != '\0' || l < 0 || l >= INT_MAX)
! 142: usage();
! 143: context = (int)l;
! 144: } else
! 145: context = 3;
1.9 millert 146: break;
1.6 millert 147: case 'w':
1.23 ! millert 148: wflag = 1;
! 149: break;
! 150: case 'X':
! 151: read_excludes_file(optarg);
! 152: break;
! 153: case 'x':
! 154: push_excludes(optarg);
1.6 millert 155: break;
156: default:
157: usage();
158: break;
159: }
1.1 deraadt 160: }
1.6 millert 161: argc -= optind;
162: argv += optind;
163:
1.23 ! millert 164: /*
! 165: * Do sanity checks, fill in stb1 and stb2 and call the appropriate
! 166: * driver routine. Both drivers use the contents of stb1 and stb2.
! 167: */
1.6 millert 168: if (argc != 2)
1.23 ! millert 169: usage();
! 170: if (strcmp(argv[0], "-") == 0) {
1.1 deraadt 171: stb1.st_mode = S_IFREG;
1.23 ! millert 172: gotstdin = 1;
! 173: } else if (stat(argv[0], &stb1) != 0)
! 174: error("%s", argv[0]);
! 175: if (strcmp(argv[1], "-") == 0) {
1.1 deraadt 176: stb2.st_mode = S_IFREG;
1.23 ! millert 177: gotstdin = 1;
! 178: } else if (stat(argv[1], &stb2) != 0)
! 179: error("%s", argv[1]);
! 180: if (gotstdin && (S_ISDIR(stb1.st_mode) || S_ISDIR(stb2.st_mode)))
! 181: errorx("can't compare - to a directory");
! 182: if (S_ISDIR(stb1.st_mode) && S_ISDIR(stb2.st_mode)) {
! 183: if (format == D_IFDEF)
! 184: errorx("-D option not supported with directories");
! 185: set_argstr(oargv, argv);
! 186: diffdir(argv[0], argv[1]);
! 187: } else
! 188: diffreg(argv[0], argv[1], 0);
! 189: exit(status);
1.1 deraadt 190: }
191:
1.23 ! millert 192: void
! 193: quit(int signo)
1.1 deraadt 194: {
1.15 millert 195: if (tempfiles[0] != NULL)
1.13 millert 196: unlink(tempfiles[0]);
1.15 millert 197: if (tempfiles[1] != NULL)
1.13 millert 198: unlink(tempfiles[1]);
1.23 ! millert 199: _exit(status);
1.3 tedu 200: }
1.1 deraadt 201:
1.3 tedu 202: void *
1.8 millert 203: emalloc(size_t n)
1.3 tedu 204: {
205: void *p;
206:
207: if ((p = malloc(n)) == NULL)
1.22 millert 208: error(NULL);
1.3 tedu 209: return (p);
1.1 deraadt 210: }
211:
1.3 tedu 212: void *
1.8 millert 213: erealloc(void *p, size_t n)
1.1 deraadt 214: {
1.3 tedu 215: void *q;
1.1 deraadt 216:
1.3 tedu 217: if ((q = realloc(p, n)) == NULL)
1.22 millert 218: error(NULL);
1.3 tedu 219: return (q);
1.1 deraadt 220: }
221:
1.15 millert 222: __dead void
223: error(const char *fmt, ...)
224: {
225: va_list ap;
226: int sverrno = errno;
227:
228: if (tempfiles[0] != NULL)
229: unlink(tempfiles[0]);
230: if (tempfiles[1] != NULL)
231: unlink(tempfiles[1]);
232: errno = sverrno;
233: va_start(ap, fmt);
1.23 ! millert 234: verr(2, fmt, ap);
1.15 millert 235: va_end(ap);
236: }
237:
238: __dead void
239: errorx(const char *fmt, ...)
1.1 deraadt 240: {
1.15 millert 241: va_list ap;
242:
243: if (tempfiles[0] != NULL)
244: unlink(tempfiles[0]);
245: if (tempfiles[1] != NULL)
246: unlink(tempfiles[1]);
247: va_start(ap, fmt);
1.23 ! millert 248: verrx(2, fmt, ap);
1.15 millert 249: va_end(ap);
1.6 millert 250: }
251:
1.23 ! millert 252: void
! 253: set_argstr(char **av, char **ave)
! 254: {
! 255: size_t argsize;
! 256: char **ap;
! 257:
! 258: argsize = 4 + (char *)ave - (char *)av + 1;
! 259: diffargs = emalloc(argsize);
! 260: strlcpy(diffargs, "diff", argsize);
! 261: for (ap = av + 1; ap < ave; ap++) {
! 262: if (strcmp(*ap, "--") != 0) {
! 263: strlcat(diffargs, " ", argsize);
! 264: strlcat(diffargs, *ap, argsize);
! 265: }
! 266: }
! 267: }
! 268:
! 269: /*
! 270: * Read in an excludes file and push each line.
! 271: */
! 272: void
! 273: read_excludes_file(char *file)
! 274: {
! 275: FILE *fp;
! 276: char *buf, *pattern;
! 277: size_t len;
! 278:
! 279: if (strcmp(file, "-") == 0)
! 280: fp = stdin;
! 281: else if ((fp = fopen(file, "r")) == NULL)
! 282: error("%s", file);
! 283: while ((buf = fgetln(fp, &len)) != NULL) {
! 284: if (buf[len - 1] == '\n')
! 285: len--;
! 286: pattern = emalloc(len + 1);
! 287: memcpy(pattern, buf, len);
! 288: pattern[len] = '\0';
! 289: push_excludes(pattern);
! 290: }
! 291: if (strcmp(file, "-") != 0)
! 292: fclose(fp);
! 293: }
! 294:
! 295: /*
! 296: * Push a pattern onto the excludes list.
! 297: */
! 298: void
! 299: push_excludes(char *pattern)
! 300: {
! 301: struct excludes *entry;
! 302:
! 303: entry = emalloc(sizeof(*entry));
! 304: entry->pattern = pattern;
! 305: entry->next = excludes_list;
! 306: excludes_list = entry;
! 307: }
! 308:
1.6 millert 309: __dead void
310: usage(void)
311: {
1.14 deraadt 312: (void)fprintf(stderr,
1.21 millert 313: "usage: diff [-bitw] [-c | -e | -f | -n | -u ] file1 file2\n"
1.11 millert 314: " diff [-bitw] -C number file1 file2\n"
315: " diff [-bitw] -D string file1 file2\n"
316: " diff [-bitw] -U number file1 file2\n"
1.23 ! millert 317: " diff [-biNwt] [-c | -e | -f | -n | -u ] [-r] [-s] [-S name]"
! 318: " [-X file]\n [-x pattern] dir1 dir2\n");
1.6 millert 319:
1.15 millert 320: exit(2);
1.1 deraadt 321: }