# 2.11BSD#431 - /usr/src/new/PORT/B/src/bed/deco.c

##### Functions

    allright          X
    balance           X
    colonhack         X
    copyin            X
    copyinout         X
    copyout           X
    delbody           X
    delete            X
    delfixed          X
    delfocus          X
    delhole           X
    delsublist        X
    delsubset         X
    delvarying        X
    delwhole          X
    ishole            X
    nonewline         X

       1: /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */
       2: static char rcsid[] = "$Header: deco.c,v 2.3 84/07/19 11:45:12 guido Exp $";
       3:
       4: /*
       5:  * B editor -- Delete and copy commands.
       6:  */
       7:
       8: #include <ctype.h>
       9:
      10: #include "b.h"
      11: #include "erro.h"
      12: #include "bobj.h"
      13: #include "node.h"
      14: #include "gram.h"
      15: #include "supr.h"
      16: #include "queu.h"
      17:
      18:
      19: value copyout(); /* Forward */
      20:
      21: /*
      22:  * DELETE and COPY currently share a buffer, called the copy buffer.
      23:  * (Physically, there is one such a buffer in each environment.)
      24:  * In ordinary use, the copy buffer receives the text deleted by the
      25:  * last DELETE command (unless it just removed a hole); the COPY command
      26:  * can then be used (with the focus on a hole) to copy it back.
      27:  * When some portion of text must be held while other text is deleted,
      28:  * the COPY command again, but now with the focus on the text to be held,
      29:  * copies it to the buffer and deleted text won't overwrite the buffer
      30:  * until it is copied back at least once.
      31:  * If the buffer holds text that was explicitly copied out but not yet
      32:  * copied back in, it is saved on a file when the editor exits, so it can
      33:  * be used in the next session; but this is not true for text implicitly
      34:  * placed in the buffer through DELETE.
      35:  */
      36:
      37: /*
      38:  * Delete command -- delete the text in the focus, or delete the hole
      39:  * if it is only a hole.
      40:  */
      41:
      42: Visible bool
      43: delete(ep)
      44:     register environ *ep;
      45: {
      46:     higher(ep);
      47:     shrink(ep);
      48:     if (ishole(ep))
      49:         return delhole(ep);
      50:     if (!ep->copyflag) {
      51:         release(ep->copybuffer);
      52:         ep->copybuffer = copyout(ep);
      53:     }
      54:     return delbody(ep);
      55: }
      56:
      57:
      58: /*
      59:  * Delete the focus under the assumption that it contains some text.
      60:  */
      61:
      62: Visible bool
      63: delbody(ep)
      64:     register environ *ep;
      65: {
      66:     ep->changed = Yes;
      67:
      68:     subgrow(ep, No); /* Don't ignore spaces */
      69:     switch (ep->mode) {
      70:
      71:     case SUBRANGE:
      72:         if (ep->s1&1)
      73:             return delfixed(ep);
      74:         return delvarying(ep);
      75:
      76:     case SUBSET:
      77:         return delsubset(ep, Yes);
      78:
      79:     case SUBLIST:
      80:         return delsublist(ep);
      81:
      82:     case WHOLE:
      83:         return delwhole(ep);
      84:
      85:     default:
      86:         Abort();
      87:         /* NOTREACHED */
      88:     }
      89: }
      90:
      91:
      92: /*
      93:  * Delete portion (ep->mode == SUBRANGE) of varying text ((ep->s1&1) == 0).
      94:  */
      95:
      96: Hidden bool
      97: delvarying(ep)
      98:     register environ *ep;
      99: {
     100:     auto queue q = Qnil;
     101:     register node n = tree(ep->focus);
     102:     auto value v = (value) child(n, ep->s1/2);
     103:     register len = Length(v);
     104:
     105:     Assert(ep->mode == SUBRANGE && !(ep->s1&1)); /* Wrong call */
     106:     Assert(Type(v) == Tex); /* Inconsistent parse tree */
     107:     if (ep->s2 == 0
     108:         && !mayinsert(tree(ep->focus), ep->s1/2, 0, Str(v)[ep->s3 + 1])) {
     109:         /* Cannot do simple substring deletion. */
     110:         stringtoqueue(Str(v) + ep->s3 + 1, &q);
     111:         delfocus(&ep->focus);
     112:         ep->mode = WHOLE;
     113:         return app_queue(ep, &q);
     114:     }
     115:     v = copy(v);
     116:     putintrim(&v, ep->s2, len - ep->s3 - 1, "");
     117:     s_downi(ep, ep->s1/2);
     118:     replace(&ep->focus, (node) v);
     119:     s_up(ep);
     120:     ep->mode = VHOLE;
     121:     return Yes;
     122: }
     123:
     124:
     125: /*
     126:  * Delete portion (ep->mode == SUBRANGE) of fixed text ((ep->s1&1) == 1).
     127:  */
     128:
     129: Hidden bool
     130: delfixed(ep)
     131:     register environ *ep;
     132: {
     133:     register node n = tree(ep->focus);
     134:     char buf[15]; /* Long enough for all fixed texts */
     135:     register string repr = noderepr(n)[ep->s1/2];
     136:     register int len;
     137:     queue q = Qnil;
     138:     bool ok;
     139:
     140:     Assert(ep->mode == SUBRANGE && (ep->s1&1));
     141:     if (ep->s1 > 1) {
     142:         ep->mode = FHOLE;
     143:         return Yes;
     144:     }
     145:     Assert(fwidth(repr) < sizeof buf - 1);
     146:     len = ep->s2;
     147:     ep->s2 = ep->s3 + 1;
     148:     ep->mode = FHOLE;
     149:     nosuggtoqueue(ep, &q);
     150:     strcpy(buf, repr);
     151:     if (nchildren(tree(ep->focus)) > 0)
     152:         buf[len] = 0;
     153:     else
     154:         strcpy(buf+len, buf+ep->s2);
     155:     delfocus(&ep->focus);
     156:     ep->mode = WHOLE;
     157:     markpath(&ep->focus, 1);
     158:     ok = ins_string(ep, buf, &q, 0);
     159:     if (!ok) {
     160:         qrelease(q);
     161:         return No;
     162:     }
     163:     firstmarked(&ep->focus, 1) || Abort();
     164:     unmkpath(&ep->focus, 1);
     165:     fixfocus(ep, len);
     166:     return app_queue(ep, &q);
     167: }
     168:
     169:
     170: /*
     171:  * Delete focus if ep->mode == SUBSET.
     172:  */
     173:
     174: Hidden bool
     175: delsubset(ep, hack)
     176:     register environ *ep;
     177:     bool hack;
     178: {
     179:     auto queue q = Qnil;
     180:     auto queue q2 = Qnil;
     181:     register node n = tree(ep->focus);
     182:     register node nn;
     183:     register string *rp = noderepr(n);
     184:     register int nch = nchildren(n);
     185:     register int i;
     186:
     187:     if (hack) {
     188:         shrsubset(ep);
     189:         if (ep->s1 == ep->s2 && !(ep->s1&1)) {
     190:             nn = child(tree(ep->focus), ep->s1/2);
     191:             if (fwidth(noderepr(nn)[0]) < 0) {
     192:                 /* It starts with a newline, leave the newline */
     193:                 s_downi(ep, ep->s1/2);
     194:                 ep->mode = SUBSET;
     195:                 ep->s1 = 2;
     196:                 ep->s2 = 2*nchildren(nn) + 1;
     197:                 return delsubset(ep, hack);
     198:             }
     199:         }
     200:         subgrsubset(ep, No); /* Undo shrsubset */
     201:         if (ep->s2 == 3 && rp[1] && Strequ(rp[1], "\t"))
     202:             --ep->s2; /* Hack for deletion of unit-head or if/for/wh. head */
     203:     }
     204:     if (ep->s1 == 1 && Fw_negative(rp[0]))
     205:         ++ep->s1; /* Hack for deletion of test-suite or refinement head */
     206:
     207:     if (Fw_zero(rp[0]) ? (ep->s2 < 3 || ep->s1 > 3) : ep->s1 > 1) {
     208:         /* No deep structural change */
     209:         for (i = (ep->s1+1)/2; i <= ep->s2/2; ++i) {
     210:             s_downi(ep, i);
     211:             delfocus(&ep->focus);
     212:             s_up(ep);
     213:         }
     214:         if (ep->s1&1) {
     215:             ep->mode = FHOLE;
     216:             ep->s2 = 0;
     217:         }
     218:         else if (Type(child(tree(ep->focus), ep->s1/2)) == Tex) {
     219:             ep->mode = VHOLE;
     220:             ep->s2 = 0;
     221:         }
     222:         else {
     223:             s_downi(ep, ep->s1/2);
     224:             ep->mode = ATBEGIN;
     225:         }
     226:         return Yes;
     227:     }
     228:
     229:     balance(ep); /* Make balanced \t - \b pairs */
     230:     subsettoqueue(n, 1, ep->s1-1, &q);
     231:     subsettoqueue(n, ep->s2+1, 2*nch+1, &q2);
     232:     nonewline(&q2); /* Wonder what will happen...? */
     233:     delfocus(&ep->focus);
     234:     ep->mode = ATBEGIN;
     235:     leftvhole(ep);
     236:     if (!ins_queue(ep, &q, &q2)) {
     237:         qrelease(q2);
     238:         return No;
     239:     }
     240:     return app_queue(ep, &q2);
     241: }
     242:
     243:
     244: /*
     245:  * Delete the focus if ep->mode == SUBLIST.
     246:  */
     247:
     248: delsublist(ep)
     249:     register environ *ep;
     250: {
     251:     register node n;
     252:     register int i;
     253:     register int sym;
     254:     queue q = Qnil;
     255:     bool flag;
     256:
     257:     Assert(ep->mode == SUBLIST);
     258:     n = tree(ep->focus);
     259:     flag = fwidth(noderepr(n)[0]) < 0;
     260:     for (i = ep->s3; i > 0; --i) {
     261:         n = lastchild(n);
     262:         Assert(n);
     263:     }
     264:     if (flag) {
     265:         n = nodecopy(n);
     266:         s_down(ep);
     267:         do {
     268:             delfocus(&ep->focus);
     269:         } while (rite(&ep->focus));
     270:         if (!allowed(ep->focus, symbol(n))) {
     271:             error(DEL_REM); /* The remains wouldn't fit */
     272:             noderelease(n);
     273:             return No;
     274:         }
     275:         replace(&ep->focus, n);
     276:         s_up(ep);
     277:         s_down(ep); /* I.e., to leftmost sibling */
     278:         ep->mode = WHOLE;
     279:         return Yes;
     280:     }
     281:     sym = symbol(n);
     282:     if (sym == Optional || sym == Hole) {
     283:         delfocus(&ep->focus);
     284:         ep->mode = WHOLE;
     285:     }
     286:     else if (!allowed(ep->focus, sym)) {
     287:         preptoqueue(n, &q);
     288:         delfocus(&ep->focus);
     289:         ep->mode = WHOLE;
     290:         return app_queue(ep, &q);
     291:     }
     292:     else {
     293:         replace(&ep->focus, nodecopy(n));
     294:         ep->mode = ATBEGIN;
     295:     }
     296:     return Yes;
     297: }
     298:
     299:
     300: /*
     301:  * Delete the focus if ep->mode == WHOLE.
     302:  */
     303:
     304: Hidden bool
     305: delwhole(ep)
     306:     register environ *ep;
     307: {
     308:     register int sym = symbol(tree(ep->focus));
     309:
     310:     Assert(ep->mode == WHOLE);
     311:     if (sym == Optional || sym == Hole)
     312:         return No;
     313:     delfocus(&ep->focus);
     314:     return Yes;
     315: }
     316:
     317:
     318: /*
     319:  * Delete the focus if it is only a hole.
     320:  * Assume shrink() has been called before!
     321:  */
     322:
     323: Hidden bool
     324: delhole(ep)
     325:     register environ *ep;
     326: {
     327:     node n;
     328:     int sym;
     329:     bool flag = No;
     330:
     331:     switch (ep->mode) {
     332:
     333:     case ATBEGIN:
     334:     case VHOLE:
     335:     case FHOLE:
     336:     case ATEND:
     337:         return widen(ep);
     338:
     339:     case WHOLE:
     340:         Assert((sym = symbol(tree(ep->focus))) == Optional || sym == Hole);
     341:         if (ichild(ep->focus) != 1)
     342:             break;
     343:         if (!up(&ep->focus))
     344:             return No;
     345:         higher(ep);
     346:         ep->mode = SUBSET;
     347:         ep->s1 = 2;
     348:         ep->s2 = 2;
     349:         if (fwidth(noderepr(tree(ep->focus))[0]) < 0) {
     350:             flag = Yes;
     351:             ep->s2 = 3; /* Extend to rest of line */
     352:         }
     353:     }
     354:
     355:     ep->changed = Yes;
     356:     grow(ep);
     357:
     358:     switch (ep->mode) {
     359:
     360:     case SUBSET:
     361:         if (!delsubset(ep, No))
     362:             return No;
     363:         if (!flag)
     364:             return widen(ep);
     365:         leftvhole(ep);
     366:         oneline(ep);
     367:         return Yes;
     368:
     369:     case SUBLIST:
     370:         n = tree(ep->focus);
     371:         n = lastchild(n);
     372:         sym = symbol(n);
     373:         if (!allowed(ep->focus, sym)) {
     374:             error(DEL_REM); /* The remains wouldn't fit */
     375:             return No;
     376:         }
     377:         flag = samelevel(sym, symbol(tree(ep->focus)));
     378:         replace(&ep->focus, nodecopy(n));
     379:         if (flag) {
     380:             ep->mode = SUBLIST;
     381:             ep->s3 = 1;
     382:         }
     383:         else
     384:             ep->mode = WHOLE;
     385:         return Yes;
     386:
     387:     case WHOLE:
     388:         Assert(!parent(ep->focus)); /* Must be at root! */
     389:         return No;
     390:
     391:     default:
     392:         Abort();
     393:         /* NOTREACHED */
     394:
     395:     }
     396: }
     397:
     398:
     399: /*
     400:  * Subroutine to delete the focus.
     401:  */
     402:
     403: Visible Procedure
     404: delfocus(pp)
     405:     register path *pp;
     406: {
     407:     register path pa = parent(*pp);
     408:     register int sympa = pa ? symbol(tree(pa)) : Rootsymbol;
     409:
     410:     replace(pp, child(gram(sympa), ichild(*pp)));
     411: }
     412:
     413:
     414: /*
     415:  * Copy command -- copy the focus to the copy buffer if it contains
     416:  * some text, copy the copy buffer into the focus if the focus is
     417:  * empty (just a hole).
     418:  */
     419:
     420: Visible bool
     421: copyinout(ep)
     422:     register environ *ep;
     423: {
     424:     shrink(ep);
     425:     if (!ishole(ep)) {
     426:         release(ep->copybuffer);
     427:         ep->copybuffer = copyout(ep);
     428:         ep->copyflag = !!ep->copybuffer;
     429:         return ep->copyflag;
     430:     }
     431:     else {
     432:         fixit(ep); /* Make sure it looks like a hole now */
     433:         if (!copyin(ep, (queue) ep->copybuffer))
     434:             return No;
     435:         ep->copyflag = No;
     436:         return Yes;
     437:     }
     438: }
     439:
     440:
     441: /*
     442:  * Copy the focus to the copy buffer.
     443:  */
     444:
     445: Visible value
     446: copyout(ep)
     447:     register environ *ep;
     448: {
     449:     auto queue q = Qnil;
     450:     auto path p;
     451:     register node n;
     452:     register value v;
     453:     char buf[15];
     454:     register string *rp;
     455:     register int i;
     456:
     457:     switch (ep->mode) {
     458:     case WHOLE:
     459:         preptoqueue(tree(ep->focus), &q);
     460:         break;
     461:     case SUBLIST:
     462:         p = pathcopy(ep->focus);
     463:         for (i = ep->s3; i > 0; --i)
     464:             downrite(&p) || Abort();
     465:         for (i = ep->s3; i > 0; --i) {
     466:             up(&p) || Abort();
     467:             n = tree(p);
     468:             subsettoqueue(n, 1, 2*nchildren(n) - 1, &q);
     469:         }
     470:         pathrelease(p);
     471:         break;
     472:     case SUBSET:
     473:         balance(ep);
     474:         subsettoqueue(tree(ep->focus), ep->s1, ep->s2, &q);
     475:         break;
     476:     case SUBRANGE:
     477:         Assert(ep->s3 >= ep->s2);
     478:         if (ep->s1&1) { /* Fixed text */
     479:             Assert(ep->s3 - ep->s2 + 1 < sizeof buf);
     480:             rp = noderepr(tree(ep->focus));
     481:             Assert(ep->s2 < Fwidth(rp[ep->s1/2]));
     482:             strncpy(buf, rp[ep->s1/2] + ep->s2, ep->s3 - ep->s2 + 1);
     483:             buf[ep->s3 - ep->s2 + 1] = 0;
     484:             stringtoqueue(buf, &q);
     485:         }
     486:         else { /* Varying text */
     487:             v = (value) child(tree(ep->focus), ep->s1/2);
     488:             Assert(Type(v) == Tex);
     489:             v = trim(v, ep->s2, Length(v) - ep->s3 - 1);
     490:             preptoqueue((node)v, &q);
     491:             release(v);
     492:         }
     493:         break;
     494:     default:
     495:         Abort();
     496:     }
     497:     nonewline(&q);
     498:     return (value)q;
     499: }
     500:
     501:
     502: /*
     503:  * Subroutine to ensure the copy buffer doesn't start with a newline.
     504:  */
     505:
     506: Hidden Procedure
     507: nonewline(pq)
     508:     register queue *pq;
     509: {
     510:     register node n;
     511:     register int c;
     512:
     513:     if (!emptyqueue(*pq)) {
     514:         for (;;) {
     515:             n = queuebehead(pq);
     516:             if (Type(n) == Tex) {
     517:                 if (Str((value) n)[0] != '\n')
     518:                     preptoqueue(n, pq);
     519:                 noderelease(n);
     520:                 break;
     521:             }
     522:             else {
     523:                 c = nodechar(n);
     524:                 if (c != '\n')
     525:                     preptoqueue(n, pq);
     526:                 else
     527:                     splitnode(n, pq);
     528:                 noderelease(n);
     529:                 if (c != '\n')
     530:                     break;
     531:             }
     532:         }
     533:     }
     534: }
     535:
     536:
     537: /*
     538:  * Refinement for copyout, case SUBSET: make sure that \t is balanced with \b.
     539:  * Actually it can only handle the case where a \t is in the subset and the
     540:  * matching \b is immediately following.
     541:  */
     542:
     543: Hidden Procedure
     544: balance(ep)
     545:     environ *ep;
     546: {
     547:     string *rp = noderepr(tree(ep->focus));
     548:     int i;
     549:     int level = 0;
     550:
     551:     Assert(ep->mode == SUBSET);
     552:     for (i = ep->s1/2; i*2 < ep->s2; ++i) {
     553:         if (rp[i]) {
     554:             if (index(rp[i], '\t'))
     555:                 ++level;
     556:             else if (index(rp[i], '\b'))
     557:                 --level;
     558:         }
     559:     }
     560:     if (level > 0 && i*2 == ep->s2 && rp[i] && index(rp[i], '\b'))
     561:         ep->s2 = 2*i + 1;
     562: }
     563:
     564:
     565: /*
     566:  * Copy the copy buffer to the focus.
     567:  */
     568:
     569: Hidden bool
     570: copyin(ep, q)
     571:     register environ *ep;
     572:     /*auto*/ queue q;
     573: {
     574:     auto queue q2 = Qnil;
     575:
     576:     if (!q) {
     577:         error(COPY_EMPTY); /* Empty copy buffer */
     578:         return No;
     579:     }
     580:     ep->changed = Yes;
     581:     q = qcopy(q);
     582:     if (!ins_queue(ep, &q, &q2)) {
     583:         qrelease(q2);
     584:         return No;
     585:     }
     586:     return app_queue(ep, &q2);
     587: }
     588:
     589:
     590: /*
     591:  * Find out whether the focus looks like a hole or if it has some real
     592:  * text in it.
     593:  * Assumes shrink(ep) has already been performed.
     594:  */
     595:
     596: Visible bool
     597: ishole(ep)
     598:     register environ *ep;
     599: {
     600:     register int sym;
     601:
     602:     switch (ep->mode) {
     603:
     604:     case ATBEGIN:
     605:     case ATEND:
     606:     case VHOLE:
     607:     case FHOLE:
     608:         return Yes;
     609:
     610:     case SUBLIST:
     611:     case SUBRANGE:
     612:         return No;
     613:
     614:     case SUBSET:
     615:         return colonhack(ep); /* (Side-effect!) */
     616:
     617:     case WHOLE:
     618:         sym = symbol(tree(ep->focus));
     619:         return sym == Optional || sym == Hole;
     620:
     621:     default:
     622:         Abort();
     623:         /* NOTREACHED */
     624:     }
     625: }
     626:
     627:
     628: /*
     629:  * Amendment to ishole so that it categorizes '?: ?' as a hole.
     630:  * This makes deletion of empty refinements / alternative-suites
     631:  * easier (Steven).
     632:  */
     633:
     634: Hidden bool
     635: colonhack(ep)
     636:     environ *ep;
     637: {
     638:     node n = tree(ep->focus);
     639:     node n1;
     640:     string *rp = noderepr(n);
     641:     int i;
     642:     int sym;
     643:
     644:     for (i = ep->s1; i <= ep->s2; ++i) {
     645:         if (i&1) {
     646:             if (!allright(rp[i/2]))
     647:                 return No;
     648:         }
     649:         else {
     650:             n1 = child(n, i/2);
     651:             if (Type(n1) == Tex)
     652:                 return No;
     653:             sym = symbol(n1);
     654:             if (sym != Hole && sym != Optional)
     655:                 return No;
     656:         }
     657:     }
     658:     return Yes;
     659: }
     660:
     661:
     662: /*
     663:  * Refinement for colonhack.  Recognize strings that are almost blank
     664:  * (i.e. containing only spaces, colons and the allowed control characters).
     665:  */
     666:
     667: Hidden bool
     668: allright(repr)
     669:     string repr;
     670: {
     671:     if (repr) {
     672:         for (; *repr; ++repr) {
     673:             if (!index(": \t\b\n\r", *repr))
     674:                 return No;
     675:         }
     676:     }
     677:     return Yes;
     678: }

