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