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: }

Defined functions

discard defined in line 135; used 3 times
dupmatch defined in line 161; used 1 times
  • in line 83
feedfreelist defined in line 115; used 1 times
gettop defined in line 252; used 2 times
newcell defined in line 95; used 1 times

Defined variables

Hidden defined in line 115; never used
Procedure defined in line 135; never used
Visible defined in line 135; never used
freelist defined in line 22; used 6 times
rcsid defined in line 2; never used

Defined macros

CELLSIZE defined in line 24; used 2 times
MALLOCLOSS defined in line 31; used 2 times
PAGESIZE defined in line 27; used 2 times
Last modified: 1985-08-27
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1261
Valid CSS Valid XHTML 1.0 Strict