#### Defined functions

allright defined in line 667; used 1 times

- in line 646

balance defined in line 543; used 2 times

- in line 229, 473

colonhack defined in line 634; used 1 times

- in line 615

copyin defined in line 569; used 1 times

- in line 433

copyinout defined in line 420; used 1 times

- in /usr/src/new/PORT/B/src/bed/demo.c line 615

copyout defined in line 445; used 5 times

- in line 19, 52, 427
- in /usr/src/new/PORT/B/src/bed/ins2.c line 29, 39

delbody defined in line 62; used 2 times

- in line 54
- in /usr/src/new/PORT/B/src/bed/ins2.c line 40

delete defined in line 42; used 4 times

- in /usr/src/new/PORT/B/src/bed/demo.c line 136, 154, 619, 791

delfixed defined in line 129; used 1 times

- in line 73

delfocus defined in line 403; used 16 times

- in line 111, 155, 211, 233, 268, 283-288(2), 313
- in /usr/src/new/PORT/B/src/bed/demo.c line 126
- in /usr/src/new/PORT/B/src/bed/ins2.c line 215, 268
- in /usr/src/new/PORT/B/src/bed/que1.c line 255
- in /usr/src/new/PORT/B/src/bed/que2.c line 299, 412, 564
- in /usr/src/new/PORT/B/src/bed/sugg.c line 305

delhole defined in line 323; used 1 times

- in line 49

delsublist defined in line 248; used 1 times

- in line 80

delsubset defined in line 174; used 3 times

- in line 77, 197, 361

delvarying defined in line 96; used 1 times

- in line 74

delwhole defined in line 304; used 1 times

- in line 83

ishole defined in line 596; used 4 times

- in line 48, 425
- in /usr/src/new/PORT/B/src/bed/demo.c line 790
- in /usr/src/new/PORT/B/src/bed/ins2.c line 37

nonewline defined in line 506; used 2 times

- in line 232, 497

#### 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: 1705 |