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

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

unix.superglobalmegacorp.com

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