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