|
|
1.1 ! root 1: /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */ ! 2: static char rcsid[] = "$Header: cell.c,v 2.4 85/02/12 11:18:00 timo Exp $"; ! 3: ! 4: /* ! 5: * B editor -- Screen management package, cell list manipulation routines. ! 6: */ ! 7: ! 8: #include "b.h" ! 9: #include "bobj.h" ! 10: #include "node.h" ! 11: #include "eval.h" ! 12: #include "cell.h" ! 13: ! 14: ! 15: extern bool dflag; ! 16: extern bool noscroll; ! 17: ! 18: /* ! 19: * Definitions for internals of cell manipulations. ! 20: */ ! 21: ! 22: Hidden cell *freelist; ! 23: ! 24: #define CELLSIZE (sizeof(cell)) ! 25: ! 26: #ifndef PAGESIZE /* 4.2 BSD freaks compile with -DPAGESIZE='getpagesize()' */ ! 27: #define PAGESIZE 1024 ! 28: #endif ! 29: ! 30: #ifndef MALLOCLOSS ! 31: #define MALLOCLOSS (sizeof(char*)) ! 32: /* number of bytes taken by malloc administration per block */ ! 33: #endif ! 34: ! 35: ! 36: /* ! 37: * Replace `oldlcnt' cells from `tops', starting at the one numbered `oldlno', ! 38: * by the list `rep'. ! 39: * Returns a pointer to the deleted chain (with a Nil end pointer). ! 40: */ ! 41: ! 42: Visible cell * ! 43: replist(tops, rep, oldlno, oldlcnt) ! 44: cell *tops; ! 45: cell *rep; ! 46: int oldlno; ! 47: register int oldlcnt; ! 48: { ! 49: cell head; ! 50: register cell *p; ! 51: register cell *q; ! 52: register cell *old; ! 53: register cell *end; ! 54: register int diff; ! 55: int i; ! 56: int replcnt; ! 57: ! 58: if (!tops) /* Start with empty list */ ! 59: return rep; ! 60: head.c_link = tops; ! 61: p = &head; ! 62: for (diff = oldlno; diff > 0; --diff) { ! 63: p = p->c_link; ! 64: Assert(p); ! 65: } ! 66: q = p; ! 67: for (i = oldlcnt; i > 0 && p; --i) ! 68: p = p->c_link; ! 69: if (i > 0) { ! 70: #ifndef NDEBUG ! 71: debug("[replist jackpot]"); ! 72: #endif NDEBUG ! 73: oldlcnt -= i; ! 74: } ! 75: old = q->c_link; ! 76: q->c_link = rep; ! 77: if (p) { ! 78: end = p->c_link; ! 79: p->c_link = Cnil; ! 80: } ! 81: for (replcnt = 0; q->c_link; ++replcnt, q = q->c_link) ! 82: ; ! 83: dupmatch(old, rep, oldlcnt, replcnt); ! 84: discard(old); ! 85: if (p) ! 86: q->c_link = end; ! 87: return head.c_link; ! 88: } ! 89: ! 90: ! 91: /* ! 92: * Allocate a new cell. ! 93: */ ! 94: ! 95: Hidden cell * ! 96: newcell() ! 97: { ! 98: register cell *p; ! 99: ! 100: if (!freelist) ! 101: feedfreelist(); ! 102: p = freelist; ! 103: freelist = p->c_link; ! 104: p->c_link = Cnil; ! 105: return p; ! 106: } ! 107: ! 108: ! 109: /* ! 110: * Feed the free list with a block of new entries. ! 111: * We try to keep them together on a page ! 112: * to keep consecutive accesses fast. ! 113: */ ! 114: ! 115: Hidden Procedure ! 116: feedfreelist() ! 117: { ! 118: register int n = (PAGESIZE-MALLOCLOSS) / CELLSIZE; ! 119: register cell *p = (cell*) malloc((unsigned)(n*CELLSIZE)); ! 120: ! 121: Assert(n > 0); ! 122: if (!p) ! 123: syserr("feedfreelist: malloc"); ! 124: freelist = p; ! 125: for (; n > 1; --n, ++p) ! 126: p->c_link = p+1; ! 127: p->c_link = Cnil; ! 128: } ! 129: ! 130: ! 131: /* ! 132: * Discard all entries of a list of cells. ! 133: */ ! 134: ! 135: Visible Procedure ! 136: discard(p) ! 137: register cell *p; ! 138: { ! 139: register cell *savefreelist; ! 140: ! 141: if (!p) ! 142: return; ! 143: savefreelist = p; ! 144: for (;;) { ! 145: noderelease(p->c_data); ! 146: p->c_data = Nnil; ! 147: if (!p->c_link) ! 148: break; ! 149: p = p->c_link; ! 150: } ! 151: p->c_link = freelist; ! 152: freelist = savefreelist; ! 153: } ! 154: ! 155: ! 156: /* ! 157: * Replace the `onscreen' fields in the replacement chain by those ! 158: * in the old chain, if they match. ! 159: */ ! 160: ! 161: Hidden Procedure ! 162: dupmatch(old, rep, oldcnt, repcnt) ! 163: register cell *old; ! 164: register cell *rep; ! 165: int oldcnt; ! 166: int repcnt; ! 167: { ! 168: register int diff = repcnt - oldcnt; ! 169: ! 170: #ifndef NDEBUG ! 171: if (dflag) ! 172: debug("[dupmatch(oldcnt=%d, newcnt=%d)]", oldcnt, repcnt); ! 173: #endif NDEBUG ! 174: while (rep && old) { ! 175: if (old->c_length == rep->c_length ! 176: && eqlines(old->c_data, rep->c_data)) { ! 177: if (old->c_onscreen != Nowhere) { ! 178: rep->c_onscreen = old->c_onscreen; ! 179: rep->c_oldindent = old->c_oldindent; ! 180: rep->c_oldvhole = old->c_oldvhole; ! 181: rep->c_oldfocus = old->c_oldfocus; ! 182: } ! 183: rep = rep->c_link; ! 184: old = old->c_link; ! 185: } ! 186: else { ! 187: if (diff >= 0) { ! 188: --diff; ! 189: rep = rep->c_link; ! 190: } ! 191: if (diff < 0) { ! 192: ++diff; ! 193: old = old->c_link; ! 194: } ! 195: } ! 196: } ! 197: } ! 198: ! 199: ! 200: /* ! 201: * Build a list of cells consisting of the first `lcnt' lines of the tree. ! 202: */ ! 203: ! 204: Visible cell * ! 205: build(p, lcnt) ! 206: /*auto*/ path p; ! 207: register int lcnt; ! 208: { ! 209: cell head; ! 210: register cell *q = &head; ! 211: ! 212: p = pathcopy(p); ! 213: for (;;) { ! 214: q = q->c_link = newcell(); ! 215: q->c_onscreen = Nowhere; ! 216: q->c_data = nodecopy(tree(p)); ! 217: q->c_length = linelen(q->c_data); ! 218: q->c_newindent = Level(p) * TABS; ! 219: q->c_oldindent = 0; ! 220: q->c_oldvhole = q->c_newvhole = q->c_oldfocus = q->c_newfocus = No; ! 221: --lcnt; ! 222: if (lcnt <= 0) ! 223: break; ! 224: nextline(&p) || Abort(); ! 225: } ! 226: q->c_link = Cnil; ! 227: pathrelease(p); ! 228: return head.c_link; ! 229: } ! 230: ! 231: ! 232: /* ! 233: * Decide which line is to be on top of the screen. ! 234: * We slide a window through the list of lines, recognizing ! 235: * lines of the focus and lines already on the screen, ! 236: * and stop as soon as we find a reasonable focus position. ! 237: * ! 238: * - The focus must always be on the screen completely; ! 239: * if it is larger than the screen, its first line must be ! 240: * on top of the screen. ! 241: * - When old lines can be retained, at least one line above ! 242: * and below the focus must be shown; the retained lines ! 243: * should be moved as little as possible. ! 244: * - As little as possible blank space should be shown at the ! 245: * bottom, even if the focus is at the end of the unit. ! 246: * - If no rule applies, try to center the focus on the screen. ! 247: * - If noscroll is Yes (the terminal can't scroll), and the top ! 248: * line can't be retained, also try to center the focus on the ! 249: * screen. ! 250: */ ! 251: ! 252: Visible cell * ! 253: gettop(tops) ! 254: cell *tops; ! 255: { ! 256: register cell *pfwa = tops; /* First line of sliding window */ ! 257: register cell *plwa = tops; /* Last+1 line of sliding window */ ! 258: register cell *pffocus = Cnil; /* First line of focus */ ! 259: cell *pscreen = Cnil; /* First line still on screen */ ! 260: register int nfwa = 0; /* Corresponding line numbers in parse tree */ ! 261: register int nlwa = 0; ! 262: register int nffocus; ! 263: int nlfocus; ! 264: int nscreen; ! 265: int size; ! 266: ! 267: for (;;) { /* plwa is the current candidate for top line. */ ! 268: if (!pfwa) { ! 269: #ifndef NDEBUG ! 270: debug("[Lost the focus!]"); ! 271: #endif NDEBUG ! 272: return tops; /* To show *something*... */ ! 273: } ! 274: while (plwa && nlwa < nfwa+winheight) { ! 275: /* Find first line *not* in window */ ! 276: size = Space(plwa); ! 277: if (plwa->c_newfocus) { /* Hit a focus line */ ! 278: if (!pffocus) { /* Note first focus line */ ! 279: pffocus = plwa; ! 280: nffocus = nlwa; ! 281: } ! 282: nlfocus = nlwa + size; ! 283: } ! 284: if (plwa->c_onscreen != Nowhere) { /* Hello old chap */ ! 285: if (!pscreen) { /* Note first line on screen */ ! 286: pscreen = plwa; ! 287: nscreen = nlwa; ! 288: } ! 289: } ! 290: nlwa += size; ! 291: plwa = plwa->c_link; ! 292: } ! 293: if (pffocus) { ! 294: /* Focus in sight; stop at first reasonable opportunity */ ! 295: if (pffocus == pfwa) ! 296: break; /* Grab last chance! */ ! 297: if (!noscroll && nlwa - nfwa <= winheight - winheight/3) ! 298: break; /* Don't show too much white space at bottom */ ! 299: if (pffocus == pfwa->c_link && nlfocus < nfwa+winheight) ! 300: break; /* Near top line */ ! 301: if (pscreen && (!noscroll || nffocus > nscreen)) { ! 302: /* Conservatism may succeed */ ! 303: if (pscreen->c_onscreen >= nscreen - nfwa ! 304: && (nlfocus < nfwa+winheight ! 305: || !plwa && nlfocus == nfwa+winheight)) ! 306: break; /* focus entirely on screen */ ! 307: } ! 308: else { /* No comrades seen */ ! 309: if (nffocus - nfwa <= nfwa+winheight - nlfocus ! 310: || !plwa && nlwa <= nfwa+winheight) ! 311: break; /* Nicely centered focus or end of unit */ ! 312: } ! 313: } ! 314: if (pfwa == pscreen) { /* Say farewell to oldest comrade */ ! 315: pscreen->c_onscreen = Nowhere; ! 316: do { /* Find next in age */ ! 317: nscreen += Space(pscreen); ! 318: pscreen = pscreen->c_link; ! 319: if (pscreen == plwa) { ! 320: pscreen = Cnil; ! 321: break; ! 322: } ! 323: } while (pscreen->c_onscreen == Nowhere); ! 324: } ! 325: nfwa += Space(pfwa); ! 326: pfwa = pfwa->c_link; /* Pass the buck */ ! 327: } ! 328: return pfwa; /* This is what all those breaks aim at */ ! 329: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.