|
|
1.1 ! root 1: /* @(#) idln.getst.c: 1.1 10/15/83 (1.19 2/9/83) */ ! 2: ! 3: #include "curses.ext" ! 4: int InputPending; ! 5: ! 6: struct st { /* symbol table */ ! 7: int hash; /* hashed value of line ("text") */ ! 8: char oc, nc; /* 0, 1, or many: # times this value occurs */ ! 9: short olno; /* line # of line in "old" array */ ! 10: }; ! 11: ! 12: /* ! 13: * Routines to deal with calculation of how to do ins/del line optimally. ! 14: * Update the Screen. Consider using insert and delete line. ! 15: * Using Heckel's algorithm from April 1978 CACM. ! 16: * ! 17: * This algorithm is based on two observations: ! 18: * (1) A line that occurs once and only once in each file must be ! 19: * the same line (unchanged but possibly moved). ! 20: * (2) If i each file immediately adjacent to a "found" line pair ! 21: * there are lines identical to each other, these lines must be ! 22: * the same line. Repeated application will "find" sequences ! 23: * of unchanged lines. ! 24: * ! 25: * We view the old and new screens' hashed values as the old and new "files". ! 26: * Since crossing match lines cannot be taken advantage of with real insert ! 27: * and delete line, we ignore those matches - this is the one real disadvantage ! 28: * of this algorithm. ! 29: * ! 30: * first and last are the integer line numbers (first line is 1) of the ! 31: * portion of the screen to consider. ! 32: */ ! 33: _id_line(first, last) ! 34: register int first, last; ! 35: { ! 36: register int i, j, k, n; ! 37: int base, ndel; ! 38: int idl_offset = 0; /* number of extra del lines done so far. */ ! 39: #ifdef NONSTANDARD ! 40: static ! 41: #endif NONSTANDARD ! 42: struct st symtab[256]; ! 43: /* ! 44: * oa and na represent the old and new files (SP->cur_body and ! 45: * SP->std_body, respectively.) If they are > 0 they are ! 46: * subscripts in each other (e.g. na[4] = 3 means that na[4] ! 47: * points to oa[3]). If they are <= 0 their negative is taken ! 48: * as a symbol table index into the symtab array. ! 49: */ ! 50: #ifdef NONSTANDARD ! 51: static ! 52: #endif NONSTANDARD ! 53: short oa[256], na[256]; ! 54: ! 55: for (i=0; i<256; i++) ! 56: symtab[i].hash = symtab[i].oc = symtab[i].nc = 0; ! 57: ! 58: #ifdef DEBUG ! 59: if(outf) fprintf(outf, "_id_line(%d, %d)\n", first, last); ! 60: #endif ! 61: /* Pass 1: enter old file into symtab */ ! 62: for (i=first; i<=last; i++) { ! 63: n = _getst(SP->std_body[i]->hash, symtab); ! 64: symtab[n].nc++; ! 65: na[i] = -n; ! 66: } ! 67: ! 68: #ifdef LONGDEBUG ! 69: if(outf) fprintf(outf, "Pass 2\n"); ! 70: if(outf) fprintf(outf, "na[12] = %d\n", na[12]); ! 71: #endif ! 72: /* Pass 2: enter new into symtab */ ! 73: for (i=first; i<=last; i++) { ! 74: n = _getst(SP->cur_body[i]->hash, symtab); ! 75: symtab[n].oc++; ! 76: symtab[n].olno = i; ! 77: oa[i] = -n; ! 78: } ! 79: ! 80: #ifdef LONGDEBUG ! 81: if(outf) fprintf(outf, "Pass 3\n"); ! 82: if(outf) fprintf(outf, "\nsymtab oc nc olno hash\n"); ! 83: for (i=0; i<256; i++) ! 84: if (symtab[i].hash) ! 85: if(outf) fprintf(outf, "%d %d %d %d %d\n", ! 86: i, symtab[i].oc, symtab[i].nc, ! 87: symtab[i].olno, symtab[i].hash); ! 88: #endif ! 89: /* ! 90: * Pass 3: Match all lines with exactly one match. ! 91: * Matching lines in oa and na point at each other. ! 92: */ ! 93: for (i=first; i<=last; i++) { ! 94: n = -na[i]; ! 95: if (symtab[n].oc == 1 && symtab[n].nc == 1) { ! 96: na[i] = symtab[n].olno; ! 97: oa[na[i]] = i; ! 98: } ! 99: } ! 100: oa[first-1] = na[first-1] = first-1; ! 101: oa[last+1] = na[last+1] = last+1; ! 102: ! 103: /* Pass 4: Find following implied matches based on sequence */ ! 104: #ifdef DEBUG ! 105: if(outf) fprintf(outf, "Pass 4\n"); ! 106: #endif ! 107: for (i=first; i<=last; i++) { ! 108: if (na[i] > 0 && na[i+1] <= 0) { ! 109: j = na[i]; ! 110: if (na[i+1] == oa[j+1]) { ! 111: oa[j+1] = i+1; ! 112: na[i+1] = j+1; ! 113: } ! 114: } ! 115: } ! 116: ! 117: /* Pass 5: Find preceding implied matches based on sequence */ ! 118: #ifdef DEBUG ! 119: if(outf) fprintf(outf, "Pass 5\n"); ! 120: if(outf) fprintf(outf, "na[12] = %d\n", na[12]); ! 121: #endif ! 122: for (i=last; i>=first; i--) { ! 123: if (na[i] > 0 && na[i-1] <= 0) { ! 124: j = na[i]; ! 125: if (na[i-1] == oa[j-1]) { ! 126: oa[j-1] = i-1; ! 127: na[i-1] = j-1; ! 128: } ! 129: } ! 130: } ! 131: ! 132: #ifdef DEBUG ! 133: if(outf) fprintf(outf, "\ni oa na After pass 5\n"); ! 134: for (i=first; i<=last; i++) ! 135: if(outf) fprintf(outf, "%d %d %d\n", i, oa[i], na[i]); ! 136: if(outf) fprintf(outf, "\n"); ! 137: #endif ! 138: /* Pass 6: Find matches from more than one line, in order. */ ! 139: for (i=first; i<=last; i++) { ! 140: if (na[i] < -1 && symtab[-na[i]].nc > 1) { ! 141: j = na[i]; ! 142: #ifdef DEBUG ! 143: if(outf) fprintf(outf, "i %d, na[i] %d\n", i, na[i]); ! 144: #endif ! 145: for (k=first; k<last; k++) { ! 146: if (j == oa[k]) { ! 147: #ifdef DEBUG ! 148: if(outf) fprintf(outf, "k %d, oa[i] %d, matching them up\n", k, oa[i]); ! 149: #endif ! 150: na[i] = k; ! 151: oa[k] = i; ! 152: break; ! 153: } ! 154: } ! 155: } ! 156: } ! 157: #ifdef DEBUG ! 158: if(outf) fprintf(outf, "\ni oa na After pass 6\n"); ! 159: for (i=first; i<=last; i++) ! 160: if(outf) fprintf(outf, "%d %d %d\n", i, oa[i], na[i]); ! 161: if(outf) fprintf(outf, "\n"); ! 162: #endif ! 163: ! 164: /* ! 165: * Passes 7abcd: Remove any match lines that cross backwards. ! 166: * (Draw lines connecting the matching lines on debug output ! 167: * to see what I mean about crossing lines.) ! 168: * The na's must be monotonically increasing except for those < 0 ! 169: * which say there is no match. k counts the number of matches ! 170: * we have to throw away. ! 171: */ ! 172: n = k = 0; /* k is the added cost to throw away nw-se matches */ ! 173: /* 7a: get nw-se cost in k */ ! 174: for (i=first; i<=last; i++) { ! 175: if (na[i] > 0 && na[i] < n) { ! 176: k += SP->std_body[i]->bodylen; ! 177: } ! 178: if (na[i] > n) ! 179: n = na[i]; ! 180: } ! 181: /* 7b: get sw-ne cost in j */ ! 182: /* Consider throwing away in the other direction. */ ! 183: if (k > 0) { ! 184: j = 0; /* j is the added cost to throw away sw-ne matches */ ! 185: n = last+1; ! 186: for (i=last; i>=first; i--) { ! 187: if (na[i] > 0 && na[i] > n) { ! 188: j += SP->std_body[i]->bodylen; ! 189: } ! 190: if (na[i] > 0 && na[i] < n) ! 191: n = na[i]; ! 192: } ! 193: } ! 194: else ! 195: j = 1; /* will be > 0 for sure */ ! 196: #ifdef DEBUG ! 197: if(outf) fprintf(outf, "forward, k is %d, backward, j is %d\n", k, j); ! 198: #endif ! 199: ! 200: /* Remove whichever is cheapest. */ ! 201: if (k < j) { ! 202: /* 7c: remove nw-se */ ! 203: n = 0; ! 204: for (i=first; i<=last; i++) { ! 205: if (na[i] > 0 && na[i] < n) { ! 206: oa[na[i]] = -1; ! 207: na[i] = -1; ! 208: } ! 209: if (na[i] > n) ! 210: n = na[i]; ! 211: } ! 212: } else { ! 213: /* 7d: remove sw-ne */ ! 214: n = last+1; ! 215: for (i=last; i>=first; i--) { ! 216: if (na[i] > 0 && na[i] > n) { ! 217: oa[na[i]] = -1; ! 218: na[i] = -1; ! 219: } ! 220: if (na[i] > 0 && na[i] < n) ! 221: n = na[i]; ! 222: } ! 223: } ! 224: #ifdef DEBUG ! 225: if(outf) fprintf(outf, "\ni oa na After pass 7\n"); ! 226: for (i=first; i<=last; i++) ! 227: if(outf) fprintf(outf, "%d %d %d\n", i, oa[i], na[i]); ! 228: if(outf) fprintf(outf, "\nPass 7\n"); ! 229: if(outf) fprintf(outf, "ILmf %d/32, ILov %d\n", ! 230: SP->term_costs.ilvar, SP->term_costs.ilfixed); ! 231: if(outf) fprintf(outf, "i base j k DC n\n"); ! 232: #endif ! 233: ! 234: /* ! 235: * Pass 8: we go through and remove all matches if the ! 236: * overall ins/del lines would be too expensive to capatilize on. ! 237: * j is cost with ins/del line, k is cost without it. base is the ! 238: * logical beginning of the oa array, as the array would be after ! 239: * inserts and deletes, ignoring anything before row i. This ! 240: * approximates things by not taking into account SP->curptr motion, ! 241: * funny insert line costs, or lines that are partially equal. ! 242: * This macro is the cost to insert or delete n lines at screen line i. ! 243: * It is approximated for speed and simplicity, but shouldn't be. ! 244: * The approximation assumes each line is deleted separately. ! 245: */ ! 246: ! 247: #define idlcost(n, i) n * \ ! 248: (((SP->term_costs.ilvar * (lines-i))>>5) + SP->term_costs.ilfixed) ! 249: ! 250: base = ndel = 0; ! 251: j = k = 0; ! 252: for (i=first; i<=last; i++) { ! 253: #ifdef DEBUG ! 254: n = 0; ! 255: #endif ! 256: if (oa[i] != na[i]) { ! 257: /* Cost to turn Phys[i] into Des[i] on same line */ ! 258: if (SP->cur_body[i] == 0 || SP->cur_body[i]->length == 0) { ! 259: k += SP->std_body[i]->bodylen; ! 260: } else if (SP->std_body[i] == 0 || ! 261: SP->std_body[i]->length == 0) { ! 262: k += 2; /* guess at cost of clr to eol */ ! 263: } else { ! 264: register chtype *p0, *p1, *p2; ! 265: n = SP->cur_body[i]->length - ! 266: SP->std_body[i]->length; ! 267: if (n > 0) { ! 268: k += n; ! 269: n = SP->std_body[i]->length; ! 270: } else { ! 271: k += -n; ! 272: n = SP->cur_body[i]->length; ! 273: } ! 274: p0 = &SP->std_body[i]->body[0]; ! 275: p1 = &SP->std_body[i]->body[n]; ! 276: p2 = &SP->cur_body[i]->body[n]; ! 277: while (--p1 >= p0) ! 278: if (*p1 != *--p2) ! 279: k++; ! 280: } ! 281: } ! 282: /* cost to do using ins/del line */ ! 283: if (na[i] <= 0) { ! 284: /* totally different - plan on redrawing whole thing ! 285: * (even though chances are good they are partly the ! 286: * same - _id_char will take care of this, if it ! 287: * happens to get the same line on the screen). ! 288: * Should probably figure out what will be there on ! 289: * the screen and do above k algorithm on it. ! 290: */ ! 291: j += SP->std_body[i]->bodylen; ! 292: } else if ((n = (na[i] - base) - i) > 0) { ! 293: /* delete line */ ! 294: j += idlcost(n, i); ! 295: ndel += n; ! 296: base += n; ! 297: } else if (n < 0) { ! 298: /* insert line */ ! 299: j += idlcost((-n), i); ! 300: ndel += n; ! 301: base += n; ! 302: } ! 303: /* else they are the same line: no cost */ ! 304: #ifdef DEBUG ! 305: if(outf) fprintf(outf, "%d %d %d %d %d", i, base, j, k, SP->std_body[i]->bodylen); ! 306: if (n < 0) ! 307: if(outf) fprintf(outf, " %d lines inserted", -n); ! 308: else if (n > 0) ! 309: if(outf) fprintf(outf, " %d lines deleted", n); ! 310: if(outf) fprintf(outf, "\n"); ! 311: #endif ! 312: } ! 313: if (j >= k) { ! 314: /* It's as cheap to just redraw, so do it. */ ! 315: for (i=first; i<=last; i++) ! 316: na[i] = oa[i] = -1; ! 317: } else if (ndel < 0) { ! 318: ndel = -ndel; ! 319: #ifdef DEBUG ! 320: if(outf) fprintf(outf, "will do %d extra inserts, so del now.\n", ndel); ! 321: #endif ! 322: if (SP->des_bot_mgn - last >= 0) { ! 323: _pos(last-ndel, 0); ! 324: idl_offset += ndel; ! 325: _dellines(ndel); ! 326: } ! 327: } ! 328: ! 329: #ifdef DEBUG ! 330: if(outf) fprintf(outf, "\ni oa na After pass 8\n"); ! 331: for (i=first; i<=last; i++) ! 332: if(outf) fprintf(outf, "%d %d %d\n", i, oa[i], na[i]); ! 333: if(outf) fprintf(outf, "\n"); ! 334: #endif ! 335: /* Pass 9: Do any delete lines that are needed */ ! 336: k = first-1; /* previous matching spot in oa */ ! 337: ndel = 0; ! 338: for (i=first; i<=last; i++) { ! 339: if (oa[i] > 0) { ! 340: n = (i-k) - (oa[i]-oa[k]); ! 341: #ifdef DEBUG ! 342: if(outf) fprintf(outf, ! 343: "del loop, i %d, k %d, oa[i] %d, oa[k] %d, n %d\n", ! 344: i, k, oa[i], oa[k], n); ! 345: #endif ! 346: if (n > 0) { ! 347: if (i-n == SP->des_top_mgn+1) { ! 348: _scrollf(n); ! 349: } else { ! 350: _pos(i-n-1, 0); ! 351: _dellines(n); ! 352: } ! 353: idl_offset += n; ! 354: ndel += n; ! 355: for (j=i-n; j<=last-n; j++) { ! 356: if (oa[j] > 0 && na[oa[j]] > 0) ! 357: na[oa[j]] -= n; ! 358: _line_free(SP->cur_body[j]); ! 359: SP->cur_body[j] = SP->cur_body[j+n]; ! 360: oa[j] = oa[j+n]; ! 361: } ! 362: for ( ; j<=last; j++) { ! 363: if (oa[j] > 0 && na[oa[j]] > 0) ! 364: na[oa[j]] -= n; ! 365: _line_free(SP->cur_body[j]); ! 366: SP->cur_body[j] = NULL; ! 367: oa[j] = -1; ! 368: } ! 369: i -= n; ! 370: } ! 371: k = i; ! 372: } ! 373: } ! 374: #ifdef DEBUG ! 375: if(outf) fprintf(outf, "\ni oa na After pass 9\n"); ! 376: for (i=first; i<=last; i++) ! 377: if(outf) fprintf(outf, "%d %d %d\n", i, oa[i], na[i]); ! 378: if(outf) fprintf(outf, "\n"); ! 379: #endif ! 380: ! 381: /* Half way through - check for typeahead */ ! 382: _chk_typeahead(); ! 383: if (idl_offset == 0 && InputPending) { ! 384: #ifdef DEBUG ! 385: if (outf) fprintf(outf, "InputPending %d, aborted after dellines\n", InputPending); ! 386: #endif ! 387: return; ! 388: } ! 389: ! 390: /* for pass 10, j is the next line above i that will be used */ ! 391: for (j=first; na[j] <= 0; j++) ! 392: ; ! 393: ! 394: /* Pass 10: insert and fix remaining lines */ ! 395: for (i=first; i<=last; i++) { ! 396: if (j <= i) ! 397: for (j++; na[j] <= 0; j++) ! 398: ; ! 399: #ifdef DEBUG ! 400: if(outf) fprintf(outf, "i %d, j %d, na[i] %d, na[j] %d\n", ! 401: i, j, na[i], na[j]); ! 402: if (na[i] > 0 && na[i] != i) ! 403: if(outf) fprintf(outf, "OOPS: na[%d] is %d\n", i, na[i]); ! 404: #endif ! 405: /* There are two cases: na[i] < 0 or na[i] == i */ ! 406: if (na[i] < 0) { ! 407: /* ! 408: * This line must be fixed from scratch. First ! 409: * check to see if the line physically there is ! 410: * going to be used later, if so, move it down. ! 411: */ ! 412: if (na[j]==i || ndel+i>last && last<SP->des_bot_mgn+1) { ! 413: _pos(i-1, 0); ! 414: n = j - i; ! 415: idl_offset -= n; ! 416: ndel -= n; ! 417: _inslines(n); ! 418: _chk_typeahead(); ! 419: if (idl_offset == 0 && InputPending) { ! 420: #ifdef DEBUG ! 421: if (outf) fprintf(outf, "InputPending %d, aborted after dellines\n", InputPending); ! 422: #endif ! 423: return; ! 424: } ! 425: for (k=last; k>=j; k--) { ! 426: if (na[k] > 0) ! 427: na[k] += n; ! 428: _line_free(SP->cur_body[k]); ! 429: SP->cur_body[k] = SP->cur_body[k-n]; ! 430: oa[k] = oa[k-n]; ! 431: } ! 432: for ( ; k>=i; k--) { ! 433: if (na[k] > 0) ! 434: na[k] += n; ! 435: _line_free(SP->cur_body[k]); ! 436: SP->cur_body[k] = NULL; ! 437: oa[k] = 0; ! 438: } ! 439: } ! 440: } ! 441: /* Now transform line i to new line j */ ! 442: if (!InputPending) { ! 443: _id_char (SP->cur_body[i], SP->std_body[i], i-1); ! 444: if (SP->cur_body[i] != SP->std_body[i]) ! 445: _line_free (SP->cur_body[i]); ! 446: SP->cur_body[i] = SP->std_body[i]; ! 447: } ! 448: } ! 449: #ifdef DEBUG ! 450: if(outf) fprintf(outf, "\ni oa na After pass 10: _id_line completed\n"); ! 451: for (i=first; i<=last; i++) ! 452: if(outf) fprintf(outf, "%d %d %d\n", i, oa[i], na[i]); ! 453: if(outf) fprintf(outf, "\n"); ! 454: #endif ! 455: } ! 456: ! 457: int ! 458: _getst(val, symtab) ! 459: register struct st *symtab; ! 460: { ! 461: register int i; ! 462: register int h; ! 463: register int hopcount = 256; ! 464: ! 465: i = val & 0377; ! 466: while ((h=symtab[i].hash) && h != val) { ! 467: if (++i >= 256) ! 468: i = 0; ! 469: if (--hopcount <= 0) { ! 470: _ec_quit("Hash table full in dispcalc", ""); ! 471: } ! 472: } ! 473: symtab[i].hash = val; ! 474: #ifdef LONGDEBUG ! 475: if(outf) fprintf(outf, "_getst, val %d, init slot %d, return %d\n", ! 476: val, val & 0377, i); ! 477: #endif ! 478: return i; ! 479: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.