Annotation of src/usr.bin/diff/diff.c, Revision 1.24
1.24 ! millert 1: /* $OpenBSD: diff.c,v 1.23 2003/07/06 20:48:59 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
1.24 ! millert 24: static const char rcsid[] = "$OpenBSD: diff.c,v 1.23 2003/07/06 20:48:59 millert Exp $";
1.23 millert 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.24 ! millert 41: int aflag, bflag, iflag, Nflag, Pflag, rflag, sflag, tflag, wflag;
1.23 millert 42: int format, context, status;
43: char *start, *ifdefname, *diffargs;
44: struct stat stb1, stb2;
45: struct excludes *excludes_list;
46:
1.24 ! millert 47: #define OPTIONS "abC:cD:efhinNPrS:stU:uwX:x:"
1.23 millert 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' },
1.24 ! millert 58: { "unidirectional-new-file", no_argument, 0, 'P' },
1.23 millert 59: { "recursive", no_argument, 0, 'r' },
60: { "report-identical-files", no_argument, 0, 's' },
61: { "starting-file", required_argument, 0, 'S' },
62: { "expand-tabs", no_argument, 0, 't' },
63: { "unified", optional_argument, 0, 'U' },
64: { "ignore-all-space", no_argument, 0, 'w' },
65: { "exclude", required_argument, 0, 'x' },
66: { "exclude-from", required_argument, 0, 'X' },
67: };
1.1 deraadt 68:
1.6 millert 69: __dead void usage(void);
1.23 millert 70: void push_excludes(char *);
71: void read_excludes_file(char *file);
72: void set_argstr(char **, char **);
1.3 tedu 73:
74: int
75: main(int argc, char **argv)
1.1 deraadt 76: {
1.23 millert 77: char *ep, **oargv;
78: long l;
79: int ch, gotstdin;
1.1 deraadt 80:
1.23 millert 81: oargv = argv;
82: gotstdin = 0;
1.6 millert 83:
1.23 millert 84: while ((ch = getopt_long(argc, argv, OPTIONS, longopts, NULL)) != -1) {
1.6 millert 85: switch (ch) {
1.12 tedu 86: case 'a':
1.23 millert 87: aflag = 1;
1.12 tedu 88: break;
1.6 millert 89: case 'b':
1.23 millert 90: bflag = 1;
1.6 millert 91: break;
92: case 'C':
93: case 'c':
1.23 millert 94: format = D_CONTEXT;
95: if (optarg != NULL) {
96: l = strtol(optarg, &ep, 10);
97: if (*ep != '\0' || l < 0 || l >= INT_MAX)
98: usage();
99: context = (int)l;
100: } else
101: context = 3;
1.6 millert 102: break;
103: case 'D':
1.23 millert 104: format = D_IFDEF;
1.17 millert 105: ifdefname = optarg;
1.6 millert 106: break;
107: case 'e':
1.23 millert 108: format = D_EDIT;
1.6 millert 109: break;
110: case 'f':
1.23 millert 111: format = D_REVERSE;
1.6 millert 112: break;
1.22 millert 113: case 'h':
114: /* silently ignore for backwards compatibility */
115: break;
1.6 millert 116: case 'i':
1.23 millert 117: iflag = 1;
118: break;
119: case 'N':
120: Nflag = 1;
1.6 millert 121: break;
122: case 'n':
1.23 millert 123: format = D_NREVERSE;
1.6 millert 124: break;
1.24 ! millert 125: case 'P':
! 126: Pflag = 1;
! 127: break;
1.6 millert 128: case 'r':
1.23 millert 129: rflag = 1;
1.6 millert 130: break;
131: case 'S':
132: start = optarg;
133: break;
134: case 's':
1.23 millert 135: sflag = 1;
1.6 millert 136: break;
137: case 't':
1.23 millert 138: tflag = 1;
1.6 millert 139: break;
1.9 millert 140: case 'U':
141: case 'u':
1.23 millert 142: format = D_UNIFIED;
143: if (optarg != NULL) {
144: l = strtol(optarg, &ep, 10);
145: if (*ep != '\0' || l < 0 || l >= INT_MAX)
146: usage();
147: context = (int)l;
148: } else
149: context = 3;
1.9 millert 150: break;
1.6 millert 151: case 'w':
1.23 millert 152: wflag = 1;
153: break;
154: case 'X':
155: read_excludes_file(optarg);
156: break;
157: case 'x':
158: push_excludes(optarg);
1.6 millert 159: break;
160: default:
161: usage();
162: break;
163: }
1.1 deraadt 164: }
1.6 millert 165: argc -= optind;
166: argv += optind;
167:
1.23 millert 168: /*
169: * Do sanity checks, fill in stb1 and stb2 and call the appropriate
170: * driver routine. Both drivers use the contents of stb1 and stb2.
171: */
1.6 millert 172: if (argc != 2)
1.23 millert 173: usage();
174: if (strcmp(argv[0], "-") == 0) {
1.1 deraadt 175: stb1.st_mode = S_IFREG;
1.23 millert 176: gotstdin = 1;
177: } else if (stat(argv[0], &stb1) != 0)
178: error("%s", argv[0]);
179: if (strcmp(argv[1], "-") == 0) {
1.1 deraadt 180: stb2.st_mode = S_IFREG;
1.23 millert 181: gotstdin = 1;
182: } else if (stat(argv[1], &stb2) != 0)
183: error("%s", argv[1]);
184: if (gotstdin && (S_ISDIR(stb1.st_mode) || S_ISDIR(stb2.st_mode)))
185: errorx("can't compare - to a directory");
186: if (S_ISDIR(stb1.st_mode) && S_ISDIR(stb2.st_mode)) {
187: if (format == D_IFDEF)
188: errorx("-D option not supported with directories");
189: set_argstr(oargv, argv);
190: diffdir(argv[0], argv[1]);
191: } else
192: diffreg(argv[0], argv[1], 0);
193: exit(status);
1.1 deraadt 194: }
195:
1.23 millert 196: void
197: quit(int signo)
1.1 deraadt 198: {
1.15 millert 199: if (tempfiles[0] != NULL)
1.13 millert 200: unlink(tempfiles[0]);
1.15 millert 201: if (tempfiles[1] != NULL)
1.13 millert 202: unlink(tempfiles[1]);
1.23 millert 203: _exit(status);
1.3 tedu 204: }
1.1 deraadt 205:
1.3 tedu 206: void *
1.8 millert 207: emalloc(size_t n)
1.3 tedu 208: {
209: void *p;
210:
211: if ((p = malloc(n)) == NULL)
1.22 millert 212: error(NULL);
1.3 tedu 213: return (p);
1.1 deraadt 214: }
215:
1.3 tedu 216: void *
1.8 millert 217: erealloc(void *p, size_t n)
1.1 deraadt 218: {
1.3 tedu 219: void *q;
1.1 deraadt 220:
1.3 tedu 221: if ((q = realloc(p, n)) == NULL)
1.22 millert 222: error(NULL);
1.3 tedu 223: return (q);
1.1 deraadt 224: }
225:
1.15 millert 226: __dead void
227: error(const char *fmt, ...)
228: {
229: va_list ap;
230: int sverrno = errno;
231:
232: if (tempfiles[0] != NULL)
233: unlink(tempfiles[0]);
234: if (tempfiles[1] != NULL)
235: unlink(tempfiles[1]);
236: errno = sverrno;
237: va_start(ap, fmt);
1.23 millert 238: verr(2, fmt, ap);
1.15 millert 239: va_end(ap);
240: }
241:
242: __dead void
243: errorx(const char *fmt, ...)
1.1 deraadt 244: {
1.15 millert 245: va_list ap;
246:
247: if (tempfiles[0] != NULL)
248: unlink(tempfiles[0]);
249: if (tempfiles[1] != NULL)
250: unlink(tempfiles[1]);
251: va_start(ap, fmt);
1.23 millert 252: verrx(2, fmt, ap);
1.15 millert 253: va_end(ap);
1.6 millert 254: }
255:
1.23 millert 256: void
257: set_argstr(char **av, char **ave)
258: {
259: size_t argsize;
260: char **ap;
261:
262: argsize = 4 + (char *)ave - (char *)av + 1;
263: diffargs = emalloc(argsize);
264: strlcpy(diffargs, "diff", argsize);
265: for (ap = av + 1; ap < ave; ap++) {
266: if (strcmp(*ap, "--") != 0) {
267: strlcat(diffargs, " ", argsize);
268: strlcat(diffargs, *ap, argsize);
269: }
270: }
271: }
272:
273: /*
274: * Read in an excludes file and push each line.
275: */
276: void
277: read_excludes_file(char *file)
278: {
279: FILE *fp;
280: char *buf, *pattern;
281: size_t len;
282:
283: if (strcmp(file, "-") == 0)
284: fp = stdin;
285: else if ((fp = fopen(file, "r")) == NULL)
286: error("%s", file);
287: while ((buf = fgetln(fp, &len)) != NULL) {
288: if (buf[len - 1] == '\n')
289: len--;
290: pattern = emalloc(len + 1);
291: memcpy(pattern, buf, len);
292: pattern[len] = '\0';
293: push_excludes(pattern);
294: }
295: if (strcmp(file, "-") != 0)
296: fclose(fp);
297: }
298:
299: /*
300: * Push a pattern onto the excludes list.
301: */
302: void
303: push_excludes(char *pattern)
304: {
305: struct excludes *entry;
306:
307: entry = emalloc(sizeof(*entry));
308: entry->pattern = pattern;
309: entry->next = excludes_list;
310: excludes_list = entry;
311: }
312:
1.6 millert 313: __dead void
314: usage(void)
315: {
1.14 deraadt 316: (void)fprintf(stderr,
1.21 millert 317: "usage: diff [-bitw] [-c | -e | -f | -n | -u ] file1 file2\n"
1.11 millert 318: " diff [-bitw] -C number file1 file2\n"
319: " diff [-bitw] -D string file1 file2\n"
320: " diff [-bitw] -U number file1 file2\n"
1.24 ! millert 321: " diff [-biNPwt] [-c | -e | -f | -n | -u ] [-r] [-s] [-S name]"
1.23 millert 322: " [-X file]\n [-x pattern] dir1 dir2\n");
1.6 millert 323:
1.15 millert 324: exit(2);
1.1 deraadt 325: }