Annotation of 3BSD/cmd/ex/z, revision 1.1.1.1

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

unix.superglobalmegacorp.com

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