[comp.os.minix] Fixes & improvements to diff & diffc

morearty@cory.Berkeley.EDU.UUCP (06/04/87)

There is a bug in the (very useful) 'diffc' program recently posted.
(Someone mentioned the bug in a recent posting.)  This article
contains the fix for it.  Also, I have changed the 'diff' program
so that it looks for THREE matching lines instead of one, which
greatly improves its ability to produce a minimal listing of
differences between files.

==================

Following is a hand-done 'diff' on the 'diffc.c' program.  I didn't
save the original and don't feel like looking it up; but if I
remember right, this is the only important change.

	*** old diffc.c, in main() ***
	            newbeg = max(newmin - context, 1);
	            newend = newmax + context;

	!           if (preoldend < newbeg - 1) {
	                if (preoldend >= 0) {
	                    dumphunk();
	                }
	--- new diffc.c ---
	            newbeg = max(newmin - context, 1);
	            newend = newmax + context;

	!           if (preoldend < oldbeg) {
	                if (preoldend >= 0) {
	                    dumphunk();
	                }
==================

And now, the changes for 'diff.c'.  I made extensive changes to this
program for my own use, so the same warning applies -- I hope I
haven't left out any of the important changes.  Let me know if I did.
You can stick the equal_3() routine anywhere in the program; right
below equal_line() would probably be the best place.  And I have
only included below my version of diff(), not the original one, but
I have marked the changed lines.

Note that my changes produce slightly undesirable results in one
case -- if there is a difference right at the end of the files.  For
example, if file 'a' reads

	hello

and file 'b' reads

	hi there
	hello

then instead of producing

	1a1
	> hi there

(or something like that) it produces

	1c1,2
	< hello
	---
	> hi there
	> hello

So who cares; it's still accurate.


+ /* equal_3: return whether THREE pairs of lines are equal */
+
+ int equal_3(struct line *l1, struct line *l2)
+ {
+ 	register int i;
+
+	for (i=0; i<3 && l1 && l2; ++i, l1=l1->l_next, l2=l2->l_next) {
+		if (!equal_line(l1, l2))
+			return 0;
+	}
+	return (i==3);
+ }

*********************

  /* diff procedure */
  void diff(FILE *fp1, FILE *fp2)
  {
	struct f f1, f2;
!	struct line *l1, *s1, *b1, *l2, *s2, *b2;
	register struct line *ll;

	/* initialize windows to empty */
	init_f(&f1, fp1);
	init_f(&f2, fp2);
	/* read first line of each file */
	l1 = next(&f1);
	l2 = next(&f2);
	while (l1 && l2) {
		if (equal_line(l1, l2)) {	/* lines are equal */
  equal:
			advance(&f1);		/* remove lines from windows */
			advance(&f2);
			l1 = next(&f1);		/* read next lines */
			l2 = next(&f2);
			continue;
		}
!		s1 = b1 = l1;
!		s2 = b2 = l2;
+		/* read several more lines, so we have 3 from each file */
+		next(&f1); next(&f1);
+		next(&f2); next(&f2);
		/* start searching */
  search:
		/* read line from file2.  If EOF, exit loop */
		if ((l2 = next(&f2)) == 0)
			continue;
		ll = s1;
+		b2 = b2->l_next;
		do {
!			if (equal_3(ll, b2)) {
				aside(&f1, ll);
+				aside(&f2, b2);
				differ(&f1, &f2);
				goto equal;
			}
		} while (ll = ll->l_next);

		/* read line from file1.  If EOF, exit loop */
		if ((l1 = next(&f1)) == 0)
			continue;
		ll = s2;
+		b1 = b1->l_next;
		do {
!			if (equal_3(ll, b1)) {
				aside(&f2, ll);
+				aside(&f1, b1);
				differ(&f1, &f2);
				goto equal;
			}
		} while (ll = ll->l_next);
		goto search;
	}

	/* one of the files reached EOF */
	if (l1) /* eof on 2 */
		while (next(&f1)) {}
	if (l2)
		while (next(&f2)) {}
	f1.f_ewin = 0;
	f2.f_ewin = 0;
	differ(&f1, &f2);
  }


--
Mike Morearty
ARPA: morearty@cory.Berkeley.EDU	USENET: ucbvax!cory!morearty

allbery@ncoast.UUCP (Brandon Allbery) (06/10/87)

I have the original "diffc" for UNIX available somewhere or other.  It works
fine -- been using it for a few years now -- but is very pre-"new context
diffs", so someone may want to update it.  If there's interest, I think I can
drop in into comp.os.minix.  (Or you can get it from someone archiving the
mod.sources/comp.sources.unix newsgroup.)

++Brandon
-- 
Copyright (C) 1987 Brandon S. Allbery.  Redistribution permitted only if the
	redistributor permits further redistribution.
		 ---- Moderator for comp.sources.misc ----
Brandon S. Allbery	{decvax,cbosgd}!cwruecmp!ncoast!allbery
aXcess Company		{ames,mit-eddie,talcott}!necntc!ncoast!allbery
6615 Center St. #A1-105	necntc!ncoast!allbery@harvard.HARVARD.EDU
Mentor, OH 44060-4101	+01 216 974 9210	(also eddie.MIT.EDU)