|
|
1.1 root 1: /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */
2: static char rcsid[] = "$Header: supr.c,v 2.3 84/07/23 13:03:15 guido Exp $";
3:
4: /*
5: * B editor -- Superroutines.
6: */
7:
8: #include "b.h"
9: #include "feat.h"
10: #include "bobj.h"
11: #include "node.h"
12: #include "supr.h"
13: #include "gram.h"
14:
15: /*
16: * Compute the length of the ep->s1'th item of node tree(ep->focus).
17: */
18:
19: Visible int
20: lenitem(ep)
21: register environ *ep;
22: {
23: register node n = tree(ep->focus);
24: register node nn;
25:
26: if (ep->s1&1) /* Fixed text */
27: return fwidth(noderepr(n)[ep->s1/2]);
28: /* Else, variable text or a whole node */
29: nn = child(n, ep->s1/2);
30: return width(nn);
31: }
32:
33:
34: /*
35: * Find the largest possible representation of the focus.
36: * E.g., a WHOLE can also be represented as a SUBSET of its parent,
37: * provided it has a parent.
38: * Also, a SUBSET may be extended with some empty left and right
39: * items and then look like a WHOLE, etc.
40: * This process is repeated until no more improvements can be made.
41: */
42:
43: Visible Procedure
44: grow(ep)
45: environ *ep;
46: {
47: subgrow(ep, Yes);
48: }
49:
50: Visible Procedure
51: subgrow(ep, ignorespaces)
52: register environ *ep;
53: bool ignorespaces;
54: {
55: register node n;
56: register int sym;
57: register int i;
58: register int len;
59: register string repr;
60:
61: switch (ep->mode) {
62: case ATBEGIN:
63: case ATEND:
64: case VHOLE:
65: case FHOLE:
66: ritevhole(ep);
67: if (ep->mode != FHOLE && ep->mode != VHOLE || lenitem(ep) == 0)
68: leftvhole(ep);
69:
70: }
71:
72: for (;;) {
73: n = tree(ep->focus);
74: sym = symbol(n);
75:
76: switch (ep->mode) {
77:
78: case VHOLE:
79: case FHOLE:
80: if ((sym == Optional || sym == Hole) && ep->s2 == 0) {
81: ep->mode = WHOLE;
82: continue;
83: }
84: if (lenitem(ep) <= 0) {
85: ep->mode = SUBSET;
86: ep->s2 = ep->s1;
87: continue;
88: }
89: return;
90:
91: case ATBEGIN:
92: case ATEND:
93: if (sym == Optional || sym == Hole) {
94: ep->mode = WHOLE;
95: continue;
96: }
97: return;
98:
99: case SUBRANGE:
100: if (ep->s1&1) {
101: repr = noderepr(n)[ep->s1/2];
102: len = fwidth(repr);
103: if (!ignorespaces) {
104: while (ep->s2 > 0 && repr[ep->s2-1] == ' ')
105: --ep->s2;
106: while (ep->s3 < len && repr[ep->s3+1] == ' ')
107: ++ep->s3;
108: }
109: }
110: else
111: len = Length((value) firstchild(n));
112: if (ep->s2 == 0 && ep->s3 >= len - 1) {
113: ep->mode = SUBSET;
114: ep->s2 = ep->s1;
115: continue;
116: }
117: return;
118:
119: case SUBSET:
120: subgrsubset(ep, ignorespaces);
121: if (ep->s1 == 1) {
122: if (ep->s2 == 2*nchildren(n) + 1) {
123: ep->mode = WHOLE;
124: continue;
125: }
126: if (ep->s2 == 2*nchildren(n) - 1 && issublist(sym)) {
127: ep->mode = SUBLIST;
128: ep->s3 = 1;
129: return;
130: }
131: }
132: return;
133:
134: case SUBLIST:
135: for (i = ep->s3; i > 0; --i)
136: n = lastchild(n);
137: sym = symbol(n);
138: if (sym == Optional) {
139: ep->mode = WHOLE;
140: continue;
141: }
142: return;
143:
144: case WHOLE:
145: ep->s1 = 2*ichild(ep->focus);
146: if (up(&ep->focus)) {
147: ep->mode = SUBSET;
148: ep->s2 = ep->s1;
149: higher(ep);
150: continue;
151: }
152: return; /* Leave as WHOLE if there is no parent */
153:
154: default:
155: Abort();
156: /* NOTREACHED */
157:
158: }
159:
160: }
161: /* Not reached */
162: }
163:
164:
165: /*
166: * Ditto to find smallest possible representation.
167: */
168:
169: Visible Procedure
170: shrink(ep)
171: register environ *ep;
172: {
173: register node n;
174: register int sym;
175:
176: for (;;) {
177: n = tree(ep->focus);
178: sym = symbol(n);
179:
180: switch (ep->mode) {
181:
182: case WHOLE:
183: if (sym == Hole || sym == Optional)
184: return;
185: ep->mode = SUBSET;
186: ep->s1 = 1;
187: ep->s2 = 2*nchildren(n) + 1;
188: continue;
189:
190: case SUBLIST:
191: if (sym == Hole || sym == Optional) {
192: ep->mode = WHOLE;
193: return;
194: }
195: if (ep->s3 == 1) {
196: ep->mode = SUBSET;
197: ep->s1 = 1;
198: ep->s2 = 2*nchildren(n) - 1;
199: continue;
200: }
201: return;
202:
203: case SUBSET:
204: if (sym == Hole || sym == Optional) {
205: ep->mode = WHOLE;
206: return;
207: }
208: shrsubset(ep);
209: if (ep->s1 == ep->s2) {
210: if (isunititem(ep)) {
211: ep->mode = SUBRANGE;
212: ep->s2 = 0;
213: ep->s3 = lenitem(ep) - 1;
214: return;
215: }
216: else {
217: s_downi(ep, ep->s1/2);
218: ep->mode = WHOLE;
219: continue;
220: }
221: }
222: return;
223:
224: case SUBRANGE:
225: if (sym == Optional || sym == Hole)
226: ep->mode = WHOLE;
227: return;
228:
229: case ATBEGIN:
230: ritevhole(ep);
231: if (ep->mode == ATBEGIN) {
232: if (sym == Optional || sym == Hole)
233: ep->mode = WHOLE;
234: return;
235: }
236: continue;
237:
238: case FHOLE:
239: case VHOLE:
240: ritevhole(ep);
241: if (ep->mode != VHOLE && ep->mode != FHOLE)
242: continue;
243: sym = symbol(tree(ep->focus));
244: if (sym == Optional || sym == Hole && ep->s2 == 0)
245: ep->mode = WHOLE;
246: return;
247:
248: case ATEND:
249: return;
250:
251: default:
252: Abort();
253: /* NOTREACHED */
254:
255: }
256: }
257: /* Not reached */
258:
259: }
260:
261:
262: /*
263: * Subroutine to find the largest way to describe a SUBSET focus
264: * (modulo surrounding blanks and newlines).
265: */
266:
267: Visible Procedure
268: growsubset(ep)
269: environ *ep;
270: {
271: subgrsubset(ep, Yes);
272: }
273:
274: Visible Procedure
275: subgrsubset(ep, ignorespaces)
276: register environ *ep;
277: bool ignorespaces;
278: {
279: register node n = tree(ep->focus);
280: register string *rp = noderepr(n);
281: register nch21 = nchildren(n)*2 + 1;
282: register int i;
283:
284: Assert(ep->mode == SUBSET);
285: for (i = ep->s1; i > 1 && subisnull(n, rp, i-1, ignorespaces); --i)
286: ;
287: ep->s1 = i;
288: for (i = ep->s2; i < nch21 && subisnull(n, rp, i+1, ignorespaces); ++i)
289: ;
290: ep->s2 = i;
291: }
292:
293:
294: /*
295: * Ditto for the smallest way.
296: */
297:
298: Visible Procedure /* Ought to be Hidden */
299: shrsubset(ep)
300: register environ *ep;
301: {
302: register node n = tree(ep->focus);
303: register string *rp = noderepr(n);
304: register int s1 = ep->s1;
305: register int s2 = ep->s2;
306:
307: for (; s1 < s2 && isnull(n, rp, s1); ++s1)
308: ;
309: ep->s1 = s1;
310: for (; s2 > s1 && isnull(n, rp, s2); --s2)
311: ;
312: ep->s2 = s2;
313: }
314:
315:
316: /*
317: * Subroutine for grow/shrink to see whether item i is (almost) invisible.
318: */
319:
320: Visible bool
321: isnull(n, rp, i)
322: node n;
323: string *rp;
324: int i;
325: {
326: return subisnull(n, rp, i, Yes);
327: }
328:
329: Hidden Procedure
330: subisnull(n, rp, i, ignorespaces)
331: register node n;
332: register string *rp;
333: register int i;
334: bool ignorespaces;
335: {
336: register string repr;
337: register node nn;
338:
339: if (i&1) { /* Fixed text */
340: repr = rp[i/2];
341: return !Fw_positive(repr) || ignorespaces && allspaces(repr);
342: }
343: nn = child(n, i/2);
344: return width(nn) == 0;
345: }
346:
347:
348: /*
349: * Find the rightmost VHOLE which would look the same as the current one.
350: */
351:
352: Visible Procedure
353: ritevhole(ep)
354: register environ *ep;
355: {
356: register node n;
357: register int ich;
358: register int len;
359: register int s1save;
360:
361: for (;;) {
362: n = tree(ep->focus);
363:
364: switch (ep->mode) {
365:
366: case WHOLE:
367: ep->mode = ATEND;
368: break;
369:
370: case VHOLE:
371: case FHOLE:
372: len = lenitem(ep);
373: Assert(len >= 0);
374: if (ep->s2 < len)
375: return; /* Hole in middle of string */
376: s1save = ep->s1;
377: if (nextitem(ep)) {
378: if (isunititem(ep)) {
379: ep->mode = (ep->s1&1) ? FHOLE : VHOLE;
380: ep->s2 = 0;
381: }
382: else if (fwidth(noderepr(child(n, ep->s1/2))[0]) < 0) {
383: /* Next item begins with newline -- avoid */
384: ep->s1 = s1save;
385: return;
386: }
387: else {
388: s_downi(ep, ep->s1/2);
389: ep->mode = ATBEGIN;
390: }
391: break;
392: }
393: ep->mode = ATEND;
394: /* Fall through */
395: case ATEND:
396: if (!parent(ep->focus) || width(n) < 0)
397: return;
398: ich = ichild(ep->focus);
399: ep->s1 = 2*ich;
400: s_up(ep);
401: if (nextitem(ep)) {
402: /* Note -- negative width cannot occur (see test above) */
403: if (isunititem(ep)) {
404: ep->mode = (ep->s1&1) ? FHOLE : VHOLE;
405: ep->s2 = 0;
406: }
407: else {
408: ep->mode = ATBEGIN;
409: s_downi(ep, ep->s1/2);
410: }
411: break;
412: }
413: continue;
414:
415: case ATBEGIN:
416: if (fwidth(noderepr(n)[0]) < 0)
417: return; /* Already at dangerous position */
418: ep->mode = FHOLE;
419: ep->s1 = 1;
420: ep->s2 = 0;
421: continue;
422:
423: default:
424: Abort();
425: /* NOTREACHED */
426:
427: }
428: }
429: }
430:
431:
432: /*
433: * Ditto to the left.
434: */
435:
436: Visible Procedure
437: leftvhole(ep)
438: register environ *ep;
439: {
440: register int ich;
441:
442: for (;;) {
443: switch (ep->mode) {
444:
445: case WHOLE:
446: ep->mode = ATBEGIN;
447: break;
448:
449: case VHOLE:
450: case FHOLE:
451: if (ep->s2 > 0)
452: return;
453: if (previtem(ep)) {
454: if (isunititem(ep)) {
455: ep->mode = (ep->s1&1) ? FHOLE : VHOLE;
456: ep->s2 = lenitem(ep);
457: }
458: else {
459: s_downi(ep, ep->s1/2);
460: ep->mode = ATEND;
461: }
462: }
463: else if (fwidth(noderepr(tree(ep->focus))[0]) < 0)
464: return;
465: else
466: ep->mode = ATBEGIN;
467: continue;
468:
469: case ATBEGIN:
470: ich = ichild(ep->focus);
471: if (!up(&ep->focus))
472: return;
473: higher(ep);
474: ep->s1 = 2*ich;
475: if (prevnnitem(ep)) {
476: if (isunititem(ep)) {
477: ep->mode = (ep->s1&1) ? FHOLE : VHOLE;
478: ep->s2 = lenitem(ep);
479: }
480: else {
481: s_downi(ep, ep->s1/2);
482: ep->mode = ATEND;
483: }
484: }
485: else if (fwidth(noderepr(tree(ep->focus))[0]) < 0) {
486: s_downi(ep, ich); /* Undo up */
487: return;
488: }
489: else
490: ep->mode = ATBEGIN;
491: continue;
492:
493: case ATEND:
494: lastnnitem(ep);
495: if (isunititem(ep)) {
496: ep->s2 = lenitem(ep);
497: ep->mode = (ep->s1&1) ? FHOLE : VHOLE;
498: }
499: else
500: s_downi(ep, ep->s1/2);
501: continue;
502:
503: default:
504: Abort();
505:
506: }
507: }
508: }
509:
510:
511: /*
512: * Safe up, downi, left and rite routines:
513: * 1) Rather die than fail;
514: * 2) Update ep->highest properly.
515: */
516:
517: Visible Procedure
518: s_up(ep)
519: register environ *ep;
520: {
521: if (!up(&ep->focus))
522: syserr("s_up failed");
523: higher(ep);
524: }
525:
526: Visible Procedure
527: s_downi(ep, i)
528: register environ *ep;
529: register int i;
530: {
531: if (!downi(&ep->focus, i))
532: syserr("s_downi failed");
533: }
534:
535: Visible Procedure
536: s_down(ep)
537: register environ *ep;
538: {
539: if (!down(&ep->focus))
540: syserr("s_down failed");
541: }
542:
543: Visible Procedure
544: s_downrite(ep)
545: register environ *ep;
546: {
547: if (!downrite(&ep->focus))
548: syserr("s_downrite failed");
549: }
550:
551: Visible Procedure
552: s_left(ep)
553: register environ *ep;
554: {
555: register int ich = ichild(ep->focus);
556:
557: s_up(ep);
558: s_downi(ep, ich-1);
559: }
560:
561: Visible Procedure
562: s_rite(ep)
563: register environ *ep;
564: {
565: register int ich = ichild(ep->focus);
566:
567: s_up(ep);
568: s_downi(ep, ich+1);
569: }
570:
571:
572: /*
573: * Find next item in a subset, using ep->s1 as index.
574: * (This used to be less trivial, so it's still a subroutine rather than
575: * coded in-line or as a macro.)
576: */
577:
578: Visible bool
579: nextitem(ep)
580: register environ *ep;
581: {
582: if (ep->s1 >= 2*nchildren(tree(ep->focus)) + 1)
583: return No; /* Already at last item */
584: ++ep->s1;
585: return Yes;
586: }
587:
588:
589: /*
590: * Ditto for previous.
591: */
592:
593: Visible bool
594: previtem(ep)
595: register environ *ep;
596: {
597: if (ep->s1 <= 1
598: || ep->s1 == 2 && fwidth(noderepr(tree(ep->focus))[0]) < 0)
599: return No; /* Already at first item */
600: --ep->s1;
601: return Yes;
602: }
603:
604:
605: /*
606: * Test whether item ep->s1 is "small", i.e., fixed or varying text
607: * but not a whole subtree.
608: */
609:
610: Visible bool
611: isunititem(ep)
612: register environ *ep;
613: {
614: return (ep->s1&1) || Type(child(tree(ep->focus), ep->s1/2)) == Tex;
615: }
616:
617:
618: /*
619: * Check for consistent mode information.
620: */
621:
622: Visible bool
623: checkep(ep)
624: register environ *ep;
625: {
626: switch (ep->mode) {
627:
628: case FHOLE:
629: if (!(ep->s1&1))
630: break;
631: if (ep->s2 < 0 || ep->s2 > lenitem(ep))
632: break;
633: return Yes;
634:
635: case VHOLE:
636: if (!(ep->s1&1)) {
637: if (Type(child(tree(ep->focus), ep->s1/2)) != Tex)
638: break;
639: }
640: if (ep->s2 < 0 || ep->s2 > lenitem(ep))
641: break;
642: return Yes;
643:
644: case SUBSET:
645: if (ep->s2 == ep->s1 && isunititem(ep) && lenitem(ep) <= 0)
646: break;
647: return Yes;
648:
649: default:
650: return Yes;
651:
652: }
653: dbmess(ep);
654: return No;
655: }
656:
657:
658: /*
659: * Like {next,prev,first,last}item, but with empty items skipped
660: * (i.e., those with length <= 0).
661: */
662:
663: Visible bool
664: nextnnitem(ep)
665: register environ *ep;
666: {
667: register int s1save = ep->s1;
668:
669: while (nextitem(ep)) {
670: if (lenitem(ep) != 0)
671: return Yes;
672: }
673: ep->s1 = s1save;
674: return No;
675: }
676:
677: Visible bool
678: prevnnitem(ep)
679: register environ *ep;
680: {
681: register int s1save = ep->s1;
682: register int len;
683:
684: while (previtem(ep)) {
685: len = lenitem(ep);
686: if (len > 0 || len < 0 && ep->s1 > 1)
687: return Yes;
688: }
689: ep->s1 = s1save;
690: return No;
691: }
692:
693:
694: Visible Procedure
695: firstnnitem(ep)
696: register environ *ep;
697: {
698: ep->s1 = fwidth(noderepr(tree(ep->focus))[0]) < 0 ? 2 : 1;
699: while (lenitem(ep) == 0) {
700: if (!nextitem(ep))
701: break;
702: }
703: return;
704: }
705:
706: Visible Procedure
707: lastnnitem(ep)
708: register environ *ep;
709: {
710: ep->s1 = 2*nchildren(tree(ep->focus)) + 1;
711: while (lenitem(ep) == 0) {
712: if (!previtem(ep))
713: break;
714: }
715: return;
716: }
717:
718:
719: /*
720: * Prepare the focus for insertion.
721: * If the focus isn't a hole, make a hole just before it which becomes the
722: * new focus.
723: * Also repair strange statuses left by moves, so we may have more chance
724: * to insert a character.
725: */
726:
727: Visible Procedure
728: fixit(ep)
729: register environ *ep;
730: {
731: /* First, make a hole if it's not already a hole. */
732:
733: switch (ep->mode) {
734:
735: case FHOLE:
736: break;
737:
738: case VHOLE:
739: if (ep->s1&1)
740: ep->mode = FHOLE;
741: break;
742:
743: case SUBRANGE:
744: if (ep->s1&1)
745: ep->mode = FHOLE;
746: else
747: ep->mode = VHOLE;
748: break;
749:
750: case SUBSET:
751: if (ep->s1&1) {
752: if (ep->s1 == 1)
753: ep->mode = ATBEGIN;
754: else {
755: ep->mode = FHOLE;
756: ep->s2 = 0;
757: }
758: }
759: else if (Type(child(tree(ep->focus), ep->s1/2)) == Tex) {
760: ep->mode = VHOLE;
761: ep->s2 = 0;
762: }
763: else {
764: s_downi(ep, ep->s1/2);
765: ep->mode = ATBEGIN;
766: }
767: break;
768:
769: case ATBEGIN:
770: case SUBLIST:
771: case WHOLE:
772: ep->mode = ATBEGIN;
773: break;
774:
775: case ATEND:
776: break;
777:
778: default:
779: Abort();
780: }
781:
782: leftvhole(ep);
783: if (ep->mode == ATEND && symbol(tree(ep->focus)) == Hole)
784: ep->mode = WHOLE; /***** Experiment! *****/
785: }
786:
787:
788: /*
789: * Small utility to see if a string contains only spaces
790: * (this is true for the empty string "").
791: * The string pointer must not be null!
792: */
793:
794: Visible bool
795: allspaces(str)
796: register string str;
797: {
798: Assert(str);
799: for (; *str; ++str) {
800: if (*str != ' ')
801: return No;
802: }
803: return Yes;
804: }
805:
806:
807: /*
808: * Function to compute the actual width of the focus.
809: */
810:
811: Visible int
812: focwidth(ep)
813: register environ *ep;
814: {
815: node nn;
816: register node n = tree(ep->focus);
817: register string *rp = noderepr(n);
818: register int i;
819: register int w;
820: int len = 0;
821:
822: switch (ep->mode) {
823:
824: case VHOLE:
825: case FHOLE:
826: case ATEND:
827: case ATBEGIN:
828: return 0;
829:
830: case WHOLE:
831: return width(n);
832:
833: case SUBRANGE:
834: return ep->s3 - ep->s2 + 1;
835:
836: case SUBSET:
837: for (i = ep->s1; i <= ep->s2; ++i) {
838: if (i&1)
839: w = fwidth(rp[i/2]);
840: else {
841: nn = child(n, i/2);
842: w = width(nn);
843: }
844: if (w < 0 && len >= 0)
845: len = w;
846: else if (w >= 0 && len < 0)
847: ;
848: else
849: len += w;
850: }
851: return len;
852:
853: case SUBLIST:
854: len = width(n);
855: for (i = ep->s3; i > 0; --i)
856: n = lastchild(n);
857: w = width(n);
858: if (w < 0 && len >= 0)
859: return w;
860: if (w >= 0 && len < 0)
861: return len;
862: return len - w;
863:
864: default:
865: Abort();
866: /* NOTREACHED */
867: }
868: }
869:
870:
871: /*
872: * Compute the offset of the focus from the beginning of the current node.
873: * This may be input again to fixfocus to allow restoration of this position.
874: */
875:
876: Visible int
877: focoffset(ep)
878: register environ *ep;
879: {
880: node nn;
881: register node n;
882: register string *rp;
883: register int w;
884: register int len;
885: register int i;
886:
887: switch (ep->mode) {
888:
889: case WHOLE:
890: case SUBLIST:
891: return 0;
892:
893: case ATBEGIN:
894: return ep->spflag;
895:
896: case ATEND:
897: w = width(tree(ep->focus));
898: if (w < 0)
899: return w;
900: return w + ep->spflag;
901:
902: case SUBSET:
903: case FHOLE:
904: case VHOLE:
905: case SUBRANGE:
906: n = tree(ep->focus);
907: rp = noderepr(n);
908: len = 0;
909: for (i = 1; i < ep->s1; ++i) {
910: if (i&1)
911: w = Fwidth(rp[i/2]);
912: else {
913: nn = child(n, i/2);
914: w = width(nn);
915: }
916: if (w < 0) {
917: if (len >= 0)
918: len = w;
919: else
920: len += w;
921: }
922: else if (len >= 0)
923: len += w;
924: }
925: if (ep->mode == SUBSET || len < 0)
926: return len;
927: return len + ep->s2 + ep->spflag;
928:
929: default:
930: Abort();
931: /* NOTREACHED */
932: }
933: }
934:
935:
936: /*
937: * Return the first character of the focus (maybe '\n'; 0 if zero-width).
938: */
939:
940: Visible int
941: focchar(ep)
942: environ *ep;
943: {
944: node n = tree(ep->focus);
945: string str;
946: string *rp;
947: int i;
948: int c;
949:
950: switch (ep->mode) {
951:
952: case VHOLE:
953: case FHOLE:
954: case ATBEGIN:
955: case ATEND:
956: return 0;
957:
958: case WHOLE:
959: case SUBLIST:
960: return nodechar(n);
961:
962: case SUBSET:
963: rp = noderepr(n);
964: for (i = ep->s1; i <= ep->s2; ++i) {
965: if (i&1) {
966: if (!Fw_zero(rp[i/2]))
967: return rp[i/2][0];
968: }
969: else {
970: c = nodechar(child(n, i/2));
971: if (c)
972: return c;
973: }
974: }
975: return 0;
976:
977: case SUBRANGE:
978: if (ep->s1&1)
979: str = noderepr(n)[ep->s1/2];
980: else {
981: Assert(Type(child(n, ep->s1/2)) == Tex);
982: str = Str((value)child(n, ep->s1/2));
983: }
984: return str[ep->s2];
985:
986: default:
987: Abort();
988: /* NOTREACHED */
989:
990: }
991: }
992:
993:
994: /*
995: * Subroutine to return first character of node.
996: */
997:
998: Visible int
999: nodechar(n)
1000: node n;
1001: {
1002: string *rp;
1003: int nch;
1004: int i;
1005: int c;
1006:
1007: if (Type(n) == Tex)
1008: return Str((value)n)[0];
1009: rp = noderepr(n);
1010: if (!Fw_zero(rp[0]))
1011: return rp[0][0];
1012: nch = nchildren(n);
1013: for (i = 1; i <= nch; ++i) {
1014: c = nodechar(child(n, i));
1015: if (c)
1016: return c;
1017: if (!Fw_zero(rp[i]))
1018: return rp[i][0];
1019: }
1020: return 0;
1021: }
1022:
1023:
1024: /*
1025: * Function to compute the actual indentation level at the focus.
1026: */
1027:
1028: Visible int
1029: focindent(ep)
1030: environ *ep;
1031: {
1032: int y = Ycoord(ep->focus);
1033: int x = Xcoord(ep->focus);
1034: int level = Level(ep->focus);
1035: node n = tree(ep->focus);
1036:
1037: switch (ep->mode) {
1038:
1039: case WHOLE:
1040: case ATBEGIN:
1041: case SUBLIST:
1042: break;
1043:
1044: case ATEND:
1045: evalcoord(n, 1 + nchildren(n), &y, &x, &level);
1046: break;
1047:
1048: case SUBSET:
1049: case FHOLE:
1050: case VHOLE:
1051: evalcoord(n, ep->s1/2, &y, &x, &level);
1052: break;
1053:
1054: default:
1055: Abort();
1056: }
1057: return level;
1058: }
1059:
1060:
1061: /*
1062: * Routines to move 'environ' structures.
1063: */
1064:
1065: emove(s, d)
1066: environ *s;
1067: environ *d;
1068: {
1069: #ifdef STRUCTASS
1070: *d = *s;
1071: #else !STRUCTASS
1072: d->focus = s->focus;
1073:
1074: d->mode = s->mode;
1075: d->copyflag = s->copyflag;
1076: d->spflag = s->spflag;
1077: d->changed = s->changed;
1078:
1079: d->s1 = s->s1;
1080: d->s2 = s->s2;
1081: d->s3 = s->s3;
1082:
1083: d->highest = s->highest;
1084:
1085: d->copybuffer = s->copybuffer;
1086: #ifdef RECORDING
1087: d->oldmacro = s->oldmacro;
1088: d->newmacro = s->newmacro;
1089: #endif RECORDING
1090:
1091: d->generation = s->generation;
1092: #endif !STRUCTASS
1093: }
1094:
1095: ecopy(s, d)
1096: environ *s;
1097: environ *d;
1098: {
1099: emove(s, d);
1100: pathcopy(d->focus);
1101: copy(d->copybuffer);
1102: #ifdef RECORDING
1103: copy(d->oldmacro);
1104: copy(d->newmacro);
1105: #endif RECORDING
1106: }
1107:
1108: erelease(e)
1109: environ *e;
1110: {
1111: pathrelease(e->focus);
1112: release(e->copybuffer);
1113: #ifdef RECORDING
1114: release(e->oldmacro);
1115: release(e->newmacro);
1116: #endif RECORDING
1117: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.