|
|
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.