Annotation of 3BSD/cmd/ex/ex_cmdsub.c, revision 1.1.1.1

1.1       root        1: /* Copyright (c) 1979 Regents of the University of California */
                      2: #include "ex.h"
                      3: #include "ex_argv.h"
                      4: #include "ex_temp.h"
                      5: #include "ex_tty.h"
                      6: 
                      7: /*
                      8:  * Command mode subroutines implementing
                      9:  *     append, args, copy, delete, join, move, put,
                     10:  *     shift, tag, yank, z and undo
                     11:  */
                     12: 
                     13: bool   endline = 1;
                     14: line   *tad1;
                     15: 
                     16: /*
                     17:  * Append after line a lines returned by function f.
                     18:  * Be careful about intermediate states to avoid scramble
                     19:  * if an interrupt comes in.
                     20:  */
                     21: append(f, a)
                     22:        int (*f)();
                     23:        line *a;
                     24: {
                     25:        register line *a1, *a2, *rdot;
                     26:        int nline;
                     27: 
                     28:        nline = 0;
                     29:        dot = a;
                     30:        /*
                     31:         * This is probably a bug, since it's different than the other tests
                     32:         * in appendnone, delete, and deletenone. It is known to fail for
                     33:         * the command :g/foo/r xxx (where there is one foo and the file
                     34:         * xxx exists) and you try to undo it. I'm leaving it in for now
                     35:         * because I'm afraid if I change it I'll break something.
                     36:         */
                     37:        if (!inglobal && !inopen && f != getsub) {
                     38:                undap1 = undap2 = dot + 1;
                     39:                undkind = UNDCHANGE;
                     40:        }
                     41:        while ((*f)() == 0) {
                     42:                if (truedol >= endcore) {
                     43:                        if (morelines() < 0) {
                     44:                                if (!inglobal && f == getsub) {
                     45:                                        undap1 = addr1;
                     46:                                        undap2 = addr2 + 1;
                     47:                                }
                     48:                                error("Out of memory@- too many lines in file");
                     49:                        }
                     50:                }
                     51:                nline++;
                     52:                a1 = truedol + 1;
                     53:                a2 = a1 + 1;
                     54:                dot++;
                     55:                undap2++;
                     56:                dol++;
                     57:                unddol++;
                     58:                truedol++;
                     59:                for (rdot = dot; a1 > rdot;)
                     60:                        *--a2 = *--a1;
                     61:                *rdot = 0;
                     62:                putmark(rdot);
                     63:                if (f == gettty) {
                     64:                        dirtcnt++;
                     65:                        TSYNC();
                     66:                }
                     67:        }
                     68:        return (nline);
                     69: }
                     70: 
                     71: appendnone()
                     72: {
                     73: 
                     74:        if (inopen >= 0 && (inopen || !inglobal)) {
                     75:                undkind = UNDCHANGE;
                     76:                undap1 = undap2 = addr1;
                     77:        }
                     78: }
                     79: 
                     80: /*
                     81:  * Print out the argument list, with []'s around the current name.
                     82:  */
                     83: pargs()
                     84: {
                     85:        register char **av = argv0, *as = args0;
                     86:        register int ac;
                     87: 
                     88:        for (ac = 0; ac < argc0; ac++) {
                     89:                if (ac != 0)
                     90:                        putchar(' ');
                     91:                if (ac + argc == argc0 - 1)
                     92:                        printf("[");
                     93:                lprintf("%s", as);
                     94:                if (ac + argc == argc0 - 1)
                     95:                        printf("]");
                     96:                as = av ? *++av : strend(as) + 1;
                     97:        }
                     98:        noonl();
                     99: }
                    100: 
                    101: /*
                    102:  * Delete lines; two cases are if we are really deleting,
                    103:  * more commonly we are just moving lines to the undo save area.
                    104:  */
                    105: delete(hush)
                    106:        bool hush;
                    107: {
                    108:        register line *a1, *a2;
                    109: 
                    110:        nonzero();
                    111:        if (inopen >= 0 && (inopen || !inglobal)) {
                    112:                register int (*dsavint)();
                    113: 
                    114:                change();
                    115:                dsavint = signal(SIGINT, SIG_IGN);
                    116:                undkind = UNDCHANGE;
                    117:                a1 = addr1;
                    118:                squish();
                    119:                a2 = addr2;
                    120:                if (a2++ != dol) {
                    121:                        reverse(a1, a2);
                    122:                        reverse(a2, dol + 1);
                    123:                        reverse(a1, dol + 1);
                    124:                }
                    125:                dol -= a2 - a1;
                    126:                unddel = a1 - 1;
                    127:                if (a1 > dol)
                    128:                        a1 = dol;
                    129:                dot = a1;
                    130:                pkill[0] = pkill[1] = 0;
                    131:                signal(SIGINT, dsavint);
                    132:        } else {
                    133:                register line *a3;
                    134:                register int i;
                    135: 
                    136:                change();
                    137:                a1 = addr1;
                    138:                a2 = addr2 + 1;
                    139:                a3 = truedol;
                    140:                i = a2 - a1;
                    141:                unddol -= i;
                    142:                undap2 -= i;
                    143:                dol -= i;
                    144:                truedol -= i;
                    145:                do
                    146:                        *a1++ = *a2++;
                    147:                while (a2 <= a3);
                    148:                a1 = addr1;
                    149:                if (a1 > dol)
                    150:                        a1 = dol;
                    151:                dot = a1;
                    152:        }
                    153:        if (!hush)
                    154:                killed();
                    155: }
                    156: 
                    157: deletenone()
                    158: {
                    159: 
                    160:        if (inopen >= 0 && (inopen || !inglobal)) {
                    161:                undkind = UNDCHANGE;
                    162:                squish();
                    163:                unddel = addr1;
                    164:        }
                    165: }
                    166: 
                    167: /*
                    168:  * Crush out the undo save area, moving the open/visual
                    169:  * save area down in its place.
                    170:  */
                    171: squish()
                    172: {
                    173:        register line *a1 = dol + 1, *a2 = unddol + 1, *a3 = truedol + 1;
                    174: 
                    175:        if (inopen == -1)
                    176:                return;
                    177:        if (a1 < a2 && a2 < a3)
                    178:                do
                    179:                        *a1++ = *a2++;
                    180:                while (a2 < a3);
                    181:        truedol -= unddol - dol;
                    182:        unddol = dol;
                    183: }
                    184: 
                    185: /*
                    186:  * Join lines.  Special hacks put in spaces, two spaces if
                    187:  * preceding line ends with '.', or no spaces if next line starts with ).
                    188:  */
                    189: static int jcount, jnoop();
                    190: 
                    191: join(c)
                    192:        int c;
                    193: {
                    194:        register line *a1;
                    195:        register char *cp, *cp1;
                    196: 
                    197:        cp = genbuf;
                    198:        *cp = 0;
                    199:        for (a1 = addr1; a1 <= addr2; a1++) {
                    200:                getline(*a1);
                    201:                cp1 = linebuf;
                    202:                if (a1 != addr1 && c == 0) {
                    203:                        while (*cp1 == ' ' || *cp1 == '\t')
                    204:                                cp1++;
                    205:                        if (*cp1 && cp > genbuf && cp[-1] != ' ' && cp[-1] != '\t') {
                    206:                                if (*cp1 != ')') {
                    207:                                        *cp++ = ' ';
                    208:                                        if (cp[-2] == '.')
                    209:                                                *cp++ = ' ';
                    210:                                }
                    211:                        }
                    212:                }
                    213:                while (*cp++ = *cp1++)
                    214:                        if (cp > &genbuf[LBSIZE-2])
                    215:                                error("Line overflow|Result line of join would be too long");
                    216:                cp--;
                    217:        }
                    218:        strcLIN(genbuf);
                    219:        delete(0);
                    220:        jcount = 1;
                    221:        ignore(append(jnoop, --addr1));
                    222: }
                    223: 
                    224: static
                    225: jnoop()
                    226: {
                    227: 
                    228:        return(--jcount);
                    229: }
                    230: 
                    231: /*
                    232:  * Move and copy lines.  Hard work is done by move1 which
                    233:  * is also called by undo.
                    234:  */
                    235: int    getcopy();
                    236: 
                    237: move()
                    238: {
                    239:        register line *adt;
                    240:        bool iscopy = 0;
                    241: 
                    242:        if (Command[0] == 'm') {
                    243:                setdot1();
                    244:                markpr(addr2 == dot ? addr1 - 1 : addr2 + 1);
                    245:        } else {
                    246:                iscopy++;
                    247:                setdot();
                    248:        }
                    249:        nonzero();
                    250:        adt = address(0);
                    251:        if (adt == 0)
                    252:                serror("%s where?|%s requires a trailing address", Command);
                    253:        newline();
                    254:        move1(iscopy, adt);
                    255:        killed();
                    256: }
                    257: 
                    258: move1(cflag, addrt)
                    259:        int cflag;
                    260:        line *addrt;
                    261: {
                    262:        register line *adt, *ad1, *ad2;
                    263:        int lines;
                    264: 
                    265:        adt = addrt;
                    266:        lines = (addr2 - addr1) + 1;
                    267:        if (cflag) {
                    268:                tad1 = addr1;
                    269:                ad1 = dol;
                    270:                ignore(append(getcopy, ad1++));
                    271:                ad2 = dol;
                    272:        } else {
                    273:                ad2 = addr2;
                    274:                for (ad1 = addr1; ad1 <= ad2;)
                    275:                        *ad1++ &= ~01;
                    276:                ad1 = addr1;
                    277:        }
                    278:        ad2++;
                    279:        if (adt < ad1) {
                    280:                if (adt + 1 == ad1 && !cflag && !inglobal)
                    281:                        error("That move would do nothing!");
                    282:                dot = adt + (ad2 - ad1);
                    283:                if (++adt != ad1) {
                    284:                        reverse(adt, ad1);
                    285:                        reverse(ad1, ad2);
                    286:                        reverse(adt, ad2);
                    287:                }
                    288:        } else if (adt >= ad2) {
                    289:                dot = adt++;
                    290:                reverse(ad1, ad2);
                    291:                reverse(ad2, adt);
                    292:                reverse(ad1, adt);
                    293:        } else
                    294:                error("Move to a moved line");
                    295:        change();
                    296:        if (!inglobal)
                    297:                if (cflag) {
                    298:                        undap1 = addrt + 1;
                    299:                        undap2 = undap1 + lines;
                    300:                        deletenone();
                    301:                } else {
                    302:                        undkind = UNDMOVE;
                    303:                        undap1 = addr1;
                    304:                        undap2 = addr2;
                    305:                        unddel = addrt;
                    306:                        squish();
                    307:                }
                    308: }
                    309: 
                    310: getcopy()
                    311: {
                    312: 
                    313:        if (tad1 > addr2)
                    314:                return (EOF);
                    315:        getline(*tad1++);
                    316:        return (0);
                    317: }
                    318: 
                    319: /*
                    320:  * Put lines in the buffer from the undo save area.
                    321:  */
                    322: getput()
                    323: {
                    324: 
                    325:        if (tad1 > unddol)
                    326:                return (EOF);
                    327:        getline(*tad1++);
                    328:        tad1++;
                    329:        return (0);
                    330: }
                    331: 
                    332: put()
                    333: {
                    334:        register int cnt;
                    335: 
                    336:        cnt = unddol - dol;
                    337:        if (cnt && inopen && pkill[0] && pkill[1]) {
                    338:                pragged(1);
                    339:                return;
                    340:        }
                    341:        tad1 = dol + 1;
                    342:        ignore(append(getput, addr2));
                    343:        undkind = UNDPUT;
                    344:        notecnt = cnt;
                    345:        netchange(cnt);
                    346: }
                    347: 
                    348: /*
                    349:  * A tricky put, of a group of lines in the middle
                    350:  * of an existing line.  Only from open/visual.
                    351:  * Argument says pkills have meaning, e.g. called from
                    352:  * put; it is 0 on calls from putreg.
                    353:  */
                    354: pragged(kill)
                    355:        bool kill;
                    356: {
                    357:        extern char *cursor;
                    358:        register char *gp = &genbuf[cursor - linebuf];
                    359: 
                    360:        /*
                    361:         * This kind of stuff is TECO's forte.
                    362:         * We just grunge along, since it cuts
                    363:         * across our line-oriented model of the world
                    364:         * almost scrambling our addled brain.
                    365:         */
                    366:        if (!kill)
                    367:                getDOT();
                    368:        strcpy(genbuf, linebuf);
                    369:        getline(*unddol);
                    370:        if (kill)
                    371:                *pkill[1] = 0;
                    372:        strcat(linebuf, gp);
                    373:        putmark(unddol);
                    374:        getline(dol[1]);
                    375:        if (kill)
                    376:                strcLIN(pkill[0]);
                    377:        strcpy(gp, linebuf);
                    378:        strcLIN(genbuf);
                    379:        putmark(dol+1);
                    380:        undkind = UNDCHANGE;
                    381:        undap1 = dot;
                    382:        undap2 = dot + 1;
                    383:        unddel = dot - 1;
                    384:        undo(1);
                    385: }
                    386: 
                    387: /*
                    388:  * Shift lines, based on c.
                    389:  * If c is neither < nor >, then this is a lisp aligning =.
                    390:  */
                    391: shift(c, cnt)
                    392:        int c;
                    393:        int cnt;
                    394: {
                    395:        register line *addr;
                    396:        register char *cp;
                    397:        char *dp;
                    398:        register int i;
                    399: 
                    400:        if (!inglobal)
                    401:                save12(), undkind = UNDCHANGE;
                    402:        cnt *= value(SHIFTWIDTH);
                    403:        for (addr = addr1; addr <= addr2; addr++) {
                    404:                dot = addr;
                    405: #ifdef LISPCODE
                    406:                if (c == '=' && addr == addr1 && addr != addr2)
                    407:                        continue;
                    408: #endif
                    409:                getDOT();
                    410:                i = whitecnt(linebuf);
                    411:                switch (c) {
                    412: 
                    413:                case '>':
                    414:                        if (linebuf[0] == 0)
                    415:                                continue;
                    416:                        cp = genindent(i + cnt);
                    417:                        break;
                    418: 
                    419:                case '<':
                    420:                        if (i == 0)
                    421:                                continue;
                    422:                        i -= cnt;
                    423:                        cp = i > 0 ? genindent(i) : genbuf;
                    424:                        break;
                    425: 
                    426: #ifdef LISPCODE
                    427:                default:
                    428:                        i = lindent(addr);
                    429:                        getDOT();
                    430:                        cp = genindent(i);
                    431:                        break;
                    432: #endif
                    433:                }
                    434:                if (cp + strlen(dp = vpastwh(linebuf)) >= &genbuf[LBSIZE - 2])
                    435:                        error("Line too long|Result line after shift would be too long");
                    436:                CP(cp, dp);
                    437:                strcLIN(genbuf);
                    438:                putmark(addr);
                    439:        }
                    440:        killed();
                    441: }
                    442: 
                    443: /*
                    444:  * Find a tag in the tags file.
                    445:  * Most work here is in parsing the tags file itself.
                    446:  */
                    447: tagfind(quick)
                    448:        bool quick;
                    449: {
                    450:        char cmdbuf[BUFSIZ];
                    451:        char filebuf[FNSIZE];
                    452:        register int c, d;
                    453:        bool samef = 1;
                    454:        bool notagsfile = 0;
                    455:        short master = -1;
                    456:        short omagic;
                    457: 
                    458:        omagic = value(MAGIC);
                    459:        if (!skipend()) {
                    460:                register char *lp = lasttag;
                    461: 
                    462:                while (!iswhite(peekchar()) && !endcmd(peekchar()))
                    463:                        if (lp < &lasttag[sizeof lasttag - 2])
                    464:                                *lp++ = getchar();
                    465:                        else
                    466:                                ignchar();
                    467:                *lp++ = 0;
                    468:                if (!endcmd(peekchar()))
                    469: badtag:
                    470:                        error("Bad tag|Give one tag per line");
                    471:        } else if (lasttag[0] == 0)
                    472:                error("No previous tag");
                    473:        c = getchar();
                    474:        if (!endcmd(c))
                    475:                goto badtag;
                    476:        if (c == EOF)
                    477:                ungetchar(c);
                    478:        clrstats();
                    479:        do {
                    480:                io = open(master ? "tags" : MASTERTAGS, 0);
                    481:                if (master && io < 0)
                    482:                        notagsfile = 1;
                    483:                while (getfile() == 0) {
                    484:                        register char *cp = linebuf;
                    485:                        register char *lp = lasttag;
                    486:                        char *oglobp;
                    487: 
                    488:                        while (*cp && *lp == *cp)
                    489:                                cp++, lp++;
                    490:                        if (*lp || !iswhite(*cp))
                    491:                                continue;
                    492:                        close(io);
                    493:                        while (*cp && iswhite(*cp))
                    494:                                cp++;
                    495:                        if (!*cp)
                    496: badtags:
                    497:                                serror("%s: Bad tags file entry", lasttag);
                    498:                        lp = filebuf;
                    499:                        while (*cp && *cp != ' ' && *cp != '\t') {
                    500:                                if (lp < &filebuf[sizeof filebuf - 2])
                    501:                                        *lp++ = *cp;
                    502:                                cp++;
                    503:                        }
                    504:                        *lp++ = 0;
                    505:                        if (*cp == 0)
                    506:                                goto badtags;
                    507:                        if (dol != zero) {
                    508:                                /*
                    509:                                 * Save current position in 't for ^^ in visual.
                    510:                                 */
                    511:                                names['t'-'a'] = *dot &~ 01;
                    512:                                if (inopen) {
                    513:                                        extern char *ncols['z'-'a'+1];
                    514:                                        extern char *cursor;
                    515: 
                    516:                                        ncols['t'-'a'] = cursor;
                    517:                                }
                    518:                        }
                    519:                        strcpy(cmdbuf, cp);
                    520:                        if (strcmp(filebuf, savedfile) || !edited) {
                    521:                                char cmdbuf2[sizeof filebuf + 10];
                    522: 
                    523:                                if (!quick) {
                    524:                                        ckaw();
                    525:                                        if (chng && dol > zero)
                    526:                                                error("No write@since last change (:tag! overrides)");
                    527:                                }
                    528:                                oglobp = globp;
                    529:                                strcpy(cmdbuf2, "e! ");
                    530:                                strcat(cmdbuf2, filebuf);
                    531:                                globp = cmdbuf2;
                    532:                                d = peekc; ungetchar(0);
                    533:                                /*
                    534:                                 * BUG: if it isn't found (user edited header
                    535:                                 * line) we get left in nomagic mode.
                    536:                                 */
                    537:                                value(MAGIC) = 0;
                    538:                                commands(1, 1);
                    539:                                peekc = d;
                    540:                                globp = oglobp;
                    541:                                value(MAGIC) = omagic;
                    542:                                samef = 0;
                    543:                        }
                    544:                        oglobp = globp;
                    545:                        globp = cmdbuf;
                    546:                        d = peekc; ungetchar(0);
                    547:                        if (samef)
                    548:                                markpr(dot);
                    549:                        value(MAGIC) = 0;
                    550:                        commands(1, 1);
                    551:                        peekc = d;
                    552:                        globp = oglobp;
                    553:                        value(MAGIC) = omagic;
                    554:                        return;
                    555:                }
                    556:        } while (++master == 0);
                    557:        if (notagsfile)
                    558:                error("No tags file");
                    559:        serror("%s: No such tag@in tags file", lasttag);
                    560: }
                    561: 
                    562: /*
                    563:  * Save lines from addr1 thru addr2 as though
                    564:  * they had been deleted.
                    565:  */
                    566: yank()
                    567: {
                    568: 
                    569:        save12();
                    570:        undkind = UNDNONE;
                    571:        killcnt(addr2 - addr1 + 1);
                    572: }
                    573: 
                    574: /*
                    575:  * z command; print windows of text in the file.
                    576:  *
                    577:  * If this seems unreasonably arcane, the reasons
                    578:  * are historical.  This is one of the first commands
                    579:  * added to the first ex (then called en) and the
                    580:  * number of facilities here were the major advantage
                    581:  * of en over ed since they allowed more use to be
                    582:  * made of fast terminals w/o typing .,.22p all the time.
                    583:  */
                    584: bool   zhadpr;
                    585: bool   znoclear;
                    586: short  zweight;
                    587: 
                    588: zop(hadpr)
                    589:        int hadpr;
                    590: {
                    591:        register int c, lines, op;
                    592:        bool excl;
                    593: 
                    594:        zhadpr = hadpr;
                    595:        notempty();
                    596:        znoclear = 0;
                    597:        zweight = 0;
                    598:        excl = exclam();
                    599:        switch (c = op = getchar()) {
                    600: 
                    601:        case '^':
                    602:                zweight = 1;
                    603:        case '-':
                    604:        case '+':
                    605:                while (peekchar() == op) {
                    606:                        ignchar();
                    607:                        zweight++;
                    608:                }
                    609:        case '=':
                    610:        case '.':
                    611:                c = getchar();
                    612:                break;
                    613: 
                    614:        case EOF:
                    615:                znoclear++;
                    616:                break;
                    617: 
                    618:        default:
                    619:                op = 0;
                    620:                break;
                    621:        }
                    622:        if (isdigit(c)) {
                    623:                lines = c - '0';
                    624:                for(;;) {
                    625:                        c = getchar();
                    626:                        if (!isdigit(c))
                    627:                                break;
                    628:                        lines *= 10;
                    629:                        lines += c - '0';
                    630:                }
                    631:                if (lines < LINES)
                    632:                        znoclear++;
                    633:                value(WINDOW) = lines;
                    634:                if (op == '=')
                    635:                        lines += 2;
                    636:        } else
                    637:                lines = op == EOF ? value(SCROLL) : excl ? LINES - 1 : 2*value(SCROLL);
                    638:        if (inopen || c != EOF) {
                    639:                ungetchar(c);
                    640:                newline();
                    641:        }
                    642:        addr1 = addr2;
                    643:        if (addr2 == 0 && dot < dol && op == 0)
                    644:                addr1 = addr2 = dot+1;
                    645:        setdot();
                    646:        zop2(lines, op);
                    647: }
                    648: 
                    649: zop2(lines, op)
                    650:        register int lines;
                    651:        register int op;
                    652: {
                    653:        register line *split;
                    654: 
                    655:        split = NULL;
                    656:        switch (op) {
                    657: 
                    658:        case EOF:
                    659:                if (addr2 == dol)
                    660:                        error("\nAt EOF");
                    661:        case '+':
                    662:                if (addr2 == dol)
                    663:                        error("At EOF");
                    664:                addr2 += lines * zweight;
                    665:                if (addr2 > dol)
                    666:                        error("Hit BOTTOM");
                    667:                addr2++;
                    668:        default:
                    669:                addr1 = addr2;
                    670:                addr2 += lines-1;
                    671:                dot = addr2;
                    672:                break;
                    673: 
                    674:        case '=':
                    675:        case '.':
                    676:                znoclear = 0;
                    677:                lines--;
                    678:                lines >>= 1;
                    679:                if (op == '=')
                    680:                        lines--;
                    681:                addr1 = addr2 - lines;
                    682:                if (op == '=')
                    683:                        dot = split = addr2;
                    684:                addr2 += lines;
                    685:                if (op == '.') {
                    686:                        markDOT();
                    687:                        dot = addr2;
                    688:                }
                    689:                break;
                    690: 
                    691:        case '^':
                    692:        case '-':
                    693:                addr2 -= lines * zweight;
                    694:                if (addr2 < one)
                    695:                        error("Hit TOP");
                    696:                lines--;
                    697:                addr1 = addr2 - lines;
                    698:                dot = addr2;
                    699:                break;
                    700:        }
                    701:        if (addr1 <= zero)
                    702:                addr1 = one;
                    703:        if (addr2 > dol)
                    704:                addr2 = dol;
                    705:        if (dot > dol)
                    706:                dot = dol;
                    707:        if (addr1 > addr2)
                    708:                return;
                    709:        if (op == EOF && zhadpr) {
                    710:                getline(*addr1);
                    711:                putchar('\r' | QUOTE);
                    712:                shudclob = 1;
                    713:        } else if (znoclear == 0 && CL != NOSTR && !inopen) {
                    714:                flush1();
                    715:                vclear();
                    716:        }
                    717:        if (addr2 - addr1 > 1)
                    718:                pstart();
                    719:        if (split) {
                    720:                plines(addr1, split - 1, 0);
                    721:                splitit();
                    722:                plines(split, split, 0);
                    723:                splitit();
                    724:                addr1 = split + 1;
                    725:        }
                    726:        plines(addr1, addr2, 0);
                    727: }
                    728: 
                    729: static
                    730: splitit()
                    731: {
                    732:        register int l;
                    733: 
                    734:        for (l = COLUMNS > 80 ? 40 : COLUMNS / 2; l > 0; l--)
                    735:                putchar('-');
                    736:        putnl();
                    737: }
                    738: 
                    739: plines(adr1, adr2, movedot)
                    740:        line *adr1;
                    741:        register line *adr2;
                    742:        bool movedot;
                    743: {
                    744:        register line *addr;
                    745: 
                    746:        pofix();
                    747:        for (addr = adr1; addr <= adr2; addr++) {
                    748:                getline(*addr);
                    749:                pline(lineno(addr));
                    750:                if (inopen)
                    751:                        putchar('\n' | QUOTE);
                    752:                if (movedot)
                    753:                        dot = addr;
                    754:        }
                    755: }
                    756: 
                    757: pofix()
                    758: {
                    759: 
                    760:        if (inopen && Outchar != termchar) {
                    761:                vnfl();
                    762:                setoutt();
                    763:        }
                    764: }
                    765: 
                    766: /*
                    767:  * Dudley doright to the rescue.
                    768:  * Undo saves the day again.
                    769:  * A tip of the hatlo hat to Warren Teitleman
                    770:  * who made undo as useful as do.
                    771:  *
                    772:  * Command level undo works easily because
                    773:  * the editor has a unique temporary file
                    774:  * index for every line which ever existed.
                    775:  * We don't have to save large blocks of text,
                    776:  * only the indices which are small.  We do this
                    777:  * by moving them to after the last line in the
                    778:  * line buffer array, and marking down info
                    779:  * about whence they came.
                    780:  *
                    781:  * Undo is its own inverse.
                    782:  */
                    783: undo(c)
                    784:        bool c;
                    785: {
                    786:        register int i;
                    787:        register line *jp, *kp;
                    788:        line *dolp1, *newdol, *newadot;
                    789: 
                    790:        if (inglobal && inopen <= 0)
                    791:                error("Can't undo in global@commands");
                    792:        if (!c)
                    793:                somechange();
                    794:        pkill[0] = pkill[1] = 0;
                    795:        change();
                    796:        if (undkind == UNDMOVE) {
                    797:                /*
                    798:                 * Command to be undone is a move command.
                    799:                 * This is handled as a special case by noting that
                    800:                 * a move "a,b m c" can be inverted by another move.
                    801:                 */
                    802:                if ((i = (jp = unddel) - undap2) > 0) {
                    803:                        /*
                    804:                         * when c > b inverse is a+(c-b),c m a-1
                    805:                         */
                    806:                        addr2 = jp;
                    807:                        addr1 = (jp = undap1) + i;
                    808:                        unddel = jp-1;
                    809:                } else {
                    810:                        /*
                    811:                         * when b > c inverse is  c+1,c+1+(b-a) m b
                    812:                         */
                    813:                        addr1 = ++jp;
                    814:                        addr2 = jp + ((unddel = undap2) - undap1);
                    815:                }
                    816:                kp = undap1;
                    817:                move1(0, unddel);
                    818:                dot = kp;
                    819:                Command = "move";
                    820:                killed();
                    821:        } else {
                    822:                int cnt;
                    823: 
                    824:                newadot = dot;
                    825:                cnt = lineDOL();
                    826:                newdol = dol;
                    827:                dolp1 = dol + 1;
                    828:                /*
                    829:                 * Command to be undone is a non-move.
                    830:                 * All such commands are treated as a combination of
                    831:                 * a delete command and a append command.
                    832:                 * We first move the lines appended by the last command
                    833:                 * from undap1 to undap2-1 so that they are just before the
                    834:                 * saved deleted lines.
                    835:                 */
                    836:                if ((i = (kp = undap2) - (jp = undap1)) > 0) {
                    837:                        if (kp != dolp1) {
                    838:                                reverse(jp, kp);
                    839:                                reverse(kp, dolp1);
                    840:                                reverse(jp, dolp1);
                    841:                        }
                    842:                        /*
                    843:                         * Account for possible backward motion of target
                    844:                         * for restoration of saved deleted lines.
                    845:                         */
                    846:                        if (unddel >= jp)
                    847:                                unddel -= i;
                    848:                        newdol -= i;
                    849:                        /*
                    850:                         * For the case where no lines are restored, dot
                    851:                         * is the line before the first line deleted.
                    852:                         */
                    853:                        dot = jp-1;
                    854:                }
                    855:                /*
                    856:                 * Now put the deleted lines, if any, back where they were.
                    857:                 * Basic operation is: dol+1,unddol m unddel
                    858:                 */
                    859:                if (undkind == UNDPUT) {
                    860:                        unddel = undap1 - 1;
                    861:                        squish();
                    862:                }
                    863:                jp = unddel + 1;
                    864:                if ((i = (kp = unddol) - dol) > 0) {
                    865:                        if (jp != dolp1) {
                    866:                                reverse(jp, dolp1);
                    867:                                reverse(dolp1, ++kp);
                    868:                                reverse(jp, kp);
                    869:                        }
                    870:                        /*
                    871:                         * Account for possible forward motion of the target
                    872:                         * for restoration of the deleted lines.
                    873:                         */
                    874:                        if (undap1 >= jp)
                    875:                                undap1 += i;
                    876:                        /*
                    877:                         * Dot is the first resurrected line.
                    878:                         */
                    879:                        dot = jp;
                    880:                        newdol += i;
                    881:                }
                    882:                /*
                    883:                 * Clean up so we are invertible
                    884:                 */
                    885:                unddel = undap1 - 1;
                    886:                undap1 = jp;
                    887:                undap2 = jp + i;
                    888:                dol = newdol;
                    889:                netchHAD(cnt);
                    890:                if (undkind == UNDALL) {
                    891:                        dot = undadot;
                    892:                        undadot = newadot;
                    893:                }
                    894:                undkind = UNDCHANGE;
                    895:        }
                    896:        if (dot == zero && dot != dol)
                    897:                dot = one;
                    898: }
                    899: 
                    900: /*
                    901:  * Be (almost completely) sure there really
                    902:  * was a change, before claiming to undo.
                    903:  */
                    904: somechange()
                    905: {
                    906:        register line *ip, *jp;
                    907: 
                    908:        switch (undkind) {
                    909: 
                    910:        case UNDMOVE:
                    911:                return;
                    912: 
                    913:        case UNDCHANGE:
                    914:                if (undap1 == undap2 && dol == unddol)
                    915:                        break;
                    916:                return;
                    917: 
                    918:        case UNDPUT:
                    919:                if (undap1 != undap2)
                    920:                        return;
                    921:                break;
                    922: 
                    923:        case UNDALL:
                    924:                if (unddol - dol != lineDOL())
                    925:                        return;
                    926:                for (ip = one, jp = dol + 1; ip <= dol; ip++, jp++)
                    927:                        if ((*ip &~ 01) != (*jp &~ 01))
                    928:                                return;
                    929:                break;
                    930: 
                    931:        case UNDNONE:
                    932:                error("Nothing to undo");
                    933:        }
                    934:        error("Nothing changed|Last undoable command didn't change anything");
                    935: }
                    936: 
                    937: /*
                    938:  * Map command:
                    939:  * map src dest
                    940:  */
                    941: mapcmd(un)
                    942:        int un; /* true if this is unmap command */
                    943: {
                    944:        char lhs[10], rhs[100]; /* max sizes resp. */
                    945:        register char *p;
                    946:        register char c;
                    947:        char *dname;
                    948: 
                    949:        if (skipend()) {
                    950:                int i;
                    951: 
                    952:                /* print current mapping values */
                    953:                if (peekchar() != EOF)
                    954:                        ignchar();
                    955:                if (inopen)
                    956:                        pofix();
                    957:                for (i=0; arrows[i].mapto; i++)
                    958:                        if (arrows[i].cap) {
                    959:                                lprintf("%s", arrows[i].descr);
                    960:                                putchar('\t');
                    961:                                lprintf("%s", arrows[i].cap);
                    962:                                putchar('\t');
                    963:                                lprintf("%s", arrows[i].mapto);
                    964:                                putNFL();
                    965:                        }
                    966:                return;
                    967:        }
                    968: 
                    969:        ignore(skipwh());
                    970:        for (p=lhs; ; ) {
                    971:                c = getchar();
                    972:                if (c == CTRL(v)) {
                    973:                        c = getchar();
                    974:                } else if (any(c, " \t")) {
                    975:                        if (un)
                    976:                                eol();  /* will usually cause an error */
                    977:                        else
                    978:                                break;
                    979:                } else if (endcmd(c)) {
                    980:                        ungetchar(c);
                    981:                        if (un) {
                    982:                                newline();
                    983:                                addmac(lhs, NOSTR, NOSTR);
                    984:                                return;
                    985:                        } else
                    986:                                error("Missing rhs");
                    987:                }
                    988:                *p++ = c;
                    989:        }
                    990:        *p = 0;
                    991: 
                    992:        if (skipend())
                    993:                error("Missing rhs");
                    994:        for (p=rhs; ; ) {
                    995:                c = getchar();
                    996:                if (c == CTRL(v)) {
                    997:                        c = getchar();
                    998:                } else if (endcmd(c)) {
                    999:                        ungetchar(c);
                   1000:                        break;
                   1001:                }
                   1002:                *p++ = c;
                   1003:        }
                   1004:        *p = 0;
                   1005:        newline();
                   1006:        /*
                   1007:         * Special hack for function keys: #1 means key f1, etc.
                   1008:         * If the terminal doesn't have function keys, we just use #1.
                   1009:         */
                   1010:        if (lhs[0] == '#') {
                   1011:                char *fnkey;
                   1012:                char *fkey();
                   1013:                char funkey[3];
                   1014: 
                   1015:                fnkey = fkey(lhs[1] - '0');
                   1016:                funkey[0] = 'f'; funkey[1] = lhs[1]; funkey[2] = 0;
                   1017:                if (fnkey)
                   1018:                        strcpy(lhs, fnkey);
                   1019:                dname = funkey;
                   1020:        } else {
                   1021:                dname = lhs;
                   1022:        }
                   1023:        addmac(lhs,rhs,dname);
                   1024: }
                   1025: 
                   1026: /*
                   1027:  * Add a macro definition to those that already exist. The sequence of
                   1028:  * chars "src" is mapped into "dest". If src is already mapped into something
                   1029:  * this overrides the mapping. There is no recursion. Unmap is done by
                   1030:  * using NOSTR for dest.
                   1031:  */
                   1032: addmac(src,dest,dname)
                   1033:        register char *src, *dest, *dname;
                   1034: {
                   1035:        register int slot, zer;
                   1036: 
                   1037:        if (dest) {
                   1038:                /* Make sure user doesn't screw himself */
                   1039:                /*
                   1040:                 * Prevent tail recursion. We really should be
                   1041:                 * checking to see if src is a suffix of dest
                   1042:                 * but we are too lazy here, so we don't bother unless
                   1043:                 * src is only 1 char long.
                   1044:                 */
                   1045:                if (src[1] == 0 && src[0] == dest[strlen(dest)-1])
                   1046:                        error("No tail recursion");
                   1047:                /*
                   1048:                 * We don't let the user rob himself of ":", and making
                   1049:                 * multi char words is a bad idea so we don't allow it.
                   1050:                 * Note that if user sets mapinput and maps all of return,
                   1051:                 * linefeed, and escape, he can screw himself. This is
                   1052:                 * so weird I don't bother to check for it.
                   1053:                 */
                   1054:                if (isalpha(src[0]) && src[1] || any(src[0],":"))
                   1055:                        error("Too dangerous to map that");
                   1056:                /*
                   1057:                 * If the src were null it would cause the dest to
                   1058:                 * be mapped always forever. This is not good.
                   1059:                 */
                   1060:                if (src[0] == 0)
                   1061:                        error("Null lhs");
                   1062:        }
                   1063: 
                   1064:        /* see if we already have a def for src */
                   1065:        zer = -1;
                   1066:        for (slot=0; arrows[slot].mapto; slot++) {
                   1067:                if (arrows[slot].cap) {
                   1068:                        if (eq(src, arrows[slot].cap))
                   1069:                                break;  /* if so, reuse slot */
                   1070:                } else {
                   1071:                        zer = slot;     /* remember an empty slot */
                   1072:                }
                   1073:        }
                   1074: 
                   1075:        if (dest == NOSTR) {
                   1076:                /* unmap */
                   1077:                if (arrows[slot].cap) {
                   1078:                        arrows[slot].cap = NOSTR;
                   1079:                        arrows[slot].descr = NOSTR;
                   1080:                } else {
                   1081:                        error("Not mapped|That macro wasn't mapped");
                   1082:                }
                   1083:                return;
                   1084:        }
                   1085: 
                   1086:        /* reuse empty slot, if we found one and src isn't already defined */
                   1087:        if (zer >= 0 && arrows[slot].mapto == 0)
                   1088:                slot = zer;
                   1089: 
                   1090:        /* if not, append to end */
                   1091:        if (slot >= MAXNOMACS)
                   1092:                error("Too many macros");
                   1093:        if (msnext == 0)        /* first time */
                   1094:                msnext = mapspace;
                   1095:        /* Check is a bit conservative, we charge for dname even if reusing src */
                   1096:        if (msnext - mapspace + strlen(dest) + strlen(src) + strlen(dname) + 3 > MAXCHARMACS)
                   1097:                error("Too much macro text");
                   1098:        CP(msnext, src);
                   1099:        arrows[slot].cap = msnext;
                   1100:        msnext += strlen(src) + 1;      /* plus 1 for null on the end */
                   1101:        CP(msnext, dest);
                   1102:        arrows[slot].mapto = msnext;
                   1103:        msnext += strlen(dest) + 1;
                   1104:        if (dname) {
                   1105:                CP(msnext, dname);
                   1106:                arrows[slot].descr = msnext;
                   1107:                msnext += strlen(dname) + 1;
                   1108:        } else {
                   1109:                /* default descr to string user enters */
                   1110:                arrows[slot].descr = src;
                   1111:        }
                   1112: }
                   1113: 
                   1114: /*
                   1115:  * Implements macros from command mode. c is the buffer to
                   1116:  * get the macro from.
                   1117:  */
                   1118: cmdmac(c)
                   1119: char c;
                   1120: {
                   1121:        char macbuf[BUFSIZ];
                   1122:        line *ad, *a1, *a2;
                   1123:        char *oglobp;
                   1124:        char pk;
                   1125:        bool oinglobal;
                   1126: 
                   1127:        lastmac = c;
                   1128:        oglobp = globp;
                   1129:        oinglobal = inglobal;
                   1130:        pk = peekc; peekc = 0;
                   1131:        if (inglobal < 2)
                   1132:                inglobal = 1;
                   1133:        regbuf(c, macbuf, sizeof(macbuf));
                   1134:        a1 = addr1; a2 = addr2;
                   1135:        for (ad=a1; ad<=a2; ad++) {
                   1136:                globp = macbuf;
                   1137:                dot = ad;
                   1138:                commands(1,1);
                   1139:        }
                   1140:        globp = oglobp;
                   1141:        inglobal = oinglobal;
                   1142:        peekc = pk;
                   1143: }

unix.superglobalmegacorp.com

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