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