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