|
|
1.1 ! root 1: /* ! 2: * Parts of diff that depend on the minimal common ! 3: * subsequence algorithm of Hirschberg. ! 4: */ ! 5: ! 6: #include "diff.h" ! 7: #include <mdata.h> ! 8: ! 9: #define U unsigned /* Short form */ ! 10: #define NSBRK 512 /* Size of each sbrk -- allocator */ ! 11: typedef unsigned int hash_t; ! 12: #if NBPCHAR==16 /* Short address machines */ ! 13: #define LAST ((vaddr_t)MININT) ! 14: typedef unsigned short vaddr_t; ! 15: #else ! 16: #define LAST ((vaddr_t)MINLONG) ! 17: typedef unsigned long vaddr_t; ! 18: #endif ! 19: /* Assume MININT is a single bit */ ! 20: ! 21: static char partial[] = "diff: partial line omitted from %s\n"; ! 22: static char jackpot[] = "Jackpot %d %d\n"; ! 23: ! 24: /* ! 25: * Tables for the table-driven CRC16 algorithm. ! 26: * This is used as the hash of the input lines ! 27: * and should be relatively uniform statistically. ! 28: */ ! 29: static hash_t crctab1[] = { ! 30: 0000000, 0140301, 0140601, 0000500, ! 31: 0141401, 0001700, 0001200, 0141101, ! 32: 0143001, 0003300, 0003600, 0143501, ! 33: 0002400, 0142701, 0142201, 0002100, ! 34: }; ! 35: ! 36: static hash_t crctab2[] = { ! 37: 0000000, 0146001, 0154001, 0012000, ! 38: 0170001, 0036000, 0024000, 0162001, ! 39: 0120001, 0066000, 0074000, 0132001, ! 40: 0050000, 0116001, 0104001, 0043000, ! 41: }; ! 42: ! 43: typedef struct LINES { ! 44: vaddr_t l_num; ! 45: hash_t l_hash; ! 46: } LINES; ! 47: ! 48: /* ! 49: * A K-candidate entry ! 50: */ ! 51: typedef struct CAND { ! 52: vaddr_t a; ! 53: vaddr_t b; ! 54: struct CAND *prev; ! 55: } CAND; ! 56: ! 57: int compar(); ! 58: hash_t inhash(); ! 59: CAND *candidate(); ! 60: ! 61: char line1[LSIZE]; /* First file's input line buffer */ ! 62: char line2[LSIZE]; ! 63: char nomem[] = "Out of memory"; ! 64: ! 65: int *allrp; ! 66: int *allep; ! 67: ! 68: /* ! 69: * Called to invoke heurist version of ! 70: * diff. ! 71: */ ! 72: diffh(args) ! 73: char **args; ! 74: { ! 75: execv("/usr/lib/diffh", args); ! 76: cerr("-h doesn't work"); ! 77: } ! 78: ! 79: /* ! 80: * Routine is given two file streams and ! 81: * it produces the minimal list of ! 82: * differences by the Hirschberg algorithm ! 83: */ ! 84: diff(fp1, fp2) ! 85: FILE *fp1, *fp2; ! 86: { ! 87: register hash_t hash; ! 88: register vaddr_t ln1; ! 89: register vaddr_t ln2; ! 90: register LINES *V; ! 91: register vaddr_t *P; ! 92: register vaddr_t *E; ! 93: register vaddr_t *K; ! 94: register vaddr_t *J; ! 95: ! 96: /* ! 97: * Calculate the hash tables for ! 98: * the second file ! 99: * and sort with hash as primary key, ! 100: * line-number secondary. ! 101: */ ! 102: V = (LINES *)alloc(sizeof (LINES)); ! 103: V->l_num = V->l_hash = 0; /* unneeded? */ ! 104: ln2 = 0; ! 105: while ((hash = inhash(fp2, fn2)) != 0) { ! 106: register LINES *Vp; ! 107: ! 108: Vp = (LINES *)alloc(sizeof (LINES)); ! 109: Vp->l_num = ++ln2; ! 110: Vp->l_hash = hash; ! 111: } ! 112: qsort(V+1, (int)ln2, sizeof (LINES), compar); ! 113: /* ! 114: * Read first file, building ! 115: * a table per line of ! 116: * pointers to the first elements ! 117: * of the hash-equivalent list in file2. ! 118: */ ! 119: P = (vaddr_t *)alloc(sizeof (vaddr_t)); ! 120: for (ln1=0; (hash = inhash(fp1, fn1))!=0; ln1++) { ! 121: register vaddr_t *Pp; ! 122: register vaddr_t lo, mid, hi; ! 123: ! 124: Pp = (vaddr_t *)alloc(sizeof (vaddr_t)); ! 125: lo = 1; ! 126: hi = ln2; ! 127: while (lo <= hi) { ! 128: mid = (lo+hi)/2; ! 129: if (hash <= V[mid].l_hash) ! 130: hi = mid-1; else ! 131: lo = mid+1; ! 132: } ! 133: if (hi!=0 && V[hi].l_hash==V[hi+1].l_hash) ! 134: cerr("fatal search botch"); ! 135: if (hash == V[++hi].l_hash) ! 136: *Pp = hi; else ! 137: *Pp = 0; ! 138: } ! 139: /* ! 140: * Throw away the hash values. ! 141: * Mark the last line of each hash-equivalent ! 142: * class of lines and fake line 0. ! 143: */ ! 144: { ! 145: register vaddr_t *Ep, *eEp; ! 146: register LINES *Vp; ! 147: ! 148: E = V; ! 149: E[0] = LAST; ! 150: for (Ep=E+1, Vp=V+1, eEp=&E[ln2]; Ep <= eEp; Vp++, Ep++) { ! 151: *Ep = Vp->l_num; ! 152: if (Ep==eEp || Vp->l_hash!=(Vp+1)->l_hash) ! 153: *Ep |= LAST; ! 154: } ! 155: } ! 156: { ! 157: register int i; ! 158: register vaddr_t *Pp; ! 159: ! 160: Pp = &E[ln2+3]; ! 161: for (i=1; i<=ln1; i++) ! 162: Pp[i] = P[i]; ! 163: P = Pp; ! 164: ralloc(&Pp[ln1+1]); ! 165: } ! 166: /* ! 167: * Set up to build list of K-candidates for ! 168: * all k. The K table overwrites P (when ! 169: * we add K[k+2] to the table we no longer ! 170: * need P[k]. ! 171: */ ! 172: { ! 173: register vaddr_t k; ! 174: register vaddr_t i; ! 175: register CAND *cp; ! 176: ! 177: K = &E[ln2+1]; ! 178: K[0] = candidate((vaddr_t)0, (vaddr_t)0, NULL); ! 179: K[1] = candidate(ln1+1, ln2+1, NULL); ! 180: k = 0; ! 181: for (i=1; i<=ln1; i++) { ! 182: if (P[i] != 0) ! 183: k = merge(K, k, i, E, P[i]); ! 184: } ! 185: /* ! 186: * `k' is the length of the maximal ! 187: * common subsequence, thus K[k] points ! 188: * to the list of lines in the subsequnce. ! 189: * Store the list in `J' in a handier ! 190: * format. E, K (all but K[k]) and P ! 191: * are redundant so J overlays them. ! 192: */ ! 193: cp = K[k]; ! 194: J = E; ! 195: for (i=0; i<=ln1; i++) ! 196: J[i] = 0; ! 197: J[ln1+1] = ln2+1; /* fence */ ! 198: while (cp != NULL) { ! 199: J[cp->a] = cp->b; ! 200: cp = cp->prev; ! 201: } ! 202: } ! 203: { ! 204: register vaddr_t i, j, k, l; ! 205: ! 206: /* ! 207: * Matching lines are now stored as pairs ! 208: * (i, J[i]), J[i]!=0. Produce output ! 209: * scripts and look for jackpots. ! 210: */ ! 211: rewind(fp1); ! 212: rewind(fp2); ! 213: fgets(line1, LSIZE, fp1); ! 214: fgets(line2, LSIZE, fp2); ! 215: for (i=j=1; i<=ln1 || j<=ln2; ) { ! 216: if (j == J[i]) { ! 217: if (!(*equal)(line1, line2)) { ! 218: /* ! 219: * This can be avoided at ! 220: * the expense of another ! 221: * pass. So we settle for this ! 222: * potentially non-minimal result. ! 223: * Possibly this printout could ! 224: * disappear. ! 225: */ ! 226: fprintf(stderr, jackpot, i, j); ! 227: change( (U)i, (U)i, (U)j, (U)j ); ! 228: text1(line1); ! 229: prsep(); ! 230: text2(line2); ! 231: prend(); ! 232: } else ! 233: text(line1); ! 234: i++; ! 235: fgets(line1, LSIZE, fp1); ! 236: j++; ! 237: fgets(line2, LSIZE, fp2); ! 238: continue; ! 239: } ! 240: for (k=i; J[k]==0; k++) ! 241: ; ! 242: l = J[k]; ! 243: if (i == k) ! 244: append( (U)i, (U)j, (U)(l-1) ); ! 245: else if (j == l) ! 246: delete( (U)i, (U)(k-1), (U)j ); ! 247: else ! 248: change( (U)i, (U)(k-1), (U)j, (U)(l-1) ); ! 249: while (i != k) { ! 250: text1(line1); ! 251: i++; ! 252: fgets(line1, LSIZE, fp1); ! 253: } ! 254: prsep(); ! 255: while (j != l) { ! 256: text2(line2); ! 257: j++; ! 258: fgets(line2, LSIZE, fp2); ! 259: } ! 260: prend(); ! 261: } ! 262: } ! 263: } ! 264: ! 265: /* ! 266: * Read input characters and hash for each ! 267: * line. Return the hash value computed ! 268: * using CRC-16 methods. A zero value ! 269: * means EOF or error and thus will not ! 270: * be returned as a hash value. ! 271: */ ! 272: hash_t ! 273: inhash(fp, fn) ! 274: register FILE *fp; ! 275: char *fn; ! 276: { ! 277: register int c; ! 278: register int tmp; ! 279: register int hash; ! 280: register int space; ! 281: ! 282: space = hash = 0; ! 283: while ((c = getc(fp)) != '\n') { ! 284: if (c == EOF) { ! 285: if (hash != 0) ! 286: fprintf(stderr, partial, fn); ! 287: return (0); ! 288: } ! 289: if (bflag && (c==' ' || c=='\t')) { ! 290: space++; ! 291: continue; ! 292: } ! 293: compute: ! 294: tmp = c^hash; ! 295: hash = (hash>>8) ^ crctab1[tmp&017] ^ crctab2[(tmp&0360)>>4]; ! 296: if (space) { ! 297: c = ' '; ! 298: space = 0; ! 299: goto compute; ! 300: } ! 301: } ! 302: if (hash == 0) ! 303: hash++; ! 304: return (hash); ! 305: } ! 306: ! 307: /* ! 308: * Sort comparison routine. ! 309: * Hash value is primary key, ! 310: * line number secondary. ! 311: */ ! 312: compar(a, b) ! 313: register LINES *a, *b; ! 314: { ! 315: if (a->l_hash < b->l_hash) ! 316: return (-1); ! 317: if (a->l_hash > b->l_hash) ! 318: return (1); ! 319: if (a->l_num < b->l_num) ! 320: return (-1); ! 321: if (a->l_num > b->l_num) ! 322: return (1); ! 323: return (0); ! 324: } ! 325: ! 326: /* ! 327: * Build an entry in the K-candidates ! 328: * table ! 329: */ ! 330: CAND * ! 331: candidate(a, b, prev) ! 332: vaddr_t a; ! 333: vaddr_t b; ! 334: CAND *prev; ! 335: { ! 336: register CAND *v; ! 337: ! 338: v = (CAND *)alloc(sizeof(CAND)); ! 339: v->a = a; ! 340: v->b = b; ! 341: v->prev = prev; ! 342: return (v); ! 343: } ! 344: ! 345: /* ! 346: * The merge step, called for ! 347: * each index in file 1. ! 348: * `k' is index of last filled element ! 349: * of `K', `i' is current index in ! 350: * file 1, and `p' is first element ! 351: * of class of lines in file 2 ! 352: * equivalent to line `i' by hash value. ! 353: */ ! 354: merge(K, k, i, E, p) ! 355: CAND **K; ! 356: vaddr_t k, i; ! 357: vaddr_t *E; ! 358: vaddr_t p; ! 359: { ! 360: register vaddr_t r; ! 361: register CAND *c; ! 362: ! 363: r = 0; ! 364: c = K[0]; ! 365: do { ! 366: register vaddr_t lo, mid, hi; ! 367: register vaddr_t j; ! 368: ! 369: j = E[p]&~LAST; ! 370: lo = r; ! 371: hi = k; ! 372: if (K[lo]->b >= j) ! 373: continue; ! 374: while (lo <= hi) { ! 375: mid = (lo+hi)/2; ! 376: if (j <= K[mid]->b) ! 377: hi = mid-1; else ! 378: lo = mid+1; ! 379: } ! 380: if (K[hi]->b<j && j<=K[hi+1]->b) { ! 381: if (j < K[hi+1]->b) { ! 382: #if SIMUL ! 383: register CAND *prev; ! 384: prev = K[hi]; ! 385: #endif ! 386: K[r] = c; ! 387: r = hi+1; ! 388: #if SIMUL ! 389: c = candidate(i, j, prev); ! 390: #else ! 391: c = candidate(i, j, K[hi]); ! 392: #endif ! 393: } ! 394: if (hi == k) { ! 395: K[k+2] = K[k+1]; ! 396: k++; ! 397: break; ! 398: } ! 399: } ! 400: } while (!(E[p++] & LAST)); ! 401: K[r] = c; ! 402: return (k); ! 403: } ! 404: ! 405: /* ! 406: * This allocator simply does sbrk calls so that ! 407: * it can grow (easily) the space as it needs without ! 408: * threading it. It also checks and prints and error ! 409: * if out of space. ! 410: */ ! 411: char * ! 412: alloc(size) ! 413: register unsigned size; ! 414: { ! 415: register int *cp; ! 416: ! 417: if ((size = (size+sizeof(int)-1)/sizeof(int)) == 0) ! 418: cerr(nomem); ! 419: if (allrp==NULL || allrp+size>=allep) { ! 420: if ((allep = (int *)sbrk(NSBRK)) == NULL) ! 421: cerr(nomem); ! 422: if (allrp == NULL) ! 423: allrp = allep; ! 424: allep += NSBRK/sizeof(int); ! 425: } ! 426: cp = allrp; ! 427: allrp += size; ! 428: return (cp); ! 429: } ! 430: ! 431: /* ! 432: * Like the brk system call, reset ! 433: * current end of memory to `ep'. ! 434: */ ! 435: ralloc(ep) ! 436: register int *ep; ! 437: { ! 438: allrp = ep; ! 439: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.