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