file reorg, pathnames.h, paths.h
[unix-history] / usr / src / usr.bin / diff / diff3 / diff3.c
CommitLineData
f6227721 1#ifndef lint
88bf5909 2static char sccsid[] = "@(#)diff3.c 4.4 (Berkeley) %G%";
f6227721 3#endif
953c3384
BS
4
5#include <stdio.h>
953c3384
BS
6
7/* diff3 - 3-way differential file comparison*/
8
a040b36e 9/* diff3 [-ex3EX] d13 d23 f1 f2 f3 [m1 m3]
953c3384
BS
10 *
11 * d13 = diff report on f1 vs f3
12 * d23 = diff report on f2 vs f3
13 * f1, f2, f3 the 3 files
a040b36e
VJ
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).
953c3384
BS
17*/
18
19struct 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 */
25struct diff {struct range old, new;};
26
27#define NC 200
a040b36e
VJ
28struct diff d13[NC];
29struct diff d23[NC];
953c3384
BS
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(!?)
a040b36e
VJ
35 * array overlap indicates which sections in de correspond to
36 * lines that are different in all three files.
953c3384 37*/
953c3384 38struct diff de[NC];
a040b36e
VJ
39char overlap[NC];
40int overlapcnt =0;
41
953c3384
BS
42char line[256];
43FILE *fp[3];
953c3384
BS
44/* the number of the last-read line in each file
45 * is kept in cline[0-2]
46*/
47int cline[3];
48/* the latest known correspondence between line
49 * numbers of the 3 files is stored in last[1-3]
50*/
51int last[4];
52int eflag;
a040b36e 53int oflag; /* indicates whether to mark overlaps (-E or -X)*/
953c3384 54int debug = 0;
a040b36e
VJ
55char f1mark[40], f3mark[40]; /*markers for -E and -X*/
56
953c3384
BS
57
58main(argc,argv)
59char **argv;
60{
61 register i,m,n;
a040b36e 62 eflag=0; oflag=0;
953c3384
BS
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;
a040b36e
VJ
73 break;
74 case 'E':
75 eflag = 3;
76 oflag = 1;
77 break;
78 case 'X':
79 oflag = eflag = 1;
80 break;
953c3384
BS
81 }
82 argv++;
83 argc--;
84 }
85 if(argc<6) {
86 fprintf(stderr,"diff3: arg count\n");
87 exit(1);
88 }
a040b36e 89 if (oflag) {
88bf5909
VJ
90 (void)sprintf(f1mark,"<<<<<<< %s",argc>=7?argv[6]:argv[3]);
91 (void)sprintf(f3mark,">>>>>>> %s",argc>=8?argv[7]:argv[5]);
a040b36e
VJ
92 }
93
953c3384
BS
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
112readin(name,dd)
113char *name;
114struct 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;
88bf5909 151 (void)fclose(fp[0]);
953c3384
BS
152 return(i);
153}
154
155number(lc)
156char **lc;
157{
158 register nn;
159 nn = 0;
160 while(digit(**lc))
161 nn = nn*10 + *(*lc)++ - '0';
162 return(nn);
163}
164
165digit(c)
166{
167 return(c>='0'&&c<='9');
168}
169
170getchange(b)
171FILE *b;
172{
173 while(getline(b))
174 if(digit(line[0]))
175 return(1);
176 return(0);
177}
178
179getline(b)
180FILE *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
196merge(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);
88bf5909 219 keep(2,&d1->new);
953c3384
BS
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");
88bf5909 229 keep(1,&d2->new);
953c3384
BS
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
295separate(s)
296char *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*/
305change(i,rold,dup)
306struct 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--;
88bf5909
VJ
316 (void)skip(i,rold->from,(char *)0);
317 (void)skip(i,rold->to," ");
953c3384
BS
318}
319
320/* print the range of line numbers, rold.from thru rold.to
321 * as n1,n2 or n1
322*/
323prange(rold)
324struct 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*/
88bf5909
VJ
341keep(i,rnew)
342struct range *rnew;
953c3384
BS
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*/
356skip(i,from,pr)
357char *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*/
374duplicate(r1,r2)
375struct 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);
88bf5909
VJ
382 (void)skip(0,r1->from,(char *)0);
383 (void)skip(1,r2->from,(char *)0);
953c3384
BS
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);
88bf5909 394 return(0);
953c3384
BS
395 }
396 } while(c!= '\n');
397 }
398 repos(nchar);
399 return(1);
400}
401
402repos(nchar)
403{
404 register i;
405 for(i=0;i<2;i++)
88bf5909 406 (void)fseek(fp[i], (long)-nchar, 1);
953c3384
BS
407}
408
409trouble()
410{
411 fprintf(stderr,"diff3: logic error\n");
412 abort();
413}
414
415/* collect an editing script for later regurgitation
416*/
417edit(diff,dup,j)
418struct diff *diff;
419{
420 if(((dup+1)&eflag)==0)
421 return(j);
422 j++;
a040b36e
VJ
423 overlap[j] = !dup;
424 if (!dup) overlapcnt++;
953c3384
BS
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 */
435edscript(n)
436{
437 register j,k;
438 char block[BUFSIZ];
439 for(n=n;n>0;n--) {
a040b36e
VJ
440 if (!oflag || !overlap[n])
441 prange(&de[n].old);
442 else
443 printf("%da\n=======\n", de[n].old.to -1);
88bf5909 444 (void)fseek(fp[2], (long)de[n].new.from, 0);
953c3384
BS
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();
88bf5909 449 (void)fwrite(block, 1, j, stdout);
953c3384 450 }
a040b36e
VJ
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 }
953c3384 457 }
a040b36e 458 exit(overlapcnt);
953c3384 459}