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

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

unix.superglobalmegacorp.com

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