xref: /illumos-gate/usr/src/contrib/ast/src/cmd/ksh93/edit/vi.c (revision b30d1939)
1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin *                                                                      *
3da2e3ebdSchin *               This software is part of the ast package               *
4*b30d1939SAndy Fiddaman *          Copyright (c) 1982-2012 AT&T Intellectual Property          *
5da2e3ebdSchin *                      and is licensed under the                       *
6*b30d1939SAndy Fiddaman *                 Eclipse Public License, Version 1.0                  *
77c2fbfb3SApril Chin *                    by AT&T Intellectual Property                     *
8da2e3ebdSchin *                                                                      *
9da2e3ebdSchin *                A copy of the License is available at                 *
10*b30d1939SAndy Fiddaman *          http://www.eclipse.org/org/documents/epl-v10.html           *
11*b30d1939SAndy Fiddaman *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12da2e3ebdSchin *                                                                      *
13da2e3ebdSchin *              Information and Software Systems Research               *
14da2e3ebdSchin *                            AT&T Research                             *
15da2e3ebdSchin *                           Florham Park NJ                            *
16da2e3ebdSchin *                                                                      *
17da2e3ebdSchin *                  David Korn <dgk@research.att.com>                   *
18da2e3ebdSchin *                                                                      *
19da2e3ebdSchin ***********************************************************************/
20da2e3ebdSchin #pragma prototyped
21da2e3ebdSchin /* Adapted for ksh by David Korn */
22da2e3ebdSchin /*+	VI.C			P.D. Sullivan
23da2e3ebdSchin  *
24da2e3ebdSchin  *	One line editor for the shell based on the vi editor.
25da2e3ebdSchin  *
26da2e3ebdSchin  *	Questions to:
27da2e3ebdSchin  *		P.D. Sullivan
28da2e3ebdSchin  *		cbosgd!pds
29da2e3ebdSchin -*/
30da2e3ebdSchin 
31da2e3ebdSchin 
32da2e3ebdSchin #if KSHELL
33da2e3ebdSchin #   include	"defs.h"
34da2e3ebdSchin #else
35da2e3ebdSchin #   include	<ast.h>
36da2e3ebdSchin #   include	"FEATURE/options"
3734f9b3eeSRoland Mainz #   include	<ctype.h>
38da2e3ebdSchin #endif	/* KSHELL */
39da2e3ebdSchin #include	"io.h"
40da2e3ebdSchin 
41da2e3ebdSchin #include	"history.h"
42da2e3ebdSchin #include	"edit.h"
43da2e3ebdSchin #include	"terminal.h"
44da2e3ebdSchin #include	"FEATURE/time"
45da2e3ebdSchin 
46*b30d1939SAndy Fiddaman #ifdef ECHOCTL
47*b30d1939SAndy Fiddaman #   define echoctl	ECHOCTL
48da2e3ebdSchin #else
49*b30d1939SAndy Fiddaman #   define echoctl	0
50*b30d1939SAndy Fiddaman #endif /* ECHOCTL */
51da2e3ebdSchin 
52da2e3ebdSchin #ifndef FIORDCHK
53da2e3ebdSchin #   define NTICKS	5		/* number of ticks for typeahead */
54da2e3ebdSchin #endif /* FIORDCHK */
55da2e3ebdSchin 
56da2e3ebdSchin #define	MAXCHAR	MAXLINE-2		/* max char per line */
57da2e3ebdSchin 
58da2e3ebdSchin #if SHOPT_MULTIBYTE
59da2e3ebdSchin #   include	"lexstates.h"
60da2e3ebdSchin #   define gencpy(a,b)	ed_gencpy(a,b)
61da2e3ebdSchin #   define genncpy(a,b,n)	ed_genncpy(a,b,n)
62da2e3ebdSchin #   define genlen(str)	ed_genlen(str)
63da2e3ebdSchin #   define digit(c)	((c&~STRIP)==0 && isdigit(c))
64da2e3ebdSchin #   define is_print(c)	((c&~STRIP) || isprint(c))
65da2e3ebdSchin #   if !_lib_iswprint && !defined(iswprint)
66da2e3ebdSchin #	define iswprint(c)	((c&~0177) || isprint(c))
67da2e3ebdSchin #   endif
68da2e3ebdSchin     static int _isalph(int);
69da2e3ebdSchin     static int _ismetach(int);
70da2e3ebdSchin     static int _isblank(int);
71da2e3ebdSchin #   undef  isblank
72da2e3ebdSchin #   define isblank(v)	_isblank(virtual[v])
73da2e3ebdSchin #   define isalph(v)	_isalph(virtual[v])
74da2e3ebdSchin #   define ismetach(v)	_ismetach(virtual[v])
75da2e3ebdSchin #else
76da2e3ebdSchin     static genchar	_c;
77da2e3ebdSchin #   define gencpy(a,b)	strcpy((char*)(a),(char*)(b))
78da2e3ebdSchin #   define genncpy(a,b,n) strncpy((char*)(a),(char*)(b),n)
79da2e3ebdSchin #   define genlen(str)	strlen(str)
80da2e3ebdSchin #   define isalph(v)	((_c=virtual[v])=='_'||isalnum(_c))
81da2e3ebdSchin #   undef  isblank
82da2e3ebdSchin #   define isblank(v)	isspace(virtual[v])
83da2e3ebdSchin #   define ismetach(v)	ismeta(virtual[v])
84da2e3ebdSchin #   define digit(c)	isdigit(c)
85da2e3ebdSchin #   define is_print(c)	isprint(c)
86da2e3ebdSchin #endif	/* SHOPT_MULTIBYTE */
87da2e3ebdSchin 
88da2e3ebdSchin #if ( 'a' == 97) /* ASCII? */
89da2e3ebdSchin #   define fold(c)	((c)&~040)	/* lower and uppercase equivalent */
90da2e3ebdSchin #else
91da2e3ebdSchin #   define fold(c)	((c)|0100)	/* lower and uppercase equivalent */
92da2e3ebdSchin #endif
93da2e3ebdSchin 
94da2e3ebdSchin #ifndef iswascii
95da2e3ebdSchin #define iswascii(c)	(!((c)&(~0177)))
96da2e3ebdSchin #endif
97da2e3ebdSchin 
98da2e3ebdSchin typedef struct _vi_
99da2e3ebdSchin {
100da2e3ebdSchin 	int direction;
101da2e3ebdSchin 	int lastmacro;
102da2e3ebdSchin 	char addnl;		/* boolean - add newline flag */
103da2e3ebdSchin 	char last_find;		/* last find command */
104da2e3ebdSchin 	char last_cmd;		/* last command */
105da2e3ebdSchin 	char repeat_set;
106da2e3ebdSchin 	char nonewline;
107da2e3ebdSchin 	int findchar;		/* last find char */
108da2e3ebdSchin 	genchar *lastline;
109da2e3ebdSchin 	int first_wind;		/* first column of window */
110da2e3ebdSchin 	int last_wind;		/* last column in window */
111da2e3ebdSchin 	int lastmotion;		/* last motion */
112da2e3ebdSchin 	int long_char; 		/* line bigger than window */
113da2e3ebdSchin 	int long_line;		/* line bigger than window */
114da2e3ebdSchin 	int ocur_phys;		/* old current physical position */
115da2e3ebdSchin 	int ocur_virt;		/* old last virtual position */
116da2e3ebdSchin 	int ofirst_wind;	/* old window first col */
117da2e3ebdSchin 	int o_v_char;		/* prev virtual[ocur_virt] */
118da2e3ebdSchin 	int repeat;		/* repeat count for motion cmds */
119da2e3ebdSchin 	int lastrepeat;		/* last repeat count for motion cmds */
120da2e3ebdSchin 	int u_column;		/* undo current column */
121da2e3ebdSchin 	int U_saved;		/* original virtual saved */
122da2e3ebdSchin 	genchar *U_space;	/* used for U command */
123da2e3ebdSchin 	genchar *u_space;	/* used for u command */
124da2e3ebdSchin #ifdef FIORDCHK
125da2e3ebdSchin 	clock_t typeahead;	/* typeahead occurred */
126da2e3ebdSchin #else
127da2e3ebdSchin 	int typeahead;		/* typeahead occurred */
128da2e3ebdSchin #endif	/* FIORDCHK */
129da2e3ebdSchin #if SHOPT_MULTIBYTE
130da2e3ebdSchin 	int bigvi;
131da2e3ebdSchin #endif
132da2e3ebdSchin 	Edit_t	*ed;		/* pointer to edit data */
133da2e3ebdSchin } Vi_t;
134da2e3ebdSchin 
135da2e3ebdSchin #define editb	(*vp->ed)
136da2e3ebdSchin 
137da2e3ebdSchin #undef putchar
138da2e3ebdSchin #define putchar(c)	ed_putchar(vp->ed,c)
139da2e3ebdSchin 
140da2e3ebdSchin #define crallowed	editb.e_crlf
141da2e3ebdSchin #define cur_virt	editb.e_cur		/* current virtual column */
142da2e3ebdSchin #define cur_phys	editb.e_pcur	/* current phys column cursor is at */
143da2e3ebdSchin #define curhline	editb.e_hline		/* current history line */
144da2e3ebdSchin #define first_virt	editb.e_fcol		/* first allowable column */
145da2e3ebdSchin #define	globals		editb.e_globals		/* local global variables */
146da2e3ebdSchin #define histmin		editb.e_hismin
147da2e3ebdSchin #define histmax		editb.e_hismax
148da2e3ebdSchin #define last_phys	editb.e_peol		/* last column in physical */
149da2e3ebdSchin #define last_virt	editb.e_eol		/* last column */
150da2e3ebdSchin #define lsearch		editb.e_search		/* last search string */
151da2e3ebdSchin #define lookahead	editb.e_lookahead	/* characters in buffer */
152da2e3ebdSchin #define previous	editb.e_lbuf		/* lookahead buffer */
153da2e3ebdSchin #define max_col		editb.e_llimit		/* maximum column */
154da2e3ebdSchin #define Prompt		editb.e_prompt		/* pointer to prompt */
155da2e3ebdSchin #define plen		editb.e_plen		/* length of prompt */
156da2e3ebdSchin #define physical	editb.e_physbuf		/* physical image */
157da2e3ebdSchin #define usreof		editb.e_eof		/* user defined eof char */
158da2e3ebdSchin #define usrerase	editb.e_erase		/* user defined erase char */
159da2e3ebdSchin #define usrlnext	editb.e_lnext		/* user defined next literal */
160da2e3ebdSchin #define usrkill		editb.e_kill		/* user defined kill char */
161da2e3ebdSchin #define virtual		editb.e_inbuf	/* pointer to virtual image buffer */
162da2e3ebdSchin #define	window		editb.e_window		/* window buffer */
163da2e3ebdSchin #define	w_size		editb.e_wsize		/* window size */
164da2e3ebdSchin #define	inmacro		editb.e_inmacro		/* true when in macro */
165da2e3ebdSchin #define yankbuf		editb.e_killbuf		/* yank/delete buffer */
166da2e3ebdSchin 
167da2e3ebdSchin 
168da2e3ebdSchin #define	ABORT	-2			/* user abort */
169da2e3ebdSchin #define	APPEND	-10			/* append chars */
170da2e3ebdSchin #define	BAD	-1			/* failure flag */
171da2e3ebdSchin #define	BIGVI	-15			/* user wants real vi */
172da2e3ebdSchin #define	CONTROL	-20			/* control mode */
173da2e3ebdSchin #define	ENTER	-25			/* enter flag */
174da2e3ebdSchin #define	GOOD	0			/* success flag */
175da2e3ebdSchin #define	INPUT	-30			/* input mode */
176da2e3ebdSchin #define	INSERT	-35			/* insert mode */
177da2e3ebdSchin #define	REPLACE	-40			/* replace chars */
178da2e3ebdSchin #define	SEARCH	-45			/* search flag */
179da2e3ebdSchin #define	TRANSLATE	-50		/* translate virt to phys only */
180da2e3ebdSchin 
181da2e3ebdSchin #define	INVALID	(-1)			/* invalid column */
182da2e3ebdSchin 
183da2e3ebdSchin static const char paren_chars[] = "([{)]}";   /* for % command */
184da2e3ebdSchin 
185da2e3ebdSchin static void	cursor(Vi_t*, int);
186da2e3ebdSchin static void	del_line(Vi_t*,int);
187da2e3ebdSchin static int	getcount(Vi_t*,int);
188da2e3ebdSchin static void	getline(Vi_t*,int);
189da2e3ebdSchin static int	getrchar(Vi_t*);
190da2e3ebdSchin static int	mvcursor(Vi_t*,int);
191da2e3ebdSchin static void	pr_string(Vi_t*,const char*);
192da2e3ebdSchin static void	putstring(Vi_t*,int, int);
193da2e3ebdSchin static void	refresh(Vi_t*,int);
194da2e3ebdSchin static void	replace(Vi_t*,int, int);
195da2e3ebdSchin static void	restore_v(Vi_t*);
196da2e3ebdSchin static void	save_last(Vi_t*);
197da2e3ebdSchin static void	save_v(Vi_t*);
198da2e3ebdSchin static int	search(Vi_t*,int);
199da2e3ebdSchin static void	sync_cursor(Vi_t*);
200da2e3ebdSchin static int	textmod(Vi_t*,int,int);
201da2e3ebdSchin 
202da2e3ebdSchin /*+	VI_READ( fd, shbuf, nchar )
203da2e3ebdSchin  *
204da2e3ebdSchin  *	This routine implements a one line version of vi and is
205da2e3ebdSchin  * called by _filbuf.c
206da2e3ebdSchin  *
207da2e3ebdSchin -*/
208da2e3ebdSchin 
209da2e3ebdSchin /*
210da2e3ebdSchin  * if reedit is non-zero, initialize edit buffer with reedit chars
211da2e3ebdSchin  */
ed_viread(void * context,int fd,register char * shbuf,int nchar,int reedit)212da2e3ebdSchin int ed_viread(void *context, int fd, register char *shbuf, int nchar, int reedit)
213da2e3ebdSchin {
214da2e3ebdSchin 	Edit_t *ed = (Edit_t*)context;
215da2e3ebdSchin 	register int i;			/* general variable */
216*b30d1939SAndy Fiddaman 	register int term_char=0;	/* read() termination character */
217da2e3ebdSchin 	register Vi_t *vp = ed->e_vi;
218da2e3ebdSchin 	char prompt[PRSIZE+2];		/* prompt */
219da2e3ebdSchin 	genchar Physical[2*MAXLINE];	/* physical image */
220da2e3ebdSchin 	genchar Ubuf[MAXLINE];	/* used for U command */
221da2e3ebdSchin 	genchar ubuf[MAXLINE];	/* used for u command */
222da2e3ebdSchin 	genchar Window[MAXLINE];	/* window image */
223da2e3ebdSchin 	int Globals[9];			/* local global variables */
224da2e3ebdSchin 	int esc_or_hang=0;		/* <ESC> or hangup */
225da2e3ebdSchin 	char cntl_char=0;		/* TRUE if control character present */
226da2e3ebdSchin #if SHOPT_RAWONLY
227da2e3ebdSchin #   define viraw	1
228da2e3ebdSchin #else
229*b30d1939SAndy Fiddaman 	int viraw = (sh_isoption(SH_VIRAW) || ed->sh->st.trap[SH_KEYTRAP]);
230da2e3ebdSchin #   ifndef FIORDCHK
231da2e3ebdSchin 	clock_t oldtime, newtime;
232da2e3ebdSchin 	struct tms dummy;
233da2e3ebdSchin #   endif /* FIORDCHK */
234da2e3ebdSchin #endif /* SHOPT_RAWONLY */
235da2e3ebdSchin 	if(!vp)
236da2e3ebdSchin 	{
237da2e3ebdSchin 		ed->e_vi = vp =  newof(0,Vi_t,1,0);
238da2e3ebdSchin 		vp->lastline = (genchar*)malloc(MAXLINE*CHARSIZE);
239da2e3ebdSchin 		vp->direction = -1;
240da2e3ebdSchin 		vp->ed = ed;
241da2e3ebdSchin 	}
242da2e3ebdSchin 
243da2e3ebdSchin 	/*** setup prompt ***/
244da2e3ebdSchin 
245da2e3ebdSchin 	Prompt = prompt;
246da2e3ebdSchin 	ed_setup(vp->ed,fd, reedit);
247da2e3ebdSchin 	shbuf[reedit] = 0;
248da2e3ebdSchin 
249da2e3ebdSchin #if !SHOPT_RAWONLY
250da2e3ebdSchin 	if(!viraw)
251da2e3ebdSchin 	{
252da2e3ebdSchin 		/*** Change the eol characters to '\r' and eof  ***/
253da2e3ebdSchin 		/* in addition to '\n' and make eof an ESC	*/
254da2e3ebdSchin 		if(tty_alt(ERRIO) < 0)
255da2e3ebdSchin 			return(reexit?reedit:ed_read(context, fd, shbuf, nchar,0));
256da2e3ebdSchin 
257da2e3ebdSchin #ifdef FIORDCHK
258da2e3ebdSchin 		ioctl(fd,FIORDCHK,&vp->typeahead);
259da2e3ebdSchin #else
260da2e3ebdSchin 		/* time the current line to determine typeahead */
261da2e3ebdSchin 		oldtime = times(&dummy);
262da2e3ebdSchin #endif /* FIORDCHK */
263da2e3ebdSchin #if KSHELL
264da2e3ebdSchin 		/* abort of interrupt has occurred */
265*b30d1939SAndy Fiddaman 		if(ed->sh->trapnote&SH_SIGSET)
266da2e3ebdSchin 			i = -1;
267da2e3ebdSchin 		else
268da2e3ebdSchin #endif /* KSHELL */
269da2e3ebdSchin 		/*** Read the line ***/
270da2e3ebdSchin 		i = ed_read(context, fd, shbuf, nchar, 0);
271da2e3ebdSchin #ifndef FIORDCHK
272da2e3ebdSchin 		newtime = times(&dummy);
273da2e3ebdSchin 		vp->typeahead = ((newtime-oldtime) < NTICKS);
274da2e3ebdSchin #endif /* FIORDCHK */
275da2e3ebdSchin 	    if(echoctl)
276da2e3ebdSchin 	    {
277da2e3ebdSchin 		if( i <= 0 )
278da2e3ebdSchin 		{
279da2e3ebdSchin 			/*** read error or eof typed ***/
280da2e3ebdSchin 			tty_cooked(ERRIO);
281da2e3ebdSchin 			return(i);
282da2e3ebdSchin 		}
283da2e3ebdSchin 		term_char = shbuf[--i];
284da2e3ebdSchin 		if( term_char == '\r' )
285da2e3ebdSchin 			term_char = '\n';
286da2e3ebdSchin 		if( term_char=='\n' || term_char==ESC )
287da2e3ebdSchin 			shbuf[i--] = '\0';
288da2e3ebdSchin 		else
289da2e3ebdSchin 			shbuf[i+1] = '\0';
290da2e3ebdSchin 	    }
291da2e3ebdSchin 	    else
292da2e3ebdSchin 	    {
293da2e3ebdSchin 		register int c = shbuf[0];
294da2e3ebdSchin 
295da2e3ebdSchin 		/*** Save and remove the last character if its an eol, ***/
296da2e3ebdSchin 		/* changing '\r' to '\n' */
297da2e3ebdSchin 
298da2e3ebdSchin 		if( i == 0 )
299da2e3ebdSchin 		{
300da2e3ebdSchin 			/*** ESC was typed as first char of line ***/
301da2e3ebdSchin 			esc_or_hang = 1;
302da2e3ebdSchin 			term_char = ESC;
303da2e3ebdSchin 			shbuf[i--] = '\0';	/* null terminate line */
304da2e3ebdSchin 		}
305da2e3ebdSchin 		else if( i<0 || c==usreof )
306da2e3ebdSchin 		{
307da2e3ebdSchin 			/*** read error or eof typed ***/
308da2e3ebdSchin 			tty_cooked(ERRIO);
309da2e3ebdSchin 			if( c == usreof )
310da2e3ebdSchin 				i = 0;
311da2e3ebdSchin 			return(i);
312da2e3ebdSchin 		}
313da2e3ebdSchin 		else
314da2e3ebdSchin 		{
315da2e3ebdSchin 			term_char = shbuf[--i];
316da2e3ebdSchin 			if( term_char == '\r' )
317da2e3ebdSchin 				term_char = '\n';
318da2e3ebdSchin #if !defined(VEOL2) && !defined(ECHOCTL)
319da2e3ebdSchin 			if(term_char=='\n')
320da2e3ebdSchin 			{
321da2e3ebdSchin 				tty_cooked(ERRIO);
322da2e3ebdSchin 				return(i+1);
323da2e3ebdSchin 			}
324da2e3ebdSchin #endif
325da2e3ebdSchin 			if( term_char=='\n' || term_char==usreof )
326da2e3ebdSchin 			{
327da2e3ebdSchin 				/*** remove terminator & null terminate ***/
328da2e3ebdSchin 				shbuf[i--] = '\0';
329da2e3ebdSchin 			}
330da2e3ebdSchin 			else
331da2e3ebdSchin 			{
332da2e3ebdSchin 				/** terminator was ESC, which is not xmitted **/
333da2e3ebdSchin 				term_char = ESC;
334da2e3ebdSchin 				shbuf[i+1] = '\0';
335da2e3ebdSchin 			}
336da2e3ebdSchin 		}
337da2e3ebdSchin 	    }
338da2e3ebdSchin 	}
339da2e3ebdSchin 	else
340da2e3ebdSchin #endif /* SHOPT_RAWONLY */
341da2e3ebdSchin 	{
342da2e3ebdSchin 		/*** Set raw mode ***/
343da2e3ebdSchin 
344da2e3ebdSchin #if !SHOPT_RAWONLY
345da2e3ebdSchin 		if( editb.e_ttyspeed == 0 )
346da2e3ebdSchin 		{
347da2e3ebdSchin 			/*** never did TCGETA, so do it ***/
348da2e3ebdSchin 			/* avoids problem if user does 'sh -o viraw' */
349da2e3ebdSchin 			tty_alt(ERRIO);
350da2e3ebdSchin 		}
351da2e3ebdSchin #endif /* SHOPT_RAWONLY */
352da2e3ebdSchin 		if(tty_raw(ERRIO,0) < 0 )
353da2e3ebdSchin 			return(reedit?reedit:ed_read(context, fd, shbuf, nchar,0));
354da2e3ebdSchin 		i = last_virt-1;
355da2e3ebdSchin 	}
356da2e3ebdSchin 
357da2e3ebdSchin 	/*** Initialize some things ***/
358da2e3ebdSchin 
359da2e3ebdSchin 	virtual = (genchar*)shbuf;
360da2e3ebdSchin #if SHOPT_MULTIBYTE
361da2e3ebdSchin 	virtual = (genchar*)roundof((char*)virtual-(char*)0,sizeof(genchar));
362da2e3ebdSchin 	shbuf[i+1] = 0;
363da2e3ebdSchin 	i = ed_internal(shbuf,virtual)-1;
364da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
365da2e3ebdSchin 	globals = Globals;
366da2e3ebdSchin 	cur_phys = i + 1;
367da2e3ebdSchin 	cur_virt = i;
368da2e3ebdSchin 	first_virt = 0;
369da2e3ebdSchin 	vp->first_wind = 0;
370da2e3ebdSchin 	last_virt = i;
371da2e3ebdSchin 	last_phys = i;
372da2e3ebdSchin 	vp->last_wind = i;
373da2e3ebdSchin 	vp->long_line = ' ';
374da2e3ebdSchin 	vp->long_char = ' ';
375da2e3ebdSchin 	vp->o_v_char = '\0';
376da2e3ebdSchin 	vp->ocur_phys = 0;
377da2e3ebdSchin 	vp->ocur_virt = MAXCHAR;
378da2e3ebdSchin 	vp->ofirst_wind = 0;
379da2e3ebdSchin 	physical = Physical;
380da2e3ebdSchin 	vp->u_column = INVALID - 1;
381da2e3ebdSchin 	vp->U_space = Ubuf;
382da2e3ebdSchin 	vp->u_space = ubuf;
383da2e3ebdSchin 	window = Window;
384da2e3ebdSchin 	window[0] = '\0';
385da2e3ebdSchin 
386da2e3ebdSchin 	if(!yankbuf)
387da2e3ebdSchin 		yankbuf = (genchar*)malloc(MAXLINE*CHARSIZE);
388da2e3ebdSchin 	if( vp->last_cmd == '\0' )
389da2e3ebdSchin 	{
390da2e3ebdSchin 		/*** first time for this shell ***/
391da2e3ebdSchin 
392da2e3ebdSchin 		vp->last_cmd = 'i';
393da2e3ebdSchin 		vp->findchar = INVALID;
394da2e3ebdSchin 		vp->lastmotion = '\0';
395da2e3ebdSchin 		vp->lastrepeat = 1;
396da2e3ebdSchin 		vp->repeat = 1;
397da2e3ebdSchin 		*yankbuf = 0;
398da2e3ebdSchin 	}
399da2e3ebdSchin 
400da2e3ebdSchin 	/*** fiddle around with prompt length ***/
401da2e3ebdSchin 	if( nchar+plen > MAXCHAR )
402da2e3ebdSchin 		nchar = MAXCHAR - plen;
403da2e3ebdSchin 	max_col = nchar - 2;
404da2e3ebdSchin 
405da2e3ebdSchin 	if( !viraw )
406da2e3ebdSchin 	{
407da2e3ebdSchin 		int kill_erase = 0;
408da2e3ebdSchin 		for(i=(echoctl?last_virt:0); i<last_virt; ++i )
409da2e3ebdSchin 		{
410da2e3ebdSchin 			/*** change \r to \n, check for control characters, ***/
411da2e3ebdSchin 			/* delete appropriate ^Vs,			*/
412da2e3ebdSchin 			/* and estimate last physical column */
413da2e3ebdSchin 
414da2e3ebdSchin 			if( virtual[i] == '\r' )
415da2e3ebdSchin 				virtual[i] = '\n';
416da2e3ebdSchin 		    if(!echoctl)
417da2e3ebdSchin 		    {
418da2e3ebdSchin 			register int c = virtual[i];
419da2e3ebdSchin 			if( c<=usrerase)
420da2e3ebdSchin 			{
421da2e3ebdSchin 				/*** user typed escaped erase or kill char ***/
422da2e3ebdSchin 				cntl_char = 1;
423da2e3ebdSchin 				if(is_print(c))
424da2e3ebdSchin 					kill_erase++;
425da2e3ebdSchin 			}
426da2e3ebdSchin 			else if( !is_print(c) )
427da2e3ebdSchin 			{
428da2e3ebdSchin 				cntl_char = 1;
429da2e3ebdSchin 
430da2e3ebdSchin 				if( c == usrlnext )
431da2e3ebdSchin 				{
432da2e3ebdSchin 					if( i == last_virt )
433da2e3ebdSchin 					{
434da2e3ebdSchin 						/*** eol/eof was escaped ***/
435da2e3ebdSchin 						/* so replace ^V with it */
436da2e3ebdSchin 						virtual[i] = term_char;
437da2e3ebdSchin 						break;
438da2e3ebdSchin 					}
439da2e3ebdSchin 
440da2e3ebdSchin 					/*** delete ^V ***/
441da2e3ebdSchin 					gencpy((&virtual[i]), (&virtual[i+1]));
442da2e3ebdSchin 					--cur_virt;
443da2e3ebdSchin 					--last_virt;
444da2e3ebdSchin 				}
445da2e3ebdSchin 			}
446da2e3ebdSchin 		    }
447da2e3ebdSchin 		}
448da2e3ebdSchin 
449da2e3ebdSchin 		/*** copy virtual image to window ***/
450da2e3ebdSchin 		if(last_virt > 0)
451da2e3ebdSchin 			last_phys = ed_virt_to_phys(vp->ed,virtual,physical,last_virt,0,0);
452da2e3ebdSchin 		if( last_phys >= w_size )
453da2e3ebdSchin 		{
454da2e3ebdSchin 			/*** line longer than window ***/
455da2e3ebdSchin 			vp->last_wind = w_size - 1;
456da2e3ebdSchin 		}
457da2e3ebdSchin 		else
458da2e3ebdSchin 			vp->last_wind = last_phys;
459da2e3ebdSchin 		genncpy(window, virtual, vp->last_wind+1);
460da2e3ebdSchin 
461da2e3ebdSchin 		if( term_char!=ESC  && (last_virt==INVALID
462da2e3ebdSchin 			|| virtual[last_virt]!=term_char) )
463da2e3ebdSchin 		{
464da2e3ebdSchin 			/*** Line not terminated with ESC or escaped (^V) ***/
465da2e3ebdSchin 			/* eol, so return after doing a total update */
466da2e3ebdSchin 			/* if( (speed is greater or equal to 1200 */
467da2e3ebdSchin 			/* and something was typed) and */
468da2e3ebdSchin 			/* (control character present */
469da2e3ebdSchin 			/* or typeahead occurred) ) */
470da2e3ebdSchin 
471da2e3ebdSchin 			tty_cooked(ERRIO);
472da2e3ebdSchin 			if( editb.e_ttyspeed==FAST && last_virt!=INVALID
473da2e3ebdSchin 				&& (vp->typeahead || cntl_char) )
474da2e3ebdSchin 			{
475da2e3ebdSchin 				refresh(vp,TRANSLATE);
476da2e3ebdSchin 				pr_string(vp,Prompt);
477da2e3ebdSchin 				putstring(vp,0, last_phys+1);
478da2e3ebdSchin 				if(echoctl)
479da2e3ebdSchin 					ed_crlf(vp->ed);
480da2e3ebdSchin 				else
481da2e3ebdSchin 					while(kill_erase-- > 0)
482da2e3ebdSchin 						putchar(' ');
483da2e3ebdSchin 			}
484da2e3ebdSchin 
485da2e3ebdSchin 			if( term_char=='\n' )
486da2e3ebdSchin 			{
487da2e3ebdSchin 				if(!echoctl)
488da2e3ebdSchin 					ed_crlf(vp->ed);
489da2e3ebdSchin 				virtual[++last_virt] = '\n';
490da2e3ebdSchin 			}
491da2e3ebdSchin 			vp->last_cmd = 'i';
492da2e3ebdSchin 			save_last(vp);
493da2e3ebdSchin #if SHOPT_MULTIBYTE
494da2e3ebdSchin 			virtual[last_virt+1] = 0;
495da2e3ebdSchin 			last_virt = ed_external(virtual,shbuf);
496da2e3ebdSchin 			return(last_virt);
497da2e3ebdSchin #else
498da2e3ebdSchin 			return(++last_virt);
499da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
500da2e3ebdSchin 		}
501da2e3ebdSchin 
502da2e3ebdSchin 		/*** Line terminated with escape, or escaped eol/eof, ***/
503da2e3ebdSchin 		/*  so set raw mode */
504da2e3ebdSchin 
505da2e3ebdSchin 		if( tty_raw(ERRIO,0) < 0 )
506da2e3ebdSchin 		{
507da2e3ebdSchin 			tty_cooked(ERRIO);
508da2e3ebdSchin 			/*
509da2e3ebdSchin 			 * The following prevents drivers that return 0 on
510da2e3ebdSchin 			 * causing an infinite loop
511da2e3ebdSchin 			 */
512da2e3ebdSchin 			if(esc_or_hang)
513da2e3ebdSchin 				return(-1);
514da2e3ebdSchin 			virtual[++last_virt] = '\n';
515da2e3ebdSchin #if SHOPT_MULTIBYTE
516da2e3ebdSchin 			virtual[last_virt+1] = 0;
517da2e3ebdSchin 			last_virt = ed_external(virtual,shbuf);
518da2e3ebdSchin 			return(last_virt);
519da2e3ebdSchin #else
520da2e3ebdSchin 			return(++last_virt);
521da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
522da2e3ebdSchin 		}
523da2e3ebdSchin 
524da2e3ebdSchin 		if(echoctl) /*** for cntl-echo erase the ^[ ***/
525da2e3ebdSchin 			pr_string(vp,"\b\b\b\b      \b\b");
526da2e3ebdSchin 
527da2e3ebdSchin 
528da2e3ebdSchin 		if(crallowed)
529da2e3ebdSchin 		{
530da2e3ebdSchin 			/*** start over since there may be ***/
531da2e3ebdSchin 			/*** a control char, or cursor might not ***/
532da2e3ebdSchin 			/*** be at left margin (this lets us know ***/
533da2e3ebdSchin 			/*** where we are ***/
534da2e3ebdSchin 			cur_phys = 0;
535da2e3ebdSchin 			window[0] = '\0';
536da2e3ebdSchin 			pr_string(vp,Prompt);
537da2e3ebdSchin 			if( term_char==ESC && (last_virt<0 || virtual[last_virt]!=ESC))
538da2e3ebdSchin 				refresh(vp,CONTROL);
539da2e3ebdSchin 			else
540da2e3ebdSchin 				refresh(vp,INPUT);
541da2e3ebdSchin 		}
542da2e3ebdSchin 		else
543da2e3ebdSchin 		{
544da2e3ebdSchin 			/*** just update everything internally ***/
545da2e3ebdSchin 			refresh(vp,TRANSLATE);
546da2e3ebdSchin 		}
547da2e3ebdSchin 	}
548da2e3ebdSchin 
549da2e3ebdSchin 	/*** Handle usrintr, usrquit, or EOF ***/
550da2e3ebdSchin 
551da2e3ebdSchin 	i = sigsetjmp(editb.e_env,0);
552da2e3ebdSchin 	if( i != 0 )
553da2e3ebdSchin 	{
5547c2fbfb3SApril Chin 		if(vp->ed->e_multiline)
5557c2fbfb3SApril Chin 		{
5567c2fbfb3SApril Chin 			cur_virt = last_virt;
5577c2fbfb3SApril Chin 			sync_cursor(vp);
5587c2fbfb3SApril Chin 		}
559da2e3ebdSchin 		virtual[0] = '\0';
560da2e3ebdSchin 		tty_cooked(ERRIO);
561da2e3ebdSchin 
562da2e3ebdSchin 		switch(i)
563da2e3ebdSchin 		{
564da2e3ebdSchin 		case UEOF:
565da2e3ebdSchin 			/*** EOF ***/
566da2e3ebdSchin 			return(0);
567da2e3ebdSchin 
568da2e3ebdSchin 		case UINTR:
569da2e3ebdSchin 			/** interrupt **/
570da2e3ebdSchin 			return(-1);
571da2e3ebdSchin 		}
572da2e3ebdSchin 		return(-1);
573da2e3ebdSchin 	}
574da2e3ebdSchin 
575da2e3ebdSchin 	/*** Get a line from the terminal ***/
576da2e3ebdSchin 
577da2e3ebdSchin 	vp->U_saved = 0;
578da2e3ebdSchin 	if(reedit)
57934f9b3eeSRoland Mainz 	{
58034f9b3eeSRoland Mainz 		cur_phys = vp->first_wind;
58134f9b3eeSRoland Mainz 		vp->ofirst_wind = INVALID;
582da2e3ebdSchin 		refresh(vp,INPUT);
58334f9b3eeSRoland Mainz 	}
584da2e3ebdSchin 	if(viraw)
585da2e3ebdSchin 		getline(vp,APPEND);
586da2e3ebdSchin 	else if(last_virt>=0 && virtual[last_virt]==term_char)
587da2e3ebdSchin 		getline(vp,APPEND);
588da2e3ebdSchin 	else
589da2e3ebdSchin 		getline(vp,ESC);
590da2e3ebdSchin 	if(vp->ed->e_multiline)
591da2e3ebdSchin 		cursor(vp, last_phys);
592da2e3ebdSchin 	/*** add a new line if user typed unescaped \n ***/
593da2e3ebdSchin 	/* to cause the shell to process the line */
594da2e3ebdSchin 	tty_cooked(ERRIO);
595da2e3ebdSchin 	if(ed->e_nlist)
596da2e3ebdSchin 	{
597da2e3ebdSchin 		ed->e_nlist = 0;
598da2e3ebdSchin 		stakset(ed->e_stkptr,ed->e_stkoff);
599da2e3ebdSchin 	}
600da2e3ebdSchin 	if( vp->addnl )
601da2e3ebdSchin 	{
602da2e3ebdSchin 		virtual[++last_virt] = '\n';
603da2e3ebdSchin 		ed_crlf(vp->ed);
604da2e3ebdSchin 	}
605da2e3ebdSchin 	if( ++last_virt >= 0 )
606da2e3ebdSchin 	{
607da2e3ebdSchin #if SHOPT_MULTIBYTE
608da2e3ebdSchin 		if(vp->bigvi)
609da2e3ebdSchin 		{
610da2e3ebdSchin 			vp->bigvi = 0;
611da2e3ebdSchin 			shbuf[last_virt-1] = '\n';
612da2e3ebdSchin 		}
613da2e3ebdSchin 		else
614da2e3ebdSchin 		{
615da2e3ebdSchin 			virtual[last_virt] = 0;
616da2e3ebdSchin 			last_virt = ed_external(virtual,shbuf);
617da2e3ebdSchin 		}
618da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
619*b30d1939SAndy Fiddaman #if SHOPT_EDPREDICT
620*b30d1939SAndy Fiddaman 		if(vp->ed->nhlist)
621*b30d1939SAndy Fiddaman 			ed_histlist(vp->ed,0);
622*b30d1939SAndy Fiddaman #endif /* SHOPT_EDPREDICT */
623da2e3ebdSchin 		return(last_virt);
624da2e3ebdSchin 	}
625da2e3ebdSchin 	else
626da2e3ebdSchin 		return(-1);
627da2e3ebdSchin }
628da2e3ebdSchin 
629da2e3ebdSchin 
630da2e3ebdSchin /*{	APPEND( char, mode )
631da2e3ebdSchin  *
632da2e3ebdSchin  *	This routine will append char after cur_virt in the virtual image.
633da2e3ebdSchin  * mode	=	APPEND, shift chars right before appending
634da2e3ebdSchin  *		REPLACE, replace char if possible
635da2e3ebdSchin  *
636da2e3ebdSchin }*/
637da2e3ebdSchin 
append(Vi_t * vp,int c,int mode)638da2e3ebdSchin static void append(Vi_t *vp,int c, int mode)
639da2e3ebdSchin {
640da2e3ebdSchin 	register int i,j;
641da2e3ebdSchin 
642da2e3ebdSchin 	if( last_virt<max_col && last_phys<max_col )
643da2e3ebdSchin 	{
644da2e3ebdSchin 		if( mode==APPEND || (cur_virt==last_virt  && last_virt>=0))
645da2e3ebdSchin 		{
646da2e3ebdSchin 			j = (cur_virt>=0?cur_virt:0);
647da2e3ebdSchin 			for(i = ++last_virt;  i > j; --i)
648da2e3ebdSchin 				virtual[i] = virtual[i-1];
649da2e3ebdSchin 		}
650da2e3ebdSchin 		virtual[++cur_virt] = c;
651da2e3ebdSchin 	}
652da2e3ebdSchin 	else
653da2e3ebdSchin 		ed_ringbell();
654da2e3ebdSchin 	return;
655da2e3ebdSchin }
656da2e3ebdSchin 
657da2e3ebdSchin /*{	BACKWORD( nwords, cmd )
658da2e3ebdSchin  *
659da2e3ebdSchin  *	This routine will position cur_virt at the nth previous word.
660da2e3ebdSchin  *
661da2e3ebdSchin }*/
662da2e3ebdSchin 
backword(Vi_t * vp,int nwords,register int cmd)663da2e3ebdSchin static void backword(Vi_t *vp,int nwords, register int cmd)
664da2e3ebdSchin {
665da2e3ebdSchin 	register int tcur_virt = cur_virt;
666da2e3ebdSchin 	while( nwords-- && tcur_virt > first_virt )
667da2e3ebdSchin 	{
668da2e3ebdSchin 		if( !isblank(tcur_virt) && isblank(tcur_virt-1)
669da2e3ebdSchin 			&& tcur_virt>first_virt )
670da2e3ebdSchin 			--tcur_virt;
671da2e3ebdSchin 		else if(cmd != 'B')
672da2e3ebdSchin 		{
673da2e3ebdSchin 			register int last = isalph(tcur_virt-1);
674da2e3ebdSchin 			register int cur = isalph(tcur_virt);
675da2e3ebdSchin 			if((!cur && last) || (cur && !last))
676da2e3ebdSchin 				--tcur_virt;
677da2e3ebdSchin 		}
678da2e3ebdSchin 		while( isblank(tcur_virt) && tcur_virt>=first_virt )
679da2e3ebdSchin 			--tcur_virt;
680da2e3ebdSchin 		if( cmd == 'B' )
681da2e3ebdSchin 		{
682da2e3ebdSchin 			while( !isblank(tcur_virt) && tcur_virt>=first_virt )
683da2e3ebdSchin 				--tcur_virt;
684da2e3ebdSchin 		}
685da2e3ebdSchin 		else
686da2e3ebdSchin 		{
687da2e3ebdSchin 			if(isalph(tcur_virt))
688da2e3ebdSchin 				while( isalph(tcur_virt) && tcur_virt>=first_virt )
689da2e3ebdSchin 					--tcur_virt;
690da2e3ebdSchin 			else
691da2e3ebdSchin 				while( !isalph(tcur_virt) && !isblank(tcur_virt)
692da2e3ebdSchin 					&& tcur_virt>=first_virt )
693da2e3ebdSchin 					--tcur_virt;
694da2e3ebdSchin 		}
695da2e3ebdSchin 		cur_virt = ++tcur_virt;
696da2e3ebdSchin 	}
697da2e3ebdSchin 	return;
698da2e3ebdSchin }
699da2e3ebdSchin 
700da2e3ebdSchin /*{	CNTLMODE()
701da2e3ebdSchin  *
702da2e3ebdSchin  *	This routine implements the vi command subset.
703da2e3ebdSchin  *	The cursor will always be positioned at the char of interest.
704da2e3ebdSchin  *
705da2e3ebdSchin }*/
706da2e3ebdSchin 
cntlmode(Vi_t * vp)707da2e3ebdSchin static int cntlmode(Vi_t *vp)
708da2e3ebdSchin {
709da2e3ebdSchin 	register int c;
710da2e3ebdSchin 	register int i;
711da2e3ebdSchin 	genchar tmp_u_space[MAXLINE];	/* temporary u_space */
712da2e3ebdSchin 	genchar *real_u_space;		/* points to real u_space */
713da2e3ebdSchin 	int tmp_u_column = INVALID;	/* temporary u_column */
714da2e3ebdSchin 	int was_inmacro;
715da2e3ebdSchin 
716da2e3ebdSchin 	if(!vp->U_saved)
717da2e3ebdSchin 	{
718da2e3ebdSchin 		/*** save virtual image if never done before ***/
719da2e3ebdSchin 		virtual[last_virt+1] = '\0';
720da2e3ebdSchin 		gencpy(vp->U_space, virtual);
721da2e3ebdSchin 		vp->U_saved = 1;
722da2e3ebdSchin 	}
723da2e3ebdSchin 
724da2e3ebdSchin 	save_last(vp);
725da2e3ebdSchin 
726da2e3ebdSchin 	real_u_space = vp->u_space;
727da2e3ebdSchin 	curhline = histmax;
728da2e3ebdSchin 	first_virt = 0;
729da2e3ebdSchin 	vp->repeat = 1;
730da2e3ebdSchin 	if( cur_virt > INVALID )
731da2e3ebdSchin 	{
732da2e3ebdSchin 		/*** make sure cursor is at the last char ***/
733da2e3ebdSchin 		sync_cursor(vp);
734da2e3ebdSchin 	}
735*b30d1939SAndy Fiddaman 	else if(last_virt > INVALID )
736*b30d1939SAndy Fiddaman 		cur_virt++;
737da2e3ebdSchin 
738da2e3ebdSchin 	/*** Read control char until something happens to cause a ***/
739da2e3ebdSchin 	/* return to APPEND/REPLACE mode	*/
740da2e3ebdSchin 
741da2e3ebdSchin 	while( c=ed_getchar(vp->ed,-1) )
742da2e3ebdSchin 	{
743da2e3ebdSchin 		vp->repeat_set = 0;
744da2e3ebdSchin 		was_inmacro = inmacro;
745da2e3ebdSchin 		if( c == '0' )
746da2e3ebdSchin 		{
747da2e3ebdSchin 			/*** move to leftmost column ***/
748da2e3ebdSchin 			cur_virt = 0;
749da2e3ebdSchin 			sync_cursor(vp);
750da2e3ebdSchin 			continue;
751da2e3ebdSchin 		}
752da2e3ebdSchin 
753da2e3ebdSchin 		if( digit(c) )
754da2e3ebdSchin 		{
755da2e3ebdSchin 			c = getcount(vp,c);
756da2e3ebdSchin 			if( c == '.' )
757da2e3ebdSchin 				vp->lastrepeat = vp->repeat;
758da2e3ebdSchin 		}
759da2e3ebdSchin 
760da2e3ebdSchin 		/*** see if it's a move cursor command ***/
761da2e3ebdSchin 
762da2e3ebdSchin 		if(mvcursor(vp,c))
763da2e3ebdSchin 		{
764da2e3ebdSchin 			sync_cursor(vp);
765da2e3ebdSchin 			vp->repeat = 1;
766da2e3ebdSchin 			continue;
767da2e3ebdSchin 		}
768da2e3ebdSchin 
769da2e3ebdSchin 		/*** see if it's a repeat of the last command ***/
770da2e3ebdSchin 
771da2e3ebdSchin 		if( c == '.' )
772da2e3ebdSchin 		{
773da2e3ebdSchin 			c = vp->last_cmd;
774da2e3ebdSchin 			vp->repeat = vp->lastrepeat;
775da2e3ebdSchin 			i = textmod(vp,c, c);
776da2e3ebdSchin 		}
777da2e3ebdSchin 		else
778da2e3ebdSchin 		{
779da2e3ebdSchin 			i = textmod(vp,c, 0);
780da2e3ebdSchin 		}
781da2e3ebdSchin 
782da2e3ebdSchin 		/*** see if it's a text modification command ***/
783da2e3ebdSchin 
784da2e3ebdSchin 		switch(i)
785da2e3ebdSchin 		{
786da2e3ebdSchin 		case BAD:
787da2e3ebdSchin 			break;
788da2e3ebdSchin 
789da2e3ebdSchin 		default:		/** input mode **/
790da2e3ebdSchin 			if(!was_inmacro)
791da2e3ebdSchin 			{
792da2e3ebdSchin 				vp->last_cmd = c;
793da2e3ebdSchin 				vp->lastrepeat = vp->repeat;
794da2e3ebdSchin 			}
795da2e3ebdSchin 			vp->repeat = 1;
796da2e3ebdSchin 			if( i == GOOD )
797da2e3ebdSchin 				continue;
798da2e3ebdSchin 			return(i);
799da2e3ebdSchin 		}
800da2e3ebdSchin 
801da2e3ebdSchin 		switch( c )
802da2e3ebdSchin 		{
803da2e3ebdSchin 			/***** Other stuff *****/
804da2e3ebdSchin 
805da2e3ebdSchin 		case cntl('L'):		/** Redraw line **/
806da2e3ebdSchin 			/*** print the prompt and ***/
807da2e3ebdSchin 			/* force a total refresh */
8087c2fbfb3SApril Chin 			if(vp->nonewline==0 && !vp->ed->e_nocrnl)
809da2e3ebdSchin 				putchar('\n');
810da2e3ebdSchin 			vp->nonewline = 0;
811da2e3ebdSchin 			pr_string(vp,Prompt);
812da2e3ebdSchin 			window[0] = '\0';
813da2e3ebdSchin 			cur_phys = vp->first_wind;
814da2e3ebdSchin 			vp->ofirst_wind = INVALID;
815da2e3ebdSchin 			vp->long_line = ' ';
816da2e3ebdSchin 			break;
817da2e3ebdSchin 
818da2e3ebdSchin 		case cntl('V'):
819da2e3ebdSchin 		{
820da2e3ebdSchin 			register const char *p = fmtident(e_version);
821da2e3ebdSchin 			save_v(vp);
822da2e3ebdSchin 			del_line(vp,BAD);
823da2e3ebdSchin 			while(c = *p++)
824da2e3ebdSchin 				append(vp,c,APPEND);
825da2e3ebdSchin 			refresh(vp,CONTROL);
826da2e3ebdSchin 			ed_getchar(vp->ed,-1);
827da2e3ebdSchin 			restore_v(vp);
828*b30d1939SAndy Fiddaman 			ed_ungetchar(vp->ed,'a');
829da2e3ebdSchin 			break;
830da2e3ebdSchin 		}
831da2e3ebdSchin 
832da2e3ebdSchin 		case '/':		/** Search **/
833da2e3ebdSchin 		case '?':
834da2e3ebdSchin 		case 'N':
835da2e3ebdSchin 		case 'n':
836da2e3ebdSchin 			save_v(vp);
837da2e3ebdSchin 			switch( search(vp,c) )
838da2e3ebdSchin 			{
839da2e3ebdSchin 			case GOOD:
840da2e3ebdSchin 				/*** force a total refresh ***/
841da2e3ebdSchin 				window[0] = '\0';
842da2e3ebdSchin 				goto newhist;
843da2e3ebdSchin 
844da2e3ebdSchin 			case BAD:
845da2e3ebdSchin 				/*** no match ***/
846da2e3ebdSchin 					ed_ringbell();
8475ae8bd53SToomas Soome 				/* FALLTHROUGH */
848da2e3ebdSchin 
849da2e3ebdSchin 			default:
850da2e3ebdSchin 				if( vp->u_column == INVALID )
851da2e3ebdSchin 					del_line(vp,BAD);
852da2e3ebdSchin 				else
853da2e3ebdSchin 					restore_v(vp);
854da2e3ebdSchin 				break;
855da2e3ebdSchin 			}
856da2e3ebdSchin 			break;
857da2e3ebdSchin 
858da2e3ebdSchin 		case 'j':		/** get next command **/
859da2e3ebdSchin 		case '+':		/** get next command **/
860*b30d1939SAndy Fiddaman #if SHOPT_EDPREDICT
861*b30d1939SAndy Fiddaman 			if(vp->ed->hlist)
862*b30d1939SAndy Fiddaman 			{
863*b30d1939SAndy Fiddaman 				if(vp->ed->hoff >= vp->ed->hmax)
864*b30d1939SAndy Fiddaman 					goto ringbell;
865*b30d1939SAndy Fiddaman 				vp->ed->hoff++;
866*b30d1939SAndy Fiddaman 				goto hupdate;
867*b30d1939SAndy Fiddaman 			}
868*b30d1939SAndy Fiddaman #endif /* SHOPT_EDPREDICT */
869da2e3ebdSchin 			curhline += vp->repeat;
870da2e3ebdSchin 			if( curhline > histmax )
871da2e3ebdSchin 			{
872da2e3ebdSchin 				curhline = histmax;
873da2e3ebdSchin 				goto ringbell;
874da2e3ebdSchin 			}
875da2e3ebdSchin 			else if(curhline==histmax && tmp_u_column!=INVALID )
876da2e3ebdSchin 			{
877da2e3ebdSchin 				vp->u_space = tmp_u_space;
878da2e3ebdSchin 				vp->u_column = tmp_u_column;
879da2e3ebdSchin 				restore_v(vp);
880da2e3ebdSchin 				vp->u_space = real_u_space;
881da2e3ebdSchin 				break;
882da2e3ebdSchin 			}
883da2e3ebdSchin 			save_v(vp);
884da2e3ebdSchin 			cur_virt = INVALID;
885da2e3ebdSchin 			goto newhist;
886da2e3ebdSchin 
887da2e3ebdSchin 		case 'k':		/** get previous command **/
888da2e3ebdSchin 		case '-':		/** get previous command **/
889*b30d1939SAndy Fiddaman #if SHOPT_EDPREDICT
890*b30d1939SAndy Fiddaman 			if(vp->ed->hlist)
891*b30d1939SAndy Fiddaman 			{
892*b30d1939SAndy Fiddaman 				if(vp->ed->hoff == 0)
893*b30d1939SAndy Fiddaman 					goto ringbell;
894*b30d1939SAndy Fiddaman 				vp->ed->hoff--;
895*b30d1939SAndy Fiddaman 			 hupdate:
896*b30d1939SAndy Fiddaman 				ed_histlist(vp->ed,*vp->ed->hlist!=0);
897*b30d1939SAndy Fiddaman 				vp->nonewline++;
898*b30d1939SAndy Fiddaman 				ed_ungetchar(vp->ed,cntl('L'));
899*b30d1939SAndy Fiddaman 				continue;
900*b30d1939SAndy Fiddaman 			}
901*b30d1939SAndy Fiddaman #endif /* SHOPT_EDPREDICT */
902da2e3ebdSchin 			if( curhline == histmax )
903da2e3ebdSchin 			{
904da2e3ebdSchin 				vp->u_space = tmp_u_space;
905da2e3ebdSchin 				i = vp->u_column;
906da2e3ebdSchin 				save_v(vp);
907da2e3ebdSchin 				vp->u_space = real_u_space;
908da2e3ebdSchin 				tmp_u_column = vp->u_column;
909da2e3ebdSchin 				vp->u_column = i;
910da2e3ebdSchin 			}
911da2e3ebdSchin 
912da2e3ebdSchin 			curhline -= vp->repeat;
913da2e3ebdSchin 			if( curhline <= histmin )
914da2e3ebdSchin 			{
915da2e3ebdSchin 				curhline += vp->repeat;
916da2e3ebdSchin 				goto ringbell;
917da2e3ebdSchin 			}
918da2e3ebdSchin 			save_v(vp);
919da2e3ebdSchin 			cur_virt = INVALID;
920da2e3ebdSchin 		newhist:
921da2e3ebdSchin 			if(curhline!=histmax || cur_virt==INVALID)
922da2e3ebdSchin 				hist_copy((char*)virtual, MAXLINE, curhline,-1);
923da2e3ebdSchin 			else
924da2e3ebdSchin 			{
925da2e3ebdSchin 				strcpy((char*)virtual,(char*)vp->u_space);
926da2e3ebdSchin #if SHOPT_MULTIBYTE
927da2e3ebdSchin 				ed_internal((char*)vp->u_space,vp->u_space);
928da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
929da2e3ebdSchin 			}
930da2e3ebdSchin #if SHOPT_MULTIBYTE
931da2e3ebdSchin 			ed_internal((char*)virtual,virtual);
932da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
933da2e3ebdSchin 			if((last_virt=genlen(virtual)-1) >= 0  && cur_virt == INVALID)
934da2e3ebdSchin 				cur_virt = 0;
935*b30d1939SAndy Fiddaman #if SHOPT_EDPREDICT
936*b30d1939SAndy Fiddaman 			if(vp->ed->hlist)
937*b30d1939SAndy Fiddaman 			{
938*b30d1939SAndy Fiddaman 				ed_histlist(vp->ed,0);
939*b30d1939SAndy Fiddaman 				if(c=='\n')
940*b30d1939SAndy Fiddaman 					ed_ungetchar(vp->ed,c);
941*b30d1939SAndy Fiddaman 				ed_ungetchar(vp->ed,cntl('L'));
942*b30d1939SAndy Fiddaman 				vp->nonewline = 1;
943*b30d1939SAndy Fiddaman 				cur_virt = 0;
944*b30d1939SAndy Fiddaman 			}
945*b30d1939SAndy Fiddaman #endif /*SHOPT_EDPREDICT */
946da2e3ebdSchin 			break;
947da2e3ebdSchin 
948da2e3ebdSchin 
949da2e3ebdSchin 		case 'u':		/** undo the last thing done **/
950da2e3ebdSchin 			restore_v(vp);
951da2e3ebdSchin 			break;
952da2e3ebdSchin 
953da2e3ebdSchin 		case 'U':		/** Undo everything **/
954da2e3ebdSchin 			save_v(vp);
955da2e3ebdSchin 			if( virtual[0] == '\0' )
956da2e3ebdSchin 				goto ringbell;
957da2e3ebdSchin 			else
958da2e3ebdSchin 			{
959da2e3ebdSchin 				gencpy(virtual, vp->U_space);
960da2e3ebdSchin 				last_virt = genlen(vp->U_space) - 1;
961da2e3ebdSchin 				cur_virt = 0;
962da2e3ebdSchin 			}
963da2e3ebdSchin 			break;
964da2e3ebdSchin 
965da2e3ebdSchin #if KSHELL
966da2e3ebdSchin 		case 'v':
967da2e3ebdSchin 			if(vp->repeat_set==0)
968da2e3ebdSchin 				goto vcommand;
969da2e3ebdSchin #endif /* KSHELL */
9705ae8bd53SToomas Soome 			/* FALLTHROUGH */
971da2e3ebdSchin 
972da2e3ebdSchin 		case 'G':		/** goto command repeat **/
973da2e3ebdSchin 			if(vp->repeat_set==0)
974da2e3ebdSchin 				vp->repeat = histmin+1;
975da2e3ebdSchin 			if( vp->repeat <= histmin || vp->repeat > histmax )
976da2e3ebdSchin 			{
977da2e3ebdSchin 				goto ringbell;
978da2e3ebdSchin 			}
979da2e3ebdSchin 			curhline = vp->repeat;
980da2e3ebdSchin 			save_v(vp);
981da2e3ebdSchin 			if(c == 'G')
982da2e3ebdSchin 			{
983da2e3ebdSchin 				cur_virt = INVALID;
984da2e3ebdSchin 				goto newhist;
985da2e3ebdSchin 			}
986da2e3ebdSchin 
987da2e3ebdSchin #if KSHELL
988da2e3ebdSchin 		vcommand:
989da2e3ebdSchin 			if(ed_fulledit(vp->ed)==GOOD)
990da2e3ebdSchin 				return(BIGVI);
991da2e3ebdSchin 			else
992da2e3ebdSchin 				goto ringbell;
993da2e3ebdSchin #endif	/* KSHELL */
994da2e3ebdSchin 
995da2e3ebdSchin 		case '#':	/** insert(delete) # to (no)comment command **/
996da2e3ebdSchin 			if( cur_virt != INVALID )
997da2e3ebdSchin 			{
998da2e3ebdSchin 				register genchar *p = &virtual[last_virt+1];
999da2e3ebdSchin 				*p = 0;
1000da2e3ebdSchin 				/*** see whether first char is comment char ***/
1001da2e3ebdSchin 				c = (virtual[0]=='#');
1002da2e3ebdSchin 				while(p-- >= virtual)
1003da2e3ebdSchin 				{
1004da2e3ebdSchin 					if(*p=='\n' || p<virtual)
1005da2e3ebdSchin 					{
1006da2e3ebdSchin 						if(c) /* delete '#' */
1007da2e3ebdSchin 						{
1008da2e3ebdSchin 							if(p[1]=='#')
1009da2e3ebdSchin 							{
1010da2e3ebdSchin 								last_virt--;
1011da2e3ebdSchin 								gencpy(p+1,p+2);
1012da2e3ebdSchin 							}
1013da2e3ebdSchin 						}
1014da2e3ebdSchin 						else
1015da2e3ebdSchin 						{
1016da2e3ebdSchin 							cur_virt = p-virtual;
1017da2e3ebdSchin 							append(vp,'#', APPEND);
1018da2e3ebdSchin 						}
1019da2e3ebdSchin 					}
1020da2e3ebdSchin 				}
1021da2e3ebdSchin 				if(c)
1022da2e3ebdSchin 				{
1023da2e3ebdSchin 					curhline = histmax;
1024da2e3ebdSchin 					cur_virt = 0;
1025da2e3ebdSchin 					break;
1026da2e3ebdSchin 				}
1027da2e3ebdSchin 				refresh(vp,INPUT);
1028da2e3ebdSchin 			}
10295ae8bd53SToomas Soome 			/* FALLTHROUGH */
1030da2e3ebdSchin 
1031da2e3ebdSchin 		case '\n':		/** send to shell **/
1032*b30d1939SAndy Fiddaman #if SHOPT_EDPREDICT
1033*b30d1939SAndy Fiddaman 			if(!vp->ed->hlist)
1034da2e3ebdSchin 			return(ENTER);
1035*b30d1939SAndy Fiddaman 		case '\t':		/** bring choice to edit **/
1036*b30d1939SAndy Fiddaman 			if(vp->ed->hlist)
1037*b30d1939SAndy Fiddaman 			{
1038*b30d1939SAndy Fiddaman 				if(vp->repeat > vp->ed->nhlist-vp->ed->hoff)
1039*b30d1939SAndy Fiddaman 					goto ringbell;
1040*b30d1939SAndy Fiddaman 				curhline = vp->ed->hlist[vp->repeat+vp->ed->hoff-1]->index;
1041*b30d1939SAndy Fiddaman 				goto newhist;
1042*b30d1939SAndy Fiddaman 			}
1043*b30d1939SAndy Fiddaman 			goto ringbell;
1044*b30d1939SAndy Fiddaman #else
1045*b30d1939SAndy Fiddaman 			return(ENTER);
1046*b30d1939SAndy Fiddaman #endif /* SHOPT_EDPREDICT */
1047da2e3ebdSchin 	        case ESC:
1048da2e3ebdSchin 			/* don't ring bell if next char is '[' */
1049da2e3ebdSchin 			if(!lookahead)
1050da2e3ebdSchin 			{
1051da2e3ebdSchin 				char x;
1052da2e3ebdSchin 				if(sfpkrd(editb.e_fd,&x,1,'\r',400L,-1)>0)
1053da2e3ebdSchin 					ed_ungetchar(vp->ed,x);
1054da2e3ebdSchin 			}
1055da2e3ebdSchin 			if(lookahead)
1056da2e3ebdSchin 			{
1057da2e3ebdSchin 				ed_ungetchar(vp->ed,c=ed_getchar(vp->ed,1));
1058da2e3ebdSchin 				if(c=='[')
1059da2e3ebdSchin 				{
1060da2e3ebdSchin 					vp->repeat = 1;
1061da2e3ebdSchin 					continue;
1062da2e3ebdSchin 				}
1063da2e3ebdSchin 			}
10645ae8bd53SToomas Soome 			/* FALLTHROUGH */
1065da2e3ebdSchin 		default:
1066da2e3ebdSchin 		ringbell:
1067da2e3ebdSchin 			ed_ringbell();
1068da2e3ebdSchin 			vp->repeat = 1;
1069da2e3ebdSchin 			continue;
1070da2e3ebdSchin 		}
1071da2e3ebdSchin 
1072da2e3ebdSchin 		refresh(vp,CONTROL);
1073da2e3ebdSchin 		vp->repeat = 1;
1074da2e3ebdSchin 	}
1075da2e3ebdSchin /* NOTREACHED */
1076da2e3ebdSchin 	return(0);
1077da2e3ebdSchin }
1078da2e3ebdSchin 
1079da2e3ebdSchin /*{	CURSOR( new_current_physical )
1080da2e3ebdSchin  *
1081da2e3ebdSchin  *	This routine will position the virtual cursor at
1082da2e3ebdSchin  * physical column x in the window.
1083da2e3ebdSchin  *
1084da2e3ebdSchin }*/
1085da2e3ebdSchin 
cursor(Vi_t * vp,register int x)1086da2e3ebdSchin static void cursor(Vi_t *vp,register int x)
1087da2e3ebdSchin {
1088da2e3ebdSchin #if SHOPT_MULTIBYTE
1089da2e3ebdSchin 	while(physical[x]==MARKER)
1090da2e3ebdSchin 		x++;
1091da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
1092da2e3ebdSchin 	cur_phys = ed_setcursor(vp->ed, physical, cur_phys,x,vp->first_wind);
1093da2e3ebdSchin }
1094da2e3ebdSchin 
1095da2e3ebdSchin /*{	DELETE( nchars, mode )
1096da2e3ebdSchin  *
1097da2e3ebdSchin  *	Delete nchars from the virtual space and leave cur_virt positioned
1098da2e3ebdSchin  * at cur_virt-1.
1099da2e3ebdSchin  *
1100da2e3ebdSchin  *	If mode	= 'c', do not save the characters deleted
1101da2e3ebdSchin  *		= 'd', save them in yankbuf and delete.
1102da2e3ebdSchin  *		= 'y', save them in yankbuf but do not delete.
1103da2e3ebdSchin  *
1104da2e3ebdSchin }*/
1105da2e3ebdSchin 
cdelete(Vi_t * vp,register int nchars,int mode)1106da2e3ebdSchin static void cdelete(Vi_t *vp,register int nchars, int mode)
1107da2e3ebdSchin {
1108da2e3ebdSchin 	register int i;
1109da2e3ebdSchin 	register genchar *cp;
1110da2e3ebdSchin 
1111da2e3ebdSchin 	if( cur_virt < first_virt )
1112da2e3ebdSchin 	{
1113da2e3ebdSchin 		ed_ringbell();
1114da2e3ebdSchin 		return;
1115da2e3ebdSchin 	}
1116da2e3ebdSchin 	if( nchars > 0 )
1117da2e3ebdSchin 	{
1118da2e3ebdSchin 		cp = virtual+cur_virt;
1119da2e3ebdSchin 		vp->o_v_char = cp[0];
1120da2e3ebdSchin 		if( (cur_virt-- + nchars) > last_virt )
1121da2e3ebdSchin 		{
1122da2e3ebdSchin 			/*** set nchars to number actually deleted ***/
1123da2e3ebdSchin 			nchars = last_virt - cur_virt;
1124da2e3ebdSchin 		}
1125da2e3ebdSchin 
1126da2e3ebdSchin 		/*** save characters to be deleted ***/
1127da2e3ebdSchin 
1128da2e3ebdSchin 		if( mode != 'c' )
1129da2e3ebdSchin 		{
1130da2e3ebdSchin 			i = cp[nchars];
1131da2e3ebdSchin 			cp[nchars] = 0;
1132da2e3ebdSchin 			gencpy(yankbuf,cp);
1133da2e3ebdSchin 			cp[nchars] = i;
1134da2e3ebdSchin 		}
1135da2e3ebdSchin 
1136da2e3ebdSchin 		/*** now delete these characters ***/
1137da2e3ebdSchin 
1138da2e3ebdSchin 		if( mode != 'y' )
1139da2e3ebdSchin 		{
1140da2e3ebdSchin 			gencpy(cp,cp+nchars);
1141da2e3ebdSchin 			last_virt -= nchars;
1142da2e3ebdSchin 		}
1143da2e3ebdSchin 	}
1144da2e3ebdSchin 	return;
1145da2e3ebdSchin }
1146da2e3ebdSchin 
1147da2e3ebdSchin /*{	DEL_LINE( mode )
1148da2e3ebdSchin  *
1149da2e3ebdSchin  *	This routine will delete the line.
1150da2e3ebdSchin  *	mode = GOOD, do a save_v()
1151da2e3ebdSchin  *
1152da2e3ebdSchin }*/
del_line(register Vi_t * vp,int mode)1153da2e3ebdSchin static void del_line(register Vi_t *vp, int mode)
1154da2e3ebdSchin {
1155da2e3ebdSchin 	if( last_virt == INVALID )
1156da2e3ebdSchin 		return;
1157da2e3ebdSchin 
1158da2e3ebdSchin 	if( mode == GOOD )
1159da2e3ebdSchin 		save_v(vp);
1160da2e3ebdSchin 
1161da2e3ebdSchin 	cur_virt = 0;
1162da2e3ebdSchin 	first_virt = 0;
1163da2e3ebdSchin 	cdelete(vp,last_virt+1, BAD);
1164da2e3ebdSchin 	refresh(vp,CONTROL);
1165da2e3ebdSchin 
1166da2e3ebdSchin 	cur_virt = INVALID;
1167da2e3ebdSchin 	cur_phys = 0;
1168da2e3ebdSchin 	vp->findchar = INVALID;
1169da2e3ebdSchin 	last_phys = INVALID;
1170da2e3ebdSchin 	last_virt = INVALID;
1171da2e3ebdSchin 	vp->last_wind = INVALID;
1172da2e3ebdSchin 	vp->first_wind = 0;
1173da2e3ebdSchin 	vp->o_v_char = '\0';
1174da2e3ebdSchin 	vp->ocur_phys = 0;
1175da2e3ebdSchin 	vp->ocur_virt = MAXCHAR;
1176da2e3ebdSchin 	vp->ofirst_wind = 0;
1177da2e3ebdSchin 	window[0] = '\0';
1178da2e3ebdSchin 	return;
1179da2e3ebdSchin }
1180da2e3ebdSchin 
1181da2e3ebdSchin /*{	DELMOTION( motion, mode )
1182da2e3ebdSchin  *
1183da2e3ebdSchin  *	Delete thru motion.
1184da2e3ebdSchin  *
1185da2e3ebdSchin  *	mode	= 'd', save deleted characters, delete
1186da2e3ebdSchin  *		= 'c', do not save characters, change
1187da2e3ebdSchin  *		= 'y', save characters, yank
1188da2e3ebdSchin  *
1189da2e3ebdSchin  *	Returns 1 if operation successful; else 0.
1190da2e3ebdSchin  *
1191da2e3ebdSchin }*/
1192da2e3ebdSchin 
delmotion(Vi_t * vp,int motion,int mode)1193da2e3ebdSchin static int delmotion(Vi_t *vp,int motion, int mode)
1194da2e3ebdSchin {
1195da2e3ebdSchin 	register int begin, end, delta;
1196da2e3ebdSchin 	/* the following saves a register */
1197da2e3ebdSchin 
1198da2e3ebdSchin 	if( cur_virt == INVALID )
1199da2e3ebdSchin 		return(0);
1200da2e3ebdSchin 	if( mode != 'y' )
1201da2e3ebdSchin 		save_v(vp);
1202da2e3ebdSchin 	begin = cur_virt;
1203da2e3ebdSchin 
1204da2e3ebdSchin 	/*** fake out the motion routines by appending a blank ***/
1205da2e3ebdSchin 
1206da2e3ebdSchin 	virtual[++last_virt] = ' ';
1207da2e3ebdSchin 	end = mvcursor(vp,motion);
1208da2e3ebdSchin 	virtual[last_virt--] = 0;
1209da2e3ebdSchin 	if(!end)
1210da2e3ebdSchin 		return(0);
1211da2e3ebdSchin 
1212da2e3ebdSchin 	end = cur_virt;
1213da2e3ebdSchin 	if( mode=='c' && end>begin && strchr("wW", motion) )
1214da2e3ebdSchin 	{
1215da2e3ebdSchin 		/*** called by change operation, user really expects ***/
1216da2e3ebdSchin 		/* the effect of the eE commands, so back up to end of word */
1217da2e3ebdSchin 		while( end>begin && isblank(end-1) )
1218da2e3ebdSchin 			--end;
1219da2e3ebdSchin 		if( end == begin )
1220da2e3ebdSchin 			++end;
1221da2e3ebdSchin 	}
1222da2e3ebdSchin 
1223da2e3ebdSchin 	delta = end - begin;
1224da2e3ebdSchin 	if( delta >= 0 )
1225da2e3ebdSchin 	{
1226da2e3ebdSchin 		cur_virt = begin;
1227da2e3ebdSchin 		if( strchr("eE;,TtFf%", motion) )
1228da2e3ebdSchin 			++delta;
1229da2e3ebdSchin 	}
1230da2e3ebdSchin 	else
1231da2e3ebdSchin 	{
1232da2e3ebdSchin 		delta = -delta + (motion=='%');
1233da2e3ebdSchin 	}
1234da2e3ebdSchin 
1235da2e3ebdSchin 	cdelete(vp,delta, mode);
1236da2e3ebdSchin 	if( mode == 'y' )
1237da2e3ebdSchin 		cur_virt = begin;
1238da2e3ebdSchin 	return(1);
1239da2e3ebdSchin }
1240da2e3ebdSchin 
1241da2e3ebdSchin 
1242da2e3ebdSchin /*{	ENDWORD( nwords, cmd )
1243da2e3ebdSchin  *
1244da2e3ebdSchin  *	This routine will move cur_virt to the end of the nth word.
1245da2e3ebdSchin  *
1246da2e3ebdSchin }*/
1247da2e3ebdSchin 
endword(Vi_t * vp,int nwords,register int cmd)1248da2e3ebdSchin static void endword(Vi_t *vp, int nwords, register int cmd)
1249da2e3ebdSchin {
1250da2e3ebdSchin 	register int tcur_virt = cur_virt;
1251da2e3ebdSchin 	while( nwords-- )
1252da2e3ebdSchin 	{
1253da2e3ebdSchin 		if( !isblank(tcur_virt) && tcur_virt<=last_virt )
1254da2e3ebdSchin 			++tcur_virt;
1255da2e3ebdSchin 		while( isblank(tcur_virt) && tcur_virt<=last_virt )
1256da2e3ebdSchin 			++tcur_virt;
1257da2e3ebdSchin 		if( cmd == 'E' )
1258da2e3ebdSchin 		{
1259da2e3ebdSchin 			while( !isblank(tcur_virt) && tcur_virt<=last_virt )
1260da2e3ebdSchin 				++tcur_virt;
1261da2e3ebdSchin 		}
1262da2e3ebdSchin 		else
1263da2e3ebdSchin 		{
1264da2e3ebdSchin 			if( isalph(tcur_virt) )
1265da2e3ebdSchin 				while( isalph(tcur_virt) && tcur_virt<=last_virt )
1266da2e3ebdSchin 					++tcur_virt;
1267da2e3ebdSchin 			else
1268da2e3ebdSchin 				while( !isalph(tcur_virt) && !isblank(tcur_virt)
1269da2e3ebdSchin 					&& tcur_virt<=last_virt )
1270da2e3ebdSchin 					++tcur_virt;
1271da2e3ebdSchin 		}
1272da2e3ebdSchin 		if( tcur_virt > first_virt )
1273da2e3ebdSchin 			tcur_virt--;
1274da2e3ebdSchin 	}
1275da2e3ebdSchin 	cur_virt = tcur_virt;
1276da2e3ebdSchin 	return;
1277da2e3ebdSchin }
1278da2e3ebdSchin 
1279da2e3ebdSchin /*{	FORWARD( nwords, cmd )
1280da2e3ebdSchin  *
1281da2e3ebdSchin  *	This routine will move cur_virt forward to the next nth word.
1282da2e3ebdSchin  *
1283da2e3ebdSchin }*/
1284da2e3ebdSchin 
forward(Vi_t * vp,register int nwords,int cmd)1285da2e3ebdSchin static void forward(Vi_t *vp,register int nwords, int cmd)
1286da2e3ebdSchin {
1287da2e3ebdSchin 	register int tcur_virt = cur_virt;
1288da2e3ebdSchin 	while( nwords-- )
1289da2e3ebdSchin 	{
1290da2e3ebdSchin 		if( cmd == 'W' )
1291da2e3ebdSchin 		{
1292da2e3ebdSchin 			while( !isblank(tcur_virt) && tcur_virt < last_virt )
1293da2e3ebdSchin 				++tcur_virt;
1294da2e3ebdSchin 		}
1295da2e3ebdSchin 		else
1296da2e3ebdSchin 		{
1297da2e3ebdSchin 			if( isalph(tcur_virt) )
1298da2e3ebdSchin 			{
1299da2e3ebdSchin 				while( isalph(tcur_virt) && tcur_virt<last_virt )
1300da2e3ebdSchin 					++tcur_virt;
1301da2e3ebdSchin 			}
1302da2e3ebdSchin 			else
1303da2e3ebdSchin 			{
1304da2e3ebdSchin 				while( !isalph(tcur_virt) && !isblank(tcur_virt)
1305da2e3ebdSchin 					&& tcur_virt < last_virt )
1306da2e3ebdSchin 					++tcur_virt;
1307da2e3ebdSchin 			}
1308da2e3ebdSchin 		}
1309da2e3ebdSchin 		while( isblank(tcur_virt) && tcur_virt < last_virt )
1310da2e3ebdSchin 			++tcur_virt;
1311da2e3ebdSchin 	}
1312da2e3ebdSchin 	cur_virt = tcur_virt;
1313da2e3ebdSchin 	return;
1314da2e3ebdSchin }
1315da2e3ebdSchin 
1316da2e3ebdSchin 
1317da2e3ebdSchin 
1318da2e3ebdSchin /*{	GETCOUNT(c)
1319da2e3ebdSchin  *
1320da2e3ebdSchin  *	Set repeat to the user typed number and return the terminating
1321da2e3ebdSchin  * character.
1322da2e3ebdSchin  *
1323da2e3ebdSchin }*/
1324da2e3ebdSchin 
getcount(register Vi_t * vp,register int c)1325da2e3ebdSchin static int getcount(register Vi_t *vp,register int c)
1326da2e3ebdSchin {
1327da2e3ebdSchin 	register int i;
1328da2e3ebdSchin 
1329da2e3ebdSchin 	/*** get any repeat count ***/
1330da2e3ebdSchin 
1331da2e3ebdSchin 	if( c == '0' )
1332da2e3ebdSchin 		return(c);
1333da2e3ebdSchin 
1334da2e3ebdSchin 	vp->repeat_set++;
1335da2e3ebdSchin 	i = 0;
1336da2e3ebdSchin 	while( digit(c) )
1337da2e3ebdSchin 	{
1338da2e3ebdSchin 		i = i*10 + c - '0';
1339da2e3ebdSchin 		c = ed_getchar(vp->ed,-1);
1340da2e3ebdSchin 	}
1341da2e3ebdSchin 
1342da2e3ebdSchin 	if( i > 0 )
1343da2e3ebdSchin 		vp->repeat *= i;
1344da2e3ebdSchin 	return(c);
1345da2e3ebdSchin }
1346da2e3ebdSchin 
1347da2e3ebdSchin 
1348da2e3ebdSchin /*{	GETLINE( mode )
1349da2e3ebdSchin  *
1350da2e3ebdSchin  *	This routine will fetch a line.
1351da2e3ebdSchin  *	mode	= APPEND, allow escape to cntlmode subroutine
1352da2e3ebdSchin  *		  appending characters.
1353da2e3ebdSchin  *		= REPLACE, allow escape to cntlmode subroutine
1354da2e3ebdSchin  *		  replacing characters.
1355da2e3ebdSchin  *		= SEARCH, no escape allowed
1356da2e3ebdSchin  *		= ESC, enter control mode immediately
1357da2e3ebdSchin  *
1358da2e3ebdSchin  *	The cursor will always be positioned after the last
1359da2e3ebdSchin  * char printed.
1360da2e3ebdSchin  *
1361da2e3ebdSchin  *	This routine returns when cr, nl, or (eof in column 0) is
1362da2e3ebdSchin  * received (column 0 is the first char position).
1363da2e3ebdSchin  *
1364da2e3ebdSchin }*/
1365da2e3ebdSchin 
getline(register Vi_t * vp,register int mode)1366da2e3ebdSchin static void getline(register Vi_t* vp,register int mode)
1367da2e3ebdSchin {
1368da2e3ebdSchin 	register int c;
1369da2e3ebdSchin 	register int tmp;
1370da2e3ebdSchin 	int	max_virt=0, last_save=0;
1371da2e3ebdSchin 	genchar saveline[MAXLINE];
1372da2e3ebdSchin 	vp->addnl = 1;
1373da2e3ebdSchin 
1374da2e3ebdSchin 	if( mode == ESC )
1375da2e3ebdSchin 	{
1376da2e3ebdSchin 		/*** go directly to control mode ***/
1377da2e3ebdSchin 		goto escape;
1378da2e3ebdSchin 	}
1379da2e3ebdSchin 
1380da2e3ebdSchin 	for(;;)
1381da2e3ebdSchin 	{
1382da2e3ebdSchin 		if( (c=ed_getchar(vp->ed,mode==SEARCH?1:-2)) == usreof )
1383da2e3ebdSchin 			c = UEOF;
1384da2e3ebdSchin 		else if( c == usrerase )
1385da2e3ebdSchin 			c = UERASE;
1386da2e3ebdSchin 		else if( c == usrkill )
1387da2e3ebdSchin 			c = UKILL;
1388da2e3ebdSchin 		else if( c == editb.e_werase )
1389da2e3ebdSchin 			c = UWERASE;
1390da2e3ebdSchin 		else if( c == usrlnext )
1391da2e3ebdSchin 			c = ULNEXT;
1392*b30d1939SAndy Fiddaman 		else if(mode==SEARCH && c==editb.e_intr)
1393*b30d1939SAndy Fiddaman 			c = UINTR;
1394da2e3ebdSchin 
1395da2e3ebdSchin 		if( c == ULNEXT)
1396da2e3ebdSchin 		{
1397da2e3ebdSchin 			/*** implement ^V to escape next char ***/
1398da2e3ebdSchin 			c = ed_getchar(vp->ed,2);
1399da2e3ebdSchin 			append(vp,c, mode);
1400da2e3ebdSchin 			refresh(vp,INPUT);
1401da2e3ebdSchin 			continue;
1402da2e3ebdSchin 		}
1403*b30d1939SAndy Fiddaman 		if(c!='\t')
1404*b30d1939SAndy Fiddaman 			vp->ed->e_tabcount = 0;
1405da2e3ebdSchin 
1406da2e3ebdSchin 		switch( c )
1407da2e3ebdSchin 		{
1408da2e3ebdSchin 		case ESC:		/** enter control mode **/
1409da2e3ebdSchin 			if(!sh_isoption(SH_VI))
1410da2e3ebdSchin 			{
1411da2e3ebdSchin 				append(vp,c, mode);
1412da2e3ebdSchin 				break;
1413da2e3ebdSchin 			}
1414da2e3ebdSchin 			if( mode == SEARCH )
1415da2e3ebdSchin 			{
1416da2e3ebdSchin 				ed_ringbell();
1417da2e3ebdSchin 				continue;
1418da2e3ebdSchin 			}
1419da2e3ebdSchin 			else
1420da2e3ebdSchin 			{
1421da2e3ebdSchin 	escape:
1422da2e3ebdSchin 				if( mode == REPLACE )
1423da2e3ebdSchin 				{
1424da2e3ebdSchin 					c = max_virt-cur_virt;
1425da2e3ebdSchin 					if(c > 0 && last_save>=cur_virt)
1426da2e3ebdSchin 					{
1427da2e3ebdSchin 						genncpy((&virtual[cur_virt]),&saveline[cur_virt],c);
1428da2e3ebdSchin 						if(last_virt>=last_save)
1429da2e3ebdSchin 							last_virt=last_save-1;
1430da2e3ebdSchin 						refresh(vp,INPUT);
1431da2e3ebdSchin 					}
1432da2e3ebdSchin 					--cur_virt;
1433da2e3ebdSchin 				}
1434da2e3ebdSchin 				tmp = cntlmode(vp);
1435da2e3ebdSchin 				if( tmp == ENTER || tmp == BIGVI )
1436da2e3ebdSchin 				{
1437da2e3ebdSchin #if SHOPT_MULTIBYTE
1438da2e3ebdSchin 					vp->bigvi = (tmp==BIGVI);
1439da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
1440da2e3ebdSchin 					return;
1441da2e3ebdSchin 				}
1442da2e3ebdSchin 				if( tmp == INSERT )
1443da2e3ebdSchin 				{
1444da2e3ebdSchin 					mode = APPEND;
1445da2e3ebdSchin 					continue;
1446da2e3ebdSchin 				}
1447da2e3ebdSchin 				mode = tmp;
1448da2e3ebdSchin 				if(mode==REPLACE)
1449da2e3ebdSchin 				{
1450da2e3ebdSchin 					c = last_save = last_virt+1;
1451da2e3ebdSchin 					if(c >= MAXLINE)
1452da2e3ebdSchin 						c = MAXLINE-1;
1453da2e3ebdSchin 					genncpy(saveline, virtual, c);
1454da2e3ebdSchin 				}
1455da2e3ebdSchin 			}
1456da2e3ebdSchin 			break;
1457da2e3ebdSchin 
1458*b30d1939SAndy Fiddaman 		case UINTR:
1459*b30d1939SAndy Fiddaman 				first_virt = 0;
1460*b30d1939SAndy Fiddaman 				cdelete(vp,cur_virt+1, BAD);
1461*b30d1939SAndy Fiddaman 				cur_virt = -1;
1462*b30d1939SAndy Fiddaman 				return;
1463da2e3ebdSchin 		case UERASE:		/** user erase char **/
1464da2e3ebdSchin 				/*** treat as backspace ***/
1465da2e3ebdSchin 
1466da2e3ebdSchin 		case '\b':		/** backspace **/
1467da2e3ebdSchin 			if( virtual[cur_virt] == '\\' )
1468da2e3ebdSchin 			{
1469da2e3ebdSchin 				cdelete(vp,1, BAD);
1470da2e3ebdSchin 				append(vp,usrerase, mode);
1471da2e3ebdSchin 			}
1472da2e3ebdSchin 			else
1473da2e3ebdSchin 			{
1474da2e3ebdSchin 				if( mode==SEARCH && cur_virt==0 )
1475da2e3ebdSchin 				{
1476da2e3ebdSchin 					first_virt = 0;
1477da2e3ebdSchin