|
|
1.1 root 1: /*
2: * Internal part of diff3.
3: * This file resides in /usr/lib/diff3.
4: * It is called as:
5: * /usr/lib/diff3 [options] generator
6: * Generator is the generator for the tempfile
7: * names (as in /tmp/d30239). `a' and `b' are used.
8: */
9:
10: #include <stdio.h>
11: #include <ctype.h>
12:
13: #define NINF 3 /* Number of input files */
14:
15: typedef long SEEK; /* May be made long */
16:
17: /*
18: * A set of changes between two files.
19: * This is just pairs of ranges from each file.
20: */
21: typedef struct CHANGES {
22: SEEK c_seek; /* Seek position after header line */
23: unsigned c_oldbeg; /* Old (first) file - beginning line number */
24: unsigned c_oldend; /* end line number */
25: unsigned c_newbeg; /* New (second) file - beginning */
26: unsigned c_newend; /* end line number */
27: } CHANGES;
28:
29: int eflag; /* Type of ed script */
30: int ndiffs; /* Number of differences found */
31: unsigned lastchange[NINF];
32: char line[1000]; /* Input line buffer */
33:
34: FILE *fp13; /* Changes of file 1 versus file 3 */
35: FILE *fp23; /* Changes of file 2 versus file 3 */
36:
37: FILE *diffopen();
38: CHANGES *getdiff();
39:
40: main(argc, argv)
41: int argc;
42: char *argv[];
43: {
44: register char *ap;
45:
46: if (argc>1 && *argv[1]=='-') {
47: for (ap = &argv[1][1]; *ap!='\0'; ap++)
48: switch (*ap) {
49: case 'e':
50: eflag = 03;
51: break;
52:
53: case 'x':
54: eflag = 01;
55: break;
56:
57: case '3':
58: eflag = 02;
59: break;
60:
61: default:
62: cerr("bad option `%s'", argv[1]);
63: }
64: argv++;
65: argc--;
66: }
67: if (argc != 2)
68: ierr("main");
69: fp13 = diffopen(argv[1], 'a');
70: fp23 = diffopen(argv[1], 'b');
71: collate();
72: exit(ndiffs!=0);
73: }
74:
75: /*
76: * Open one of the difference files
77: * (i.e. the output of `diff').
78: * Arguments are the generator name and
79: * an identifying letter.
80: */
81: FILE *
82: diffopen(gener, let)
83: char *gener;
84: int let;
85: {
86: FILE *fp;
87:
88: sprintf(line, "%s%c", gener, let);
89: if ((fp = fopen(line, "r")) == NULL)
90: cerr("cannot open intermediate file `%s'", line);
91: return (fp);
92: }
93:
94: /*
95: * Read in one entry from the specified
96: * file of differences. The `fp'
97: * argument is the stream containing one
98: * of the output files of `diff'.
99: */
100: CHANGES *
101: getdiff(fp)
102: FILE *fp;
103: {
104: register CHANGES *cp;
105: char *linep;
106: register int type;
107:
108: while (fgets(line, sizeof line, fp) != NULL) {
109: if (!isdigit(line[0]))
110: continue;
111: if ((cp = (CHANGES *)malloc(sizeof (CHANGES))) == NULL)
112: cerr("out of memory for changes");
113: linep = line;
114: cp->c_oldbeg = cp->c_oldend = readnum(&linep);
115: if (*linep == ',') {
116: linep++;
117: cp->c_oldend = readnum(&linep);
118: }
119: type = *linep++;
120: cp->c_newbeg = cp->c_newend = readnum(&linep);
121: if (*linep == ',') {
122: linep++;
123: cp->c_newend = readnum(&linep);
124: }
125: if (type == 'a')
126: cp->c_oldbeg++;
127: else if (type == 'd')
128: cp->c_newbeg++;
129: cp->c_oldend++;
130: cp->c_newend++;
131: cp->c_seek = ftell(fp);
132: ndiffs++;
133: return (cp);
134: }
135: return (NULL);
136: }
137:
138: /*
139: * Read a line number from the line.
140: * The pointer is given by reference
141: * so that it can be updated.
142: * Leading and trailing space is skipped.
143: */
144: readnum(npp)
145: register char **npp;
146: {
147: register char *np;
148: register int n = 0;
149:
150: np = *npp;
151: while (isspace(*np))
152: np++;
153: while (isdigit(*np))
154: n = n*10 + *np++ - '0';
155: while (isspace(*np))
156: np++;
157: *npp = np;
158: return (n);
159: }
160:
161: /*
162: * Read through the two difference
163: * files, collating changes that we
164: * encounter to produce one consistent
165: * view of changes on all three files.
166: */
167: collate()
168: {
169: register CHANGES *p13, *p23;
170: register CHANGES *n13, *n23;
171:
172: if ((p13 = getdiff(fp13)) != NULL)
173: n13 = getdiff(fp13); else
174: n13 = NULL;
175: if ((p23 = getdiff(fp23)) != NULL)
176: n23 = getdiff(fp23); else
177: n23 = NULL;
178: while (p13!=NULL || p23!=NULL) {
179: /*
180: * Differences found in the
181: * first file.
182: */
183: if (p23==NULL || (p13!=NULL && p13->c_newend<p23->c_newbeg)) {
184: prsep(1);
185: prchanges(1, p13, fp13);
186: prdummy(2, p13);
187: prchanges(3, p13, fp13);
188: cfree(p13);
189: if ((p13 = n13) != NULL)
190: n13 = getdiff(fp13);
191: continue;
192: }
193: /*
194: * Differences found in the
195: * second file.
196: */
197: if (p13==NULL || (p23!=NULL && p23->c_newend<p13->c_newbeg)) {
198: prsep(2);
199: prdummy(1, p23);
200: prchanges(2, p23, fp23);
201: prchanges(3, p23, fp23);
202: cfree(p23);
203: if ((p23 = n23) != NULL)
204: p23 = getdiff(fp23);
205: continue;
206: }
207: /*
208: * Merge changes that overlap
209: * with next change in first file.
210: * This happens as a result of
211: * the extension of a change as below.
212: */
213: if (n13!=NULL && p13->c_newend >= n13->c_newbeg) {
214: n13->c_oldbeg = p13->c_oldbeg;
215: n13->c_newbeg = p13->c_newbeg;
216: cfree(p13);
217: p13 = n13;
218: n13 = getdiff(fp13);
219: continue;
220: }
221: /*
222: * Do the same merge as above
223: * only for the second file of changed.
224: */
225: if (n23!=NULL && p23->c_newend >= n23->c_newbeg) {
226: n23->c_oldbeg = p23->c_oldbeg;
227: n23->c_newbeg = p23->c_newbeg;
228: cfree(p23);
229: p23 = n23;
230: n23 = getdiff(fp23);
231: continue;
232: }
233: /*
234: * Find lines only in third file or
235: * different in all. The difference
236: * between these two cases has to
237: * be tested by reading the actual
238: * different lines and comparing them.
239: */
240: if (p13->c_newbeg == p23->c_newbeg
241: && p13->c_newend == p23->c_newend) {
242: register int mat;
243: register CHANGES *cp;
244: register FILE *fp;
245:
246: mat = match12(p13, p23);
247: prsep(mat ? 3 : 0);
248: /*
249: * This masks out the editing changes
250: * desired, i.e. all different and 3 different
251: * for -e, and the individual cases for -x and -3.
252: */
253: if (eflag & (mat+01))
254: preditor(p13);
255: prchanges(1, p13, mat?NULL:fp13);
256: prchanges(2, p23, fp23);
257: /*
258: * Depends on whether a `c' or
259: * an `a' operation.
260: */
261: if (p13->c_oldend > p13->c_oldbeg) {
262: cp = p13;
263: fp = fp13;
264: } else {
265: cp = p23;
266: fp = fp23;
267: }
268: prchanges(3, cp, fp);
269: cfree(p13);
270: if ((p13 = n13) != NULL)
271: n13 = getdiff(fp13);
272: cfree(p23);
273: if ((p23 = n23) != NULL)
274: n23 = getdiff(fp23);
275: continue;
276: }
277: /*
278: * When a range of lines overlaps that
279: * of another range in the other change
280: * file, the ranges have to be adjusted.
281: */
282: if (p13->c_newbeg < p23->c_newbeg) {
283: p23->c_oldbeg -= p23->c_newbeg-p13->c_newbeg;
284: p23->c_newbeg = p13->c_newbeg;
285: } else if (p23->c_newbeg < p13->c_newbeg) {
286: p13->c_oldbeg -= p13->c_newbeg-p23->c_newbeg;
287: p13->c_newbeg = p23->c_newbeg;
288: }
289: if (p13->c_newend > p23->c_newend) {
290: p23->c_oldend += p13->c_newend-p23->c_newend;
291: p23->c_newend = p13->c_newend;
292: } else if (p23->c_newend > p13->c_newend) {
293: p13->c_oldend += p23->c_newend-p13->c_newend;
294: p13->c_newend = p23->c_newend;
295: }
296: }
297: }
298:
299: /*
300: * Free a CHANGES node, checking first
301: * to see if it is NULL.
302: */
303: cfree(cp)
304: register CHANGES *cp;
305: {
306: if (cp != NULL)
307: free((char *)cp);
308: }
309:
310: /*
311: * Since we have only the output of two diffs,
312: * we have to cross-check the output for a match
313: * between files one and two. This will use the
314: * line ranges found in the c_before of each
315: * CHANGES description.
316: * We have to seek both file descriptors back
317: * to where they were at entry upon leaving this routine.
318: */
319: match12(cp13, cp23)
320: register CHANGES *cp13, *cp23;
321: {
322: register int n;
323: register char *lp;
324: register int ret = 1;
325: long seek13, seek23;
326:
327: n = cp13->c_oldend - cp13->c_oldbeg;
328: if (n != cp23->c_oldend - cp23->c_oldbeg)
329: return (0);
330: if (n == 0)
331: return (1);
332: seek13 = ftell(fp13);
333: seek23 = ftell(fp23);
334: fseek(fp13, (long)cp13->c_seek, 0);
335: fseek(fp23, (long)cp23->c_seek, 0);
336: do {
337: if (fgets(line, sizeof line, fp13) == NULL)
338: ierr("match12/1");
339: for (lp = line; *lp++ != '\0'; )
340: ;
341: if (fgets(lp, sizeof line - (lp-line), fp23) == NULL)
342: ierr("match12/2");
343: if (line[0]!='<' || line[1]!=' ')
344: ierr("match12/3");
345: if (*lp++!='<' || *lp++!=' ')
346: ierr("match12/4");
347: if (strcmp(lp, line+2) != 0) {
348: ret = 0;
349: break;
350: }
351: } while (--n);
352: fseek(fp13, seek13, 0);
353: fseek(fp23, seek23, 0);
354: return (ret);
355: }
356:
357: /*
358: * Print out the changes on file numbered `fn' (1-3),
359: * given the CHANGES structure reference `cp'.
360: * Since file 3 is always the `new' file, if `fn==3'
361: * then the new range is used, otherwise the old.
362: * `prt' is set, if the text needs to be printed.
363: */
364: prchanges(fn, cp, prtfp)
365: int fn;
366: CHANGES *cp;
367: FILE *prtfp;
368: {
369: register unsigned beg, end;
370: register char recog;
371: register int nl;
372: long oseek;
373:
374: if (eflag)
375: return;
376: if (fn == 3) {
377: recog = '>';
378: beg = cp->c_newbeg;
379: end = cp->c_newend;
380: } else {
381: recog = '<';
382: beg = cp->c_oldbeg;
383: end = cp->c_oldend;
384: }
385: lastchange[fn-1] = end;
386: printf("%d: ", fn);
387: predcom(beg, end);
388: if (prtfp == NULL)
389: return;
390: oseek = ftell(prtfp);
391: fseek(prtfp, (long)cp->c_seek, 0);
392: while (fgets(line, sizeof line, prtfp) != NULL)
393: if (line[0]==recog && line[1]==' ')
394: break;
395: for (nl = end-beg; nl-- > 0; ) {
396: if (line[0]!=recog || line[1]!=' ')
397: break;
398: printf(" %s", line+2);
399: if (fgets(line, sizeof line, prtfp) == NULL)
400: break;
401: }
402: fseek(prtfp, oseek, 0);
403: }
404:
405: /*
406: * Print out dummy changes.
407: */
408: prdummy(fn, cp)
409: register int fn;
410: register CHANGES *cp;
411: {
412: register unsigned diff;
413:
414: if (eflag)
415: return;
416: diff = lastchange[3-1] - lastchange[fn-1];
417: lastchange[fn-1] = cp->c_newend-diff;
418: printf("%d: ", fn);
419: predcom(cp->c_newbeg-diff, cp->c_newend-diff);
420: }
421:
422: /*
423: * Print out an entry in the editor
424: * script given the first difference
425: * file (between files 1 and 3).
426: * Line numbers have to be adjusted
427: * because this script is printed in
428: * forward order. Special handling is
429: * done for a line which is `.'
430: */
431: preditor(cp)
432: register CHANGES *cp;
433: {
434: register int nl;
435: long seek13;
436: static int lnadjust;
437:
438: predcom(cp->c_oldbeg+lnadjust, cp->c_oldend+lnadjust);
439: if (cp->c_oldend > cp->c_oldbeg)
440: lnadjust -= cp->c_oldend-cp->c_oldbeg;
441: seek13 = ftell(fp13);
442: fseek(fp13, (long)cp->c_seek, 0);
443: while (fgets(line, sizeof line, fp13) != NULL)
444: if (line[0]=='>' && line[1]==' ')
445: break;
446: for (nl = cp->c_newend-cp->c_newbeg; nl-- > 0; ) {
447: if (line[0]!='>' || line[1]!=' ')
448: break;
449: if (line[2]=='.' && line[3]=='\n' && line[4]=='\0')
450: fputs("~\n.\ns/~/./\na\n", stdout);
451: else
452: fputs(line+2, stdout);
453: lnadjust++;
454: if (fgets(line, sizeof line, fp13) == NULL)
455: break;
456: }
457: fputs(".\n", stdout);
458: fseek(fp13, seek13, 0);
459: }
460:
461: /*
462: * Print out an editing command based
463: * upon the range of lines given.
464: * They have been adjusted in `readdiffs'
465: * so that an `a' and `c' are differentiable.
466: */
467: predcom(beg, end)
468: register unsigned beg, end;
469: {
470: if (end <= beg)
471: printf("%da\n", beg-1);
472: else {
473: printf("%d", beg);
474: if (end > beg+1)
475: printf(",%d", end-1);
476: printf("c\n");
477: }
478: }
479:
480: /*
481: * Print out a separator.
482: * The `fn' is which file differs.
483: * If `fn' is 0, it means all files differ.
484: */
485: prsep(fn)
486: register int fn;
487: {
488: if (!eflag)
489: if (fn != 0)
490: printf("====%d\n", fn); else
491: printf("====\n");
492: }
493:
494: /*
495: * Error routines
496: */
497: /* VARARGS */
498: cerr(x)
499: {
500: fprintf(stderr, "diff3: %r\n", &x);
501: exit(2);
502: }
503:
504: /*
505: * Internal error.
506: */
507: ierr(type)
508: char *type;
509: {
510: cerr("internal error in %s", type);
511: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.