Annotation of 43BSD/contrib/B/src/bed/deco.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.