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