|
|
1.1 root 1: /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */
2: static char rcsid[] = "$Header: que1.c,v 2.4 84/10/26 12:04:28 guido Exp $";
3:
4: /*
5: * B editor -- Manipulate queues of nodes, lower levels.
6: */
7:
8: #include "b.h"
9: #include "feat.h"
10: #include "bobj.h"
11: #include "node.h"
12: #include "supr.h"
13: #include "queu.h"
14: #include "gram.h"
15:
16: #include <ctype.h>
17:
18:
19: value grab_com();
20:
21:
22: /*
23: * Append queue 2 to the end of queue 1.
24: */
25:
26: Visible Procedure
27: joinqueues(pq, q)
28: register queue *pq;
29: register queue q;
30: {
31: if (emptyqueue(q))
32: return;
33: while (*pq) {
34: if (Refcnt(*pq) > 1)
35: uniql((value*)pq);
36: pq = &(*pq)->q_link;
37: }
38: *pq = q;
39: }
40:
41:
42: /*
43: * Prepend a node to a queue ("push").
44: * Empty strings and Optional holes are silently discarded.
45: */
46:
47: Visible Procedure
48: preptoqueue(n, pq)
49: node n;
50: register queue *pq;
51: {
52: register queue q;
53:
54: if (Type(n) == Tex) {
55: int len = Length((value)n);
56: if (len == 0)
57: return;
58: n = nodecopy(n);
59: }
60: else { /* Avoid Optional holes */
61: if (symbol(n) == Optional)
62: return;
63: n = nodecopy(n);
64: }
65: q = (queue) grab_com(2);
66: q->q_data = n;
67: q->q_link = *pq;
68: *pq = q;
69: }
70:
71:
72: /*
73: * Append a node to the end of a queue (same extras as preptoqueue).
74: */
75:
76: Visible Procedure
77: addtoqueue(pq, n)
78: register queue *pq;
79: register node n;
80: {
81: auto queue q = Qnil;
82:
83: preptoqueue(n, &q);
84: joinqueues(pq, q);
85: }
86:
87:
88: /*
89: * Push a string onto a queue.
90: */
91:
92: Visible Procedure
93: stringtoqueue(str, pq)
94: register string str;
95: register queue *pq;
96: {
97: register value v;
98:
99: if (str == NULL)
100: return;
101: v = mk_text(str);
102: preptoqueue((node) v, pq);
103: release(v);
104: }
105:
106:
107: /*
108: * Append a string to a queue.
109: */
110:
111: Visible Procedure
112: addstringtoqueue(pq, str)
113: register queue *pq;
114: register string str;
115: {
116: register value v = mk_text(str);
117:
118: addtoqueue(pq, (node) v);
119: release(v);
120: }
121:
122:
123: /*
124: * Get the first node of a queue and delink it ("pop").
125: */
126:
127: Visible node
128: queuebehead(pq)
129: register queue *pq;
130: {
131: register node n;
132: register queue q = *pq;
133:
134: Assert(q);
135:
136: n = nodecopy(q->q_data);
137: *pq = qcopy(q->q_link);
138: qrelease(q);
139: return n;
140: }
141:
142:
143: /*
144: * Split a node in successive queue elements which are pushed
145: * on the queue using preptoqueue.
146: * 'Atomic' nodes (texts and holes) are pushed unadorned.
147: */
148:
149: Visible Procedure
150: splitnode(n, pq)
151: register node n;
152: register queue *pq;
153: {
154: register node nn;
155: register string *rp;
156: register int i;
157: register int sym;
158:
159: if (Type(n) == Tex) {
160: preptoqueue(n, pq);
161: return;
162: }
163: sym = symbol(n);
164: if (sym == Optional)
165: return;
166: if (sym == Hole) {
167: preptoqueue(n, pq);
168: return;
169: }
170:
171: rp = noderepr(n);
172: for (i = nchildren(n); i >= 0; --i) {
173: if (rp[i] && rp[i][0])
174: stringtoqueue(rp[i], pq);
175: if (i) {
176: nn = child(n, i);
177: if (Type(nn) == Tex || symbol(nn) != Optional)
178: preptoqueue(nn, pq);
179: }
180: }
181: }
182:
183:
184: /*
185: * Substitute the focus for its parent, appending the remainder of
186: * the parent to the queue.
187: * The focus must be the first child and not preceded by fixed text.
188: * The focus must be allowed in the place of its parent.
189: * If any of these conditions is not met, No is returned and nothing
190: * is changed.
191: */
192:
193: Visible bool
194: resttoqueue(pp, pq)
195: register path *pp;
196: register queue *pq;
197: {
198: auto queue q = Qnil;
199: register path pa = parent(*pp);
200: register node n = tree(*pp);
201: register int sym = symbol(n);
202: /* register markbits x; */
203:
204: if (!pa || ichild(*pp) != 1
205: || fwidth(noderepr(tree(pa))[0]) != 0 || !allowed(pa, sym))
206: return No;
207:
208: n = nodecopy(n);
209: /* x = marks(n); */
210: up(pp) || Abort();
211: splitnode(tree(*pp), &q);
212: noderelease(queuebehead(&q));
213: replace(pp, n);
214: /* if (x) { */
215: /* markpath(pp, x); */ /* Actually, should restore all n's marks? */
216: /* } */
217: joinqueues(pq, q);
218: return Yes;
219: }
220:
221:
222: /*
223: * Like resttoqueue, but exactly from current position in fixed text.
224: * Also, it cannot fail.
225: */
226:
227: Visible Procedure
228: nosuggtoqueue(ep, pq)
229: register environ *ep;
230: queue *pq;
231: {
232: auto queue q = Qnil;
233: register int i;
234: register string *rp;
235: register node n;
236: register node nn;
237: register int sym;
238: string str;
239:
240: if (issuggestion(ep))
241: return;
242: Assert((ep->mode == FHOLE || ep->mode == VHOLE) && (ep->s1&1));
243:
244: n = tree(ep->focus);
245: rp = noderepr(n);
246: for (i = nchildren(n); i > ep->s1/2; --i) {
247: if (!Fw_zero(rp[i]))
248: stringtoqueue(rp[i], &q);
249: nn = child(n, i);
250: sym = symbol(nn);
251: if (sym != Optional) {
252: preptoqueue(nn, &q);
253: if (sym != Hole) {
254: s_downi(ep, i);
255: delfocus(&ep->focus);
256: s_up(ep);
257: }
258: }
259: }
260: str = rp[i];
261: if (str && str[ep->s2]) /* Push partial first text */
262: stringtoqueue(str + ep->s2, &q);
263: joinqueues(pq, q);
264: }
265:
266:
267: /*
268: * Check whether the remainder of the current node is all suggestion.
269: */
270:
271: Visible bool
272: issuggestion(ep)
273: register environ *ep;
274: {
275: register node n;
276: register int nch;
277: register int sym;
278: register int i;
279:
280: if (ep->mode != VHOLE && ep->mode != FHOLE || !(ep->s1&1))
281: return No; /* Actually wrong call? */
282:
283: n = tree(ep->focus);
284: nch = nchildren(n);
285: for (i = ep->s1/2 + 1; i <= nch; ++i) {
286: sym = symbol(child(n, i));
287: if (sym != Hole && sym != Optional)
288: return No;
289: }
290: return Yes;
291: }
292:
293:
294: /*
295: * See if a node fits in a hole.
296: */
297:
298: Visible bool
299: fitnode(pp, n)
300: register path *pp;
301: register node n;
302: {
303: if (!allowed(*pp, symbol(n)))
304: return No;
305: replace(pp, nodecopy(n));
306: return Yes;
307: }
308:
309:
310: /*
311: * Fit a string in a hole.
312: * Returns the number of characters consumed.
313: * (This does not have to be the maximum possible, but a reasonable attempt
314: * is made. If the internal buffer is exhausted, it leaves the rest for
315: * another call.)
316: */
317:
318: Visible int
319: fitstring(pp, str, alt_c)
320: register path *pp;
321: register string str;
322: int alt_c;
323: {
324: environ dummyenv;
325: register node n;
326: register int ich;
327: register int len;
328: register string cp;
329: char buf[1024];
330:
331: Assert(str);
332: if (!str[0])
333: return 0;
334: if (!insguess(pp, str[0], &dummyenv)) {
335: if (!alt_c)
336: return 0;
337: if (!insguess(pp, alt_c, &dummyenv))
338: return 0;
339: }
340: if (Type(tree(*pp)) == Tex)
341: up(pp) || Abort();
342: if (dummyenv.mode == FHOLE) {
343: cp = noderepr(tree(*pp))[0];
344: len = 1;
345: if (cp) {
346: ++str;
347: ++cp;
348: while (*str >= ' ' && *str == *cp) {
349: ++len;
350: ++str;
351: ++cp;
352: }
353: }
354: return len;
355: }
356: if (dummyenv.mode == VHOLE) {
357: buf[0] = str[0];
358: ++str;
359: len = 1;
360: n = tree(*pp);
361: ich = dummyenv.s1/2;
362: while (*str && mayinsert(n, ich, len, *str) && len < sizeof buf - 1) {
363: buf[len] = *str;
364: ++str;
365: ++len;
366: }
367: if (len > 1) {
368: buf[len] = 0;
369: downi(pp, ich) || Abort();
370: replace(pp, (node) mk_text(buf));
371: up(pp) || Abort();
372: }
373: return len;
374: }
375: return 1;
376: }
377:
378:
379: /*
380: * Set the focus position (some VHOLE/FHOLE setting, probably)
381: * at the 'len'th character from the beginning of the current node.
382: * This may involve going to a child or moving beyond the current subtree.
383: * Negative 'len' values may be given to indicate negative widths;
384: * this is implemented incomplete.
385: */
386:
387: Visible Procedure
388: fixfocus(ep, len)
389: register environ *ep;
390: register int len;
391: {
392: node nn;
393: register node n = tree(ep->focus);
394: register string *rp;
395: register int i = 0;
396: register int nch;
397: register int w;
398:
399: if (Type(n) == Tex) {
400: w = Length((value)n);
401: Assert(w >= len && len >= 0);
402: if (w > len)
403: ep->spflag = No;
404: ep->mode = VHOLE;
405: ep->s1 = ichild(ep->focus) * 2;
406: ep->s2 = len;
407: s_up(ep);
408: return;
409: }
410: nch = nchildren(n);
411: w = width(n);
412: if (len > w && w >= 0) {
413: i = ichild(ep->focus); /* Change initial condition for for-loop */
414: if (!up(&ep->focus)) {
415: ep->mode = ATEND;
416: return;
417: }
418: higher(ep);
419: n = tree(ep->focus);
420: }
421:
422: rp = noderepr(n);
423: for (; i <= nch; ++i) {
424: if (i) {
425: nn = child(n, i);
426: w = width(nn);
427: if (w < 0 || w >= len && len >= 0) {
428: s_downi(ep, i);
429: fixfocus(ep, len);
430: return;
431: }
432: if (len >= 0)
433: len -= w;
434: }
435: w = Fwidth(rp[i]);
436: if (w >= len && len >= 0) {
437: if (w > len)
438: ep->spflag = No;
439: ep->mode = FHOLE;
440: ep->s1 = 2*i + 1;
441: ep->s2 = len;
442: return;
443: }
444: else if (w < 0)
445: len = 0;
446: else
447: len -= w;
448: }
449: ep->mode = ATEND;
450: }
451:
452:
453: /*
454: * Apply, if possible, a special fix relating to spaces:
455: * when a space has been interpreted as joining character
456: * and we end up in the following hole, but we don't succeed
457: * in filling the hole; it is then tried to delete the hole
458: * and the space.
459: * Usually this doesn't occur, but it may occur when inserting
460: * after a space that was already fixed on the screen but now
461: * deserves re-interpretation.
462: */
463:
464: Visible bool
465: spacefix(ep)
466: environ *ep;
467: {
468: path pa;
469: node n;
470: string *rp;
471:
472: if (ichild(ep->focus) != 2 || symbol(tree(ep->focus)) != Hole)
473: return No;
474: pa = parent(ep->focus);
475: n = tree(pa);
476: rp = noderepr(n);
477: if (!Fw_zero(rp[0]) || Fwidth(rp[1]) != 1 || rp[1][0] != ' ')
478: return No;
479: n = firstchild(n);
480: if (!allowed(pa, symbol(n)))
481: return No;
482: s_up(ep);
483: replace(&ep->focus, nodecopy(n));
484: ep->mode = ATEND;
485: ep->spflag = Yes;
486: return Yes;
487: }
488:
489:
490: /*
491: * Prepend a subset of a node to a queue.
492: */
493:
494: Visible Procedure
495: subsettoqueue(n, s1, s2, pq)
496: register node n;
497: register int s1;
498: register int s2;
499: register queue *pq;
500: {
501: register string *rp = noderepr(n);
502:
503: for (; s2 >= s1; --s2) {
504: if (s2&1)
505: stringtoqueue(rp[s2/2], pq);
506: else
507: preptoqueue(child(n, s2/2), pq);
508: }
509: }
510:
511: #ifdef SHOWBUF
512:
513: /*
514: * Produce flat text out of a queue's first line, to show it on screen.
515: */
516:
517: Visible string
518: querepr(qv)
519: value qv;
520: {
521: queue q = (queue)qv;
522: node n;
523: static char buf[1000]; /***** Cannot overflow? *****/
524: string cp;
525: string sp;
526: string *rp;
527: int nch;
528: int i;
529: int len;
530:
531: cp = buf;
532: for (; q; q = q->q_link) {
533: n = q->q_data;
534: if (Type(n) == Tex) {
535: for (sp = Str((value) n); cp < buf+80 && *sp; ++sp) {
536: if (!isprint(*sp) && *sp != ' ')
537: break;
538: *cp++ = *sp;
539: }
540: if (*sp == '\n') {
541: if (!emptyqueue(q->q_link)) {
542: strcpy(cp, " ...");
543: cp += 4;
544: }
545: break;
546: }
547: }
548: else {
549: rp = noderepr(n);
550: nch = nchildren(n);
551: for (i = 0; i <= nch; ++i) {
552: if (i > 0) {
553: if (Type(child(n, i)) == Tex) {
554: len = Length((value)child(n, i));
555: if (len > 80)
556: len = 80;
557: strncpy(cp, Str((value)child(n, i)), len);
558: cp += len;
559: }
560: else {
561: strcpy(cp, "...");
562: cp += 3;
563: }
564: }
565: if (Fw_negative(rp[i])) {
566: strcpy(cp, " ...");
567: cp += 4;
568: break;
569: }
570: if (Fw_positive(rp[i])) {
571: strcpy(cp, rp[i]);
572: while (*cp)
573: ++cp;
574: if (cp[-1] == '\t' || cp[-1] == '\b')
575: --cp;
576: }
577: }
578: }
579: if (cp >= buf+80) {
580: strcpy(buf+76, "...");
581: break;
582: }
583: }
584: *cp = 0;
585: return buf;
586: }
587:
588: #endif SHOWBUF
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.