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