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

Defined functions

allspaces defined in line 794; used 3 times
checkep defined in line 622; used 3 times
ecopy defined in line 1095; used 1 times
emove defined in line 1065; used 2 times
erelease defined in line 1108; used 1 times
firstnnitem defined in line 694; never used
focindent defined in line 1028; used 3 times
growsubset defined in line 267; never used
isnull defined in line 320; used 2 times
isunititem defined in line 610; used 7 times
lastnnitem defined in line 706; used 1 times
nextitem defined in line 578; used 4 times
nextnnitem defined in line 663; used 1 times
nodechar defined in line 998; used 4 times
previtem defined in line 593; used 3 times
prevnnitem defined in line 677; used 2 times
s_left defined in line 551; never used
s_rite defined in line 561; never used
shrsubset defined in line 298; used 2 times
subgrow defined in line 50; used 2 times
subgrsubset defined in line 274; used 3 times
subisnull defined in line 329; used 3 times

Defined variables

rcsid defined in line 2; never used
Last modified: 1985-08-27
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2891
Valid CSS Valid XHTML 1.0 Strict