Annotation of 43BSDReno/usr.bin/ex/ex_cmdsub.c, revision 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.10 (Berkeley) 6/24/90";
        !             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 void (*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.