xref: /plan9/sys/src/cmd/diff/diffreg.c (revision 3e12c5d1bb89fc02707907988834ef147769ddaf)
1*3e12c5d1SDavid du Colombier #include <u.h>
2*3e12c5d1SDavid du Colombier #include <libc.h>
3*3e12c5d1SDavid du Colombier #include <bio.h>
4*3e12c5d1SDavid du Colombier #include "diff.h"
5*3e12c5d1SDavid du Colombier 
6*3e12c5d1SDavid du Colombier /*	diff - differential file comparison
7*3e12c5d1SDavid du Colombier *
8*3e12c5d1SDavid du Colombier *	Uses an algorithm due to Harold Stone, which finds
9*3e12c5d1SDavid du Colombier *	a pair of longest identical subsequences in the two
10*3e12c5d1SDavid du Colombier *	files.
11*3e12c5d1SDavid du Colombier *
12*3e12c5d1SDavid du Colombier *	The major goal is to generate the match vector J.
13*3e12c5d1SDavid du Colombier *	J[i] is the index of the line in file1 corresponding
14*3e12c5d1SDavid du Colombier *	to line i file0. J[i] = 0 if there is no
15*3e12c5d1SDavid du Colombier *	such line in file1.
16*3e12c5d1SDavid du Colombier *
17*3e12c5d1SDavid du Colombier *	Lines are hashed so as to work in core. All potential
18*3e12c5d1SDavid du Colombier *	matches are located by sorting the lines of each file
19*3e12c5d1SDavid du Colombier *	on the hash (called value). In particular, this
20*3e12c5d1SDavid du Colombier *	collects the equivalence classes in file1 together.
21*3e12c5d1SDavid du Colombier *	Subroutine equiv replaces the value of each line in
22*3e12c5d1SDavid du Colombier *	file0 by the index of the first element of its
23*3e12c5d1SDavid du Colombier *	matching equivalence in (the reordered) file1.
24*3e12c5d1SDavid du Colombier *	To save space equiv squeezes file1 into a single
25*3e12c5d1SDavid du Colombier *	array member in which the equivalence classes
26*3e12c5d1SDavid du Colombier *	are simply concatenated, except that their first
27*3e12c5d1SDavid du Colombier *	members are flagged by changing sign.
28*3e12c5d1SDavid du Colombier *
29*3e12c5d1SDavid du Colombier *	Next the indices that point into member are unsorted into
30*3e12c5d1SDavid du Colombier *	array class according to the original order of file0.
31*3e12c5d1SDavid du Colombier *
32*3e12c5d1SDavid du Colombier *	The cleverness lies in routine stone. This marches
33*3e12c5d1SDavid du Colombier *	through the lines of file0, developing a vector klist
34*3e12c5d1SDavid du Colombier *	of "k-candidates". At step i a k-candidate is a matched
35*3e12c5d1SDavid du Colombier *	pair of lines x,y (x in file0 y in file1) such that
36*3e12c5d1SDavid du Colombier *	there is a common subsequence of lenght k
37*3e12c5d1SDavid du Colombier *	between the first i lines of file0 and the first y
38*3e12c5d1SDavid du Colombier *	lines of file1, but there is no such subsequence for
39*3e12c5d1SDavid du Colombier *	any smaller y. x is the earliest possible mate to y
40*3e12c5d1SDavid du Colombier *	that occurs in such a subsequence.
41*3e12c5d1SDavid du Colombier *
42*3e12c5d1SDavid du Colombier *	Whenever any of the members of the equivalence class of
43*3e12c5d1SDavid du Colombier *	lines in file1 matable to a line in file0 has serial number
44*3e12c5d1SDavid du Colombier *	less than the y of some k-candidate, that k-candidate
45*3e12c5d1SDavid du Colombier *	with the smallest such y is replaced. The new
46*3e12c5d1SDavid du Colombier *	k-candidate is chained (via pred) to the current
47*3e12c5d1SDavid du Colombier *	k-1 candidate so that the actual subsequence can
48*3e12c5d1SDavid du Colombier *	be recovered. When a member has serial number greater
49*3e12c5d1SDavid du Colombier *	that the y of all k-candidates, the klist is extended.
50*3e12c5d1SDavid du Colombier *	At the end, the longest subsequence is pulled out
51*3e12c5d1SDavid du Colombier *	and placed in the array J by unravel.
52*3e12c5d1SDavid du Colombier *
53*3e12c5d1SDavid du Colombier *	With J in hand, the matches there recorded are
54*3e12c5d1SDavid du Colombier *	check'ed against reality to assure that no spurious
55*3e12c5d1SDavid du Colombier *	matches have crept in due to hashing. If they have,
56*3e12c5d1SDavid du Colombier *	they are broken, and "jackpot " is recorded--a harmless
57*3e12c5d1SDavid du Colombier *	matter except that a true match for a spuriously
58*3e12c5d1SDavid du Colombier *	mated line may now be unnecessarily reported as a change.
59*3e12c5d1SDavid du Colombier *
60*3e12c5d1SDavid du Colombier *	Much of the complexity of the program comes simply
61*3e12c5d1SDavid du Colombier *	from trying to minimize core utilization and
62*3e12c5d1SDavid du Colombier *	maximize the range of doable problems by dynamically
63*3e12c5d1SDavid du Colombier *	allocating what is needed and reusing what is not.
64*3e12c5d1SDavid du Colombier *	The core requirements for problems larger than somewhat
65*3e12c5d1SDavid du Colombier *	are (in words) 2*length(file0) + length(file1) +
66*3e12c5d1SDavid du Colombier *	3*(number of k-candidates installed),  typically about
67*3e12c5d1SDavid du Colombier *	6n words for files of length n.
68*3e12c5d1SDavid du Colombier */
69*3e12c5d1SDavid du Colombier /* TIDY THIS UP */
70*3e12c5d1SDavid du Colombier struct cand {
71*3e12c5d1SDavid du Colombier 	int x;
72*3e12c5d1SDavid du Colombier 	int y;
73*3e12c5d1SDavid du Colombier 	int pred;
74*3e12c5d1SDavid du Colombier } cand;
75*3e12c5d1SDavid du Colombier struct line {
76*3e12c5d1SDavid du Colombier 	int serial;
77*3e12c5d1SDavid du Colombier 	int value;
78*3e12c5d1SDavid du Colombier } *file[2], line;
79*3e12c5d1SDavid du Colombier int len[2];
80*3e12c5d1SDavid du Colombier struct line *sfile[2];	/*shortened by pruning common prefix and suffix*/
81*3e12c5d1SDavid du Colombier int slen[2];
82*3e12c5d1SDavid du Colombier int pref, suff;	/*length of prefix and suffix*/
83*3e12c5d1SDavid du Colombier int *class;	/*will be overlaid on file[0]*/
84*3e12c5d1SDavid du Colombier int *member;	/*will be overlaid on file[1]*/
85*3e12c5d1SDavid du Colombier int *klist;		/*will be overlaid on file[0] after class*/
86*3e12c5d1SDavid du Colombier struct cand *clist;	/* merely a free storage pot for candidates */
87*3e12c5d1SDavid du Colombier int clen;
88*3e12c5d1SDavid du Colombier int *J;		/*will be overlaid on class*/
89*3e12c5d1SDavid du Colombier long *ixold;	/*will be overlaid on klist*/
90*3e12c5d1SDavid du Colombier long *ixnew;	/*will be overlaid on file[1]*/
91*3e12c5d1SDavid du Colombier /* END OF SOME TIDYING */
92*3e12c5d1SDavid du Colombier 
93*3e12c5d1SDavid du Colombier static void
94*3e12c5d1SDavid du Colombier sort(struct line *a, int n)	/*shellsort CACM #201*/
95*3e12c5d1SDavid du Colombier {
96*3e12c5d1SDavid du Colombier 	int m;
97*3e12c5d1SDavid du Colombier 	struct line *ai, *aim, *j, *k;
98*3e12c5d1SDavid du Colombier 	struct line w;
99*3e12c5d1SDavid du Colombier 	int i;
100*3e12c5d1SDavid du Colombier 
101*3e12c5d1SDavid du Colombier 	m = 0;
102*3e12c5d1SDavid du Colombier 	for (i = 1; i <= n; i *= 2)
103*3e12c5d1SDavid du Colombier 		m = 2*i - 1;
104*3e12c5d1SDavid du Colombier 	for (m /= 2; m != 0; m /= 2) {
105*3e12c5d1SDavid du Colombier 		k = a+(n-m);
106*3e12c5d1SDavid du Colombier 		for (j = a+1; j <= k; j++) {
107*3e12c5d1SDavid du Colombier 			ai = j;
108*3e12c5d1SDavid du Colombier 			aim = ai+m;
109*3e12c5d1SDavid du Colombier 			do {
110*3e12c5d1SDavid du Colombier 				if (aim->value > ai->value ||
111*3e12c5d1SDavid du Colombier 				   aim->value == ai->value &&
112*3e12c5d1SDavid du Colombier 				   aim->serial > ai->serial)
113*3e12c5d1SDavid du Colombier 					break;
114*3e12c5d1SDavid du Colombier 				w = *ai;
115*3e12c5d1SDavid du Colombier 				*ai = *aim;
116*3e12c5d1SDavid du Colombier 				*aim = w;
117*3e12c5d1SDavid du Colombier 
118*3e12c5d1SDavid du Colombier 				aim = ai;
119*3e12c5d1SDavid du Colombier 				ai -= m;
120*3e12c5d1SDavid du Colombier 			} while (ai > a && aim >= ai);
121*3e12c5d1SDavid du Colombier 		}
122*3e12c5d1SDavid du Colombier 	}
123*3e12c5d1SDavid du Colombier }
124*3e12c5d1SDavid du Colombier 
125*3e12c5d1SDavid du Colombier static void
126*3e12c5d1SDavid du Colombier unsort(struct line *f, int l, int *b)
127*3e12c5d1SDavid du Colombier {
128*3e12c5d1SDavid du Colombier 	int *a;
129*3e12c5d1SDavid du Colombier 	int i;
130*3e12c5d1SDavid du Colombier 
131*3e12c5d1SDavid du Colombier 	a = MALLOC(int, (l+1));
132*3e12c5d1SDavid du Colombier 	for(i=1;i<=l;i++)
133*3e12c5d1SDavid du Colombier 		a[f[i].serial] = f[i].value;
134*3e12c5d1SDavid du Colombier 	for(i=1;i<=l;i++)
135*3e12c5d1SDavid du Colombier 		b[i] = a[i];
136*3e12c5d1SDavid du Colombier 	FREE(a);
137*3e12c5d1SDavid du Colombier }
138*3e12c5d1SDavid du Colombier 
139*3e12c5d1SDavid du Colombier static void
140*3e12c5d1SDavid du Colombier prune(void)
141*3e12c5d1SDavid du Colombier {
142*3e12c5d1SDavid du Colombier 	int i,j;
143*3e12c5d1SDavid du Colombier 
144*3e12c5d1SDavid du Colombier 	for(pref=0;pref<len[0]&&pref<len[1]&&
145*3e12c5d1SDavid du Colombier 		file[0][pref+1].value==file[1][pref+1].value;
146*3e12c5d1SDavid du Colombier 		pref++ ) ;
147*3e12c5d1SDavid du Colombier 	for(suff=0;suff<len[0]-pref&&suff<len[1]-pref&&
148*3e12c5d1SDavid du Colombier 		file[0][len[0]-suff].value==file[1][len[1]-suff].value;
149*3e12c5d1SDavid du Colombier 		suff++) ;
150*3e12c5d1SDavid du Colombier 	for(j=0;j<2;j++) {
151*3e12c5d1SDavid du Colombier 		sfile[j] = file[j]+pref;
152*3e12c5d1SDavid du Colombier 		slen[j] = len[j]-pref-suff;
153*3e12c5d1SDavid du Colombier 		for(i=0;i<=slen[j];i++)
154*3e12c5d1SDavid du Colombier 			sfile[j][i].serial = i;
155*3e12c5d1SDavid du Colombier 	}
156*3e12c5d1SDavid du Colombier }
157*3e12c5d1SDavid du Colombier 
158*3e12c5d1SDavid du Colombier static void
159*3e12c5d1SDavid du Colombier equiv(struct line *a, int n, struct line *b, int m, int *c)
160*3e12c5d1SDavid du Colombier {
161*3e12c5d1SDavid du Colombier 	int i, j;
162*3e12c5d1SDavid du Colombier 
163*3e12c5d1SDavid du Colombier 	i = j = 1;
164*3e12c5d1SDavid du Colombier 	while(i<=n && j<=m) {
165*3e12c5d1SDavid du Colombier 		if(a[i].value < b[j].value)
166*3e12c5d1SDavid du Colombier 			a[i++].value = 0;
167*3e12c5d1SDavid du Colombier 		else if(a[i].value == b[j].value)
168*3e12c5d1SDavid du Colombier 			a[i++].value = j;
169*3e12c5d1SDavid du Colombier 		else
170*3e12c5d1SDavid du Colombier 			j++;
171*3e12c5d1SDavid du Colombier 	}
172*3e12c5d1SDavid du Colombier 	while(i <= n)
173*3e12c5d1SDavid du Colombier 		a[i++].value = 0;
174*3e12c5d1SDavid du Colombier 	b[m+1].value = 0;
175*3e12c5d1SDavid du Colombier 	j = 0;
176*3e12c5d1SDavid du Colombier 	while(++j <= m) {
177*3e12c5d1SDavid du Colombier 		c[j] = -b[j].serial;
178*3e12c5d1SDavid du Colombier 		while(b[j+1].value == b[j].value) {
179*3e12c5d1SDavid du Colombier 			j++;
180*3e12c5d1SDavid du Colombier 			c[j] = b[j].serial;
181*3e12c5d1SDavid du Colombier 		}
182*3e12c5d1SDavid du Colombier 	}
183*3e12c5d1SDavid du Colombier 	c[j] = -1;
184*3e12c5d1SDavid du Colombier }
185*3e12c5d1SDavid du Colombier 
186*3e12c5d1SDavid du Colombier static int
187*3e12c5d1SDavid du Colombier newcand(int x, int  y, int pred)
188*3e12c5d1SDavid du Colombier {
189*3e12c5d1SDavid du Colombier 	struct cand *q;
190*3e12c5d1SDavid du Colombier 
191*3e12c5d1SDavid du Colombier 	clist = REALLOC(clist, struct cand, (clen+1));
192*3e12c5d1SDavid du Colombier 	q = clist + clen;
193*3e12c5d1SDavid du Colombier 	q->x = x;
194*3e12c5d1SDavid du Colombier 	q->y = y;
195*3e12c5d1SDavid du Colombier 	q->pred = pred;
196*3e12c5d1SDavid du Colombier 	return clen++;
197*3e12c5d1SDavid du Colombier }
198*3e12c5d1SDavid du Colombier 
199*3e12c5d1SDavid du Colombier static int
200*3e12c5d1SDavid du Colombier search(int *c, int k, int y)
201*3e12c5d1SDavid du Colombier {
202*3e12c5d1SDavid du Colombier 	int i, j, l;
203*3e12c5d1SDavid du Colombier 	int t;
204*3e12c5d1SDavid du Colombier 
205*3e12c5d1SDavid du Colombier 	if(clist[c[k]].y < y)	/*quick look for typical case*/
206*3e12c5d1SDavid du Colombier 		return k+1;
207*3e12c5d1SDavid du Colombier 	i = 0;
208*3e12c5d1SDavid du Colombier 	j = k+1;
209*3e12c5d1SDavid du Colombier 	while((l=(i+j)/2) > i) {
210*3e12c5d1SDavid du Colombier 		t = clist[c[l]].y;
211*3e12c5d1SDavid du Colombier 		if(t > y)
212*3e12c5d1SDavid du Colombier 			j = l;
213*3e12c5d1SDavid du Colombier 		else if(t < y)
214*3e12c5d1SDavid du Colombier 			i = l;
215*3e12c5d1SDavid du Colombier 		else
216*3e12c5d1SDavid du Colombier 			return l;
217*3e12c5d1SDavid du Colombier 	}
218*3e12c5d1SDavid du Colombier 	return l+1;
219*3e12c5d1SDavid du Colombier }
220*3e12c5d1SDavid du Colombier 
221*3e12c5d1SDavid du Colombier static int
222*3e12c5d1SDavid du Colombier stone(int *a, int n, int *b, int *c)
223*3e12c5d1SDavid du Colombier {
224*3e12c5d1SDavid du Colombier 	int i, k,y;
225*3e12c5d1SDavid du Colombier 	int j, l;
226*3e12c5d1SDavid du Colombier 	int oldc, tc;
227*3e12c5d1SDavid du Colombier 	int oldl;
228*3e12c5d1SDavid du Colombier 
229*3e12c5d1SDavid du Colombier 	k = 0;
230*3e12c5d1SDavid du Colombier 	c[0] = newcand(0,0,0);
231*3e12c5d1SDavid du Colombier 	for(i=1; i<=n; i++) {
232*3e12c5d1SDavid du Colombier 		j = a[i];
233*3e12c5d1SDavid du Colombier 		if(j==0)
234*3e12c5d1SDavid du Colombier 			continue;
235*3e12c5d1SDavid du Colombier 		y = -b[j];
236*3e12c5d1SDavid du Colombier 		oldl = 0;
237*3e12c5d1SDavid du Colombier 		oldc = c[0];
238*3e12c5d1SDavid du Colombier 		do {
239*3e12c5d1SDavid du Colombier 			if(y <= clist[oldc].y)
240*3e12c5d1SDavid du Colombier 				continue;
241*3e12c5d1SDavid du Colombier 			l = search(c, k, y);
242*3e12c5d1SDavid du Colombier 			if(l!=oldl+1)
243*3e12c5d1SDavid du Colombier 				oldc = c[l-1];
244*3e12c5d1SDavid du Colombier 			if(l<=k) {
245*3e12c5d1SDavid du Colombier 				if(clist[c[l]].y <= y)
246*3e12c5d1SDavid du Colombier 					continue;
247*3e12c5d1SDavid du Colombier 				tc = c[l];
248*3e12c5d1SDavid du Colombier 				c[l] = newcand(i,y,oldc);
249*3e12c5d1SDavid du Colombier 				oldc = tc;
250*3e12c5d1SDavid du Colombier 				oldl = l;
251*3e12c5d1SDavid du Colombier 			} else {
252*3e12c5d1SDavid du Colombier 				c[l] = newcand(i,y,oldc);
253*3e12c5d1SDavid du Colombier 				k++;
254*3e12c5d1SDavid du Colombier 				break;
255*3e12c5d1SDavid du Colombier 			}
256*3e12c5d1SDavid du Colombier 		} while((y=b[++j]) > 0);
257*3e12c5d1SDavid du Colombier 	}
258*3e12c5d1SDavid du Colombier 	return k;
259*3e12c5d1SDavid du Colombier }
260*3e12c5d1SDavid du Colombier 
261*3e12c5d1SDavid du Colombier static void
262*3e12c5d1SDavid du Colombier unravel(int p)
263*3e12c5d1SDavid du Colombier {
264*3e12c5d1SDavid du Colombier 	int i;
265*3e12c5d1SDavid du Colombier 	struct cand *q;
266*3e12c5d1SDavid du Colombier 
267*3e12c5d1SDavid du Colombier 	for(i=0; i<=len[0]; i++) {
268*3e12c5d1SDavid du Colombier 		if (i <= pref)
269*3e12c5d1SDavid du Colombier 			J[i] = i;
270*3e12c5d1SDavid du Colombier 		else if (i > len[0]-suff)
271*3e12c5d1SDavid du Colombier 			J[i] = i+len[1]-len[0];
272*3e12c5d1SDavid du Colombier 		else
273*3e12c5d1SDavid du Colombier 			J[i] = 0;
274*3e12c5d1SDavid du Colombier 	}
275*3e12c5d1SDavid du Colombier 	for(q=clist+p;q->y!=0;q=clist+q->pred)
276*3e12c5d1SDavid du Colombier 		J[q->x+pref] = q->y+pref;
277*3e12c5d1SDavid du Colombier }
278*3e12c5d1SDavid du Colombier 
279*3e12c5d1SDavid du Colombier static void
280*3e12c5d1SDavid du Colombier output(void)
281*3e12c5d1SDavid du Colombier {
282*3e12c5d1SDavid du Colombier 	int m, i0, i1, j0, j1;
283*3e12c5d1SDavid du Colombier 
284*3e12c5d1SDavid du Colombier 	m = len[0];
285*3e12c5d1SDavid du Colombier 	J[0] = 0;
286*3e12c5d1SDavid du Colombier 	J[m+1] = len[1]+1;
287*3e12c5d1SDavid du Colombier 	if (mode != 'e') {
288*3e12c5d1SDavid du Colombier 		for (i0 = 1; i0 <= m; i0 = i1+1) {
289*3e12c5d1SDavid du Colombier 			while (i0 <= m && J[i0] == J[i0-1]+1)
290*3e12c5d1SDavid du Colombier 				i0++;
291*3e12c5d1SDavid du Colombier 			j0 = J[i0-1]+1;
292*3e12c5d1SDavid du Colombier 			i1 = i0-1;
293*3e12c5d1SDavid du Colombier 			while (i1 < m && J[i1+1] == 0)
294*3e12c5d1SDavid du Colombier 				i1++;
295*3e12c5d1SDavid du Colombier 			j1 = J[i1+1]-1;
296*3e12c5d1SDavid du Colombier 			J[i1] = j1;
297*3e12c5d1SDavid du Colombier 			change(i0, i1, j0, j1);
298*3e12c5d1SDavid du Colombier 		}
299*3e12c5d1SDavid du Colombier 	}
300*3e12c5d1SDavid du Colombier 	else {
301*3e12c5d1SDavid du Colombier 		for (i0 = m; i0 >= 1; i0 = i1-1) {
302*3e12c5d1SDavid du Colombier 			while (i0 >= 1 && J[i0] == J[i0+1]-1 && J[i0])
303*3e12c5d1SDavid du Colombier 				i0--;
304*3e12c5d1SDavid du Colombier 			j0 = J[i0+1]-1;
305*3e12c5d1SDavid du Colombier 			i1 = i0+1;
306*3e12c5d1SDavid du Colombier 			while (i1 > 1 && J[i1-1] == 0)
307*3e12c5d1SDavid du Colombier 				i1--;
308*3e12c5d1SDavid du Colombier 			j1 = J[i1-1]+1;
309*3e12c5d1SDavid du Colombier 			J[i1] = j1;
310*3e12c5d1SDavid du Colombier 			change(i1 , i0, j1, j0);
311*3e12c5d1SDavid du Colombier 		}
312*3e12c5d1SDavid du Colombier 	}
313*3e12c5d1SDavid du Colombier 	if (m == 0)
314*3e12c5d1SDavid du Colombier 		change(1, 0, 1, len[1]);
315*3e12c5d1SDavid du Colombier }
316*3e12c5d1SDavid du Colombier 
317*3e12c5d1SDavid du Colombier void
318*3e12c5d1SDavid du Colombier diffreg(char *f, char *t)
319*3e12c5d1SDavid du Colombier {
320*3e12c5d1SDavid du Colombier 	Biobuf *b0, *b1;
321*3e12c5d1SDavid du Colombier 	int k;
322*3e12c5d1SDavid du Colombier 
323*3e12c5d1SDavid du Colombier 	b0 = prepare(0, f);
324*3e12c5d1SDavid du Colombier 	if (!b0)
325*3e12c5d1SDavid du Colombier 		return;
326*3e12c5d1SDavid du Colombier 	b1 = prepare(1, t);
327*3e12c5d1SDavid du Colombier 	if (!b1) {
328*3e12c5d1SDavid du Colombier 		FREE(file[0]);
329*3e12c5d1SDavid du Colombier 		Bclose(b0);
330*3e12c5d1SDavid du Colombier 		return;
331*3e12c5d1SDavid du Colombier 	}
332*3e12c5d1SDavid du Colombier 	clen = 0;
333*3e12c5d1SDavid du Colombier 	prune();
334*3e12c5d1SDavid du Colombier 	sort(sfile[0], slen[0]);
335*3e12c5d1SDavid du Colombier 	sort(sfile[1], slen[1]);
336*3e12c5d1SDavid du Colombier 
337*3e12c5d1SDavid du Colombier 	member = (int *)file[1];
338*3e12c5d1SDavid du Colombier 	equiv(sfile[0], slen[0], sfile[1], slen[1], member);
339*3e12c5d1SDavid du Colombier 	member = REALLOC(member, int, slen[1]+2);
340*3e12c5d1SDavid du Colombier 
341*3e12c5d1SDavid du Colombier 	class = (int *)file[0];
342*3e12c5d1SDavid du Colombier 	unsort(sfile[0], slen[0], class);
343*3e12c5d1SDavid du Colombier 	class = REALLOC(class, int, slen[0]+2);
344*3e12c5d1SDavid du Colombier 
345*3e12c5d1SDavid du Colombier 	klist = MALLOC(int, slen[0]+2);
346*3e12c5d1SDavid du Colombier 	clist = MALLOC(struct cand, 1);
347*3e12c5d1SDavid du Colombier 	k = stone(class, slen[0], member, klist);
348*3e12c5d1SDavid du Colombier 	FREE(member);
349*3e12c5d1SDavid du Colombier 	FREE(class);
350*3e12c5d1SDavid du Colombier 
351*3e12c5d1SDavid du Colombier 	J = MALLOC(int, len[0]+2);
352*3e12c5d1SDavid du Colombier 	unravel(klist[k]);
353*3e12c5d1SDavid du Colombier 	FREE(clist);
354*3e12c5d1SDavid du Colombier 	FREE(klist);
355*3e12c5d1SDavid du Colombier 
356*3e12c5d1SDavid du Colombier 	ixold = MALLOC(long, len[0]+2);
357*3e12c5d1SDavid du Colombier 	ixnew = MALLOC(long, len[1]+2);
358*3e12c5d1SDavid du Colombier 	Bseek(b0, 0, 0); Bseek(b1, 0, 0);
359*3e12c5d1SDavid du Colombier 	check(b0, b1);
360*3e12c5d1SDavid du Colombier 	output();
361*3e12c5d1SDavid du Colombier 	FREE(J); FREE(ixold); FREE(ixnew);
362*3e12c5d1SDavid du Colombier 	Bclose(b0); Bclose(b1);			/* ++++ */
363*3e12c5d1SDavid du Colombier }
364