Annotation of 42BSD/ucb/ex/ex_vmain.c, revision 1.1.1.1

1.1       root        1: /* Copyright (c) 1981 Regents of the University of California */
                      2: static char *sccsid = "@(#)ex_vmain.c  7.3     6/10/83";
                      3: #include "ex.h"
                      4: #include "ex_tty.h"
                      5: #include "ex_vis.h"
                      6: 
                      7: /*
                      8:  * This is the main routine for visual.
                      9:  * We here decode the count and possible named buffer specification
                     10:  * preceding a command and interpret a few of the commands.
                     11:  * Commands which involve a target (i.e. an operator) are decoded
                     12:  * in the routine operate in ex_voperate.c.
                     13:  */
                     14: 
                     15: #define        forbid(a)       { if (a) goto fonfon; }
                     16: 
                     17: vmain()
                     18: {
                     19:        register int c, cnt, i;
                     20:        char esave[TUBECOLS];
                     21:        char *oglobp;
                     22:        short d;
                     23:        line *addr;
                     24:        int ind, nlput;
                     25:        int shouldpo = 0;
                     26:        int onumber, olist, (*OPline)(), (*OPutchar)();
                     27: 
                     28:        vch_mac = VC_NOTINMAC;
                     29: 
                     30:        /*
                     31:         * If we started as a vi command (on the command line)
                     32:         * then go process initial commands (recover, next or tag).
                     33:         */
                     34:        if (initev) {
                     35:                oglobp = globp;
                     36:                globp = initev;
                     37:                hadcnt = cnt = 0;
                     38:                i = tchng;
                     39:                addr = dot;
                     40:                goto doinit;
                     41:        }
                     42: 
                     43:        /*
                     44:         * NB:
                     45:         *
                     46:         * The current line is always in the line buffer linebuf,
                     47:         * and the cursor at the position cursor.  You should do
                     48:         * a vsave() before moving off the line to make sure the disk
                     49:         * copy is updated if it has changed, and a getDOT() to get
                     50:         * the line back if you mung linebuf.  The motion
                     51:         * routines in ex_vwind.c handle most of this.
                     52:         */
                     53:        for (;;) {
                     54:                /*
                     55:                 * Decode a visual command.
                     56:                 * First sync the temp file if there has been a reasonable
                     57:                 * amount of change.  Clear state for decoding of next
                     58:                 * command.
                     59:                 */
                     60:                TSYNC();
                     61:                vglobp = 0;
                     62:                vreg = 0;
                     63:                hold = 0;
                     64:                seenprompt = 1;
                     65:                wcursor = 0;
                     66:                Xhadcnt = hadcnt = 0;
                     67:                Xcnt = cnt = 1;
                     68:                splitw = 0;
                     69:                if (i = holdupd) {
                     70:                        if (state == VISUAL)
                     71:                                ignore(peekkey());
                     72:                        holdupd = 0;
                     73: /*
                     74:                        if (LINE(0) < ZERO) {
                     75:                                vclear();
                     76:                                vcnt = 0;
                     77:                                i = 3;
                     78:                        }
                     79: */
                     80:                        if (state != VISUAL) {
                     81:                                vcnt = 0;
                     82:                                vsave();
                     83:                                vrepaint(cursor);
                     84:                        } else if (i == 3)
                     85:                                vredraw(WTOP);
                     86:                        else
                     87:                                vsync(WTOP);
                     88:                        vfixcurs();
                     89:                }
                     90: 
                     91:                /*
                     92:                 * Gobble up counts and named buffer specifications.
                     93:                 */
                     94:                for (;;) {
                     95: looptop:
                     96: #ifdef MDEBUG
                     97:                        if (trace)
                     98:                                fprintf(trace, "pc=%c",peekkey());
                     99: #endif
                    100:                        if (isdigit(peekkey()) && peekkey() != '0') {
                    101:                                hadcnt = 1;
                    102:                                cnt = vgetcnt();
                    103:                                forbid (cnt <= 0);
                    104:                        }
                    105:                        if (peekkey() != '"')
                    106:                                break;
                    107:                        ignore(getkey()), c = getkey();
                    108:                        /*
                    109:                         * Buffer names be letters or digits.
                    110:                         * But not '0' as that is the source of
                    111:                         * an 'empty' named buffer spec in the routine
                    112:                         * kshift (see ex_temp.c).
                    113:                         */
                    114:                        forbid (c == '0' || !isalpha(c) && !isdigit(c));
                    115:                        vreg = c;
                    116:                }
                    117: reread:
                    118:                /*
                    119:                 * Come to reread from below after some macro expansions.
                    120:                 * The call to map allows use of function key pads
                    121:                 * by performing a terminal dependent mapping of inputs.
                    122:                 */
                    123: #ifdef MDEBUG
                    124:                if (trace)
                    125:                        fprintf(trace,"pcb=%c,",peekkey());
                    126: #endif
                    127:                op = getkey();
                    128:                maphopcnt = 0;
                    129:                do {
                    130:                        /*
                    131:                         * Keep mapping the char as long as it changes.
                    132:                         * This allows for double mappings, e.g., q to #,
                    133:                         * #1 to something else.
                    134:                         */
                    135:                        c = op;
                    136:                        op = map(c,arrows);
                    137: #ifdef MDEBUG
                    138:                        if (trace)
                    139:                                fprintf(trace,"pca=%c,",c);
                    140: #endif
                    141:                        /*
                    142:                         * Maybe the mapped to char is a count. If so, we have
                    143:                         * to go back to the "for" to interpret it. Likewise
                    144:                         * for a buffer name.
                    145:                         */
                    146:                        if ((isdigit(c) && c!='0') || c == '"') {
                    147:                                ungetkey(c);
                    148:                                goto looptop;
                    149:                        }
                    150:                        if (!value(REMAP)) {
                    151:                                c = op;
                    152:                                break;
                    153:                        }
                    154:                        if (++maphopcnt > 256)
                    155:                                error("Infinite macro loop");
                    156:                } while (c != op);
                    157: 
                    158:                /*
                    159:                 * Begin to build an image of this command for possible
                    160:                 * later repeat in the buffer workcmd.  It will be copied
                    161:                 * to lastcmd by the routine setLAST
                    162:                 * if/when completely specified.
                    163:                 */
                    164:                lastcp = workcmd;
                    165:                if (!vglobp)
                    166:                        *lastcp++ = c;
                    167: 
                    168:                /*
                    169:                 * First level command decode.
                    170:                 */
                    171:                switch (c) {
                    172: 
                    173:                /*
                    174:                 * ^L           Clear screen e.g. after transmission error.
                    175:                 */
                    176: 
                    177:                /*
                    178:                 * ^R           Retype screen, getting rid of @ lines.
                    179:                 *              If in open, equivalent to ^L.
                    180:                 *              On terminals where the right arrow key sends
                    181:                 *              ^L we make ^R act like ^L, since there is no
                    182:                 *              way to get ^L.  These terminals (adm31, tvi)
                    183:                 *              are intelligent so ^R is useless.  Soroc
                    184:                 *              will probably foul this up, but nobody has
                    185:                 *              one of them.
                    186:                 */
                    187:                case CTRL(l):
                    188:                case CTRL(r):
                    189:                        if (c == CTRL(l) || (KR && *KR==CTRL(l))) {
                    190:                                vclear();
                    191:                                vdirty(0, vcnt);
                    192:                        }
                    193:                        if (state != VISUAL) {
                    194:                                /*
                    195:                                 * Get a clean line, throw away the
                    196:                                 * memory of what is displayed now,
                    197:                                 * and move back onto the current line.
                    198:                                 */
                    199:                                vclean();
                    200:                                vcnt = 0;
                    201:                                vmoveto(dot, cursor, 0);
                    202:                                continue;
                    203:                        }
                    204:                        vredraw(WTOP);
                    205:                        /*
                    206:                         * Weird glitch -- when we enter visual
                    207:                         * in a very small window we may end up with
                    208:                         * no lines on the screen because the line
                    209:                         * at the top is too long.  This forces the screen
                    210:                         * to be expanded to make room for it (after
                    211:                         * we have printed @'s ick showing we goofed).
                    212:                         */
                    213:                        if (vcnt == 0)
                    214:                                vrepaint(cursor);
                    215:                        vfixcurs();
                    216:                        continue;
                    217: 
                    218:                /*
                    219:                 * $            Escape just cancels the current command
                    220:                 *              with a little feedback.
                    221:                 */
                    222:                case ESCAPE:
                    223:                        beep();
                    224:                        continue;
                    225: 
                    226:                /*
                    227:                 * @            Macros. Bring in the macro and put it
                    228:                 *              in vmacbuf, point vglobp there and punt.
                    229:                 */
                    230:                 case '@':
                    231:                        c = getesc();
                    232:                        if (c == 0)
                    233:                                continue;
                    234:                        if (c == '@')
                    235:                                c = lastmac;
                    236:                        if (isupper(c))
                    237:                                c = tolower(c);
                    238:                        forbid(!islower(c));
                    239:                        lastmac = c;
                    240:                        vsave();
                    241:                        CATCH
                    242:                                char tmpbuf[BUFSIZ];
                    243: 
                    244:                                regbuf(c,tmpbuf,sizeof(vmacbuf));
                    245:                                macpush(tmpbuf, 1);
                    246:                        ONERR
                    247:                                lastmac = 0;
                    248:                                splitw = 0;
                    249:                                getDOT();
                    250:                                vrepaint(cursor);
                    251:                                continue;
                    252:                        ENDCATCH
                    253:                        vmacp = vmacbuf;
                    254:                        goto reread;
                    255: 
                    256:                /*
                    257:                 * .            Repeat the last (modifying) open/visual command.
                    258:                 */
                    259:                case '.':
                    260:                        /*
                    261:                         * Check that there was a last command, and
                    262:                         * take its count and named buffer unless they
                    263:                         * were given anew.  Special case if last command
                    264:                         * referenced a numeric named buffer -- increment
                    265:                         * the number and go to a named buffer again.
                    266:                         * This allows a sequence like "1pu.u.u...
                    267:                         * to successively look for stuff in the kill chain
                    268:                         * much as one does in EMACS with C-Y and M-Y.
                    269:                         */
                    270:                        forbid (lastcmd[0] == 0);
                    271:                        if (hadcnt)
                    272:                                lastcnt = cnt;
                    273:                        if (vreg)
                    274:                                lastreg = vreg;
                    275:                        else if (isdigit(lastreg) && lastreg < '9')
                    276:                                lastreg++;
                    277:                        vreg = lastreg;
                    278:                        cnt = lastcnt;
                    279:                        hadcnt = lasthad;
                    280:                        vglobp = lastcmd;
                    281:                        goto reread;
                    282: 
                    283:                /*
                    284:                 * ^U           Scroll up.  A count sticks around for
                    285:                 *              future scrolls as the scroll amount.
                    286:                 *              Attempt to hold the indentation from the
                    287:                 *              top of the screen (in logical lines).
                    288:                 *
                    289:                 * BUG:         A ^U near the bottom of the screen
                    290:                 *              on a dumb terminal (which can't roll back)
                    291:                 *              causes the screen to be cleared and then
                    292:                 *              redrawn almost as it was.  In this case
                    293:                 *              one should simply move the cursor.
                    294:                 */
                    295:                case CTRL(u):
                    296:                        if (hadcnt)
                    297:                                vSCROLL = cnt;
                    298:                        cnt = vSCROLL;
                    299:                        if (state == VISUAL)
                    300:                                ind = vcline, cnt += ind;
                    301:                        else
                    302:                                ind = 0;
                    303:                        vmoving = 0;
                    304:                        vup(cnt, ind, 1);
                    305:                        vnline(NOSTR);
                    306:                        continue;
                    307: 
                    308:                /*
                    309:                 * ^D           Scroll down.  Like scroll up.
                    310:                 */
                    311:                case CTRL(d):
                    312: #ifdef TRACE
                    313:                if (trace)
                    314:                        fprintf(trace, "before vdown in ^D, dot=%d, wdot=%d, dol=%d\n", lineno(dot), lineno(wdot), lineno(dol));
                    315: #endif
                    316:                        if (hadcnt)
                    317:                                vSCROLL = cnt;
                    318:                        cnt = vSCROLL;
                    319:                        if (state == VISUAL)
                    320:                                ind = vcnt - vcline - 1, cnt += ind;
                    321:                        else
                    322:                                ind = 0;
                    323:                        vmoving = 0;
                    324:                        vdown(cnt, ind, 1);
                    325: #ifdef TRACE
                    326:                if (trace)
                    327:                        fprintf(trace, "before vnline in ^D, dot=%d, wdot=%d, dol=%d\n", lineno(dot), lineno(wdot), lineno(dol));
                    328: #endif
                    329:                        vnline(NOSTR);
                    330: #ifdef TRACE
                    331:                if (trace)
                    332:                        fprintf(trace, "after vnline in ^D, dot=%d, wdot=%d, dol=%d\n", lineno(dot), lineno(wdot), lineno(dol));
                    333: #endif
                    334:                        continue;
                    335: 
                    336:                /*
                    337:                 * ^E           Glitch the screen down (one) line.
                    338:                 *              Cursor left on same line in file.
                    339:                 */
                    340:                case CTRL(e):
                    341:                        if (state != VISUAL)
                    342:                                continue;
                    343:                        if (!hadcnt)
                    344:                                cnt = 1;
                    345:                        /* Bottom line of file already on screen */
                    346:                        forbid(lineDOL()-lineDOT() <= vcnt-1-vcline);
                    347:                        ind = vcnt - vcline - 1 + cnt;
                    348:                        vdown(ind, ind, 1);
                    349:                        vnline(cursor);
                    350:                        continue;
                    351: 
                    352:                /*
                    353:                 * ^Y           Like ^E but up
                    354:                 */
                    355:                case CTRL(y):
                    356:                        if (state != VISUAL)
                    357:                                continue;
                    358:                        if (!hadcnt)
                    359:                                cnt = 1;
                    360:                        forbid(lineDOT()-1<=vcline); /* line 1 already there */
                    361:                        ind = vcline + cnt;
                    362:                        vup(ind, ind, 1);
                    363:                        vnline(cursor);
                    364:                        continue;
                    365: 
                    366: 
                    367:                /*
                    368:                 * m            Mark position in mark register given
                    369:                 *              by following letter.  Return is
                    370:                 *              accomplished via ' or `; former
                    371:                 *              to beginning of line where mark
                    372:                 *              was set, latter to column where marked.
                    373:                 */
                    374:                case 'm':
                    375:                        /*
                    376:                         * Getesc is generally used when a character
                    377:                         * is read as a latter part of a command
                    378:                         * to allow one to hit rubout/escape to cancel
                    379:                         * what you have typed so far.  These characters
                    380:                         * are mapped to 0 by the subroutine.
                    381:                         */
                    382:                        c = getesc();
                    383:                        if (c == 0)
                    384:                                continue;
                    385: 
                    386:                        /*
                    387:                         * Markreg checks that argument is a letter
                    388:                         * and also maps ' and ` to the end of the range
                    389:                         * to allow '' or `` to reference the previous
                    390:                         * context mark.
                    391:                         */
                    392:                        c = markreg(c);
                    393:                        forbid (c == 0);
                    394:                        vsave();
                    395:                        names[c - 'a'] = (*dot &~ 01);
                    396:                        ncols[c - 'a'] = cursor;
                    397:                        anymarks = 1;
                    398:                        continue;
                    399: 
                    400:                /*
                    401:                 * ^F           Window forwards, with 2 lines of continuity.
                    402:                 *              Count repeats.
                    403:                 */
                    404:                case CTRL(f):
                    405:                        vsave();
                    406:                        if (vcnt > 2) {
                    407:                                addr = dot + (vcnt - vcline) - 2 + (cnt-1)*basWLINES;
                    408:                                forbid(addr > dol);
                    409:                                dot = addr;
                    410:                                vcnt = vcline = 0;
                    411:                        }
                    412:                        vzop(0, 0, '+');
                    413:                        continue;
                    414: 
                    415:                /*
                    416:                 * ^B           Window backwards, with 2 lines of continuity.
                    417:                 *              Inverse of ^F.
                    418:                 */
                    419:                case CTRL(b):
                    420:                        vsave();
                    421:                        if (one + vcline != dot && vcnt > 2) {
                    422:                                addr = dot - vcline + 2 + (cnt-1)*basWLINES;
                    423:                                forbid (addr <= zero);
                    424:                                dot = addr;
                    425:                                vcnt = vcline = 0;
                    426:                        }
                    427:                        vzop(0, 0, '^');
                    428:                        continue;
                    429: 
                    430:                /*
                    431:                 * z            Screen adjustment, taking a following character:
                    432:                 *                      z<CR>           current line to top
                    433:                 *                      z<NL>           like z<CR>
                    434:                 *                      z-              current line to bottom
                    435:                 *              also z+, z^ like ^F and ^B.
                    436:                 *              A preceding count is line to use rather
                    437:                 *              than current line.  A count between z and
                    438:                 *              specifier character changes the screen size
                    439:                 *              for the redraw.
                    440:                 *
                    441:                 */
                    442:                case 'z':
                    443:                        if (state == VISUAL) {
                    444:                                i = vgetcnt();
                    445:                                if (i > 0)
                    446:                                        vsetsiz(i);
                    447:                                c = getesc();
                    448:                                if (c == 0)
                    449:                                        continue;
                    450:                        }
                    451:                        vsave();
                    452:                        vzop(hadcnt, cnt, c);
                    453:                        continue;
                    454: 
                    455:                /*
                    456:                 * Y            Yank lines, abbreviation for y_ or yy.
                    457:                 *              Yanked lines can be put later if no
                    458:                 *              changes intervene, or can be put in named
                    459:                 *              buffers and put anytime in this session.
                    460:                 */
                    461:                case 'Y':
                    462:                        ungetkey('_');
                    463:                        c = 'y';
                    464:                        break;
                    465: 
                    466:                /*
                    467:                 * J            Join lines, 2 by default.  Count is number
                    468:                 *              of lines to join (no join operator sorry.)
                    469:                 */
                    470:                case 'J':
                    471:                        forbid (dot == dol);
                    472:                        if (cnt == 1)
                    473:                                cnt = 2;
                    474:                        if (cnt > (i = dol - dot + 1))
                    475:                                cnt = i;
                    476:                        vsave();
                    477:                        vmacchng(1);
                    478:                        setLAST();
                    479:                        cursor = strend(linebuf);
                    480:                        vremote(cnt, join, 0);
                    481:                        notenam = "join";
                    482:                        vmoving = 0;
                    483:                        killU();
                    484:                        vreplace(vcline, cnt, 1);
                    485:                        if (!*cursor && cursor > linebuf)
                    486:                                cursor--;
                    487:                        if (notecnt == 2)
                    488:                                notecnt = 0;
                    489:                        vrepaint(cursor);
                    490:                        continue;
                    491: 
                    492:                /*
                    493:                 * S            Substitute text for whole lines, abbrev for c_.
                    494:                 *              Count is number of lines to change.
                    495:                 */
                    496:                case 'S':
                    497:                        ungetkey('_');
                    498:                        c = 'c';
                    499:                        break;
                    500: 
                    501:                /*
                    502:                 * O            Create a new line above current and accept new
                    503:                 *              input text, to an escape, there.
                    504:                 *              A count specifies, for dumb terminals when
                    505:                 *              slowopen is not set, the number of physical
                    506:                 *              line space to open on the screen.
                    507:                 *
                    508:                 * o            Like O, but opens lines below.
                    509:                 */
                    510:                case 'O':
                    511:                case 'o':
                    512:                        vmacchng(1);
                    513:                        voOpen(c, cnt);
                    514:                        continue;
                    515: 
                    516:                /*
                    517:                 * C            Change text to end of line, short for c$.
                    518:                 */
                    519:                case 'C':
                    520:                        if (*cursor) {
                    521:                                ungetkey('$'), c = 'c';
                    522:                                break;
                    523:                        }
                    524:                        goto appnd;
                    525: 
                    526:                /*
                    527:                 * ~    Switch case of letter under cursor
                    528:                 */
                    529:                case '~':
                    530:                        {
                    531:                                char mbuf[4];
                    532:                                setLAST();
                    533:                                mbuf[0] = 'r';
                    534:                                mbuf[1] = *cursor;
                    535:                                mbuf[2] = cursor[1]==0 ? 0 : ' ';
                    536:                                mbuf[3] = 0;
                    537:                                if (isalpha(mbuf[1]))
                    538:                                        mbuf[1] ^= ' '; /* toggle the case */
                    539:                                macpush(mbuf, 1);
                    540:                        }
                    541:                        continue;
                    542: 
                    543: 
                    544:                /*
                    545:                 * A            Append at end of line, short for $a.
                    546:                 */
                    547:                case 'A':
                    548:                        operate('$', 1);
                    549: appnd:
                    550:                        c = 'a';
                    551:                        /* fall into ... */
                    552: 
                    553:                /*
                    554:                 * a            Appends text after cursor.  Text can continue
                    555:                 *              through arbitrary number of lines.
                    556:                 */
                    557:                case 'a':
                    558:                        if (*cursor) {
                    559:                                if (state == HARDOPEN)
                    560:                                        putchar(*cursor);
                    561:                                cursor++;
                    562:                        }
                    563:                        goto insrt;
                    564: 
                    565:                /*
                    566:                 * I            Insert at beginning of whitespace of line,
                    567:                 *              short for ^i.
                    568:                 */
                    569:                case 'I':
                    570:                        operate('^', 1);
                    571:                        c = 'i';
                    572:                        /* fall into ... */
                    573: 
                    574:                /*
                    575:                 * R            Replace characters, one for one, by input
                    576:                 *              (logically), like repeated r commands.
                    577:                 *
                    578:                 * BUG:         This is like the typeover mode of many other
                    579:                 *              editors, and is only rarely useful.  Its
                    580:                 *              implementation is a hack in a low level
                    581:                 *              routine and it doesn't work very well, e.g.
                    582:                 *              you can't move around within a R, etc.
                    583:                 */
                    584:                case 'R':
                    585:                        /* fall into... */
                    586: 
                    587:                /*
                    588:                 * i            Insert text to an escape in the buffer.
                    589:                 *              Text is arbitrary.  This command reminds of
                    590:                 *              the i command in bare teco.
                    591:                 */
                    592:                case 'i':
                    593: insrt:
                    594:                        /*
                    595:                         * Common code for all the insertion commands.
                    596:                         * Save for redo, position cursor, prepare for append
                    597:                         * at command and in visual undo.  Note that nothing
                    598:                         * is doomed, unless R when all is, and save the
                    599:                         * current line in a the undo temporary buffer.
                    600:                         */
                    601:                        vmacchng(1);
                    602:                        setLAST();
                    603:                        vcursat(cursor);
                    604:                        prepapp();
                    605:                        vnoapp();
                    606:                        doomed = c == 'R' ? 10000 : 0;
                    607:                        if(FIXUNDO)
                    608:                                vundkind = VCHNG;
                    609:                        vmoving = 0;
                    610:                        CP(vutmp, linebuf);
                    611: 
                    612:                        /*
                    613:                         * If this is a repeated command, then suppress
                    614:                         * fake insert mode on dumb terminals which looks
                    615:                         * ridiculous and wastes lots of time even at 9600B.
                    616:                         */
                    617:                        if (vglobp)
                    618:                                hold = HOLDQIK;
                    619:                        vappend(c, cnt, 0);
                    620:                        continue;
                    621: 
                    622:                /*
                    623:                 * ^?           An attention, normally a ^?, just beeps.
                    624:                 *              If you are a vi command within ex, then
                    625:                 *              two ATTN's will drop you back to command mode.
                    626:                 */
                    627:                case ATTN:
                    628:                        beep();
                    629:                        if (initev || peekkey() != ATTN)
                    630:                                continue;
                    631:                        /* fall into... */
                    632: 
                    633:                /*
                    634:                 * ^\           A quit always gets command mode.
                    635:                 */
                    636:                case QUIT:
                    637:                        /*
                    638:                         * Have to be careful if we were called
                    639:                         *      g/xxx/vi
                    640:                         * since a return will just start up again.
                    641:                         * So we simulate an interrupt.
                    642:                         */
                    643:                        if (inglobal)
                    644:                                onintr();
                    645:                        /* fall into... */
                    646: 
                    647: #ifdef notdef
                    648:                /*
                    649:                 * q            Quit back to command mode, unless called as
                    650:                 *              vi on command line in which case dont do it
                    651:                 */
                    652:                case 'q':       /* quit */
                    653:                        if (initev) {
                    654:                                vsave();
                    655:                                CATCH
                    656:                                        error("Q gets ex command mode, :q leaves vi");
                    657:                                ENDCATCH
                    658:                                splitw = 0;
                    659:                                getDOT();
                    660:                                vrepaint(cursor);
                    661:                                continue;
                    662:                        }
                    663: #endif
                    664:                        /* fall into... */
                    665: 
                    666:                /*
                    667:                 * Q            Is like q, but always gets to command mode
                    668:                 *              even if command line invocation was as vi.
                    669:                 */
                    670:                case 'Q':
                    671:                        vsave();
                    672:                        /*
                    673:                         * If we are in the middle of a macro, throw away
                    674:                         * the rest and fix up undo.
                    675:                         * This code copied from getbr().
                    676:                         */
                    677:                        if (vmacp) {
                    678:                                vmacp = 0;
                    679:                                if (inopen == -1)       /* don't screw up undo for esc esc */
                    680:                                        vundkind = VMANY;
                    681:                                inopen = 1;     /* restore old setting now that macro done */
                    682:                        }
                    683:                        return;
                    684: 
                    685: 
                    686:                /*
                    687:                 * ZZ           Like :x
                    688:                 */
                    689:                 case 'Z':
                    690:                        forbid(getkey() != 'Z');
                    691:                        oglobp = globp;
                    692:                        globp = "x";
                    693:                        vclrech(0);
                    694:                        goto gogo;
                    695:                        
                    696:                /*
                    697:                 * P            Put back text before cursor or before current
                    698:                 *              line.  If text was whole lines goes back
                    699:                 *              as whole lines.  If part of a single line
                    700:                 *              or parts of whole lines splits up current
                    701:                 *              line to form many new lines.
                    702:                 *              May specify a named buffer, or the delete
                    703:                 *              saving buffers 1-9.
                    704:                 *
                    705:                 * p            Like P but after rather than before.
                    706:                 */
                    707:                case 'P':
                    708:                case 'p':
                    709:                        vmoving = 0;
                    710: #ifdef notdef
                    711:                        forbid (!vreg && value(UNDOMACRO) && inopen < 0);
                    712: #endif
                    713:                        /*
                    714:                         * If previous delete was partial line, use an
                    715:                         * append or insert to put it back so as to
                    716:                         * use insert mode on intelligent terminals.
                    717:                         */
                    718:                        if (!vreg && DEL[0]) {
                    719:                                forbid ((DEL[0] & (QUOTE|TRIM)) == OVERBUF);
                    720:                                vglobp = DEL;
                    721:                                ungetkey(c == 'p' ? 'a' : 'i');
                    722:                                goto reread;
                    723:                        }
                    724: 
                    725:                        /*
                    726:                         * If a register wasn't specified, then make
                    727:                         * sure there is something to put back.
                    728:                         */
                    729:                        forbid (!vreg && unddol == dol);
                    730:                        /*
                    731:                         * If we just did a macro the whole buffer is in
                    732:                         * the undo save area.  We don't want to put THAT.
                    733:                         */
                    734:                        forbid (vundkind == VMANY && undkind==UNDALL);
                    735:                        vsave();
                    736:                        vmacchng(1);
                    737:                        setLAST();
                    738:                        i = 0;
                    739:                        if (vreg && partreg(vreg) || !vreg && pkill[0]) {
                    740:                                /*
                    741:                                 * Restoring multiple lines which were partial
                    742:                                 * lines; will leave cursor in middle
                    743:                                 * of line after shoving restored text in to
                    744:                                 * split the current line.
                    745:                                 */
                    746:                                i++;
                    747:                                if (c == 'p' && *cursor)
                    748:                                        cursor++;
                    749:                        } else {
                    750:                                /*
                    751:                                 * In whole line case, have to back up dot
                    752:                                 * for P; also want to clear cursor so
                    753:                                 * cursor will eventually be positioned
                    754:                                 * at the beginning of the first put line.
                    755:                                 */
                    756:                                cursor = 0;
                    757:                                if (c == 'P') {
                    758:                                        dot--, vcline--;
                    759:                                        c = 'p';
                    760:                                }
                    761:                        }
                    762:                        killU();
                    763: 
                    764:                        /*
                    765:                         * The call to putreg can potentially
                    766:                         * bomb since there may be nothing in a named buffer.
                    767:                         * We thus put a catch in here.  If we didn't and
                    768:                         * there was an error we would end up in command mode.
                    769:                         */
                    770:                        addr = dol;     /* old dol */
                    771:                        CATCH
                    772:                                vremote(1, vreg ? putreg : put, vreg);
                    773:                        ONERR
                    774:                                if (vreg == -1) {
                    775:                                        splitw = 0;
                    776:                                        if (op == 'P')
                    777:                                                dot++, vcline++;
                    778:                                        goto pfixup;
                    779:                                }
                    780:                        ENDCATCH
                    781:                        splitw = 0;
                    782:                        nlput = dol - addr + 1;
                    783:                        if (!i) {
                    784:                                /*
                    785:                                 * Increment undap1, undap2 to make up
                    786:                                 * for their incorrect initialization in the
                    787:                                 * routine vremote before calling put/putreg.
                    788:                                 */
                    789:                                if (FIXUNDO)
                    790:                                        undap1++, undap2++;
                    791:                                vcline++;
                    792:                                nlput--;
                    793: 
                    794:                                /*
                    795:                                 * After a put want current line first line,
                    796:                                 * and dot was made the last line put in code
                    797:                                 * run so far.  This is why we increment vcline
                    798:                                 * above and decrease dot here.
                    799:                                 */
                    800:                                dot -= nlput - 1;
                    801:                        }
                    802: #ifdef TRACE
                    803:                        if (trace)
                    804:                                fprintf(trace, "vreplace(%d, %d, %d), undap1=%d, undap2=%d, dot=%d\n", vcline, i, nlput, lineno(undap1), lineno(undap2), lineno(dot));
                    805: #endif
                    806:                        vreplace(vcline, i, nlput);
                    807:                        if (state != VISUAL) {
                    808:                                /*
                    809:                                 * Special case in open mode.
                    810:                                 * Force action on the screen when a single
                    811:                                 * line is put even if it is identical to
                    812:                                 * the current line, e.g. on YP; otherwise
                    813:                                 * you can't tell anything happened.
                    814:                                 */
                    815:                                vjumpto(dot, cursor, '.');
                    816:                                continue;
                    817:                        }
                    818: pfixup:
                    819:                        vrepaint(cursor);
                    820:                        vfixcurs();
                    821:                        continue;
                    822: 
                    823:                /*
                    824:                 * ^^           Return to previous file.
                    825:                 *              Like a :e #, and thus can be used after a
                    826:                 *              "No Write" diagnostic.
                    827:                 */
                    828:                case CTRL(^):
                    829:                        forbid (hadcnt);
                    830:                        vsave();
                    831:                        ckaw();
                    832:                        oglobp = globp;
                    833:                        if (value(AUTOWRITE))
                    834:                                globp = "e! #";
                    835:                        else
                    836:                                globp = "e #";
                    837:                        goto gogo;
                    838: 
                    839:                /*
                    840:                 * ^]           Takes word after cursor as tag, and then does
                    841:                 *              tag command.  Read ``go right to''.
                    842:                 */
                    843:                case CTRL(]):
                    844:                        grabtag();
                    845:                        oglobp = globp;
                    846:                        globp = "tag";
                    847:                        goto gogo;
                    848: 
                    849:                /*
                    850:                 * &            Like :&
                    851:                 */
                    852:                 case '&':
                    853:                        oglobp = globp;
                    854:                        globp = "&";
                    855:                        goto gogo;
                    856:                        
                    857:                /*
                    858:                 * ^G           Bring up a status line at the bottom of
                    859:                 *              the screen, like a :file command.
                    860:                 *
                    861:                 * BUG:         Was ^S but doesn't work in cbreak mode
                    862:                 */
                    863:                case CTRL(g):
                    864:                        oglobp = globp;
                    865:                        globp = "file";
                    866: gogo:
                    867:                        addr = dot;
                    868:                        vsave();
                    869:                        goto doinit;
                    870: 
                    871: #ifdef SIGTSTP
                    872:                /*
                    873:                 * ^Z:  suspend editor session and temporarily return
                    874:                 *      to shell.  Only works with Berkeley/IIASA process
                    875:                 *      control in kernel.
                    876:                 */
                    877:                case CTRL(z):
                    878:                        forbid(dosusp == 0 || !ldisc);
                    879:                        vsave();
                    880:                        oglobp = globp;
                    881:                        globp = "stop";
                    882:                        goto gogo;
                    883: #endif
                    884: 
                    885:                /*
                    886:                 * :            Read a command from the echo area and
                    887:                 *              execute it in command mode.
                    888:                 */
                    889:                case ':':
                    890:                        forbid (hadcnt);
                    891:                        vsave();
                    892:                        i = tchng;
                    893:                        addr = dot;
                    894:                        if (readecho(c)) {
                    895:                                esave[0] = 0;
                    896:                                goto fixup;
                    897:                        }
                    898:                        getDOT();
                    899:                        /*
                    900:                         * Use the visual undo buffer to store the global
                    901:                         * string for command mode, since it is idle right now.
                    902:                         */
                    903:                        oglobp = globp; strcpy(vutmp, genbuf+1); globp = vutmp;
                    904: doinit:
                    905:                        esave[0] = 0;
                    906:                        fixech();
                    907: 
                    908:                        /*
                    909:                         * Have to finagle around not to lose last
                    910:                         * character after this command (when run from ex
                    911:                         * command mode).  This is clumsy.
                    912:                         */
                    913:                        d = peekc; ungetchar(0);
                    914:                        if (shouldpo) {
                    915:                                /*
                    916:                                 * So after a "Hit return..." ":", we do
                    917:                                 * another "Hit return..." the next time
                    918:                                 */
                    919:                                pofix();
                    920:                                shouldpo = 0;
                    921:                        }
                    922:                        CATCH
                    923:                                /*
                    924:                                 * Save old values of options so we can
                    925:                                 * notice when they change; switch into
                    926:                                 * cooked mode so we are interruptible.
                    927:                                 */
                    928:                                onumber = value(NUMBER);
                    929:                                olist = value(LIST);
                    930:                                OPline = Pline;
                    931:                                OPutchar = Putchar;
                    932: #ifndef CBREAK
                    933:                                vcook();
                    934: #endif
                    935:                                commands(1, 1);
                    936:                                if (dot == zero && dol > zero)
                    937:                                        dot = one;
                    938: #ifndef CBREAK
                    939:                                vraw();
                    940: #endif
                    941:                        ONERR
                    942: #ifndef CBREAK
                    943:                                vraw();
                    944: #endif
                    945:                                copy(esave, vtube[WECHO], TUBECOLS);
                    946:                        ENDCATCH
                    947:                        fixol();
                    948:                        Pline = OPline;
                    949:                        Putchar = OPutchar;
                    950:                        ungetchar(d);
                    951:                        globp = oglobp;
                    952: 
                    953:                        /*
                    954:                         * If we ended up with no lines in the buffer, make
                    955:                         * a line, and don't consider the buffer changed.
                    956:                         */
                    957:                        if (dot == zero) {
                    958:                                fixzero();
                    959:                                sync();
                    960:                        }
                    961:                        splitw = 0;
                    962: 
                    963:                        /*
                    964:                         * Special case: did list/number options change?
                    965:                         */
                    966:                        if (onumber != value(NUMBER))
                    967:                                setnumb(value(NUMBER));
                    968:                        if (olist != value(LIST))
                    969:                                setlist(value(LIST));
                    970: 
                    971: fixup:
                    972:                        /*
                    973:                         * If a change occurred, other than
                    974:                         * a write which clears changes, then
                    975:                         * we should allow an undo even if .
                    976:                         * didn't move.
                    977:                         *
                    978:                         * BUG: You can make this wrong by
                    979:                         * tricking around with multiple commands
                    980:                         * on one line of : escape, and including
                    981:                         * a write command there, but its not
                    982:                         * worth worrying about.
                    983:                         */
                    984:                        if (FIXUNDO && tchng && tchng != i)
                    985:                                vundkind = VMANY, cursor = 0;
                    986: 
                    987:                        /*
                    988:                         * If we are about to do another :, hold off
                    989:                         * updating of screen.
                    990:                         */
                    991:                        if (vcnt < 0 && Peekkey == ':') {
                    992:                                getDOT();
                    993:                                shouldpo = 1;
                    994:                                continue;
                    995:                        }
                    996:                        shouldpo = 0;
                    997: 
                    998:                        /*
                    999:                         * In the case where the file being edited is
                   1000:                         * new; e.g. if the initial state hasn't been
                   1001:                         * saved yet, then do so now.
                   1002:                         */
                   1003:                        if (unddol == truedol) {
                   1004:                                vundkind = VNONE;
                   1005:                                Vlines = lineDOL();
                   1006:                                if (!inglobal)
                   1007:                                        savevis();
                   1008:                                addr = zero;
                   1009:                                vcnt = 0;
                   1010:                                if (esave[0] == 0)
                   1011:                                        copy(esave, vtube[WECHO], TUBECOLS);
                   1012:                        }
                   1013: 
                   1014:                        /*
                   1015:                         * If the current line moved reset the cursor position.
                   1016:                         */
                   1017:                        if (dot != addr) {
                   1018:                                vmoving = 0;
                   1019:                                cursor = 0;
                   1020:                        }
                   1021: 
                   1022:                        /*
                   1023:                         * If current line is not on screen or if we are
                   1024:                         * in open mode and . moved, then redraw.
                   1025:                         */
                   1026:                        i = vcline + (dot - addr);
                   1027:                        if (i < 0 || i >= vcnt && i >= -vcnt || state != VISUAL && dot != addr) {
                   1028:                                if (state == CRTOPEN)
                   1029:                                        vup1();
                   1030:                                if (vcnt > 0)
                   1031:                                        vcnt = 0;
                   1032:                                vjumpto(dot, (char *) 0, '.');
                   1033:                        } else {
                   1034:                                /*
                   1035:                                 * Current line IS on screen.
                   1036:                                 * If we did a [Hit return...] then
                   1037:                                 * restore vcnt and clear screen if in visual
                   1038:                                 */
                   1039:                                vcline = i;
                   1040:                                if (vcnt < 0) {
                   1041:                                        vcnt = -vcnt;
                   1042:                                        if (state == VISUAL)
                   1043:                                                vclear();
                   1044:                                        else if (state == CRTOPEN) {
                   1045:                                                vcnt = 0;
                   1046:                                        }
                   1047:                                }
                   1048: 
                   1049:                                /*
                   1050:                                 * Limit max value of vcnt based on $
                   1051:                                 */
                   1052:                                i = vcline + lineDOL() - lineDOT() + 1;
                   1053:                                if (i < vcnt)
                   1054:                                        vcnt = i;
                   1055:                                
                   1056:                                /*
                   1057:                                 * Dirty and repaint.
                   1058:                                 */
                   1059:                                vdirty(0, LINES);
                   1060:                                vrepaint(cursor);
                   1061:                        }
                   1062: 
                   1063:                        /*
                   1064:                         * If in visual, put back the echo area
                   1065:                         * if it was clobberred.
                   1066:                         */
                   1067:                        if (state == VISUAL) {
                   1068:                                int sdc = destcol, sdl = destline;
                   1069: 
                   1070:                                splitw++;
                   1071:                                vigoto(WECHO, 0);
                   1072:                                for (i = 0; i < TUBECOLS - 1; i++) {
                   1073:                                        if (esave[i] == 0)
                   1074:                                                break;
                   1075:                                        vputchar(esave[i]);
                   1076:                                }
                   1077:                                splitw = 0;
                   1078:                                vgoto(sdl, sdc);
                   1079:                        }
                   1080:                        continue;
                   1081: 
                   1082:                /*
                   1083:                 * u            undo the last changing command.
                   1084:                 */
                   1085:                case 'u':
                   1086:                        vundo(1);
                   1087:                        continue;
                   1088: 
                   1089:                /*
                   1090:                 * U            restore current line to initial state.
                   1091:                 */
                   1092:                case 'U':
                   1093:                        vUndo();
                   1094:                        continue;
                   1095: 
                   1096: fonfon:
                   1097:                        beep();
                   1098:                        vmacp = 0;
                   1099:                        inopen = 1;     /* might have been -1 */
                   1100:                        continue;
                   1101:                }
                   1102: 
                   1103:                /*
                   1104:                 * Rest of commands are decoded by the operate
                   1105:                 * routine.
                   1106:                 */
                   1107:                operate(c, cnt);
                   1108:        }
                   1109: }
                   1110: 
                   1111: /*
                   1112:  * Grab the word after the cursor so we can look for it as a tag.
                   1113:  */
                   1114: grabtag()
                   1115: {
                   1116:        register char *cp, *dp;
                   1117: 
                   1118:        cp = vpastwh(cursor);
                   1119:        if (*cp) {
                   1120:                dp = lasttag;
                   1121:                do {
                   1122:                        if (dp < &lasttag[sizeof lasttag - 2])
                   1123:                                *dp++ = *cp;
                   1124:                        cp++;
                   1125:                } while (isalpha(*cp) || isdigit(*cp) || *cp == '_');
                   1126:                *dp++ = 0;
                   1127:        }
                   1128: }
                   1129: 
                   1130: /*
                   1131:  * Before appending lines, set up addr1 and
                   1132:  * the command mode undo information.
                   1133:  */
                   1134: prepapp()
                   1135: {
                   1136: 
                   1137:        addr1 = dot;
                   1138:        deletenone();
                   1139:        addr1++;
                   1140:        appendnone();
                   1141: }
                   1142: 
                   1143: /*
                   1144:  * Execute function f with the address bounds addr1
                   1145:  * and addr2 surrounding cnt lines starting at dot.
                   1146:  */
                   1147: vremote(cnt, f, arg)
                   1148:        int cnt, (*f)(), arg;
                   1149: {
                   1150:        register int oing = inglobal;
                   1151: 
                   1152:        addr1 = dot;
                   1153:        addr2 = dot + cnt - 1;
                   1154:        inglobal = 0;
                   1155:        if (FIXUNDO)
                   1156:                undap1 = undap2 = dot;
                   1157:        (*f)(arg);
                   1158:        inglobal = oing;
                   1159:        if (FIXUNDO)
                   1160:                vundkind = VMANY;
                   1161:        vmcurs = 0;
                   1162: }
                   1163: 
                   1164: /*
                   1165:  * Save the current contents of linebuf, if it has changed.
                   1166:  */
                   1167: vsave()
                   1168: {
                   1169:        char temp[LBSIZE];
                   1170: 
                   1171:        CP(temp, linebuf);
                   1172:        if (FIXUNDO && vundkind == VCHNG || vundkind == VCAPU) {
                   1173:                /*
                   1174:                 * If the undo state is saved in the temporary buffer
                   1175:                 * vutmp, then we sync this into the temp file so that
                   1176:                 * we will be able to undo even after we have moved off
                   1177:                 * the line.  It would be possible to associate a line
                   1178:                 * with vutmp but we assume that vutmp is only associated
                   1179:                 * with line dot (e.g. in case ':') above, so beware.
                   1180:                 */
                   1181:                prepapp();
                   1182:                strcLIN(vutmp);
                   1183:                putmark(dot);
                   1184:                vremote(1, yank, 0);
                   1185:                vundkind = VMCHNG;
                   1186:                notecnt = 0;
                   1187:                undkind = UNDCHANGE;
                   1188:        }
                   1189:        /*
                   1190:         * Get the line out of the temp file and do nothing if it hasn't
                   1191:         * changed.  This may seem like a loss, but the line will
                   1192:         * almost always be in a read buffer so this may well avoid disk i/o.
                   1193:         */
                   1194:        getDOT();
                   1195:        if (strcmp(linebuf, temp) == 0)
                   1196:                return;
                   1197:        strcLIN(temp);
                   1198:        putmark(dot);
                   1199: }
                   1200: 
                   1201: #undef forbid
                   1202: #define        forbid(a)       if (a) { beep(); return; }
                   1203: 
                   1204: /*
                   1205:  * Do a z operation.
                   1206:  * Code here is rather long, and very uninteresting.
                   1207:  */
                   1208: vzop(hadcnt, cnt, c)
                   1209:        bool hadcnt;
                   1210:        int cnt;
                   1211:        register int c;
                   1212: {
                   1213:        register line *addr;
                   1214: 
                   1215:        if (state != VISUAL) {
                   1216:                /*
                   1217:                 * Z from open; always like a z=.
                   1218:                 * This code is a mess and should be cleaned up.
                   1219:                 */
                   1220:                vmoveitup(1, 1);
                   1221:                vgoto(outline, 0);
                   1222:                ostop(normf);
                   1223:                setoutt();
                   1224:                addr2 = dot;
                   1225:                vclear();
                   1226:                destline = WECHO;
                   1227:                zop2(Xhadcnt ? Xcnt : value(WINDOW) - 1, '=');
                   1228:                if (state == CRTOPEN)
                   1229:                        putnl();
                   1230:                putNFL();
                   1231:                termreset();
                   1232:                Outchar = vputchar;
                   1233:                ignore(ostart());
                   1234:                vcnt = 0;
                   1235:                outline = destline = 0;
                   1236:                vjumpto(dot, cursor, 0);
                   1237:                return;
                   1238:        }
                   1239:        if (hadcnt) {
                   1240:                addr = zero + cnt;
                   1241:                if (addr < one)
                   1242:                        addr = one;
                   1243:                if (addr > dol)
                   1244:                        addr = dol;
                   1245:                markit(addr);
                   1246:        } else
                   1247:                switch (c) {
                   1248: 
                   1249:                case '+':
                   1250:                        addr = dot + vcnt - vcline;
                   1251:                        break;
                   1252: 
                   1253:                case '^':
                   1254:                        addr = dot - vcline - 1;
                   1255:                        forbid (addr < one);
                   1256:                        c = '-';
                   1257:                        break;
                   1258: 
                   1259:                default:
                   1260:                        addr = dot;
                   1261:                        break;
                   1262:                }
                   1263:        switch (c) {
                   1264: 
                   1265:        case '.':
                   1266:        case '-':
                   1267:                break;
                   1268: 
                   1269:        case '^':
                   1270:                forbid (addr <= one);
                   1271:                break;
                   1272: 
                   1273:        case '+':
                   1274:                forbid (addr >= dol);
                   1275:                /* fall into ... */
                   1276: 
                   1277:        case CR:
                   1278:        case NL:
                   1279:                c = CR;
                   1280:                break;
                   1281: 
                   1282:        default:
                   1283:                beep();
                   1284:                return;
                   1285:        }
                   1286:        vmoving = 0;
                   1287:        vjumpto(addr, NOSTR, c);
                   1288: }

unix.superglobalmegacorp.com

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