10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*3806Scf46844 * Common Development and Distribution License (the "License").
6*3806Scf46844 * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
21802Scf46844 /*
22*3806Scf46844 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23802Scf46844 * Use is subject to license terms.
24802Scf46844 */
25802Scf46844
260Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
270Sstevel@tonic-gate /* All Rights Reserved */
280Sstevel@tonic-gate
290Sstevel@tonic-gate
300Sstevel@tonic-gate /* Copyright (c) 1981 Regents of the University of California */
31802Scf46844
32802Scf46844 #pragma ident "%Z%%M% %I% %E% SMI"
330Sstevel@tonic-gate
340Sstevel@tonic-gate #include "ex.h"
350Sstevel@tonic-gate #include "ex_tty.h"
360Sstevel@tonic-gate #include "ex_vis.h"
370Sstevel@tonic-gate #ifndef PRESUNEUC
380Sstevel@tonic-gate #include <wctype.h>
390Sstevel@tonic-gate /* Undef putchar/getchar if they're defined. */
400Sstevel@tonic-gate #ifdef putchar
410Sstevel@tonic-gate # undef putchar
420Sstevel@tonic-gate #endif
430Sstevel@tonic-gate #ifdef getchar
440Sstevel@tonic-gate # undef getchar
450Sstevel@tonic-gate #endif
460Sstevel@tonic-gate #endif /* PRESUNEUC */
470Sstevel@tonic-gate
480Sstevel@tonic-gate /*
490Sstevel@tonic-gate * This is the main routine for visual.
500Sstevel@tonic-gate * We here decode the count and possible named buffer specification
510Sstevel@tonic-gate * preceding a command and interpret a few of the commands.
520Sstevel@tonic-gate * Commands which involve a target (i.e. an operator) are decoded
530Sstevel@tonic-gate * in the routine operate in ex_voperate.c.
540Sstevel@tonic-gate */
550Sstevel@tonic-gate
560Sstevel@tonic-gate #define forbid(a) { if (a) goto fonfon; }
570Sstevel@tonic-gate
580Sstevel@tonic-gate extern int windowchg;
590Sstevel@tonic-gate extern int sigok;
60*3806Scf46844 #ifdef XPG6
61*3806Scf46844 int redisplay; /* XPG6 assertion 313 [count]r\n : Also used in ex_vops2.c */
62*3806Scf46844 #endif
630Sstevel@tonic-gate void redraw(), windowinit();
640Sstevel@tonic-gate
650Sstevel@tonic-gate #ifdef XPG4
660Sstevel@tonic-gate extern int P_cursor_offset;
670Sstevel@tonic-gate #endif
680Sstevel@tonic-gate
69802Scf46844 void
vmain(void)70802Scf46844 vmain(void)
710Sstevel@tonic-gate {
72802Scf46844 int c, cnt, i;
730Sstevel@tonic-gate wchar_t esave[TUBECOLS];
740Sstevel@tonic-gate extern wchar_t atube[];
750Sstevel@tonic-gate unsigned char *oglobp;
760Sstevel@tonic-gate short d;
770Sstevel@tonic-gate line *addr;
780Sstevel@tonic-gate int ind, nlput;
790Sstevel@tonic-gate int shouldpo = 0;
800Sstevel@tonic-gate int tag_reset_wrap = 0;
810Sstevel@tonic-gate int onumber, olist, (*OPline)(), (*OPutchar)();
820Sstevel@tonic-gate
830Sstevel@tonic-gate
840Sstevel@tonic-gate vch_mac = VC_NOTINMAC;
850Sstevel@tonic-gate ixlatctl(0);
860Sstevel@tonic-gate
870Sstevel@tonic-gate /*
880Sstevel@tonic-gate * If we started as a vi command (on the command line)
890Sstevel@tonic-gate * then go process initial commands (recover, next or tag).
900Sstevel@tonic-gate */
910Sstevel@tonic-gate if (initev) {
920Sstevel@tonic-gate oglobp = globp;
930Sstevel@tonic-gate globp = initev;
940Sstevel@tonic-gate hadcnt = cnt = 0;
950Sstevel@tonic-gate i = tchng;
960Sstevel@tonic-gate addr = dot;
970Sstevel@tonic-gate goto doinit;
980Sstevel@tonic-gate }
990Sstevel@tonic-gate
1000Sstevel@tonic-gate vshowmode(""); /* As a precaution */
1010Sstevel@tonic-gate /*
1020Sstevel@tonic-gate * NB:
1030Sstevel@tonic-gate *
1040Sstevel@tonic-gate * The current line is always in the line buffer linebuf,
1050Sstevel@tonic-gate * and the cursor at the position cursor. You should do
1060Sstevel@tonic-gate * a vsave() before moving off the line to make sure the disk
1070Sstevel@tonic-gate * copy is updated if it has changed, and a getDOT() to get
1080Sstevel@tonic-gate * the line back if you mung linebuf. The motion
1090Sstevel@tonic-gate * routines in ex_vwind.c handle most of this.
1100Sstevel@tonic-gate */
1110Sstevel@tonic-gate for (;;) {
1120Sstevel@tonic-gate /*
1130Sstevel@tonic-gate * Decode a visual command.
1140Sstevel@tonic-gate * First sync the temp file if there has been a reasonable
1150Sstevel@tonic-gate * amount of change. Clear state for decoding of next
1160Sstevel@tonic-gate * command.
1170Sstevel@tonic-gate */
1180Sstevel@tonic-gate TSYNC();
1190Sstevel@tonic-gate vglobp = 0;
1200Sstevel@tonic-gate vreg = 0;
1210Sstevel@tonic-gate hold = 0;
1220Sstevel@tonic-gate seenprompt = 1;
1230Sstevel@tonic-gate wcursor = 0;
1240Sstevel@tonic-gate Xhadcnt = hadcnt = 0;
1250Sstevel@tonic-gate Xcnt = cnt = 1;
1260Sstevel@tonic-gate splitw = 0;
1270Sstevel@tonic-gate if (i = holdupd && !windowchg) {
1280Sstevel@tonic-gate if (state == VISUAL) {
1290Sstevel@tonic-gate sigok = 1;
1300Sstevel@tonic-gate (void)peekkey();
1310Sstevel@tonic-gate sigok = 0;
1320Sstevel@tonic-gate }
1330Sstevel@tonic-gate
1340Sstevel@tonic-gate holdupd = 0;
1350Sstevel@tonic-gate /*
1360Sstevel@tonic-gate if (LINE(0) < ZERO) {
1370Sstevel@tonic-gate vclear();
1380Sstevel@tonic-gate vcnt = 0;
1390Sstevel@tonic-gate i = 3;
1400Sstevel@tonic-gate }
1410Sstevel@tonic-gate */
1420Sstevel@tonic-gate if (state != VISUAL) {
1430Sstevel@tonic-gate vcnt = 0;
1440Sstevel@tonic-gate vsave();
1450Sstevel@tonic-gate vrepaint(cursor);
1460Sstevel@tonic-gate } else if (i == 3)
1470Sstevel@tonic-gate vredraw(WTOP);
1480Sstevel@tonic-gate else
1490Sstevel@tonic-gate vsync(WTOP);
1500Sstevel@tonic-gate vfixcurs();
1510Sstevel@tonic-gate } else if(windowchg)
1520Sstevel@tonic-gate redraw();
1530Sstevel@tonic-gate
154*3806Scf46844 #ifdef XPG6
155*3806Scf46844 if (redisplay) {
156*3806Scf46844 /* XPG6 assertion 313 & 254 : after [count]r\n */
157*3806Scf46844 fixdisplay();
158*3806Scf46844 }
159*3806Scf46844 redisplay = 0;
160*3806Scf46844 #endif
1610Sstevel@tonic-gate /*
1620Sstevel@tonic-gate * Gobble up counts and named buffer specifications.
1630Sstevel@tonic-gate */
1640Sstevel@tonic-gate for (;;) {
1650Sstevel@tonic-gate looptop:
1660Sstevel@tonic-gate #ifdef MDEBUG
1670Sstevel@tonic-gate if (trace)
1680Sstevel@tonic-gate fprintf(trace, "pc=%c",peekkey());
1690Sstevel@tonic-gate #endif
1700Sstevel@tonic-gate sigok = 1;
1710Sstevel@tonic-gate c = peekkey();
1720Sstevel@tonic-gate sigok = 0;
1730Sstevel@tonic-gate if (isdigit(peekkey()) && peekkey() != '0') {
1740Sstevel@tonic-gate hadcnt = 1;
1750Sstevel@tonic-gate cnt = vgetcnt();
1760Sstevel@tonic-gate forbid (cnt <= 0);
1770Sstevel@tonic-gate }
1780Sstevel@tonic-gate if (peekkey() != '"')
1790Sstevel@tonic-gate break;
1800Sstevel@tonic-gate (void)getkey(), c = getkey();
1810Sstevel@tonic-gate /*
1820Sstevel@tonic-gate * Buffer names be letters or digits.
1830Sstevel@tonic-gate * But not '0' as that is the source of
1840Sstevel@tonic-gate * an 'empty' named buffer spec in the routine
1850Sstevel@tonic-gate * kshift (see ex_temp.c).
1860Sstevel@tonic-gate */
1870Sstevel@tonic-gate if(!isascii(c) && MB_CUR_MAX > 1) {
1880Sstevel@tonic-gate /* get rest of character */
1890Sstevel@tonic-gate wchar_t wchar;
1900Sstevel@tonic-gate char multic[MULTI_BYTE_MAX];
1910Sstevel@tonic-gate ungetkey(c);
1920Sstevel@tonic-gate (void)_mbftowc(multic, &wchar, getkey, &Peekkey);
1930Sstevel@tonic-gate }
1940Sstevel@tonic-gate forbid (c == '0' || !isalpha(c) && !isascii(c) && !isdigit(c));
1950Sstevel@tonic-gate vreg = c;
1960Sstevel@tonic-gate }
1970Sstevel@tonic-gate reread:
1980Sstevel@tonic-gate /*
1990Sstevel@tonic-gate * Come to reread from below after some macro expansions.
2000Sstevel@tonic-gate * The call to map allows use of function key pads
2010Sstevel@tonic-gate * by performing a terminal dependent mapping of inputs.
2020Sstevel@tonic-gate */
2030Sstevel@tonic-gate #ifdef MDEBUG
2040Sstevel@tonic-gate if (trace)
2050Sstevel@tonic-gate fprintf(trace,"pcb=%c,",peekkey());
2060Sstevel@tonic-gate #endif
2070Sstevel@tonic-gate op = getkey();
2080Sstevel@tonic-gate maphopcnt = 0;
2090Sstevel@tonic-gate do {
2100Sstevel@tonic-gate /*
2110Sstevel@tonic-gate * Keep mapping the char as long as it changes.
2120Sstevel@tonic-gate * This allows for double mappings, e.g., q to #,
2130Sstevel@tonic-gate * #1 to something else.
2140Sstevel@tonic-gate */
2150Sstevel@tonic-gate c = op;
216802Scf46844 op = map(c, arrows, 0);
2170Sstevel@tonic-gate #ifdef MDEBUG
2180Sstevel@tonic-gate if (trace)
2190Sstevel@tonic-gate fprintf(trace,"pca=%c,",c);
2200Sstevel@tonic-gate #endif
2210Sstevel@tonic-gate /*
2220Sstevel@tonic-gate * Maybe the mapped to char is a count. If so, we have
2230Sstevel@tonic-gate * to go back to the "for" to interpret it. Likewise
2240Sstevel@tonic-gate * for a buffer name.
2250Sstevel@tonic-gate */
2260Sstevel@tonic-gate if ((isdigit(c) && c!='0') || c == '"') {
2270Sstevel@tonic-gate ungetkey(c);
2280Sstevel@tonic-gate goto looptop;
2290Sstevel@tonic-gate }
2300Sstevel@tonic-gate if (!value(vi_REMAP)) {
2310Sstevel@tonic-gate c = op;
2320Sstevel@tonic-gate break;
2330Sstevel@tonic-gate }
2340Sstevel@tonic-gate if (++maphopcnt > 256)
2350Sstevel@tonic-gate error(gettext("Infinite macro loop"));
2360Sstevel@tonic-gate } while (c != op);
2370Sstevel@tonic-gate
2380Sstevel@tonic-gate /*
2390Sstevel@tonic-gate * Begin to build an image of this command for possible
2400Sstevel@tonic-gate * later repeat in the buffer workcmd. It will be copied
2410Sstevel@tonic-gate * to lastcmd by the routine setLAST
2420Sstevel@tonic-gate * if/when completely specified.
2430Sstevel@tonic-gate */
2440Sstevel@tonic-gate lastcp = workcmd;
2450Sstevel@tonic-gate if (!vglobp)
2460Sstevel@tonic-gate *lastcp++ = c;
2470Sstevel@tonic-gate
2480Sstevel@tonic-gate /*
2490Sstevel@tonic-gate * First level command decode.
2500Sstevel@tonic-gate */
2510Sstevel@tonic-gate switch (c) {
2520Sstevel@tonic-gate
2530Sstevel@tonic-gate /*
2540Sstevel@tonic-gate * ^L Clear screen e.g. after transmission error.
2550Sstevel@tonic-gate */
2560Sstevel@tonic-gate
2570Sstevel@tonic-gate /*
2580Sstevel@tonic-gate * ^R Retype screen, getting rid of @ lines.
2590Sstevel@tonic-gate * If in open, equivalent to ^L.
2600Sstevel@tonic-gate * On terminals where the right arrow key sends
2610Sstevel@tonic-gate * ^L we make ^R act like ^L, since there is no
2620Sstevel@tonic-gate * way to get ^L. These terminals (adm31, tvi)
2630Sstevel@tonic-gate * are intelligent so ^R is useless. Soroc
2640Sstevel@tonic-gate * will probably foul this up, but nobody has
2650Sstevel@tonic-gate * one of them.
2660Sstevel@tonic-gate */
2670Sstevel@tonic-gate case CTRL('l'):
2680Sstevel@tonic-gate case CTRL('r'):
2690Sstevel@tonic-gate if (c == CTRL('l') || (key_right && *key_right==CTRL('l'))) {
2700Sstevel@tonic-gate vclear();
2710Sstevel@tonic-gate vdirty(0, vcnt);
2720Sstevel@tonic-gate }
2730Sstevel@tonic-gate if (state != VISUAL) {
2740Sstevel@tonic-gate /*
2750Sstevel@tonic-gate * Get a clean line, throw away the
2760Sstevel@tonic-gate * memory of what is displayed now,
2770Sstevel@tonic-gate * and move back onto the current line.
2780Sstevel@tonic-gate */
2790Sstevel@tonic-gate vclean();
2800Sstevel@tonic-gate vcnt = 0;
2810Sstevel@tonic-gate vmoveto(dot, cursor, 0);
2820Sstevel@tonic-gate continue;
2830Sstevel@tonic-gate }
2840Sstevel@tonic-gate vredraw(WTOP);
2850Sstevel@tonic-gate /*
2860Sstevel@tonic-gate * Weird glitch -- when we enter visual
2870Sstevel@tonic-gate * in a very small window we may end up with
2880Sstevel@tonic-gate * no lines on the screen because the line
2890Sstevel@tonic-gate * at the top is too long. This forces the screen
2900Sstevel@tonic-gate * to be expanded to make room for it (after
2910Sstevel@tonic-gate * we have printed @'s ick showing we goofed).
2920Sstevel@tonic-gate */
2930Sstevel@tonic-gate if (vcnt == 0)
2940Sstevel@tonic-gate vrepaint(cursor);
2950Sstevel@tonic-gate vfixcurs();
2960Sstevel@tonic-gate continue;
2970Sstevel@tonic-gate
2980Sstevel@tonic-gate /*
2990Sstevel@tonic-gate * $ Escape just cancels the current command
3000Sstevel@tonic-gate * with a little feedback.
3010Sstevel@tonic-gate */
3020Sstevel@tonic-gate case ESCAPE:
303802Scf46844 (void) beep();
3040Sstevel@tonic-gate continue;
3050Sstevel@tonic-gate
3060Sstevel@tonic-gate /*
3070Sstevel@tonic-gate * @ Macros. Bring in the macro and put it
3080Sstevel@tonic-gate * in vmacbuf, point vglobp there and punt.
3090Sstevel@tonic-gate */
3100Sstevel@tonic-gate case '@':
3110Sstevel@tonic-gate c = getesc();
3120Sstevel@tonic-gate if (c == 0)
3130Sstevel@tonic-gate continue;
3140Sstevel@tonic-gate if (c == '@')
3150Sstevel@tonic-gate c = lastmac;
3160Sstevel@tonic-gate if (isupper(c))
3170Sstevel@tonic-gate c = tolower(c);
3180Sstevel@tonic-gate forbid(!islower(c));
3190Sstevel@tonic-gate lastmac = c;
3200Sstevel@tonic-gate vsave();
3210Sstevel@tonic-gate CATCH
3220Sstevel@tonic-gate unsigned char tmpbuf[BUFSIZE];
3230Sstevel@tonic-gate
324802Scf46844 regbuf(c, tmpbuf, sizeof (vmacbuf));
3250Sstevel@tonic-gate macpush(tmpbuf, 1);
3260Sstevel@tonic-gate ONERR
3270Sstevel@tonic-gate lastmac = 0;
3280Sstevel@tonic-gate splitw = 0;
3290Sstevel@tonic-gate getDOT();
3300Sstevel@tonic-gate vrepaint(cursor);
3310Sstevel@tonic-gate continue;
3320Sstevel@tonic-gate ENDCATCH
3330Sstevel@tonic-gate vmacp = vmacbuf;
3340Sstevel@tonic-gate goto reread;
3350Sstevel@tonic-gate
3360Sstevel@tonic-gate /*
3370Sstevel@tonic-gate * . Repeat the last (modifying) open/visual command.
3380Sstevel@tonic-gate */
3390Sstevel@tonic-gate case '.':
3400Sstevel@tonic-gate /*
3410Sstevel@tonic-gate * Check that there was a last command, and
3420Sstevel@tonic-gate * take its count and named buffer unless they
3430Sstevel@tonic-gate * were given anew. Special case if last command
3440Sstevel@tonic-gate * referenced a numeric named buffer -- increment
3450Sstevel@tonic-gate * the number and go to a named buffer again.
3460Sstevel@tonic-gate * This allows a sequence like "1pu.u.u...
3470Sstevel@tonic-gate * to successively look for stuff in the kill chain
3480Sstevel@tonic-gate * much as one does in EMACS with C-Y and M-Y.
3490Sstevel@tonic-gate */
3500Sstevel@tonic-gate forbid (lastcmd[0] == 0);
3510Sstevel@tonic-gate if (hadcnt)
3520Sstevel@tonic-gate lastcnt = cnt;
3530Sstevel@tonic-gate if (vreg)
3540Sstevel@tonic-gate lastreg = vreg;
3550Sstevel@tonic-gate else if (isdigit(lastreg) && lastreg < '9')
3560Sstevel@tonic-gate lastreg++;
3570Sstevel@tonic-gate vreg = lastreg;
3580Sstevel@tonic-gate cnt = lastcnt;
3590Sstevel@tonic-gate hadcnt = lasthad;
3600Sstevel@tonic-gate vglobp = lastcmd;
3610Sstevel@tonic-gate goto reread;
3620Sstevel@tonic-gate
3630Sstevel@tonic-gate /*
3640Sstevel@tonic-gate * ^U Scroll up. A count sticks around for
3650Sstevel@tonic-gate * future scrolls as the scroll amount.
3660Sstevel@tonic-gate * Attempt to hold the indentation from the
3670Sstevel@tonic-gate * top of the screen (in logical lines).
3680Sstevel@tonic-gate *
3690Sstevel@tonic-gate * BUG: A ^U near the bottom of the screen
3700Sstevel@tonic-gate * on a dumb terminal (which can't roll back)
3710Sstevel@tonic-gate * causes the screen to be cleared and then
3720Sstevel@tonic-gate * redrawn almost as it was. In this case
3730Sstevel@tonic-gate * one should simply move the cursor.
3740Sstevel@tonic-gate */
3750Sstevel@tonic-gate case CTRL('u'):
3760Sstevel@tonic-gate if (hadcnt)
3770Sstevel@tonic-gate vSCROLL = cnt;
3780Sstevel@tonic-gate cnt = vSCROLL;
3790Sstevel@tonic-gate if (state == VISUAL)
3800Sstevel@tonic-gate ind = vcline, cnt += ind;
3810Sstevel@tonic-gate else
3820Sstevel@tonic-gate ind = 0;
3830Sstevel@tonic-gate vmoving = 0;
3840Sstevel@tonic-gate vup(cnt, ind, 1);
385802Scf46844 vnline((unsigned char *)NOSTR);
3860Sstevel@tonic-gate continue;
3870Sstevel@tonic-gate
3880Sstevel@tonic-gate /*
3890Sstevel@tonic-gate * ^D Scroll down. Like scroll up.
3900Sstevel@tonic-gate */
3910Sstevel@tonic-gate case CTRL('d'):
3920Sstevel@tonic-gate #ifdef TRACE
3930Sstevel@tonic-gate if (trace)
3940Sstevel@tonic-gate fprintf(trace, "before vdown in ^D, dot=%d, wdot=%d, dol=%d\n", lineno(dot), lineno(wdot), lineno(dol));
3950Sstevel@tonic-gate #endif
3960Sstevel@tonic-gate if (hadcnt)
3970Sstevel@tonic-gate vSCROLL = cnt;
3980Sstevel@tonic-gate cnt = vSCROLL;
3990Sstevel@tonic-gate if (state == VISUAL)
4000Sstevel@tonic-gate ind = vcnt - vcline - 1, cnt += ind;
4010Sstevel@tonic-gate else
4020Sstevel@tonic-gate ind = 0;
4030Sstevel@tonic-gate vmoving = 0;
4040Sstevel@tonic-gate vdown(cnt, ind, 1);
4050Sstevel@tonic-gate #ifdef TRACE
4060Sstevel@tonic-gate if (trace)
4070Sstevel@tonic-gate fprintf(trace, "before vnline in ^D, dot=%d, wdot=%d, dol=%d\n", lineno(dot), lineno(wdot), lineno(dol));
4080Sstevel@tonic-gate #endif
409802Scf46844 vnline((unsigned char *)NOSTR);
4100Sstevel@tonic-gate #ifdef TRACE
4110Sstevel@tonic-gate if (trace)
4120Sstevel@tonic-gate fprintf(trace, "after vnline in ^D, dot=%d, wdot=%d, dol=%d\n", lineno(dot), lineno(wdot), lineno(dol));
4130Sstevel@tonic-gate #endif
4140Sstevel@tonic-gate continue;
4150Sstevel@tonic-gate
4160Sstevel@tonic-gate /*
4170Sstevel@tonic-gate * ^E Glitch the screen down (one) line.
4180Sstevel@tonic-gate * Cursor left on same line in file.
4190Sstevel@tonic-gate */
4200Sstevel@tonic-gate case CTRL('e'):
4210Sstevel@tonic-gate if (state != VISUAL)
4220Sstevel@tonic-gate continue;
4230Sstevel@tonic-gate if (!hadcnt)
4240Sstevel@tonic-gate cnt = 1;
4250Sstevel@tonic-gate /* Bottom line of file already on screen */
4260Sstevel@tonic-gate forbid(lineDOL()-lineDOT() <= vcnt-1-vcline);
4270Sstevel@tonic-gate ind = vcnt - vcline - 1 + cnt;
4280Sstevel@tonic-gate vdown(ind, ind, 1);
4290Sstevel@tonic-gate vnline(cursor);
4300Sstevel@tonic-gate continue;
4310Sstevel@tonic-gate
4320Sstevel@tonic-gate /*
4330Sstevel@tonic-gate * ^Y Like ^E but up
4340Sstevel@tonic-gate */
4350Sstevel@tonic-gate case CTRL('y'):
4360Sstevel@tonic-gate if (state != VISUAL)
4370Sstevel@tonic-gate continue;
4380Sstevel@tonic-gate if (!hadcnt)
4390Sstevel@tonic-gate cnt = 1;
4400Sstevel@tonic-gate forbid(lineDOT()-1<=vcline); /* line 1 already there */
4410Sstevel@tonic-gate ind = vcline + cnt;
4420Sstevel@tonic-gate vup(ind, ind, 1);
4430Sstevel@tonic-gate vnline(cursor);
4440Sstevel@tonic-gate continue;
4450Sstevel@tonic-gate
4460Sstevel@tonic-gate
4470Sstevel@tonic-gate /*
4480Sstevel@tonic-gate * m Mark position in mark register given
4490Sstevel@tonic-gate * by following letter. Return is
4500Sstevel@tonic-gate * accomplished via ' or `; former
4510Sstevel@tonic-gate * to beginning of line where mark
4520Sstevel@tonic-gate * was set, latter to column where marked.
4530Sstevel@tonic-gate */
4540Sstevel@tonic-gate case 'm':
4550Sstevel@tonic-gate /*
4560Sstevel@tonic-gate * Getesc is generally used when a character
4570Sstevel@tonic-gate * is read as a latter part of a command
4580Sstevel@tonic-gate * to allow one to hit rubout/escape to cancel
4590Sstevel@tonic-gate * what you have typed so far. These characters
4600Sstevel@tonic-gate * are mapped to 0 by the subroutine.
4610Sstevel@tonic-gate */
4620Sstevel@tonic-gate c = getesc();
4630Sstevel@tonic-gate if (c == 0)
4640Sstevel@tonic-gate continue;
4650Sstevel@tonic-gate
4660Sstevel@tonic-gate /*
4670Sstevel@tonic-gate * Markreg checks that argument is a letter
4680Sstevel@tonic-gate * and also maps ' and ` to the end of the range
4690Sstevel@tonic-gate * to allow '' or `` to reference the previous
4700Sstevel@tonic-gate * context mark.
4710Sstevel@tonic-gate */
4720Sstevel@tonic-gate c = markreg(c);
4730Sstevel@tonic-gate forbid (c == 0);
4740Sstevel@tonic-gate vsave();
4750Sstevel@tonic-gate names[c - 'a'] = (*dot &~ 01);
4760Sstevel@tonic-gate ncols[c - 'a'] = cursor;
4770Sstevel@tonic-gate anymarks = 1;
4780Sstevel@tonic-gate continue;
4790Sstevel@tonic-gate
4800Sstevel@tonic-gate /*
4810Sstevel@tonic-gate * ^F Window forwards, with 2 lines of continuity.
4820Sstevel@tonic-gate * Count repeats.
4830Sstevel@tonic-gate */
4840Sstevel@tonic-gate case CTRL('f'):
4850Sstevel@tonic-gate vsave();
4860Sstevel@tonic-gate if (vcnt > 2) {
4870Sstevel@tonic-gate addr = dot + (vcnt - vcline) - 2 + (cnt-1)*basWLINES;
4880Sstevel@tonic-gate forbid(addr > dol);
4890Sstevel@tonic-gate dot = addr;
4900Sstevel@tonic-gate vcnt = vcline = 0;
4910Sstevel@tonic-gate }
4920Sstevel@tonic-gate vzop(0, 0, '+');
4930Sstevel@tonic-gate continue;
4940Sstevel@tonic-gate
4950Sstevel@tonic-gate /*
4960Sstevel@tonic-gate * ^B Window backwards, with 2 lines of continuity.
4970Sstevel@tonic-gate * Inverse of ^F.
4980Sstevel@tonic-gate */
4990Sstevel@tonic-gate case CTRL('b'):
5000Sstevel@tonic-gate vsave();
5010Sstevel@tonic-gate if (one + vcline != dot && vcnt > 2) {
5020Sstevel@tonic-gate addr = dot - vcline + 2 - (cnt-1)*basWLINES;
5030Sstevel@tonic-gate forbid (addr <= zero);
5040Sstevel@tonic-gate dot = addr;
5050Sstevel@tonic-gate vcnt = vcline = 0;
5060Sstevel@tonic-gate }
5070Sstevel@tonic-gate vzop(0, 0, '^');
5080Sstevel@tonic-gate continue;
5090Sstevel@tonic-gate
5100Sstevel@tonic-gate /*
5110Sstevel@tonic-gate * z Screen adjustment, taking a following character:
5120Sstevel@tonic-gate * zcarriage_return current line to top
5130Sstevel@tonic-gate * z<NL> like zcarriage_return
5140Sstevel@tonic-gate * z- current line to bottom
5150Sstevel@tonic-gate * also z+, z^ like ^F and ^B.
5160Sstevel@tonic-gate * A preceding count is line to use rather
5170Sstevel@tonic-gate * than current line. A count between z and
5180Sstevel@tonic-gate * specifier character changes the screen size
5190Sstevel@tonic-gate * for the redraw.
5200Sstevel@tonic-gate *
5210Sstevel@tonic-gate */
5220Sstevel@tonic-gate case 'z':
5230Sstevel@tonic-gate if (state == VISUAL) {
5240Sstevel@tonic-gate i = vgetcnt();
5250Sstevel@tonic-gate if (i > 0)
5260Sstevel@tonic-gate vsetsiz(i);
5270Sstevel@tonic-gate c = getesc();
5280Sstevel@tonic-gate if (c == 0)
5290Sstevel@tonic-gate continue;
5300Sstevel@tonic-gate }
5310Sstevel@tonic-gate vsave();
5320Sstevel@tonic-gate vzop(hadcnt, cnt, c);
5330Sstevel@tonic-gate continue;
5340Sstevel@tonic-gate
5350Sstevel@tonic-gate /*
5360Sstevel@tonic-gate * Y Yank lines, abbreviation for y_ or yy.
5370Sstevel@tonic-gate * Yanked lines can be put later if no
5380Sstevel@tonic-gate * changes intervene, or can be put in named
5390Sstevel@tonic-gate * buffers and put anytime in this session.
5400Sstevel@tonic-gate */
5410Sstevel@tonic-gate case 'Y':
5420Sstevel@tonic-gate ungetkey('_');
5430Sstevel@tonic-gate c = 'y';
5440Sstevel@tonic-gate break;
5450Sstevel@tonic-gate
5460Sstevel@tonic-gate /*
5470Sstevel@tonic-gate * J Join lines, 2 by default. Count is number
5480Sstevel@tonic-gate * of lines to join (no join operator sorry.)
5490Sstevel@tonic-gate */
5500Sstevel@tonic-gate case 'J':
5510Sstevel@tonic-gate forbid (dot == dol);
5520Sstevel@tonic-gate if (cnt == 1)
5530Sstevel@tonic-gate cnt = 2;
5540Sstevel@tonic-gate if (cnt > (i = dol - dot + 1))
5550Sstevel@tonic-gate cnt = i;
5560Sstevel@tonic-gate vsave();
5570Sstevel@tonic-gate vmacchng(1);
5580Sstevel@tonic-gate setLAST();
5590Sstevel@tonic-gate cursor = strend(linebuf);
5600Sstevel@tonic-gate vremote(cnt, join, 0);
5610Sstevel@tonic-gate notenam = (unsigned char *)"join";
5620Sstevel@tonic-gate vmoving = 0;
5630Sstevel@tonic-gate killU();
5640Sstevel@tonic-gate vreplace(vcline, cnt, 1);
5650Sstevel@tonic-gate if (!*cursor && cursor > linebuf)
5660Sstevel@tonic-gate cursor--;
5670Sstevel@tonic-gate if (notecnt == 2)
5680Sstevel@tonic-gate notecnt = 0;
5690Sstevel@tonic-gate vrepaint(cursor);
5700Sstevel@tonic-gate continue;
5710Sstevel@tonic-gate
5720Sstevel@tonic-gate /*
5730Sstevel@tonic-gate * S Substitute text for whole lines, abbrev for c_.
5740Sstevel@tonic-gate * Count is number of lines to change.
5750Sstevel@tonic-gate */
5760Sstevel@tonic-gate case 'S':
5770Sstevel@tonic-gate ungetkey('_');
5780Sstevel@tonic-gate c = 'c';
5790Sstevel@tonic-gate break;
5800Sstevel@tonic-gate
5810Sstevel@tonic-gate /*
5820Sstevel@tonic-gate * O Create a new line above current and accept new
5830Sstevel@tonic-gate * input text, to an escape, there.
5840Sstevel@tonic-gate * A count specifies, for dumb terminals when
5850Sstevel@tonic-gate * slowopen is not set, the number of physical
5860Sstevel@tonic-gate * line space to open on the screen.
5870Sstevel@tonic-gate *
5880Sstevel@tonic-gate * o Like O, but opens lines below.
5890Sstevel@tonic-gate */
5900Sstevel@tonic-gate case 'O':
5910Sstevel@tonic-gate case 'o':
5920Sstevel@tonic-gate vmacchng(1);
5930Sstevel@tonic-gate voOpen(c, cnt);
5940Sstevel@tonic-gate continue;
5950Sstevel@tonic-gate
5960Sstevel@tonic-gate /*
5970Sstevel@tonic-gate * C Change text to end of line, short for c$.
5980Sstevel@tonic-gate */
5990Sstevel@tonic-gate case 'C':
6000Sstevel@tonic-gate if (*cursor) {
6010Sstevel@tonic-gate ungetkey('$'), c = 'c';
6020Sstevel@tonic-gate break;
6030Sstevel@tonic-gate }
6040Sstevel@tonic-gate goto appnd;
6050Sstevel@tonic-gate
6060Sstevel@tonic-gate /*
6070Sstevel@tonic-gate * ~ Switch case of letter under cursor
6080Sstevel@tonic-gate */
6090Sstevel@tonic-gate case '~':
6100Sstevel@tonic-gate {
6110Sstevel@tonic-gate unsigned char mbuf[2049];
6120Sstevel@tonic-gate unsigned char *ccursor = cursor;
6130Sstevel@tonic-gate #ifdef PRESUNEUC
6140Sstevel@tonic-gate int tmp, length;
6150Sstevel@tonic-gate wchar_t wchar;
6160Sstevel@tonic-gate #else
6170Sstevel@tonic-gate int tmp, len, n;
6180Sstevel@tonic-gate wchar_t wc;
6190Sstevel@tonic-gate #endif /* PRESUNEUC */
6200Sstevel@tonic-gate unsigned char tmp1;
6210Sstevel@tonic-gate setLAST();
6220Sstevel@tonic-gate for (tmp = 0; tmp + 3 < 2048; ) {
6230Sstevel@tonic-gate /*
6240Sstevel@tonic-gate * Use multiple 'r' commands to replace
6250Sstevel@tonic-gate * alpha with alternate case.
6260Sstevel@tonic-gate */
6270Sstevel@tonic-gate
6280Sstevel@tonic-gate if(cnt-- <= 0)
6290Sstevel@tonic-gate break;
6300Sstevel@tonic-gate #ifdef PRESUNEUC
6310Sstevel@tonic-gate length = mbtowc(&wchar, (char *)ccursor, MULTI_BYTE_MAX);
6320Sstevel@tonic-gate #else
6330Sstevel@tonic-gate len = mbtowc(&wc, (char *)ccursor, MULTI_BYTE_MAX);
6340Sstevel@tonic-gate #endif /* PRESUNEUC */
6350Sstevel@tonic-gate #ifdef PRESUNEUC
6360Sstevel@tonic-gate if(length > 1) {
6370Sstevel@tonic-gate #else
6380Sstevel@tonic-gate n = iswalpha(wc);
6390Sstevel@tonic-gate if(len > 1 && !iswalpha(wc)) {
6400Sstevel@tonic-gate #endif /* PRESUNEUC */
6410Sstevel@tonic-gate mbuf[tmp+0] = ' ';
6420Sstevel@tonic-gate tmp++;
6430Sstevel@tonic-gate #ifdef PRESUNEUC
6440Sstevel@tonic-gate ccursor += length;
6450Sstevel@tonic-gate #else
6460Sstevel@tonic-gate ccursor += len;
6470Sstevel@tonic-gate #endif /* PRESUNEUC */
6480Sstevel@tonic-gate continue;
6490Sstevel@tonic-gate }
6500Sstevel@tonic-gate mbuf[tmp] = 'r';
6510Sstevel@tonic-gate #ifdef PRESUNEUC
6520Sstevel@tonic-gate mbuf[tmp+1] = *ccursor++;
6530Sstevel@tonic-gate #else
6540Sstevel@tonic-gate ccursor += ((len > 0) ? len : 1);
6550Sstevel@tonic-gate #endif /* PRESUNEUC */
6560Sstevel@tonic-gate /*
6570Sstevel@tonic-gate * If pointing to an alpha character,
6580Sstevel@tonic-gate * change the case.
6590Sstevel@tonic-gate */
6600Sstevel@tonic-gate
6610Sstevel@tonic-gate tmp1 = mbuf[tmp+1];
6620Sstevel@tonic-gate #ifdef PRESUNEUC
6630Sstevel@tonic-gate if (isupper((unsigned char)tmp1))
6640Sstevel@tonic-gate mbuf[tmp+1] = tolower((unsigned char)tmp1);
6650Sstevel@tonic-gate else
6660Sstevel@tonic-gate mbuf[tmp+1] = toupper((unsigned char)tmp1);
6670Sstevel@tonic-gate #else
6680Sstevel@tonic-gate if (iswupper(wc))
6690Sstevel@tonic-gate len = wctomb((char *)(mbuf + tmp + 1),
6700Sstevel@tonic-gate (wc = towlower(wc)));
6710Sstevel@tonic-gate else
6720Sstevel@tonic-gate len = wctomb((char *)(mbuf + tmp + 1),
6730Sstevel@tonic-gate (wc = towupper(wc)));
6740Sstevel@tonic-gate tmp += len - 1;
6750Sstevel@tonic-gate #endif /* PRESUNEUC */
6760Sstevel@tonic-gate if(*ccursor)
6770Sstevel@tonic-gate /*
6780Sstevel@tonic-gate * If at end of line do not advance
6790Sstevel@tonic-gate * to the next character, else use a
6800Sstevel@tonic-gate * space to advance 1 column.
6810Sstevel@tonic-gate */
6820Sstevel@tonic-gate mbuf[tmp+2] = ' ';
6830Sstevel@tonic-gate else {
6840Sstevel@tonic-gate mbuf[tmp+2] = '\0';
6850Sstevel@tonic-gate tmp +=3;
6860Sstevel@tonic-gate break;
6870Sstevel@tonic-gate }
6880Sstevel@tonic-gate tmp += 3;
6890Sstevel@tonic-gate }
6900Sstevel@tonic-gate
6910Sstevel@tonic-gate mbuf[tmp] = 0;
6920Sstevel@tonic-gate macpush(mbuf, 1);
6930Sstevel@tonic-gate }
6940Sstevel@tonic-gate continue;
6950Sstevel@tonic-gate
6960Sstevel@tonic-gate
6970Sstevel@tonic-gate /*
6980Sstevel@tonic-gate * A Append at end of line, short for $a.
6990Sstevel@tonic-gate */
7000Sstevel@tonic-gate case 'A':
7010Sstevel@tonic-gate operate('$', 1);
7020Sstevel@tonic-gate appnd:
7030Sstevel@tonic-gate c = 'a';
7040Sstevel@tonic-gate /* fall into ... */
7050Sstevel@tonic-gate
7060Sstevel@tonic-gate /*
7070Sstevel@tonic-gate * a Appends text after cursor. Text can continue
7080Sstevel@tonic-gate * through arbitrary number of lines.
7090Sstevel@tonic-gate */
7100Sstevel@tonic-gate case 'a':
7110Sstevel@tonic-gate if (*cursor) {
7120Sstevel@tonic-gate wchar_t wchar;
7130Sstevel@tonic-gate int length = mbtowc(&wchar, (char *)cursor, MULTI_BYTE_MAX);
7140Sstevel@tonic-gate if (state == HARDOPEN) {
7150Sstevel@tonic-gate if(length < 0) {
7160Sstevel@tonic-gate putoctal = 1;
7170Sstevel@tonic-gate putchar(*cursor);
7180Sstevel@tonic-gate putoctal = 0;
7190Sstevel@tonic-gate } else
7200Sstevel@tonic-gate putchar(wchar);
7210Sstevel@tonic-gate }
7220Sstevel@tonic-gate if(length < 0)
7230Sstevel@tonic-gate cursor++;
7240Sstevel@tonic-gate else
7250Sstevel@tonic-gate cursor += length;
7260Sstevel@tonic-gate }
7270Sstevel@tonic-gate goto insrt;
7280Sstevel@tonic-gate
7290Sstevel@tonic-gate /*
7300Sstevel@tonic-gate * I Insert at beginning of whitespace of line,
7310Sstevel@tonic-gate * short for ^i.
7320Sstevel@tonic-gate */
7330Sstevel@tonic-gate case 'I':
7340Sstevel@tonic-gate operate('^', 1);
7350Sstevel@tonic-gate c = 'i';
7360Sstevel@tonic-gate /* fall into ... */
7370Sstevel@tonic-gate
7380Sstevel@tonic-gate /*
7390Sstevel@tonic-gate * R Replace characters, one for one, by input
7400Sstevel@tonic-gate * (logically), like repeated r commands.
7410Sstevel@tonic-gate *
7420Sstevel@tonic-gate * BUG: This is like the typeover mode of many other
7430Sstevel@tonic-gate * editors, and is only rarely useful. Its
7440Sstevel@tonic-gate * implementation is a hack in a low level
7450Sstevel@tonic-gate * routine and it doesn't work very well, e.g.
7460Sstevel@tonic-gate * you can't move around within a R, etc.
7470Sstevel@tonic-gate */
7480Sstevel@tonic-gate case 'R':
7490Sstevel@tonic-gate /* fall into... */
7500Sstevel@tonic-gate
7510Sstevel@tonic-gate /*
7520Sstevel@tonic-gate * i Insert text to an escape in the buffer.
7530Sstevel@tonic-gate * Text is arbitrary. This command reminds of
7540Sstevel@tonic-gate * the i command in bare teco.
7550Sstevel@tonic-gate */
7560Sstevel@tonic-gate case 'i':
7570Sstevel@tonic-gate insrt:
7580Sstevel@tonic-gate /*
7590Sstevel@tonic-gate * Common code for all the insertion commands.
7600Sstevel@tonic-gate * Save for redo, position cursor, prepare for append
7610Sstevel@tonic-gate * at command and in visual undo. Note that nothing
7620Sstevel@tonic-gate * is doomed, unless R when all is, and save the
7630Sstevel@tonic-gate * current line in a the undo temporary buffer.
7640Sstevel@tonic-gate */
7650Sstevel@tonic-gate vmacchng(1);
7660Sstevel@tonic-gate setLAST();
7670Sstevel@tonic-gate vcursat(cursor);
7680Sstevel@tonic-gate prepapp();
7690Sstevel@tonic-gate vnoapp();
7700Sstevel@tonic-gate doomed = c == 'R' ? 10000 : 0;
7710Sstevel@tonic-gate if(FIXUNDO)
7720Sstevel@tonic-gate vundkind = VCHNG;
7730Sstevel@tonic-gate vmoving = 0;
7740Sstevel@tonic-gate CP(vutmp, linebuf);
7750Sstevel@tonic-gate
7760Sstevel@tonic-gate /*
7770Sstevel@tonic-gate * If this is a repeated command, then suppress
7780Sstevel@tonic-gate * fake insert mode on dumb terminals which looks
7790Sstevel@tonic-gate * ridiculous and wastes lots of time even at 9600B.
7800Sstevel@tonic-gate */
7810Sstevel@tonic-gate if (vglobp)
7820Sstevel@tonic-gate hold = HOLDQIK;
7830Sstevel@tonic-gate vappend(c, cnt, 0);
7840Sstevel@tonic-gate continue;
7850Sstevel@tonic-gate
7860Sstevel@tonic-gate /*
7870Sstevel@tonic-gate * An attention, normally a DEL, just beeps.
7880Sstevel@tonic-gate * If you are a vi command within ex, then
7890Sstevel@tonic-gate * two ATTN's will drop you back to command mode.
7900Sstevel@tonic-gate */
7910Sstevel@tonic-gate case ATTN:
792802Scf46844 (void) beep();
7930Sstevel@tonic-gate if (initev || peekkey() != ATTN)
7940Sstevel@tonic-gate continue;
7950Sstevel@tonic-gate /* fall into... */
7960Sstevel@tonic-gate
7970Sstevel@tonic-gate /*
7980Sstevel@tonic-gate * ^\ A quit always gets command mode.
7990Sstevel@tonic-gate */
8000Sstevel@tonic-gate case QUIT:
8010Sstevel@tonic-gate /*
8020Sstevel@tonic-gate * Have to be careful if we were called
8030Sstevel@tonic-gate * g/xxx/vi
8040Sstevel@tonic-gate * since a return will just start up again.
8050Sstevel@tonic-gate * So we simulate an interrupt.
8060Sstevel@tonic-gate */
8070Sstevel@tonic-gate if (inglobal)
8080Sstevel@tonic-gate onintr(0);
8090Sstevel@tonic-gate /* fall into... */
8100Sstevel@tonic-gate
8110Sstevel@tonic-gate #ifdef notdef
8120Sstevel@tonic-gate /*
8130Sstevel@tonic-gate * q Quit back to command mode, unless called as
8140Sstevel@tonic-gate * vi on command line in which case dont do it
8150Sstevel@tonic-gate */
8160Sstevel@tonic-gate case 'q': /* quit */
8170Sstevel@tonic-gate if (initev) {
8180Sstevel@tonic-gate vsave();
8190Sstevel@tonic-gate CATCH
8200Sstevel@tonic-gate error(gettext("Q gets ex command mode, :q leaves vi"));
8210Sstevel@tonic-gate ENDCATCH
8220Sstevel@tonic-gate splitw = 0;
8230Sstevel@tonic-gate getDOT();
8240Sstevel@tonic-gate vrepaint(cursor);
8250Sstevel@tonic-gate continue;
8260Sstevel@tonic-gate }
8270Sstevel@tonic-gate #endif
8280Sstevel@tonic-gate /* fall into... */
8290Sstevel@tonic-gate
8300Sstevel@tonic-gate /*
8310Sstevel@tonic-gate * Q Is like q, but always gets to command mode
8320Sstevel@tonic-gate * even if command line invocation was as vi.
8330Sstevel@tonic-gate */
8340Sstevel@tonic-gate case 'Q':
8350Sstevel@tonic-gate vsave();
8360Sstevel@tonic-gate /*
8370Sstevel@tonic-gate * If we are in the middle of a macro, throw away
8380Sstevel@tonic-gate * the rest and fix up undo.
8390Sstevel@tonic-gate * This code copied from getbr().
8400Sstevel@tonic-gate */
8410Sstevel@tonic-gate if (vmacp) {
8420Sstevel@tonic-gate vmacp = 0;
8430Sstevel@tonic-gate if (inopen == -1) /* don't mess up undo for esc esc */
8440Sstevel@tonic-gate vundkind = VMANY;
8450Sstevel@tonic-gate inopen = 1; /* restore old setting now that macro done */
8460Sstevel@tonic-gate }
8470Sstevel@tonic-gate ixlatctl(1);
8480Sstevel@tonic-gate return;
8490Sstevel@tonic-gate
8500Sstevel@tonic-gate
8510Sstevel@tonic-gate /*
8520Sstevel@tonic-gate * ZZ Like :x
8530Sstevel@tonic-gate */
8540Sstevel@tonic-gate case 'Z':
8550Sstevel@tonic-gate forbid(getkey() != 'Z');
8560Sstevel@tonic-gate oglobp = globp;
8570Sstevel@tonic-gate globp = (unsigned char *)"x";
8580Sstevel@tonic-gate vclrech(0);
8590Sstevel@tonic-gate goto gogo;
8600Sstevel@tonic-gate
8610Sstevel@tonic-gate /*
8620Sstevel@tonic-gate * P Put back text before cursor or before current
8630Sstevel@tonic-gate * line. If text was whole lines goes back
8640Sstevel@tonic-gate * as whole lines. If part of a single line
8650Sstevel@tonic-gate * or parts of whole lines splits up current
8660Sstevel@tonic-gate * line to form many new lines.
8670Sstevel@tonic-gate * May specify a named buffer, or the delete
8680Sstevel@tonic-gate * saving buffers 1-9.
8690Sstevel@tonic-gate *
8700Sstevel@tonic-gate * p Like P but after rather than before.
8710Sstevel@tonic-gate */
8720Sstevel@tonic-gate case 'P':
8730Sstevel@tonic-gate case 'p':
8740Sstevel@tonic-gate vmoving = 0;
8750Sstevel@tonic-gate #ifdef XPG4
8760Sstevel@tonic-gate P_cursor_offset = 0;
8770Sstevel@tonic-gate #endif
8780Sstevel@tonic-gate #ifdef notdef
8790Sstevel@tonic-gate forbid (!vreg && value(vi_UNDOMACRO) && inopen < 0);
8800Sstevel@tonic-gate #endif
8810Sstevel@tonic-gate /*
8820Sstevel@tonic-gate * If previous delete was partial line, use an
8830Sstevel@tonic-gate * append or insert to put it back so as to
8840Sstevel@tonic-gate * use insert mode on intelligent terminals.
8850Sstevel@tonic-gate */
8860Sstevel@tonic-gate if (!vreg && DEL[0]) {
8870Sstevel@tonic-gate setLAST();
8880Sstevel@tonic-gate forbid ((unsigned char)DEL[128] == 0200);
8890Sstevel@tonic-gate vglobp = DEL;
8900Sstevel@tonic-gate ungetkey(c == 'p' ? 'a' : 'i');
8910Sstevel@tonic-gate goto reread;
8920Sstevel@tonic-gate }
8930Sstevel@tonic-gate
8940Sstevel@tonic-gate /*
8950Sstevel@tonic-gate * If a register wasn't specified, then make
8960Sstevel@tonic-gate * sure there is something to put back.
8970Sstevel@tonic-gate */
8980Sstevel@tonic-gate forbid (!vreg && unddol == dol);
8990Sstevel@tonic-gate /*
9000Sstevel@tonic-gate * If we just did a macro the whole buffer is in
9010Sstevel@tonic-gate * the undo save area. We don't want to put THAT.
9020Sstevel@tonic-gate */
9030Sstevel@tonic-gate forbid (vundkind == VMANY && undkind==UNDALL);
9040Sstevel@tonic-gate vsave();
9050Sstevel@tonic-gate vmacchng(1);
9060Sstevel@tonic-gate setLAST();
9070Sstevel@tonic-gate i = 0;
9080Sstevel@tonic-gate if (vreg && partreg(vreg) || !vreg && pkill[0]) {
9090Sstevel@tonic-gate /*
9100Sstevel@tonic-gate * Restoring multiple lines which were partial
9110Sstevel@tonic-gate * lines; will leave cursor in middle
9120Sstevel@tonic-gate * of line after shoving restored text in to
9130Sstevel@tonic-gate * split the current line.
9140Sstevel@tonic-gate */
9150Sstevel@tonic-gate i++;
9160Sstevel@tonic-gate if (c == 'p' && *cursor)
9170Sstevel@tonic-gate cursor = nextchr(cursor);
9180Sstevel@tonic-gate } else {
9190Sstevel@tonic-gate /*
9200Sstevel@tonic-gate * In whole line case, have to back up dot
9210Sstevel@tonic-gate * for P; also want to clear cursor so
9220Sstevel@tonic-gate * cursor will eventually be positioned
9230Sstevel@tonic-gate * at the beginning of the first put line.
9240Sstevel@tonic-gate */
9250Sstevel@tonic-gate cursor = 0;
9260Sstevel@tonic-gate if (c == 'P') {
9270Sstevel@tonic-gate dot--, vcline--;
9280Sstevel@tonic-gate c = 'p';
9290Sstevel@tonic-gate }
9300Sstevel@tonic-gate }
9310Sstevel@tonic-gate killU();
9320Sstevel@tonic-gate
9330Sstevel@tonic-gate /*
9340Sstevel@tonic-gate * The call to putreg can potentially
9350Sstevel@tonic-gate * bomb since there may be nothing in a named buffer.
9360Sstevel@tonic-gate * We thus put a catch in here. If we didn't and
9370Sstevel@tonic-gate * there was an error we would end up in command mode.
9380Sstevel@tonic-gate */
9390Sstevel@tonic-gate addr = dol; /* old dol */
9400Sstevel@tonic-gate CATCH
941802Scf46844 vremote(1,
942802Scf46844 vreg ? (int (*)())putreg : put, vreg);
9430Sstevel@tonic-gate ONERR
9440Sstevel@tonic-gate if (vreg == -1) {
9450Sstevel@tonic-gate splitw = 0;
9460Sstevel@tonic-gate if (op == 'P')
9470Sstevel@tonic-gate dot++, vcline++;
9480Sstevel@tonic-gate goto pfixup;
9490Sstevel@tonic-gate }
9500Sstevel@tonic-gate ENDCATCH
9510Sstevel@tonic-gate splitw = 0;
9520Sstevel@tonic-gate nlput = dol - addr + 1;
9530Sstevel@tonic-gate if (!i) {
9540Sstevel@tonic-gate /*
9550Sstevel@tonic-gate * Increment undap1, undap2 to make up
9560Sstevel@tonic-gate * for their incorrect initialization in the
9570Sstevel@tonic-gate * routine vremote before calling put/putreg.
9580Sstevel@tonic-gate */
9590Sstevel@tonic-gate if (FIXUNDO)
9600Sstevel@tonic-gate undap1++, undap2++;
9610Sstevel@tonic-gate vcline++;
9620Sstevel@tonic-gate nlput--;
9630Sstevel@tonic-gate
9640Sstevel@tonic-gate /*
9650Sstevel@tonic-gate * After a put want current line first line,
9660Sstevel@tonic-gate * and dot was made the last line put in code
9670Sstevel@tonic-gate * run so far. This is why we increment vcline
9680Sstevel@tonic-gate * above and decrease dot here.
9690Sstevel@tonic-gate */
9700Sstevel@tonic-gate dot -= nlput - 1;
9710Sstevel@tonic-gate }
9720Sstevel@tonic-gate #ifdef TRACE
9730Sstevel@tonic-gate if (trace)
9740Sstevel@tonic-gate fprintf(trace, "vreplace(%d, %d, %d), undap1=%d, undap2=%d, dot=%d\n", vcline, i, nlput, lineno(undap1), lineno(undap2), lineno(dot));
9750Sstevel@tonic-gate #endif
9760Sstevel@tonic-gate vreplace(vcline, i, nlput);
9770Sstevel@tonic-gate #ifdef XPG4
9780Sstevel@tonic-gate if (op == 'P' && i > 0) {
9790Sstevel@tonic-gate dot += nlput - 1;
9800Sstevel@tonic-gate vcline += nlput - 1;
9810Sstevel@tonic-gate cursor += P_cursor_offset;
9820Sstevel@tonic-gate }
9830Sstevel@tonic-gate #endif
9840Sstevel@tonic-gate if (state != VISUAL) {
9850Sstevel@tonic-gate /*
9860Sstevel@tonic-gate * Special case in open mode.
9870Sstevel@tonic-gate * Force action on the screen when a single
9880Sstevel@tonic-gate * line is put even if it is identical to
9890Sstevel@tonic-gate * the current line, e.g. on YP; otherwise
9900Sstevel@tonic-gate * you can't tell anything happened.
9910Sstevel@tonic-gate */
9920Sstevel@tonic-gate vjumpto(dot, cursor, '.');
9930Sstevel@tonic-gate continue;
9940Sstevel@tonic-gate }
9950Sstevel@tonic-gate pfixup:
9960Sstevel@tonic-gate vrepaint(cursor);
9970Sstevel@tonic-gate vfixcurs();
9980Sstevel@tonic-gate continue;
9990Sstevel@tonic-gate
10000Sstevel@tonic-gate /*
10010Sstevel@tonic-gate * ^^ Return to previous file.
10020Sstevel@tonic-gate * Like a :e #, and thus can be used after a
10030Sstevel@tonic-gate * "No Write" diagnostic.
10040Sstevel@tonic-gate */
10050Sstevel@tonic-gate case CTRL('^'):
10060Sstevel@tonic-gate forbid (hadcnt);
10070Sstevel@tonic-gate vsave();
10080Sstevel@tonic-gate ckaw();
10090Sstevel@tonic-gate oglobp = globp;
10100Sstevel@tonic-gate if (value(vi_AUTOWRITE) && !value(vi_READONLY))
10110Sstevel@tonic-gate globp = (unsigned char *)"e! #";
10120Sstevel@tonic-gate else
10130Sstevel@tonic-gate globp = (unsigned char *)"e #";
10140Sstevel@tonic-gate goto gogo;
10150Sstevel@tonic-gate
10160Sstevel@tonic-gate #ifdef TAG_STACK
10170Sstevel@tonic-gate /*
10180Sstevel@tonic-gate * ^T Pop the tag stack if enabled or else reset it
10190Sstevel@tonic-gate * if not.
10200Sstevel@tonic-gate */
10210Sstevel@tonic-gate case CTRL('t'):
10220Sstevel@tonic-gate forbid (hadcnt);
10230Sstevel@tonic-gate vsave();
10240Sstevel@tonic-gate oglobp = globp;
10250Sstevel@tonic-gate globp = (unsigned char *) "pop";
10260Sstevel@tonic-gate goto gogo;
10270Sstevel@tonic-gate #endif
10280Sstevel@tonic-gate /*
10290Sstevel@tonic-gate * ^] Takes word after cursor as tag, and then does
10300Sstevel@tonic-gate * tag command. Read ``go right to''.
10310Sstevel@tonic-gate * This is not a search, so the wrapscan setting
10320Sstevel@tonic-gate * must be ignored. If set, then it is unset
10330Sstevel@tonic-gate * here and restored later.
10340Sstevel@tonic-gate */
10350Sstevel@tonic-gate case CTRL(']'):
10360Sstevel@tonic-gate grabtag();
10370Sstevel@tonic-gate oglobp = globp;
10380Sstevel@tonic-gate if (value(vi_WRAPSCAN) == 0) {
10390Sstevel@tonic-gate tag_reset_wrap = 1;
10400Sstevel@tonic-gate value(vi_WRAPSCAN) = 1;
10410Sstevel@tonic-gate }
10420Sstevel@tonic-gate globp = (unsigned char *)"tag";
10430Sstevel@tonic-gate goto gogo;
10440Sstevel@tonic-gate
10450Sstevel@tonic-gate /*
10460Sstevel@tonic-gate * & Like :&
10470Sstevel@tonic-gate */
10480Sstevel@tonic-gate case '&':
10490Sstevel@tonic-gate oglobp = globp;
10500Sstevel@tonic-gate globp = (unsigned char *)"&";
10510Sstevel@tonic-gate goto gogo;
10520Sstevel@tonic-gate
10530Sstevel@tonic-gate /*
10540Sstevel@tonic-gate * ^G Bring up a status line at the bottom of
10550Sstevel@tonic-gate * the screen, like a :file command.
10560Sstevel@tonic-gate *
10570Sstevel@tonic-gate * BUG: Was ^S but doesn't work in cbreak mode
10580Sstevel@tonic-gate */
10590Sstevel@tonic-gate case CTRL('g'):
10600Sstevel@tonic-gate oglobp = globp;
10610Sstevel@tonic-gate globp = (unsigned char *)"file";
10620Sstevel@tonic-gate gogo:
10630Sstevel@tonic-gate addr = dot;
10640Sstevel@tonic-gate vsave();
10650Sstevel@tonic-gate goto doinit;
10660Sstevel@tonic-gate
10670Sstevel@tonic-gate #ifdef SIGTSTP
10680Sstevel@tonic-gate /*
10690Sstevel@tonic-gate * ^Z: suspend editor session and temporarily return
10700Sstevel@tonic-gate * to shell. Only works with Berkeley/IIASA process
10710Sstevel@tonic-gate * control in kernel.
10720Sstevel@tonic-gate */
10730Sstevel@tonic-gate case CTRL('z'):
10740Sstevel@tonic-gate forbid(dosusp == 0);
10750Sstevel@tonic-gate vsave();
10760Sstevel@tonic-gate oglobp = globp;
10770Sstevel@tonic-gate globp = (unsigned char *)"stop";
10780Sstevel@tonic-gate goto gogo;
10790Sstevel@tonic-gate #endif
10800Sstevel@tonic-gate
10810Sstevel@tonic-gate /*
10820Sstevel@tonic-gate * : Read a command from the echo area and
10830Sstevel@tonic-gate * execute it in command mode.
10840Sstevel@tonic-gate */
10850Sstevel@tonic-gate case ':':
10860Sstevel@tonic-gate forbid (hadcnt);
10870Sstevel@tonic-gate vsave();
10880Sstevel@tonic-gate i = tchng;
10890Sstevel@tonic-gate addr = dot;
10900Sstevel@tonic-gate if (readecho(c)) {
10910Sstevel@tonic-gate esave[0] = 0;
10920Sstevel@tonic-gate goto fixup;
10930Sstevel@tonic-gate }
10940Sstevel@tonic-gate getDOT();
10950Sstevel@tonic-gate /*
10960Sstevel@tonic-gate * Use the visual undo buffer to store the global
10970Sstevel@tonic-gate * string for command mode, since it is idle right now.
10980Sstevel@tonic-gate */
10990Sstevel@tonic-gate oglobp = globp; strcpy(vutmp, genbuf+1); globp = vutmp;
11000Sstevel@tonic-gate doinit:
11010Sstevel@tonic-gate esave[0] = 0;
11020Sstevel@tonic-gate fixech();
11030Sstevel@tonic-gate
11040Sstevel@tonic-gate /*
11050Sstevel@tonic-gate * Have to finagle around not to lose last
11060Sstevel@tonic-gate * character after this command (when run from ex
11070Sstevel@tonic-gate * command mode). This is clumsy.
11080Sstevel@tonic-gate */
11090Sstevel@tonic-gate d = peekc; ungetchar(0);
11100Sstevel@tonic-gate if (shouldpo) {
11110Sstevel@tonic-gate /*
11120Sstevel@tonic-gate * So after a "Hit return..." ":", we do
11130Sstevel@tonic-gate * another "Hit return..." the next time
11140Sstevel@tonic-gate */
11150Sstevel@tonic-gate pofix();
11160Sstevel@tonic-gate shouldpo = 0;
11170Sstevel@tonic-gate }
11180Sstevel@tonic-gate CATCH
11190Sstevel@tonic-gate /*
11200Sstevel@tonic-gate * Save old values of options so we can
11210Sstevel@tonic-gate * notice when they change; switch into
11220Sstevel@tonic-gate * cooked mode so we are interruptible.
11230Sstevel@tonic-gate */
11240Sstevel@tonic-gate onumber = value(vi_NUMBER);
11250Sstevel@tonic-gate olist = value(vi_LIST);
11260Sstevel@tonic-gate OPline = Pline;
11270Sstevel@tonic-gate OPutchar = Putchar;
11280Sstevel@tonic-gate #ifndef CBREAK
11290Sstevel@tonic-gate vcook();
11300Sstevel@tonic-gate #endif
11310Sstevel@tonic-gate commands(1, 1);
11320Sstevel@tonic-gate if (dot == zero && dol > zero)
11330Sstevel@tonic-gate dot = one;
11340Sstevel@tonic-gate #ifndef CBREAK
11350Sstevel@tonic-gate vraw();
11360Sstevel@tonic-gate #endif
11370Sstevel@tonic-gate ONERR
11380Sstevel@tonic-gate #ifndef CBREAK
11390Sstevel@tonic-gate vraw();
11400Sstevel@tonic-gate #endif
11410Sstevel@tonic-gate copy(esave, vtube[WECHO], TUBECOLS * sizeof(wchar_t));
11420Sstevel@tonic-gate ENDCATCH
11430Sstevel@tonic-gate fixol();
11440Sstevel@tonic-gate Pline = OPline;
11450Sstevel@tonic-gate Putchar = OPutchar;
11460Sstevel@tonic-gate ungetchar(d);
11470Sstevel@tonic-gate globp = oglobp;
11480Sstevel@tonic-gate
11490Sstevel@tonic-gate /*
11500Sstevel@tonic-gate * If we ended up with no lines in the buffer, make
11510Sstevel@tonic-gate * a line.
11520Sstevel@tonic-gate */
11530Sstevel@tonic-gate if (dot == zero) {
11540Sstevel@tonic-gate fixzero();
11550Sstevel@tonic-gate }
11560Sstevel@tonic-gate splitw = 0;
11570Sstevel@tonic-gate
11580Sstevel@tonic-gate /*
11590Sstevel@tonic-gate * Special case: did list/number options change?
11600Sstevel@tonic-gate */
11610Sstevel@tonic-gate if (onumber != value(vi_NUMBER))
11620Sstevel@tonic-gate setnumb(value(vi_NUMBER));
11630Sstevel@tonic-gate if (olist != value(vi_LIST))
11640Sstevel@tonic-gate setlist(value(vi_LIST));
11650Sstevel@tonic-gate
11660Sstevel@tonic-gate fixup:
11670Sstevel@tonic-gate /*
11680Sstevel@tonic-gate * If a change occurred, other than
11690Sstevel@tonic-gate * a write which clears changes, then
11700Sstevel@tonic-gate * we should allow an undo even if .
11710Sstevel@tonic-gate * didn't move.
11720Sstevel@tonic-gate *
11730Sstevel@tonic-gate * BUG: You can make this wrong by
11740Sstevel@tonic-gate * tricking around with multiple commands
11750Sstevel@tonic-gate * on one line of : escape, and including
11760Sstevel@tonic-gate * a write command there, but it's not
11770Sstevel@tonic-gate * worth worrying about.
11780Sstevel@tonic-gate */
11790Sstevel@tonic-gate if (FIXUNDO && tchng && tchng != i)
11800Sstevel@tonic-gate vundkind = VMANY, cursor = 0;
11810Sstevel@tonic-gate
11820Sstevel@tonic-gate /*
11830Sstevel@tonic-gate * If we are about to do another :, hold off
11840Sstevel@tonic-gate * updating of screen.
11850Sstevel@tonic-gate */
11860Sstevel@tonic-gate if (vcnt < 0 && Peekkey == ':') {
11870Sstevel@tonic-gate getDOT();
11880Sstevel@tonic-gate shouldpo = 1;
11890Sstevel@tonic-gate continue;
11900Sstevel@tonic-gate }
11910Sstevel@tonic-gate shouldpo = 0;
11920Sstevel@tonic-gate
11930Sstevel@tonic-gate /*
11940Sstevel@tonic-gate * In the case where the file being edited is
11950Sstevel@tonic-gate * new; e.g. if the initial state hasn't been
11960Sstevel@tonic-gate * saved yet, then do so now.
11970Sstevel@tonic-gate */
11980Sstevel@tonic-gate if (unddol == truedol) {
11990Sstevel@tonic-gate vundkind = VNONE;
12000Sstevel@tonic-gate Vlines = lineDOL();
12010Sstevel@tonic-gate if (!inglobal)
12020Sstevel@tonic-gate savevis();
12030Sstevel@tonic-gate addr = zero;
12040Sstevel@tonic-gate vcnt = 0;
12050Sstevel@tonic-gate if (esave[0] == 0)
12060Sstevel@tonic-gate copy(esave, vtube[WECHO], TUBECOLS * sizeof(wchar_t));
12070Sstevel@tonic-gate }
12080Sstevel@tonic-gate
12090Sstevel@tonic-gate /*
12100Sstevel@tonic-gate * If the current line moved reset the cursor position.
12110Sstevel@tonic-gate */
12120Sstevel@tonic-gate if (dot != addr) {
12130Sstevel@tonic-gate vmoving = 0;
12140Sstevel@tonic-gate cursor = 0;
12150Sstevel@tonic-gate }
12160Sstevel@tonic-gate
12170Sstevel@tonic-gate /*
12180Sstevel@tonic-gate * If current line is not on screen or if we are
12190Sstevel@tonic-gate * in open mode and . moved, then redraw.
12200Sstevel@tonic-gate */
12210Sstevel@tonic-gate i = vcline + (dot - addr);
12220Sstevel@tonic-gate if(windowchg)
12230Sstevel@tonic-gate windowinit();
12240Sstevel@tonic-gate if (i < 0 || i >= vcnt && i >= -vcnt || state != VISUAL && dot != addr) {
12250Sstevel@tonic-gate if (state == CRTOPEN)
12260Sstevel@tonic-gate vup1();
12270Sstevel@tonic-gate if (vcnt > 0)
12280Sstevel@tonic-gate vcnt = 0;
1229802Scf46844 vjumpto(dot, (unsigned char *) 0, '.');
12300Sstevel@tonic-gate } else {
12310Sstevel@tonic-gate /*
12320Sstevel@tonic-gate * Current line IS on screen.
12330Sstevel@tonic-gate * If we did a [Hit return...] then
12340Sstevel@tonic-gate * restore vcnt and clear screen if in visual
12350Sstevel@tonic-gate */
12360Sstevel@tonic-gate vcline = i;
12370Sstevel@tonic-gate if (vcnt < 0) {
12380Sstevel@tonic-gate vcnt = -vcnt;
12390Sstevel@tonic-gate if (state == VISUAL)
12400Sstevel@tonic-gate vclear();
12410Sstevel@tonic-gate else if (state == CRTOPEN) {
12420Sstevel@tonic-gate vcnt = 0;
12430Sstevel@tonic-gate }
12440Sstevel@tonic-gate }
12450Sstevel@tonic-gate
12460Sstevel@tonic-gate /*
12470Sstevel@tonic-gate * Limit max value of vcnt based on $
12480Sstevel@tonic-gate */
12490Sstevel@tonic-gate i = vcline + lineDOL() - lineDOT() + 1;
12500Sstevel@tonic-gate if (i < vcnt)
12510Sstevel@tonic-gate vcnt = i;
12520Sstevel@tonic-gate
12530Sstevel@tonic-gate /*
12540Sstevel@tonic-gate * Dirty and repaint.
12550Sstevel@tonic-gate */
12560Sstevel@tonic-gate vdirty(0, lines);
12570Sstevel@tonic-gate vrepaint(cursor);
12580Sstevel@tonic-gate }
12590Sstevel@tonic-gate
12600Sstevel@tonic-gate /*
12610Sstevel@tonic-gate * If in visual, put back the echo area
12620Sstevel@tonic-gate * if it was clobbered.
12630Sstevel@tonic-gate */
12640Sstevel@tonic-gate if (state == VISUAL) {
12650Sstevel@tonic-gate int sdc = destcol, sdl = destline;
12660Sstevel@tonic-gate
12670Sstevel@tonic-gate splitw++;
12680Sstevel@tonic-gate vigoto(WECHO, 0);
12690Sstevel@tonic-gate for (i = 0; i < TUBECOLS - 1; i++) {
12700Sstevel@tonic-gate if (esave[i] == 0)
12710Sstevel@tonic-gate break;
12720Sstevel@tonic-gate if(esave[i] != FILLER)
1273802Scf46844 (void) vputchar(esave[i]);
12740Sstevel@tonic-gate }
12750Sstevel@tonic-gate splitw = 0;
12760Sstevel@tonic-gate vgoto(sdl, sdc);
12770Sstevel@tonic-gate }
12780Sstevel@tonic-gate if (tag_reset_wrap == 1) {
12790Sstevel@tonic-gate tag_reset_wrap = 0;
12800Sstevel@tonic-gate value(vi_WRAPSCAN) = 0;
12810Sstevel@tonic-gate }
12820Sstevel@tonic-gate continue;
12830Sstevel@tonic-gate
12840Sstevel@tonic-gate /*
12850Sstevel@tonic-gate * u undo the last changing command.
12860Sstevel@tonic-gate */
12870Sstevel@tonic-gate case 'u':
12880Sstevel@tonic-gate vundo(1);
12890Sstevel@tonic-gate continue;
12900Sstevel@tonic-gate
12910Sstevel@tonic-gate /*
12920Sstevel@tonic-gate * U restore current line to initial state.
12930Sstevel@tonic-gate */
12940Sstevel@tonic-gate case 'U':
12950Sstevel@tonic-gate vUndo();
12960Sstevel@tonic-gate continue;
12970Sstevel@tonic-gate
12980Sstevel@tonic-gate fonfon:
1299802Scf46844 (void) beep();
13000Sstevel@tonic-gate vmacp = 0;
13010Sstevel@tonic-gate inopen = 1; /* might have been -1 */
13020Sstevel@tonic-gate continue;
13030Sstevel@tonic-gate }
13040Sstevel@tonic-gate
13050Sstevel@tonic-gate /*
13060Sstevel@tonic-gate * Rest of commands are decoded by the operate
13070Sstevel@tonic-gate * routine.
13080Sstevel@tonic-gate */
13090Sstevel@tonic-gate operate(c, cnt);
13100Sstevel@tonic-gate }
13110Sstevel@tonic-gate }
13120Sstevel@tonic-gate
13130Sstevel@tonic-gate /*
13140Sstevel@tonic-gate * Grab the word after the cursor so we can look for it as a tag.
13150Sstevel@tonic-gate */
1316802Scf46844 void
1317802Scf46844 grabtag(void)
13180Sstevel@tonic-gate {
1319802Scf46844 unsigned char *cp, *dp;
13200Sstevel@tonic-gate
13210Sstevel@tonic-gate cp = vpastwh(cursor);
13220Sstevel@tonic-gate if (*cp) {
13230Sstevel@tonic-gate dp = lasttag;
13240Sstevel@tonic-gate do {
13250Sstevel@tonic-gate if (dp < &lasttag[sizeof lasttag - 2])
13260Sstevel@tonic-gate *dp++ = *cp;
13270Sstevel@tonic-gate cp++;
13280Sstevel@tonic-gate /* only allow ascii alphabetics */
13290Sstevel@tonic-gate } while ((isascii(*cp) && isalpha(*cp)) || isdigit(*cp) || *cp == '_');
13300Sstevel@tonic-gate *dp++ = 0;
13310Sstevel@tonic-gate }
13320Sstevel@tonic-gate }
13330Sstevel@tonic-gate
13340Sstevel@tonic-gate /*
13350Sstevel@tonic-gate * Before appending lines, set up addr1 and
13360Sstevel@tonic-gate * the command mode undo information.
13370Sstevel@tonic-gate */
1338802Scf46844 void
1339802Scf46844 prepapp(void)
13400Sstevel@tonic-gate {
13410Sstevel@tonic-gate
13420Sstevel@tonic-gate addr1 = dot;
13430Sstevel@tonic-gate deletenone();
13440Sstevel@tonic-gate addr1++;
13450Sstevel@tonic-gate appendnone();
13460Sstevel@tonic-gate }
13470Sstevel@tonic-gate
13480Sstevel@tonic-gate /*
13490Sstevel@tonic-gate * Execute function f with the address bounds addr1
13500Sstevel@tonic-gate * and addr2 surrounding cnt lines starting at dot.
13510Sstevel@tonic-gate */
1352802Scf46844 void
13530Sstevel@tonic-gate vremote(cnt, f, arg)
13540Sstevel@tonic-gate int cnt, (*f)(), arg;
13550Sstevel@tonic-gate {
1356802Scf46844 int oing = inglobal;
13570Sstevel@tonic-gate
13580Sstevel@tonic-gate addr1 = dot;
13590Sstevel@tonic-gate addr2 = dot + cnt - 1;
13600Sstevel@tonic-gate inglobal = 0;
13610Sstevel@tonic-gate if (FIXUNDO)
13620Sstevel@tonic-gate undap1 = undap2 = dot;
13630Sstevel@tonic-gate (*f)(arg);
13640Sstevel@tonic-gate inglobal = oing;
13650Sstevel@tonic-gate if (FIXUNDO)
13660Sstevel@tonic-gate vundkind = VMANY;
1367*3806Scf46844 /*
1368*3806Scf46844 * XPG6 assertion 273: For the following commands, don't set vmcurs
1369*3806Scf46844 * to 0, so that undo positions the cursor column correctly when
1370*3806Scf46844 * we've moved off the initial line that was changed eg. when G has
1371*3806Scf46844 * moved us off the line, or when a multi-line change was done.
1372*3806Scf46844 */
1373*3806Scf46844 if (lastcmd[0] != 'C' && lastcmd[0] != 'c' && lastcmd[0] != 'o' &&
1374*3806Scf46844 lastcmd[0] != 'R' && lastcmd[0] != 'S' && lastcmd[0] != 's' &&
1375*3806Scf46844 lastcmd[0] != 'i' && lastcmd[0] != 'a' && lastcmd[0] != 'A') {
1376*3806Scf46844 vmcurs = 0;
1377*3806Scf46844 }
13780Sstevel@tonic-gate }
13790Sstevel@tonic-gate
13800Sstevel@tonic-gate /*
13810Sstevel@tonic-gate * Save the current contents of linebuf, if it has changed.
13820Sstevel@tonic-gate */
1383802Scf46844 void
1384802Scf46844 vsave(void)
13850Sstevel@tonic-gate {
13860Sstevel@tonic-gate unsigned char temp[LBSIZE];
13870Sstevel@tonic-gate
13880Sstevel@tonic-gate strncpy(temp, linebuf, sizeof (temp));
13890Sstevel@tonic-gate if (FIXUNDO && vundkind == VCHNG || vundkind == VCAPU) {
13900Sstevel@tonic-gate /*
13910Sstevel@tonic-gate * If the undo state is saved in the temporary buffer
13920Sstevel@tonic-gate * vutmp, then we sync this into the temp file so that
13930Sstevel@tonic-gate * we will be able to undo even after we have moved off
13940Sstevel@tonic-gate * the line. It would be possible to associate a line
13950Sstevel@tonic-gate * with vutmp but we assume that vutmp is only associated
13960Sstevel@tonic-gate * with line dot (e.g. in case ':') above, so beware.
13970Sstevel@tonic-gate */
13980Sstevel@tonic-gate prepapp();
13990Sstevel@tonic-gate strcLIN(vutmp);
14000Sstevel@tonic-gate putmark(dot);
14010Sstevel@tonic-gate vremote(1, yank, 0);
14020Sstevel@tonic-gate vundkind = VMCHNG;
14030Sstevel@tonic-gate notecnt = 0;
14040Sstevel@tonic-gate undkind = UNDCHANGE;
14050Sstevel@tonic-gate }
14060Sstevel@tonic-gate /*
14070Sstevel@tonic-gate * Get the line out of the temp file and do nothing if it hasn't
14080Sstevel@tonic-gate * changed. This may seem like a loss, but the line will
14090Sstevel@tonic-gate * almost always be in a read buffer so this may well avoid disk i/o.
14100Sstevel@tonic-gate */
14110Sstevel@tonic-gate getDOT();
14120Sstevel@tonic-gate if (strncmp(linebuf, temp, sizeof (temp)) == 0)
14130Sstevel@tonic-gate return;
14140Sstevel@tonic-gate strcLIN(temp);
14150Sstevel@tonic-gate putmark(dot);
14160Sstevel@tonic-gate }
14170Sstevel@tonic-gate
14180Sstevel@tonic-gate #undef forbid
1419802Scf46844 #define forbid(a) if (a) { (void) beep(); return; }
14200Sstevel@tonic-gate
14210Sstevel@tonic-gate /*
14220Sstevel@tonic-gate * Do a z operation.
14230Sstevel@tonic-gate * Code here is rather long, and very uninteresting.
14240Sstevel@tonic-gate */
1425802Scf46844 void
1426802Scf46844 vzop(bool hadcnt, int cnt, int c)
14270Sstevel@tonic-gate {
1428802Scf46844 line *addr;
14290Sstevel@tonic-gate
14300Sstevel@tonic-gate if (state != VISUAL) {
14310Sstevel@tonic-gate /*
14320Sstevel@tonic-gate * Z from open; always like a z=.
14330Sstevel@tonic-gate * This code is a mess and should be cleaned up.
14340Sstevel@tonic-gate */
14350Sstevel@tonic-gate vmoveitup(1, 1);
14360Sstevel@tonic-gate vgoto(outline, 0);
14370Sstevel@tonic-gate ostop(normf);
14380Sstevel@tonic-gate setoutt();
14390Sstevel@tonic-gate addr2 = dot;
14400Sstevel@tonic-gate vclear();
14410Sstevel@tonic-gate destline = WECHO;
14420Sstevel@tonic-gate zop2(Xhadcnt ? Xcnt : value(vi_WINDOW) - 1, '=');
14430Sstevel@tonic-gate if (state == CRTOPEN)
14440Sstevel@tonic-gate putnl();
14450Sstevel@tonic-gate putNFL();
14460Sstevel@tonic-gate termreset();
14470Sstevel@tonic-gate Outchar = vputchar;
14480Sstevel@tonic-gate (void)ostart();
14490Sstevel@tonic-gate vcnt = 0;
14500Sstevel@tonic-gate outline = destline = 0;
14510Sstevel@tonic-gate vjumpto(dot, cursor, 0);
14520Sstevel@tonic-gate return;
14530Sstevel@tonic-gate }
14540Sstevel@tonic-gate if (hadcnt) {
14550Sstevel@tonic-gate addr = zero + cnt;
14560Sstevel@tonic-gate if (addr < one)
14570Sstevel@tonic-gate addr = one;
14580Sstevel@tonic-gate if (addr > dol)
14590Sstevel@tonic-gate addr = dol;
14600Sstevel@tonic-gate markit(addr);
14610Sstevel@tonic-gate } else
14620Sstevel@tonic-gate switch (c) {
14630Sstevel@tonic-gate
14640Sstevel@tonic-gate case '+':
14650Sstevel@tonic-gate addr = dot + vcnt - vcline;
14660Sstevel@tonic-gate break;
14670Sstevel@tonic-gate
14680Sstevel@tonic-gate case '^':
14690Sstevel@tonic-gate addr = dot - vcline - 1;
14700Sstevel@tonic-gate forbid (addr < one);
14710Sstevel@tonic-gate c = '-';
14720Sstevel@tonic-gate break;
14730Sstevel@tonic-gate
14740Sstevel@tonic-gate default:
14750Sstevel@tonic-gate addr = dot;
14760Sstevel@tonic-gate break;
14770Sstevel@tonic-gate }
14780Sstevel@tonic-gate switch (c) {
14790Sstevel@tonic-gate
14800Sstevel@tonic-gate case '.':
14810Sstevel@tonic-gate case '-':
14820Sstevel@tonic-gate break;
14830Sstevel@tonic-gate
14840Sstevel@tonic-gate case '^':
14850Sstevel@tonic-gate forbid (addr <= one);
14860Sstevel@tonic-gate break;
14870Sstevel@tonic-gate
14880Sstevel@tonic-gate case '+':
14890Sstevel@tonic-gate forbid (addr >= dol);
14900Sstevel@tonic-gate /* fall into ... */
14910Sstevel@tonic-gate
14920Sstevel@tonic-gate case CR:
14930Sstevel@tonic-gate case NL:
14940Sstevel@tonic-gate c = CR;
14950Sstevel@tonic-gate break;
14960Sstevel@tonic-gate
14970Sstevel@tonic-gate default:
1498802Scf46844 (void) beep();
14990Sstevel@tonic-gate return;
15000Sstevel@tonic-gate }
15010Sstevel@tonic-gate vmoving = 0;
1502802Scf46844 vjumpto(addr, (unsigned char *)NOSTR, c);
15030Sstevel@tonic-gate }
1504