|
|
1.1 root 1: /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */
2: static char rcsid[] = "$Header: outp.c,v 2.4 85/08/22 16:05:48 timo Exp $";
3:
4: /*
5: * B editor -- Screen management package, lower level output part.
6: */
7:
8: #include <ctype.h>
9:
10: #include "b.h"
11: #include "bobj.h"
12: #include "node.h"
13: #include "supr.h"
14: #include "gram.h"
15: #include "cell.h"
16:
17:
18: #define SOBIT 0200
19: #define CHAR 0177
20:
21:
22: /*
23: * Variables used for communication with outfocus.
24: */
25:
26: Hidden node thefocus;
27: Hidden environ wherebuf;
28: Hidden environ *where = &wherebuf;
29: Hidden bool realvhole;
30: Hidden int multiline; /* Height of focus */
31: Hidden int yfocus;
32:
33: Visible int focy; /* Where the cursor must go */
34: Visible int focx;
35:
36:
37: /*
38: * Save position of the focus for use by outnode/outfocus.
39: */
40:
41: Visible Procedure
42: savefocus(ep)
43: register environ *ep;
44: {
45: register int sym;
46: register int w;
47:
48: realvhole = No;
49: thefocus = Nnil;
50: multiline = 0;
51: yfocus = Ycoord(ep->focus);
52: w = focoffset(ep);
53: if (w < 0)
54: yfocus += -w;
55: w = focwidth(ep);
56: if (w < 0) {
57: multiline = -w;
58: if (focchar(ep) == '\n')
59: ++yfocus;
60: else
61: ++multiline;
62: return;
63: }
64: if (ep->mode == WHOLE) {
65: sym = symbol(tree(ep->focus));
66: if (sym == Optional)
67: ep->mode = ATBEGIN;
68: }
69: switch(ep->mode) {
70: case VHOLE:
71: if (ep->s1&1)
72: ep->mode = FHOLE;
73: case ATBEGIN:
74: case ATEND:
75: case FHOLE:
76: ritevhole(ep);
77: switch (ep->mode) {
78: case ATBEGIN:
79: case FHOLE:
80: sym = symbol(tree(ep->focus));
81: if (sym == Hole && (ep->mode == ATBEGIN || ep->s2 == 0)) {
82: ep->mode = WHOLE;
83: break;
84: }
85: /* Fall through */
86: case VHOLE:
87: case ATEND:
88: leftvhole(ep);
89: realvhole = 1 + ep->spflag;
90: }
91: }
92: touchpath(&ep->focus); /* Make sure it is a unique pointer */
93: thefocus = tree(ep->focus); /* No copy; used for comparison only! */
94: where->mode = ep->mode;
95: where->s1 = ep->s1;
96: where->s2 = ep->s2;
97: where->s3 = ep->s3;
98: where->spflag = ep->spflag;
99: }
100:
101:
102: /*
103: * Incorporate the information saved about the focus.
104: */
105:
106: Visible Procedure
107: setfocus(tops)
108: register cell *tops;
109: {
110: register cell *p;
111: register int i;
112:
113: for (p = tops, i = 0; i < yfocus; ++i, p = p->c_link) {
114: if (!p) {
115: #ifndef NDEBUG
116: debug("[Focus lost (setfocus)]");
117: #endif NDEBUG
118: return;
119: }
120: }
121: p->c_newvhole = realvhole;
122: i = multiline;
123: do {
124: p->c_newfocus = Yes;
125: p = p->c_link;
126: } while (--i > 0);
127: }
128:
129:
130: /*
131: * Signal that actual updata is started.
132: */
133:
134: Visible Procedure
135: startactupdate(nofocus)
136: bool nofocus;
137: {
138: if (nofocus) {
139: multiline = 0;
140: thefocus = Nnil;
141: }
142: }
143:
144:
145: /*
146: * Signal the end of the actual update.
147: */
148:
149: Visible Procedure
150: endactupdate()
151: {
152: }
153:
154:
155: /*
156: * Output a line of text.
157: */
158:
159: Visible Procedure
160: outline(p, lineno)
161: register cell *p;
162: register int lineno;
163: {
164: register node n = p->c_data;
165: register int w = width(n);
166: register string buf =
167: malloc((unsigned) (p->c_newindent + 4 + (w < 0 ? linelen(n) : w)));
168: /* some 4 extra for spflag and vhole */
169: auto string bp = buf;
170: register int i;
171: register int endarea = lineno+Space(p)-1;
172:
173: if (endarea >= winheight)
174: endarea = winheight-1;
175: for (i = p->c_newindent; i-- > 0; )
176: *bp++ = ' ';
177: if (!p->c_newfocus) {
178: smash(&bp, n, 0);
179: *bp = 0;
180: }
181: else {
182: if (multiline)
183: smash(&bp, n, SOBIT);
184: else if (n == thefocus)
185: focsmash(&bp, n);
186: else
187: smash(&bp, n, 0);
188: *bp = 0;
189: for (bp = buf; *bp && !(*bp&SOBIT); ++bp)
190: ;
191: if (*bp&SOBIT) {
192: if (focy == Nowhere) {
193: focx = indent + bp-buf;
194: focy = lineno + focx/llength;
195: focx %= llength;
196: }
197: if (multiline <= 1 && !(bp[1]&SOBIT))
198: *bp &= ~SOBIT; /* Clear mask if just one char in focus */
199: }
200: }
201: trmputdata(lineno, endarea, indent, buf);
202: }
203:
204:
205: /*
206: * Smash -- produce a linear version of a node in a buffer (which had
207: * better be long enough!). The buffer pointer is moved to the end of
208: * the resulting string.
209: * Care is taken to represent the focus.
210: * Characters in the focus have their upper bit set.
211: */
212:
213: #define Outvhole() \
214: (where->spflag && strsmash(pbuf, " ", 0), strsmash(pbuf, "?", SOBIT))
215:
216: Hidden Procedure
217: focsmash(pbuf, n)
218: string *pbuf;
219: node n;
220: {
221: value v;
222: string str;
223: register string *rp;
224: register int maxs2;
225: register int i;
226: register bool ok;
227: register int j;
228: register int mask;
229:
230: switch (where->mode) {
231:
232: case WHOLE:
233: smash(pbuf, n, SOBIT);
234: break;
235:
236: case ATBEGIN:
237: Outvhole();
238: smash(pbuf, n, 0);
239: break;
240:
241: case ATEND:
242: smash(pbuf, n, 0);
243: Outvhole();
244: break;
245:
246: case VHOLE:
247: if (!(where->s1&1)) {
248: v = (value) child(n, where->s1/2);
249: Assert(Type(v) == Tex);
250: subsmash(pbuf, Str(v), where->s2, 0);
251: Outvhole();
252: strsmash(pbuf, Str(v) + where->s2, 0);
253: break;
254: }
255: /* Else, fall through */
256: case FHOLE:
257: rp = noderepr(n);
258: maxs2 = 2*nchildren(n) + 1;
259: for (ok = Yes, i = 1; ok && i <= maxs2; ++i) {
260: if (i&1) {
261: if (i == where->s1) {
262: subsmash(pbuf, rp[i/2], where->s2, 0);
263: Outvhole();
264: if (rp[i/2])
265: strsmash(pbuf, rp[i/2] + where->s2, 0);
266: }
267: else
268: strsmash(pbuf, rp[i/2], 0);
269: }
270: else
271: ok = chismash(pbuf, n, i/2, 0);
272: }
273: break;
274:
275: case SUBRANGE:
276: rp = noderepr(n);
277: maxs2 = 2*nchildren(n) + 1;
278: for (ok = Yes, i = 1; ok && i <= maxs2; ++i) {
279: if (i&1) {
280: if (i == where->s1) {
281: subsmash(pbuf, rp[i/2], where->s2,0);
282: if (rp[i/2])
283: subsmash(pbuf, rp[i/2] + where->s2,
284: where->s3 - where->s2 + 1, SOBIT);
285: if (rp[i/2])
286: strsmash(pbuf, rp[i/2] + where->s3 + 1, 0);
287: }
288: else
289: strsmash(pbuf, rp[i/2], 0);
290: }
291: else if (i == where->s1) {
292: v = (value)child(n, i/2);
293: Assert(Type(v) == Tex);
294: str = Str(v);
295: subsmash(pbuf, str, where->s2, 0);
296: subsmash(pbuf, str + where->s2, where->s3 - where->s2 + 1,
297: SOBIT);
298: strsmash(pbuf, str + where->s3 + 1, 0);
299: }
300: else
301: ok = chismash(pbuf, n, i/2, 0);
302: }
303: break;
304:
305: case SUBLIST:
306: for (ok = Yes, j = where->s3; j > 0; --j) {
307: rp = noderepr(n);
308: maxs2 = 2*nchildren(n) - 1;
309: for (i = 1; ok && i <= maxs2; ++i) {
310: if (i&1)
311: strsmash(pbuf, rp[i/2], SOBIT);
312: else
313: ok = chismash(pbuf, n, i/2, SOBIT);
314: }
315: if (ok)
316: n = lastchild(n);
317: }
318: if (ok)
319: smash(pbuf, n, 0);
320: break;
321:
322: case SUBSET:
323: rp = noderepr(n);
324: maxs2 = 2*nchildren(n) + 1;
325: mask = 0;
326: for (ok = Yes, i = 1; ok && i <= maxs2; ++i) {
327: if (i == where->s1)
328: mask = SOBIT;
329: if (i&1)
330: strsmash(pbuf, rp[i/2], mask);
331: else
332: ok = chismash(pbuf, n, i/2, mask);
333: if (i == where->s2)
334: mask = 0;
335: }
336: break;
337:
338: default:
339: Abort();
340: }
341: }
342:
343: Hidden Procedure
344: smash(pbuf, n, mask)
345: register string *pbuf;
346: register node n;
347: register int mask;
348: {
349: register string *rp;
350: register int i;
351: register int nch;
352:
353: rp = noderepr(n);
354: strsmash(pbuf, rp[0], mask);
355: nch = nchildren(n);
356: for (i = 1; i <= nch; ++i) {
357: if (!chismash(pbuf, n, i, mask))
358: break;
359: strsmash(pbuf, rp[i], mask);
360: }
361: }
362:
363: Hidden Procedure
364: strsmash(pbuf, str, mask)
365: register string *pbuf;
366: register string str;
367: register int mask;
368: {
369: if (!str)
370: return;
371: for (; *str; ++str) {
372: if (isprint(*str) || *str == ' ')
373: **pbuf = *str|mask, ++*pbuf;
374: }
375: }
376:
377: Hidden Procedure
378: subsmash(pbuf, str, len, mask)
379: register string *pbuf;
380: register string str;
381: register int len;
382: register int mask;
383: {
384: if (!str)
385: return;
386: for (; len > 0 && *str; --len, ++str) {
387: if (isprint(*str) || *str == ' ')
388: **pbuf = *str|mask, ++*pbuf;
389: }
390: }
391:
392:
393: /*
394: * Smash a node's child.
395: * Return No if it contained a newline (to stop the parent).
396: */
397:
398: Hidden bool
399: chismash(pbuf, n, i, mask)
400: register string *pbuf;
401: register node n;
402: register int i;
403: {
404: register node nn = child(n, i);
405: register int w;
406:
407: if (Type(nn) == Tex) {
408: strsmash(pbuf, Str((value)nn), mask);
409: return Yes;
410: }
411: w = width(nn);
412: if (w < 0 && Fw_negative(noderepr(nn)[0]))
413: return No;
414: if (nn == thefocus)
415: focsmash(pbuf, nn);
416: else
417: smash(pbuf, nn, mask);
418: return w >= 0;
419: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.