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

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

unix.superglobalmegacorp.com

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