|
|
1.1 root 1: /*
2: * This code is common between diff and /usr/lib/diffh.
3: * It is a restructuring and re-write of the earlier
4: * Tom Duff code so that reading options, opening files,
5: * and outputing of the differences is common.
6: */
7:
8: #include "diff.h"
9: #include <sys/stat.h>
10: #include <signal.h>
11:
12: int dflag; /* Dynamic decision about -h or not */
13: int bflag; /* Strip trailing blanks, multiple blanks */
14: int eflag; /* Editor script */
15: int sflag; /* Sed script output (used by SCCS) */
16: int rflag; /* Reversed order of printed (usually -e) */
17: int incr; /* Line number increment for `rflag' diff */
18: char *csymbol; /* Symbol for C pre-processor (#ifdef) */
19: int sepflag; /* On if text from both files involved */
20: int caflag; /* On for a change or append */
21: unsigned ninsert; /* Number of lines inserted */
22: unsigned ndelete; /* Number of lines deleted */
23: unsigned nunchanged; /* Number of line unchanged */
24: char *tmpnam1, *tmpnam2;
25: FILE *fp1; /* First input stream */
26: FILE *fp2; /* Second input stream */
27: char *fn1, *fn2; /* Filenames */
28:
29: char buf1[BUFSIZ];
30: char buf2[BUFSIZ];
31:
32: FILE *openfile();
33: int rmexit();
34: int catchsig();
35: int streq();
36: int bstreq();
37:
38: int (*equal)() = streq;
39:
40: main(argc, argv)
41: int argc;
42: char *argv[];
43: {
44: register char *ap;
45: register char **sargv = argv;
46: fsize_t size1, size2;
47:
48: while (argc>1 && argv[1][0]=='-' && argv[1][1]!='\0') {
49: for (ap = &argv[1][1]; *ap != '\0'; ap++)
50: switch (*ap) {
51: case 'b':
52: bflag = 1;
53: equal = bstreq;
54: break;
55:
56: case 'c':
57: if (argc < 3)
58: usage();
59: csymbol = argv[2];
60: argv++;
61: argc--;
62: break;
63:
64: case 'd':
65: dflag = 1;
66: break;
67:
68: case 'e':
69: eflag = rflag = 1;
70: break;
71:
72: case 'f':
73: eflag = 1;
74: rflag = 0;
75: break;
76:
77: case 's':
78: eflag = sflag = 1;
79: break;
80:
81: case 'h':
82: diffh(sargv);
83: break;
84:
85: default:
86: usage();
87: }
88: argc--;
89: argv++;
90: }
91: if (argc != 3)
92: usage();
93: if (eflag && csymbol!=NULL)
94: cerr("-e and -c are incompatible options");
95: if (signal(SIGINT, SIG_IGN) != SIG_IGN)
96: signal(SIGINT, catchsig);
97: if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
98: signal(SIGHUP, catchsig);
99: if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
100: signal(SIGTERM, catchsig);
101: fp1 = openfile(argv[1], argv[2], &tmpnam1, &size1);
102: fp2 = openfile(argv[2], argv[1], &tmpnam2, &size2);
103: if (dflag && (size1>NBIGF || size2>NBIGF))
104: diffh(argv);
105: setbuf(fp1, buf1);
106: setbuf(fp2, buf2);
107: fn1 = argv[1];
108: fn2 = argv[2];
109: diff(fp1, fp2);
110: if (sflag)
111: printf(":I%d\n:D%d\n:U%d\n", ninsert, ndelete, nunchanged);
112: rmexit(ninsert || ndelete);
113: }
114:
115: /*
116: * Compare input lines for equality.
117: */
118: bstreq(s1, s2)
119: register char *s1, *s2;
120: {
121: for (;;) {
122: if (*s1==' ' || *s1=='\t') {
123: do {
124: s1++;
125: } while (*s1==' ' || *s1=='\t');
126: if (*s1 == '\n') {
127: while (*s2==' ' || *s2=='\t')
128: s2++;
129: return (*s2 == '\n');
130: }
131: if (*s2!=' ' && *s2!='\t')
132: return (0);
133: do {
134: s2++;
135: } while (*s2==' ' || *s2=='\t');
136: } else {
137: if (*s1 == '\n')
138: while (*s2==' ' || *s2=='\t')
139: s2++;
140: if (*s1++ != *s2)
141: return (0);
142: if (*s2++ == '\n')
143: return (1);
144: }
145: }
146: }
147:
148: /*
149: * Open the files, allowing for special standard input
150: * convention (`-') and directories. Copy any special
151: * files or pipes to a tempfile because they cannot be
152: * rewound.
153: * `ofn' is the other name, for directory concatenation.
154: */
155: FILE *
156: openfile(fn, ofn, tfnp, sizep)
157: char *fn;
158: char *ofn;
159: char **tfnp;
160: fsize_t *sizep;
161: {
162: register char *cp;
163: register int c;
164: register FILE *fp;
165: register FILE *tfp;
166: char fname[300];
167: struct stat sb;
168: static int dirflag;
169:
170: again:
171: if (fn[0]=='-' && fn[1]=='\0')
172: fp = stdin;
173: else if ((fp = fopen(fn, "r")) == NULL)
174: cerr("cannot open `%s'", fn);
175: fstat(fileno(fp), &sb);
176: *sizep = sb.st_size;
177: switch (sb.st_mode & S_IFMT) {
178: case S_IFDIR:
179: if (dirflag)
180: break;
181: dirflag++;
182: for (cp = ofn; *cp != '\0'; cp++)
183: ;
184: while (cp > ofn)
185: if (*--cp == '/') {
186: cp++;
187: break;
188: }
189: fn = sprintf(fname, "%s/%s", fn, cp);
190: goto again;
191:
192: case S_IFREG:
193: break;
194:
195: default:
196: *tfnp = "/tmp/difXXXXXX";
197: if ((tfp = fopen(mktemp(*tfnp), "w")) == NULL)
198: cerr("cannot create tempfile");
199: setbuf(fp, buf1);
200: setbuf(tfp, buf2);
201: while ((c = getc(fp)) != EOF)
202: putc(c, tfp);
203: fflush(tfp);
204: if (ferror(tfp))
205: cerr("write error on tempfile");
206: fclose(tfp);
207: if (fp != stdin)
208: fclose(fp);
209: if ((fp = fopen(*tfnp, "r")) == NULL)
210: cerr("cannot re-open tempfile");
211: }
212: return (fp);
213: }
214:
215: /*
216: * Output a text line common to both files.
217: * This is only used by the `-c' option.
218: */
219: text(line)
220: char *line;
221: {
222: ++nunchanged;
223: if (csymbol != NULL)
224: fputs(line, stdout);
225: }
226:
227: /*
228: * Output a text line from the first file.
229: */
230: text1(line)
231: register char *line;
232: {
233: if (csymbol != NULL)
234: fputs(line, stdout);
235: else if (!eflag) {
236: fputs("< ", stdout);
237: fputs(line, stdout);
238: }
239: ++ndelete;
240: }
241:
242: /*
243: * Output a line that is only in
244: * the second file.
245: */
246: text2(line)
247: register char *line;
248: {
249: if (sflag) {
250: putchar('\\');
251: putchar('\n');
252: #if REALSED
253: /*
254: * Sed is documented to strip
255: * leading blanks/tabs in appended
256: * text but doesn't. This appears
257: * to be a feature rather than a bug.
258: */
259: if (line[0]==' ' || line[0]=='\t')
260: putchar('\\');
261: #endif
262: while (*line != '\n') {
263: if (*line == '\\')
264: putchar(*line);
265: putchar(*line++);
266: }
267: } else if (eflag) {
268: if (line[0]=='.' && line[1]=='\n' && line[2]=='\0')
269: fputs("~\n.\ns/~/./\na\n", stdout); else
270: fputs(line, stdout);
271: } else if (csymbol != NULL)
272: fputs(line, stdout);
273: else {
274: fputs("> ", stdout);
275: fputs(line, stdout);
276: }
277: caflag = 1;
278: ++ninsert;
279: }
280:
281: /*
282: * Output the start of a set of
283: * changed lines.
284: * Change is from `f1',`f2' (other file is `t1,t2').
285: */
286: change(f1, f2, t1, t2)
287: unsigned f1, f2, t1, t2;
288: {
289: sepflag = 1;
290: if (csymbol != NULL)
291: printf("#ifndef %s\n", csymbol);
292: else {
293: prange(f1, f2);
294: if (sflag)
295: putchar('c');
296: else if (eflag)
297: fputs("c\n", stdout);
298: else {
299: fputs(" c ", stdout);
300: prange(t1, t2);
301: putchar('\n');
302: }
303: }
304: if (rflag)
305: incr += t2-t1 + f1-f2;
306: }
307:
308: /*
309: * Output a set of appended lines.
310: * Append after `f' the lines in
311: * range `t1,t2'.
312: */
313: append(f, t1, t2)
314: unsigned f, t1, t2;
315: {
316: f--;
317: if (csymbol != NULL)
318: printf("#ifndef %s\n", csymbol);
319: else {
320: prange(f, f);
321: if (sflag)
322: putchar('a');
323: else if (eflag) {
324: fputs("a\n", stdout);
325: } else {
326: fputs(" a ", stdout);
327: prange(t1, t2);
328: putchar('\n');
329: }
330: }
331: if (rflag)
332: incr += t2-t1+1;
333: }
334:
335: /*
336: * Output a set of deleted lines.
337: * Delete range `f1,f2' (other file
338: * number is `t'.
339: */
340: delete(f1, f2, t)
341: unsigned f1, f2, t;
342: {
343: if (csymbol != NULL)
344: printf("#ifdef %s\n", csymbol);
345: else {
346: prange(f1, f2);
347: if (eflag)
348: fputs("d\n", stdout);
349: else
350: printf(" d %u\n", t-1);
351: }
352: if (rflag)
353: incr -= f2-f1+1;
354: }
355:
356: /*
357: * Output the middle of a set of
358: * changed lines.
359: */
360: prsep()
361: {
362: if (!sepflag)
363: return;
364: sepflag = 0;
365: if (csymbol != NULL)
366: fputs("#else\n", stdout);
367: else if (!eflag)
368: fputs("---\n", stdout);
369: }
370:
371: /*
372: * Output the end part of a set
373: * of changed lines.
374: */
375: prend()
376: {
377: if (csymbol != NULL)
378: fputs("#endif\n", stdout);
379: else if (caflag) {
380: if (sflag)
381: putchar('\n');
382: else if (eflag)
383: fputs(".\n", stdout);
384: }
385: caflag = 0;
386: }
387:
388: /*
389: * Print a line range either in the form
390: * `a,b' or `a' (if a==b).
391: */
392: prange(a, b)
393: register unsigned a, b;
394: {
395: a += incr;
396: b += incr;
397: if (a == b)
398: printf("%u", a); else
399: printf("%u,%u", a, b);
400: }
401:
402: /*
403: * Exit, removing any possible temmpfiles.
404: */
405: rmexit(s)
406: {
407: if (tmpnam1 != NULL)
408: unlink(tmpnam1);
409: if (tmpnam2 != NULL)
410: unlink(tmpnam2);
411: exit(s);
412: }
413:
414: /*
415: * Catch signal and exit.
416: */
417: catchsig()
418: {
419: rmexit(2);
420: }
421: usage()
422: {
423: fprintf(stderr, "Usage: diff [-bdefhs] [-c symbol] file1 file2\n");
424: exit(2);
425: }
426:
427: /* VARARGS */
428: cerr(x)
429: {
430: fprintf(stderr, "diff: %r\n", &x);
431: exit(2);
432: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.