|
|
1.1 root 1: #ifndef lint
2: static char sccsid[] = "@(#)diff3.c 4.4 (Berkeley) 8/27/85";
3: #endif
4:
5: #include <stdio.h>
6:
7: /* diff3 - 3-way differential file comparison*/
8:
9: /* diff3 [-ex3EX] d13 d23 f1 f2 f3 [m1 m3]
10: *
11: * d13 = diff report on f1 vs f3
12: * d23 = diff report on f2 vs f3
13: * f1, f2, f3 the 3 files
14: * if changes in f1 overlap with changes in f3, m1 and m3 are used
15: * to mark the overlaps; otherwise, the file names f1 and f3 are used
16: * (only for options E and X).
17: */
18:
19: struct range {int from,to; };
20: /* from is first in range of changed lines
21: * to is last+1
22: * from=to=line after point of insertion
23: * for added lines
24: */
25: struct diff {struct range old, new;};
26:
27: #define NC 200
28: struct diff d13[NC];
29: struct diff d23[NC];
30: /* de is used to gather editing scripts,
31: * that are later spewed out in reverse order.
32: * its first element must be all zero
33: * the "new" component of de contains line positions
34: * or byte positions depending on when you look(!?)
35: * array overlap indicates which sections in de correspond to
36: * lines that are different in all three files.
37: */
38: struct diff de[NC];
39: char overlap[NC];
40: int overlapcnt =0;
41:
42: char line[256];
43: FILE *fp[3];
44: /* the number of the last-read line in each file
45: * is kept in cline[0-2]
46: */
47: int cline[3];
48: /* the latest known correspondence between line
49: * numbers of the 3 files is stored in last[1-3]
50: */
51: int last[4];
52: int eflag;
53: int oflag; /* indicates whether to mark overlaps (-E or -X)*/
54: int debug = 0;
55: char f1mark[40], f3mark[40]; /*markers for -E and -X*/
56:
57:
58: main(argc,argv)
59: char **argv;
60: {
61: register i,m,n;
62: eflag=0; oflag=0;
63: if(*argv[1]=='-') {
64: switch(argv[1][1]) {
65: default:
66: eflag = 3;
67: break;
68: case '3':
69: eflag = 2;
70: break;
71: case 'x':
72: eflag = 1;
73: break;
74: case 'E':
75: eflag = 3;
76: oflag = 1;
77: break;
78: case 'X':
79: oflag = eflag = 1;
80: break;
81: }
82: argv++;
83: argc--;
84: }
85: if(argc<6) {
86: fprintf(stderr,"diff3: arg count\n");
87: exit(1);
88: }
89: if (oflag) {
90: (void)sprintf(f1mark,"<<<<<<< %s",argc>=7?argv[6]:argv[3]);
91: (void)sprintf(f3mark,">>>>>>> %s",argc>=8?argv[7]:argv[5]);
92: }
93:
94: m = readin(argv[1],d13);
95: n = readin(argv[2],d23);
96: for(i=0;i<=2;i++)
97: if((fp[i] = fopen(argv[i+3],"r")) == NULL) {
98: printf("diff3: can't open %s\n",argv[i+3]);
99: exit(1);
100: }
101: merge(m,n);
102: }
103:
104: /*pick up the line numbers of allcahnges from
105: * one change file
106: * (this puts the numbers in a vector, which is not
107: * strictly necessary, since the vector is processed
108: * in one sequential pass. The vector could be optimized
109: * out of existence)
110: */
111:
112: readin(name,dd)
113: char *name;
114: struct diff *dd;
115: {
116: register i;
117: int a,b,c,d;
118: char kind;
119: char *p;
120: fp[0] = fopen(name,"r");
121: for(i=0;getchange(fp[0]);i++) {
122: if(i>=NC) {
123: fprintf(stderr,"diff3: too many changes\n");
124: exit(0);
125: }
126: p = line;
127: a = b = number(&p);
128: if(*p==',') {
129: p++;
130: b = number(&p);
131: }
132: kind = *p++;
133: c = d = number(&p);
134: if(*p==',') {
135: p++;
136: d = number(&p);
137: }
138: if(kind=='a')
139: a++;
140: if(kind=='d')
141: c++;
142: b++;
143: d++;
144: dd[i].old.from = a;
145: dd[i].old.to = b;
146: dd[i].new.from = c;
147: dd[i].new.to = d;
148: }
149: dd[i].old.from = dd[i-1].old.to;
150: dd[i].new.from = dd[i-1].new.to;
151: (void)fclose(fp[0]);
152: return(i);
153: }
154:
155: number(lc)
156: char **lc;
157: {
158: register nn;
159: nn = 0;
160: while(digit(**lc))
161: nn = nn*10 + *(*lc)++ - '0';
162: return(nn);
163: }
164:
165: digit(c)
166: {
167: return(c>='0'&&c<='9');
168: }
169:
170: getchange(b)
171: FILE *b;
172: {
173: while(getline(b))
174: if(digit(line[0]))
175: return(1);
176: return(0);
177: }
178:
179: getline(b)
180: FILE *b;
181: {
182: register i, c;
183: for(i=0;i<sizeof(line)-1;i++) {
184: c = getc(b);
185: if(c==EOF)
186: break;
187: line[i] = c;
188: if(c=='\n') {
189: line[++i] = 0;
190: return(i);
191: }
192: }
193: return(0);
194: }
195:
196: merge(m1,m2)
197: {
198: register struct diff *d1, *d2, *d3;
199: int dup;
200: int j;
201: int t1,t2;
202: d1 = d13;
203: d2 = d23;
204: j = 0;
205: for(;(t1 = d1<d13+m1) | (t2 = d2<d23+m2);) {
206: if(debug) {
207: printf("%d,%d=%d,%d %d,%d=%d,%d\n",
208: d1->old.from,d1->old.to,
209: d1->new.from,d1->new.to,
210: d2->old.from,d2->old.to,
211: d2->new.from,d2->new.to);
212: }
213: /* first file is different from others*/
214: if(!t2||t1&&d1->new.to < d2->new.from) {
215: /* stuff peculiar to 1st file */
216: if(eflag==0) {
217: separate("1");
218: change(1,&d1->old,0);
219: keep(2,&d1->new);
220: change(3,&d1->new,0);
221: }
222: d1++;
223: continue;
224: }
225: /* second file is different from others*/
226: if(!t1||t2&&d2->new.to < d1->new.from) {
227: if(eflag==0) {
228: separate("2");
229: keep(1,&d2->new);
230: change(2,&d2->old,0);
231: change(3,&d2->new,0);
232: }
233: d2++;
234: continue;
235: }
236: /* merge overlapping changes in first file
237: * this happens after extension see below*/
238: if(d1+1<d13+m1 &&
239: d1->new.to>=d1[1].new.from) {
240: d1[1].old.from = d1->old.from;
241: d1[1].new.from = d1->new.from;
242: d1++;
243: continue;
244: }
245: /* merge overlapping changes in second*/
246: if(d2+1<d23+m2 &&
247: d2->new.to>=d2[1].new.from) {
248: d2[1].old.from = d2->old.from;
249: d2[1].new.from = d2->new.from;
250: d2++;
251: continue;
252: }
253: /* stuff peculiar to third file or different in all*/
254: if(d1->new.from==d2->new.from&&
255: d1->new.to==d2->new.to) {
256: dup = duplicate(&d1->old,&d2->old);
257: /* dup=0 means all files differ
258: * dup =1 meands files 1&2 identical*/
259: if(eflag==0) {
260: separate(dup?"3":"");
261: change(1,&d1->old,dup);
262: change(2,&d2->old,0);
263: d3 = d1->old.to>d1->old.from?d1:d2;
264: change(3,&d3->new,0);
265: } else
266: j = edit(d1,dup,j);
267: d1++;
268: d2++;
269: continue;
270: }
271: /* overlapping changes from file1 & 2
272: * extend changes appropriately to
273: * make them coincide*/
274: if(d1->new.from<d2->new.from) {
275: d2->old.from -= d2->new.from-d1->new.from;
276: d2->new.from = d1->new.from;
277: }
278: else if(d2->new.from<d1->new.from) {
279: d1->old.from -= d1->new.from-d2->new.from;
280: d1->new.from = d2->new.from;
281: }
282: if(d1->new.to >d2->new.to) {
283: d2->old.to += d1->new.to - d2->new.to;
284: d2->new.to = d1->new.to;
285: }
286: else if(d2->new.to >d1->new.to) {
287: d1->old.to += d2->new.to - d1->new.to;
288: d1->new.to = d2->new.to;
289: }
290: }
291: if(eflag)
292: edscript(j);
293: }
294:
295: separate(s)
296: char *s;
297: {
298: printf("====%s\n",s);
299: }
300:
301: /* the range of ines rold.from thru rold.to in file i
302: * is to be changed. it is to be printed only if
303: * it does not duplicate something to be printed later
304: */
305: change(i,rold,dup)
306: struct range *rold;
307: {
308: printf("%d:",i);
309: last[i] = rold->to;
310: prange(rold);
311: if(dup)
312: return;
313: if(debug)
314: return;
315: i--;
316: (void)skip(i,rold->from,(char *)0);
317: (void)skip(i,rold->to," ");
318: }
319:
320: /* print the range of line numbers, rold.from thru rold.to
321: * as n1,n2 or n1
322: */
323: prange(rold)
324: struct range *rold;
325: {
326: if(rold->to<=rold->from)
327: printf("%da\n",rold->from-1);
328: else {
329: printf("%d",rold->from);
330: if(rold->to > rold->from+1)
331: printf(",%d",rold->to-1);
332: printf("c\n");
333: }
334: }
335:
336: /* no difference was reported by diff between file 1(or 2)
337: * and file 3, and an artificial dummy difference (trange)
338: * must be ginned up to correspond to the change reported
339: * in the other file
340: */
341: keep(i,rnew)
342: struct range *rnew;
343: {
344: register delta;
345: struct range trange;
346: delta = last[3] - last[i];
347: trange.from = rnew->from - delta;
348: trange.to = rnew->to - delta;
349: change(i,&trange,1);
350: }
351:
352: /* skip to just befor line number from in file i
353: * if "pr" is nonzero, print all skipped stuff
354: * w with string pr as a prefix
355: */
356: skip(i,from,pr)
357: char *pr;
358: {
359: register j,n;
360: for(n=0;cline[i]<from-1;n+=j) {
361: if((j=getline(fp[i]))==0)
362: trouble();
363: if(pr)
364: printf("%s%s",pr,line);
365: cline[i]++;
366: }
367: return(n);
368: }
369:
370: /* return 1 or 0 according as the old range
371: * (in file 1) contains exactly the same data
372: * as the new range (in file 2)
373: */
374: duplicate(r1,r2)
375: struct range *r1, *r2;
376: {
377: register c,d;
378: register nchar;
379: int nline;
380: if(r1->to-r1->from != r2->to-r2->from)
381: return(0);
382: (void)skip(0,r1->from,(char *)0);
383: (void)skip(1,r2->from,(char *)0);
384: nchar = 0;
385: for(nline=0;nline<r1->to-r1->from;nline++) {
386: do {
387: c = getc(fp[0]);
388: d = getc(fp[1]);
389: if(c== -1||d== -1)
390: trouble();
391: nchar++;
392: if(c!=d) {
393: repos(nchar);
394: return(0);
395: }
396: } while(c!= '\n');
397: }
398: repos(nchar);
399: return(1);
400: }
401:
402: repos(nchar)
403: {
404: register i;
405: for(i=0;i<2;i++)
406: (void)fseek(fp[i], (long)-nchar, 1);
407: }
408:
409: trouble()
410: {
411: fprintf(stderr,"diff3: logic error\n");
412: abort();
413: }
414:
415: /* collect an editing script for later regurgitation
416: */
417: edit(diff,dup,j)
418: struct diff *diff;
419: {
420: if(((dup+1)&eflag)==0)
421: return(j);
422: j++;
423: overlap[j] = !dup;
424: if (!dup) overlapcnt++;
425: de[j].old.from = diff->old.from;
426: de[j].old.to = diff->old.to;
427: de[j].new.from = de[j-1].new.to
428: +skip(2,diff->new.from,(char *)0);
429: de[j].new.to = de[j].new.from
430: +skip(2,diff->new.to,(char *)0);
431: return(j);
432: }
433:
434: /* regurgitate */
435: edscript(n)
436: {
437: register j,k;
438: char block[BUFSIZ];
439: for(n=n;n>0;n--) {
440: if (!oflag || !overlap[n])
441: prange(&de[n].old);
442: else
443: printf("%da\n=======\n", de[n].old.to -1);
444: (void)fseek(fp[2], (long)de[n].new.from, 0);
445: for(k=de[n].new.to-de[n].new.from;k>0;k-= j) {
446: j = k>BUFSIZ?BUFSIZ:k;
447: if(fread(block,1,j,fp[2])!=j)
448: trouble();
449: (void)fwrite(block, 1, j, stdout);
450: }
451: if (!oflag || !overlap[n])
452: printf(".\n");
453: else {
454: printf("%s\n.\n",f3mark);
455: printf("%da\n%s\n.\n",de[n].old.from-1,f1mark);
456: }
457: }
458: exit(overlapcnt);
459: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.