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
Defined variables
rcsid
defined in line
2;
never used
Defined macros