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