Annotation of 43BSDTahoe/ucb/ex/ex_cmdsub.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

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