|
|
1.1 root 1: static char sccsid[] = "@(#)diffreg.c 4.16 3/29/86";
2:
3: #include "diff.h"
4: /*
5: * diff - compare two files.
6: */
7:
8: /*
9: * Uses an algorithm due to Harold Stone, which finds
10: * a pair of longest identical subsequences in the two
11: * files.
12: *
13: * The major goal is to generate the match vector J.
14: * J[i] is the index of the line in file1 corresponding
15: * to line i file0. J[i] = 0 if there is no
16: * such line in file1.
17: *
18: * Lines are hashed so as to work in core. All potential
19: * matches are located by sorting the lines of each file
20: * on the hash (called ``value''). In particular, this
21: * collects the equivalence classes in file1 together.
22: * Subroutine equiv replaces the value of each line in
23: * file0 by the index of the first element of its
24: * matching equivalence in (the reordered) file1.
25: * To save space equiv squeezes file1 into a single
26: * array member in which the equivalence classes
27: * are simply concatenated, except that their first
28: * members are flagged by changing sign.
29: *
30: * Next the indices that point into member are unsorted into
31: * array class according to the original order of file0.
32: *
33: * The cleverness lies in routine stone. This marches
34: * through the lines of file0, developing a vector klist
35: * of "k-candidates". At step i a k-candidate is a matched
36: * pair of lines x,y (x in file0 y in file1) such that
37: * there is a common subsequence of length k
38: * between the first i lines of file0 and the first y
39: * lines of file1, but there is no such subsequence for
40: * any smaller y. x is the earliest possible mate to y
41: * that occurs in such a subsequence.
42: *
43: * Whenever any of the members of the equivalence class of
44: * lines in file1 matable to a line in file0 has serial number
45: * less than the y of some k-candidate, that k-candidate
46: * with the smallest such y is replaced. The new
47: * k-candidate is chained (via pred) to the current
48: * k-1 candidate so that the actual subsequence can
49: * be recovered. When a member has serial number greater
50: * that the y of all k-candidates, the klist is extended.
51: * At the end, the longest subsequence is pulled out
52: * and placed in the array J by unravel
53: *
54: * With J in hand, the matches there recorded are
55: * check'ed against reality to assure that no spurious
56: * matches have crept in due to hashing. If they have,
57: * they are broken, and "jackpot" is recorded--a harmless
58: * matter except that a true match for a spuriously
59: * mated line may now be unnecessarily reported as a change.
60: *
61: * Much of the complexity of the program comes simply
62: * from trying to minimize core utilization and
63: * maximize the range of doable problems by dynamically
64: * allocating what is needed and reusing what is not.
65: * The core requirements for problems larger than somewhat
66: * are (in words) 2*length(file0) + length(file1) +
67: * 3*(number of k-candidates installed), typically about
68: * 6n words for files of length n.
69: */
70:
71: #define prints(s) fputs(s,stdout)
72:
73: FILE *input[2];
74: FILE *fopen();
75:
76: struct cand {
77: int x;
78: int y;
79: int pred;
80: } cand;
81: struct line {
82: int serial;
83: int value;
84: } *file[2], line;
85: int len[2];
86: struct line *sfile[2]; /* shortened by pruning common prefix and suffix */
87: int slen[2];
88: int pref, suff; /* length of prefix and suffix */
89: int *class; /* will be overlaid on file[0] */
90: int *member; /* will be overlaid on file[1] */
91: int *klist; /* will be overlaid on file[0] after class */
92: struct cand *clist; /* merely a free storage pot for candidates */
93: int clen = 0;
94: int *J; /* will be overlaid on class */
95: long *ixold; /* will be overlaid on klist */
96: long *ixnew; /* will be overlaid on file[1] */
97: char *chrtran; /* translation table for case-folding */
98:
99: /* chrtran points to one of 2 translation tables:
100: * cup2low if folding upper to lower case
101: * clow2low if not folding case
102: */
103: char clow2low[256] = {
104: 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
105: 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
106: 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
107: 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
108: 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
109: 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
110: 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
111: 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
112: 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
113: 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
114: 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
115: 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
116: 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
117: 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
118: 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
119: 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff
120: };
121:
122: char cup2low[256] = {
123: 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
124: 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
125: 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
126: 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
127: 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
128: 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
129: 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
130: 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
131: 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
132: 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
133: 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
134: 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
135: 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
136: 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
137: 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
138: 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff
139: };
140:
141: diffreg()
142: {
143: register int i, j;
144: FILE *f1, *f2;
145: char buf1[BUFSIZ], buf2[BUFSIZ];
146:
147: if (hflag) {
148: diffargv[0] = "diffh";
149: execv(diffh, diffargv);
150: fprintf(stderr, "diff: ");
151: perror(diffh);
152: done();
153: }
154: chrtran = (iflag? cup2low : clow2low);
155: if ((stb1.st_mode & S_IFMT) == S_IFDIR) {
156: file1 = splice(file1, file2);
157: if (stat(file1, &stb1) < 0) {
158: fprintf(stderr, "diff: ");
159: perror(file1);
160: done();
161: }
162: } else if ((stb2.st_mode & S_IFMT) == S_IFDIR) {
163: file2 = splice(file2, file1);
164: if (stat(file2, &stb2) < 0) {
165: fprintf(stderr, "diff: ");
166: perror(file2);
167: done();
168: }
169: } else if (!strcmp(file1, "-")) {
170: if (!strcmp(file2, "-")) {
171: fprintf(stderr, "diff: can't specify - -\n");
172: done();
173: }
174: file1 = copytemp();
175: if (stat(file1, &stb1) < 0) {
176: fprintf(stderr, "diff: ");
177: perror(file1);
178: done();
179: }
180: } else if (!strcmp(file2, "-")) {
181: file2 = copytemp();
182: if (stat(file2, &stb2) < 0) {
183: fprintf(stderr, "diff: ");
184: perror(file2);
185: done();
186: }
187: }
188: if ((f1 = fopen(file1, "r")) == NULL) {
189: fprintf(stderr, "diff: ");
190: perror(file1);
191: done();
192: }
193: if ((f2 = fopen(file2, "r")) == NULL) {
194: fprintf(stderr, "diff: ");
195: perror(file2);
196: fclose(f1);
197: done();
198: }
199: if (stb1.st_size != stb2.st_size)
200: goto notsame;
201: for (;;) {
202: i = fread(buf1, 1, BUFSIZ, f1);
203: j = fread(buf2, 1, BUFSIZ, f2);
204: if (i < 0 || j < 0 || i != j)
205: goto notsame;
206: if (i == 0 && j == 0) {
207: fclose(f1);
208: fclose(f2);
209: status = 0; /* files don't differ */
210: goto same;
211: }
212: for (j = 0; j < i; j++)
213: if (buf1[j] != buf2[j])
214: goto notsame;
215: }
216: notsame:
217: /*
218: * Files certainly differ at this point; set status accordingly
219: */
220: status = 1;
221: if (!asciifile(f1) || !asciifile(f2)) {
222: printf("Binary files %s and %s differ\n", file1, file2);
223: fclose(f1);
224: fclose(f2);
225: done();
226: }
227: prepare(0, f1);
228: prepare(1, f2);
229: fclose(f1);
230: fclose(f2);
231: prune();
232: sort(sfile[0],slen[0]);
233: sort(sfile[1],slen[1]);
234:
235: member = (int *)file[1];
236: equiv(sfile[0], slen[0], sfile[1], slen[1], member);
237: member = (int *)ralloc((char *)member,(slen[1]+2)*sizeof(int));
238:
239: class = (int *)file[0];
240: unsort(sfile[0], slen[0], class);
241: class = (int *)ralloc((char *)class,(slen[0]+2)*sizeof(int));
242:
243: klist = (int *)talloc((slen[0]+2)*sizeof(int));
244: clist = (struct cand *)talloc(sizeof(cand));
245: i = stone(class, slen[0], member, klist);
246: free((char *)member);
247: free((char *)class);
248:
249: J = (int *)talloc((len[0]+2)*sizeof(int));
250: unravel(klist[i]);
251: free((char *)clist);
252: free((char *)klist);
253:
254: ixold = (long *)talloc((len[0]+2)*sizeof(long));
255: ixnew = (long *)talloc((len[1]+2)*sizeof(long));
256: check();
257: output();
258: status = anychange;
259: same:
260: if (opt == D_CONTEXT && anychange == 0)
261: printf("No differences encountered\n");
262: done();
263: }
264:
265: char *
266: copytemp()
267: {
268: char buf[BUFSIZ];
269: register int i, f;
270:
271: signal(SIGHUP,done);
272: signal(SIGINT,done);
273: signal(SIGPIPE,done);
274: signal(SIGTERM,done);
275: tempfile = mktemp("/tmp/dXXXXX");
276: f = creat(tempfile,0600);
277: if (f < 0) {
278: fprintf(stderr, "diff: ");
279: perror(tempfile);
280: done();
281: }
282: while ((i = read(0,buf,BUFSIZ)) > 0)
283: if (write(f,buf,i) != i) {
284: fprintf(stderr, "diff: ");
285: perror(tempfile);
286: done();
287: }
288: close(f);
289: return (tempfile);
290: }
291:
292: char *
293: splice(dir, file)
294: char *dir, *file;
295: {
296: char *tail;
297: char buf[BUFSIZ];
298:
299: if (!strcmp(file, "-")) {
300: fprintf(stderr, "diff: can't specify - with other arg directory\n");
301: done();
302: }
303: tail = rindex(file, '/');
304: if (tail == 0)
305: tail = file;
306: else
307: tail++;
308: sprintf(buf, "%s/%s", dir, tail);
309: return (savestr(buf));
310: }
311:
312: prepare(i, fd)
313: int i;
314: FILE *fd;
315: {
316: register struct line *p;
317: register j,h;
318:
319: fseek(fd, (long)0, 0);
320: p = (struct line *)talloc(3*sizeof(line));
321: for(j=0; h=readhash(fd);) {
322: p = (struct line *)ralloc((char *)p,(++j+3)*sizeof(line));
323: p[j].value = h;
324: }
325: len[i] = j;
326: file[i] = p;
327: }
328:
329: prune()
330: {
331: register i,j;
332: for(pref=0;pref<len[0]&&pref<len[1]&&
333: file[0][pref+1].value==file[1][pref+1].value;
334: pref++ ) ;
335: for(suff=0;suff<len[0]-pref&&suff<len[1]-pref&&
336: file[0][len[0]-suff].value==file[1][len[1]-suff].value;
337: suff++) ;
338: for(j=0;j<2;j++) {
339: sfile[j] = file[j]+pref;
340: slen[j] = len[j]-pref-suff;
341: for(i=0;i<=slen[j];i++)
342: sfile[j][i].serial = i;
343: }
344: }
345:
346: equiv(a,n,b,m,c)
347: struct line *a, *b;
348: int *c;
349: {
350: register int i, j;
351: i = j = 1;
352: while(i<=n && j<=m) {
353: if(a[i].value <b[j].value)
354: a[i++].value = 0;
355: else if(a[i].value == b[j].value)
356: a[i++].value = j;
357: else
358: j++;
359: }
360: while(i <= n)
361: a[i++].value = 0;
362: b[m+1].value = 0;
363: j = 0;
364: while(++j <= m) {
365: c[j] = -b[j].serial;
366: while(b[j+1].value == b[j].value) {
367: j++;
368: c[j] = b[j].serial;
369: }
370: }
371: c[j] = -1;
372: }
373:
374: stone(a,n,b,c)
375: int *a;
376: int *b;
377: register int *c;
378: {
379: register int i, k,y;
380: int j, l;
381: int oldc, tc;
382: int oldl;
383: k = 0;
384: c[0] = newcand(0,0,0);
385: for(i=1; i<=n; i++) {
386: j = a[i];
387: if(j==0)
388: continue;
389: y = -b[j];
390: oldl = 0;
391: oldc = c[0];
392: do {
393: if(y <= clist[oldc].y)
394: continue;
395: l = search(c, k, y);
396: if(l!=oldl+1)
397: oldc = c[l-1];
398: if(l<=k) {
399: if(clist[c[l]].y <= y)
400: continue;
401: tc = c[l];
402: c[l] = newcand(i,y,oldc);
403: oldc = tc;
404: oldl = l;
405: } else {
406: c[l] = newcand(i,y,oldc);
407: k++;
408: break;
409: }
410: } while((y=b[++j]) > 0);
411: }
412: return(k);
413: }
414:
415: newcand(x,y,pred)
416: {
417: register struct cand *q;
418: clist = (struct cand *)ralloc((char *)clist,++clen*sizeof(cand));
419: q = clist + clen -1;
420: q->x = x;
421: q->y = y;
422: q->pred = pred;
423: return(clen-1);
424: }
425:
426: search(c, k, y)
427: int *c;
428: {
429: register int i, j, l;
430: int t;
431: if(clist[c[k]].y<y) /*quick look for typical case*/
432: return(k+1);
433: i = 0;
434: j = k+1;
435: while (1) {
436: l = i + j;
437: if ((l >>= 1) <= i)
438: break;
439: t = clist[c[l]].y;
440: if(t > y)
441: j = l;
442: else if(t < y)
443: i = l;
444: else
445: return(l);
446: }
447: return(l+1);
448: }
449:
450: unravel(p)
451: {
452: register int i;
453: register struct cand *q;
454: for(i=0; i<=len[0]; i++)
455: J[i] = i<=pref ? i:
456: i>len[0]-suff ? i+len[1]-len[0]:
457: 0;
458: for(q=clist+p;q->y!=0;q=clist+q->pred)
459: J[q->x+pref] = q->y+pref;
460: }
461:
462: /* check does double duty:
463: 1. ferret out any fortuitous correspondences due
464: to confounding by hashing (which result in "jackpot")
465: 2. collect random access indexes to the two files */
466:
467: check()
468: {
469: register int i, j;
470: int jackpot;
471: long ctold, ctnew;
472: register int c,d;
473:
474: if ((input[0] = fopen(file1,"r")) == NULL) {
475: perror(file1);
476: done();
477: }
478: if ((input[1] = fopen(file2,"r")) == NULL) {
479: perror(file2);
480: done();
481: }
482: j = 1;
483: ixold[0] = ixnew[0] = 0;
484: jackpot = 0;
485: ctold = ctnew = 0;
486: for(i=1;i<=len[0];i++) {
487: if(J[i]==0) {
488: ixold[i] = ctold += skipline(0);
489: continue;
490: }
491: while(j<J[i]) {
492: ixnew[j] = ctnew += skipline(1);
493: j++;
494: }
495: if(bflag || wflag || iflag) {
496: for(;;) {
497: c = getc(input[0]);
498: d = getc(input[1]);
499: ctold++;
500: ctnew++;
501: if(bflag && isspace(c) && isspace(d)) {
502: do {
503: if(c=='\n')
504: break;
505: ctold++;
506: } while(isspace(c=getc(input[0])));
507: do {
508: if(d=='\n')
509: break;
510: ctnew++;
511: } while(isspace(d=getc(input[1])));
512: } else if ( wflag ) {
513: while( isspace(c) && c!='\n' ) {
514: c=getc(input[0]);
515: ctold++;
516: }
517: while( isspace(d) && d!='\n' ) {
518: d=getc(input[1]);
519: ctnew++;
520: }
521: }
522: if(chrtran[c] != chrtran[d]) {
523: jackpot++;
524: J[i] = 0;
525: if(c!='\n')
526: ctold += skipline(0);
527: if(d!='\n')
528: ctnew += skipline(1);
529: break;
530: }
531: if(c=='\n')
532: break;
533: }
534: } else {
535: for(;;) {
536: ctold++;
537: ctnew++;
538: if((c=getc(input[0])) != (d=getc(input[1]))) {
539: /* jackpot++; */
540: J[i] = 0;
541: if(c!='\n')
542: ctold += skipline(0);
543: if(d!='\n')
544: ctnew += skipline(1);
545: break;
546: }
547: if(c=='\n')
548: break;
549: }
550: }
551: ixold[i] = ctold;
552: ixnew[j] = ctnew;
553: j++;
554: }
555: for(;j<=len[1];j++) {
556: ixnew[j] = ctnew += skipline(1);
557: }
558: fclose(input[0]);
559: fclose(input[1]);
560: /*
561: if(jackpot)
562: fprintf(stderr, "jackpot\n");
563: */
564: }
565:
566: sort(a,n) /*shellsort CACM #201*/
567: struct line *a;
568: {
569: struct line w;
570: register int j,m;
571: struct line *ai;
572: register struct line *aim;
573: int k;
574:
575: if (n == 0)
576: return;
577: for(j=1;j<=n;j*= 2)
578: m = 2*j - 1;
579: for(m/=2;m!=0;m/=2) {
580: k = n-m;
581: for(j=1;j<=k;j++) {
582: for(ai = &a[j]; ai > a; ai -= m) {
583: aim = &ai[m];
584: if(aim < ai)
585: break; /*wraparound*/
586: if(aim->value > ai[0].value ||
587: aim->value == ai[0].value &&
588: aim->serial > ai[0].serial)
589: break;
590: w.value = ai[0].value;
591: ai[0].value = aim->value;
592: aim->value = w.value;
593: w.serial = ai[0].serial;
594: ai[0].serial = aim->serial;
595: aim->serial = w.serial;
596: }
597: }
598: }
599: }
600:
601: unsort(f, l, b)
602: struct line *f;
603: int *b;
604: {
605: register int *a;
606: register int i;
607: a = (int *)talloc((l+1)*sizeof(int));
608: for(i=1;i<=l;i++)
609: a[f[i].serial] = f[i].value;
610: for(i=1;i<=l;i++)
611: b[i] = a[i];
612: free((char *)a);
613: }
614:
615: skipline(f)
616: {
617: register i, c;
618:
619: for(i=1;(c=getc(input[f]))!='\n';i++)
620: if (c < 0)
621: return(i);
622: return(i);
623: }
624:
625: output()
626: {
627: int m;
628: register int i0, i1, j1;
629: int j0;
630: input[0] = fopen(file1,"r");
631: input[1] = fopen(file2,"r");
632: m = len[0];
633: J[0] = 0;
634: J[m+1] = len[1]+1;
635: if(opt!=D_EDIT) for(i0=1;i0<=m;i0=i1+1) {
636: while(i0<=m&&J[i0]==J[i0-1]+1) i0++;
637: j0 = J[i0-1]+1;
638: i1 = i0-1;
639: while(i1<m&&J[i1+1]==0) i1++;
640: j1 = J[i1+1]-1;
641: J[i1] = j1;
642: change(i0,i1,j0,j1);
643: } else for(i0=m;i0>=1;i0=i1-1) {
644: while(i0>=1&&J[i0]==J[i0+1]-1&&J[i0]!=0) i0--;
645: j0 = J[i0+1]-1;
646: i1 = i0+1;
647: while(i1>1&&J[i1-1]==0) i1--;
648: j1 = J[i1-1]+1;
649: J[i1] = j1;
650: change(i1,i0,j1,j0);
651: }
652: if(m==0)
653: change(1,0,1,len[1]);
654: if (opt==D_IFDEF) {
655: for (;;) {
656: #define c i0
657: c = getc(input[0]);
658: if (c < 0)
659: return;
660: putchar(c);
661: }
662: #undef c
663: }
664: if (anychange && opt == D_CONTEXT)
665: dump_context_vec();
666: }
667:
668: /*
669: * The following struct is used to record change information when
670: * doing a "context" diff. (see routine "change" to understand the
671: * highly mneumonic field names)
672: */
673: struct context_vec {
674: int a; /* start line in old file */
675: int b; /* end line in old file */
676: int c; /* start line in new file */
677: int d; /* end line in new file */
678: };
679:
680: struct context_vec *context_vec_start,
681: *context_vec_end,
682: *context_vec_ptr;
683:
684: #define MAX_CONTEXT 128
685:
686: /* indicate that there is a difference between lines a and b of the from file
687: to get to lines c to d of the to file.
688: If a is greater then b then there are no lines in the from file involved
689: and this means that there were lines appended (beginning at b).
690: If c is greater than d then there are lines missing from the to file.
691: */
692: change(a,b,c,d)
693: {
694: int ch;
695: int lowa,upb,lowc,upd;
696: struct stat stbuf;
697:
698: if (opt != D_IFDEF && a>b && c>d)
699: return;
700: if (anychange == 0) {
701: anychange = 1;
702: if(opt == D_CONTEXT) {
703: printf("*** %s ", file1);
704: stat(file1, &stbuf);
705: printf("%s--- %s ",
706: ctime(&stbuf.st_mtime), file2);
707: stat(file2, &stbuf);
708: printf("%s", ctime(&stbuf.st_mtime));
709:
710: context_vec_start = (struct context_vec *)
711: malloc(MAX_CONTEXT *
712: sizeof(struct context_vec));
713: context_vec_end = context_vec_start + MAX_CONTEXT;
714: context_vec_ptr = context_vec_start - 1;
715: }
716: }
717: if (a <= b && c <= d)
718: ch = 'c';
719: else
720: ch = (a <= b) ? 'd' : 'a';
721: if(opt == D_CONTEXT) {
722: /*
723: * if this new change is within 'context' lines of
724: * the previous change, just add it to the change
725: * record. If the record is full or if this
726: * change is more than 'context' lines from the previous
727: * change, dump the record, reset it & add the new change.
728: */
729: if ( context_vec_ptr >= context_vec_end ||
730: ( context_vec_ptr >= context_vec_start &&
731: a > (context_vec_ptr->b + 2*context) &&
732: c > (context_vec_ptr->d + 2*context) ) )
733: dump_context_vec();
734:
735: context_vec_ptr++;
736: context_vec_ptr->a = a;
737: context_vec_ptr->b = b;
738: context_vec_ptr->c = c;
739: context_vec_ptr->d = d;
740: return;
741: }
742: switch (opt) {
743:
744: case D_NORMAL:
745: case D_EDIT:
746: range(a,b,",");
747: putchar(a>b?'a':c>d?'d':'c');
748: if(opt==D_NORMAL)
749: range(c,d,",");
750: putchar('\n');
751: break;
752: case D_REVERSE:
753: putchar(a>b?'a':c>d?'d':'c');
754: range(a,b," ");
755: putchar('\n');
756: break;
757: case D_NREVERSE:
758: if (a>b)
759: printf("a%d %d\n",b,d-c+1);
760: else {
761: printf("d%d %d\n",a,b-a+1);
762: if (!(c>d))
763: /* add changed lines */
764: printf("a%d %d\n",b, d-c+1);
765: }
766: break;
767: }
768: if(opt == D_NORMAL || opt == D_IFDEF) {
769: fetch(ixold,a,b,input[0],"< ", 1);
770: if(a<=b&&c<=d && opt == D_NORMAL)
771: prints("---\n");
772: }
773: fetch(ixnew,c,d,input[1],opt==D_NORMAL?"> ":"", 0);
774: if ((opt ==D_EDIT || opt == D_REVERSE) && c<=d)
775: prints(".\n");
776: if (inifdef) {
777: fprintf(stdout, "#endif %s\n", endifname);
778: inifdef = 0;
779: }
780: }
781:
782: range(a,b,separator)
783: char *separator;
784: {
785: printf("%d", a>b?b:a);
786: if(a<b) {
787: printf("%s%d", separator, b);
788: }
789: }
790:
791: fetch(f,a,b,lb,s,oldfile)
792: long *f;
793: FILE *lb;
794: char *s;
795: {
796: register int i, j;
797: register int c;
798: register int col;
799: register int nc;
800: int oneflag = (*ifdef1!='\0') != (*ifdef2!='\0');
801:
802: /*
803: * When doing #ifdef's, copy down to current line
804: * if this is the first file, so that stuff makes it to output.
805: */
806: if (opt == D_IFDEF && oldfile){
807: long curpos = ftell(lb);
808: /* print through if append (a>b), else to (nb: 0 vs 1 orig) */
809: nc = f[a>b? b : a-1 ] - curpos;
810: for (i = 0; i < nc; i++)
811: putchar(getc(lb));
812: }
813: if (a > b)
814: return;
815: if (opt == D_IFDEF) {
816: if (inifdef)
817: fprintf(stdout, "#else %s%s\n", oneflag && oldfile==1 ? "!" : "", ifdef2);
818: else {
819: if (oneflag) {
820: /* There was only one ifdef given */
821: endifname = ifdef2;
822: if (oldfile)
823: fprintf(stdout, "#ifndef %s\n", endifname);
824: else
825: fprintf(stdout, "#ifdef %s\n", endifname);
826: }
827: else {
828: endifname = oldfile ? ifdef1 : ifdef2;
829: fprintf(stdout, "#ifdef %s\n", endifname);
830: }
831: }
832: inifdef = 1+oldfile;
833: }
834:
835: for(i=a;i<=b;i++) {
836: fseek(lb,f[i-1],0);
837: nc = f[i]-f[i-1];
838: if (opt != D_IFDEF)
839: prints(s);
840: col = 0;
841: for(j=0;j<nc;j++) {
842: c = getc(lb);
843: if (c == '\t' && tflag)
844: do
845: putchar(' ');
846: while (++col & 7);
847: else {
848: putchar(c);
849: col++;
850: }
851: }
852: }
853:
854: if (inifdef && !wantelses) {
855: fprintf(stdout, "#endif %s\n", endifname);
856: inifdef = 0;
857: }
858: }
859:
860: #define POW2 /* define only if HALFLONG is 2**n */
861: #define HALFLONG 16
862: #define low(x) (x&((1L<<HALFLONG)-1))
863: #define high(x) (x>>HALFLONG)
864:
865: /*
866: * hashing has the effect of
867: * arranging line in 7-bit bytes and then
868: * summing 1-s complement in 16-bit hunks
869: */
870: readhash(f)
871: register FILE *f;
872: {
873: register long sum;
874: register unsigned shift;
875: register t;
876: register space;
877:
878: sum = 1;
879: space = 0;
880: if(!bflag && !wflag) {
881: if(iflag)
882: for(shift=0;(t=getc(f))!='\n';shift+=7) {
883: if(t==-1)
884: return(0);
885: sum += (long)chrtran[t] << (shift
886: #ifdef POW2
887: &= HALFLONG - 1);
888: #else
889: %= HALFLONG);
890: #endif
891: }
892: else
893: for(shift=0;(t=getc(f))!='\n';shift+=7) {
894: if(t==-1)
895: return(0);
896: sum += (long)t << (shift
897: #ifdef POW2
898: &= HALFLONG - 1);
899: #else
900: %= HALFLONG);
901: #endif
902: }
903: } else {
904: for(shift=0;;) {
905: switch(t=getc(f)) {
906: case -1:
907: return(0);
908: case '\t':
909: case ' ':
910: space++;
911: continue;
912: default:
913: if(space && !wflag) {
914: shift += 7;
915: space = 0;
916: }
917: sum += (long)chrtran[t] << (shift
918: #ifdef POW2
919: &= HALFLONG - 1);
920: #else
921: %= HALFLONG);
922: #endif
923: shift += 7;
924: continue;
925: case '\n':
926: break;
927: }
928: break;
929: }
930: }
931: sum = low(sum) + high(sum);
932: return((short)low(sum) + (short)high(sum));
933: }
934:
935: #include <a.out.h>
936:
937: asciifile(f)
938: FILE *f;
939: {
940: char buf[BUFSIZ];
941: register int cnt;
942: register char *cp;
943:
944: fseek(f, (long)0, 0);
945: cnt = fread(buf, 1, BUFSIZ, f);
946: if (cnt >= sizeof (struct exec)) {
947: struct exec hdr;
948: hdr = *(struct exec *)buf;
949: if (!N_BADMAG(hdr))
950: return (0);
951: }
952: cp = buf;
953: while (--cnt >= 0)
954: if (*cp++ & 0200)
955: return (0);
956: return (1);
957: }
958:
959:
960: /* dump accumulated "context" diff changes */
961: dump_context_vec()
962: {
963: register int a, b, c, d;
964: register char ch;
965: register struct context_vec *cvp = context_vec_start;
966: register int lowa, upb, lowc, upd;
967: register int do_output;
968:
969: if ( cvp > context_vec_ptr )
970: return;
971:
972: lowa = max(1, cvp->a - context);
973: upb = min(len[0], context_vec_ptr->b + context);
974: lowc = max(1, cvp->c - context);
975: upd = min(len[1], context_vec_ptr->d + context);
976:
977: printf("***************\n*** ");
978: range(lowa,upb,",");
979: printf(" ****\n");
980:
981: /*
982: * output changes to the "old" file. The first loop suppresses
983: * output if there were no changes to the "old" file (we'll see
984: * the "old" lines as context in the "new" list).
985: */
986: do_output = 0;
987: for ( ; cvp <= context_vec_ptr; cvp++)
988: if (cvp->a <= cvp->b) {
989: cvp = context_vec_start;
990: do_output++;
991: break;
992: }
993:
994: if ( do_output ) {
995: while (cvp <= context_vec_ptr) {
996: a = cvp->a; b = cvp->b; c = cvp->c; d = cvp->d;
997:
998: if (a <= b && c <= d)
999: ch = 'c';
1000: else
1001: ch = (a <= b) ? 'd' : 'a';
1002:
1003: if (ch == 'a')
1004: fetch(ixold,lowa,b,input[0]," ");
1005: else {
1006: fetch(ixold,lowa,a-1,input[0]," ");
1007: fetch(ixold,a,b,input[0],ch == 'c' ? "! " : "- ");
1008: }
1009: lowa = b + 1;
1010: cvp++;
1011: }
1012: fetch(ixold, b+1, upb, input[0], " ");
1013: }
1014:
1015: /* output changes to the "new" file */
1016: printf("--- ");
1017: range(lowc,upd,",");
1018: printf(" ----\n");
1019:
1020: do_output = 0;
1021: for (cvp = context_vec_start; cvp <= context_vec_ptr; cvp++)
1022: if (cvp->c <= cvp->d) {
1023: cvp = context_vec_start;
1024: do_output++;
1025: break;
1026: }
1027:
1028: if (do_output) {
1029: while (cvp <= context_vec_ptr) {
1030: a = cvp->a; b = cvp->b; c = cvp->c; d = cvp->d;
1031:
1032: if (a <= b && c <= d)
1033: ch = 'c';
1034: else
1035: ch = (a <= b) ? 'd' : 'a';
1036:
1037: if (ch == 'd')
1038: fetch(ixnew,lowc,d,input[1]," ");
1039: else {
1040: fetch(ixnew,lowc,c-1,input[1]," ");
1041: fetch(ixnew,c,d,input[1],ch == 'c' ? "! " : "+ ");
1042: }
1043: lowc = d + 1;
1044: cvp++;
1045: }
1046: fetch(ixnew, d+1, upd, input[1], " ");
1047: }
1048:
1049: context_vec_ptr = context_vec_start - 1;
1050: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.