xref: /titanic_50/usr/src/lib/libshell/common/edit/vi.c (revision 3e14f97f673e8a630f076077de35afdd43dc1587)
1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin *                                                                      *
3da2e3ebdSchin *               This software is part of the ast package               *
4*3e14f97fSRoger A. Faulkner *          Copyright (c) 1982-2010 AT&T Intellectual Property          *
5da2e3ebdSchin *                      and is licensed under the                       *
6da2e3ebdSchin *                  Common Public License, Version 1.0                  *
77c2fbfb3SApril Chin *                    by AT&T Intellectual Property                     *
8da2e3ebdSchin *                                                                      *
9da2e3ebdSchin *                A copy of the License is available at                 *
10da2e3ebdSchin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11da2e3ebdSchin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
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"
37da2e3ebdSchin #   include	<ctype.h>
3834f9b3eeSRoland Mainz #endif	/* KSHELL */
39da2e3ebdSchin #include	"io.h"
40da2e3ebdSchin 
41da2e3ebdSchin #include	"history.h"
42da2e3ebdSchin #include	"edit.h"
43da2e3ebdSchin #include	"terminal.h"
44da2e3ebdSchin #include	"FEATURE/time"
45da2e3ebdSchin 
46da2e3ebdSchin #if SHOPT_OLDTERMIO
47da2e3ebdSchin #   undef ECHOCTL
48da2e3ebdSchin #   define echoctl	(vp->ed->e_echoctl)
49da2e3ebdSchin #else
50da2e3ebdSchin #   ifdef ECHOCTL
51da2e3ebdSchin #	define echoctl	ECHOCTL
52da2e3ebdSchin #   else
53da2e3ebdSchin #	define echoctl	0
54da2e3ebdSchin #   endif /* ECHOCTL */
55da2e3ebdSchin #endif /*SHOPT_OLDTERMIO */
56da2e3ebdSchin 
57da2e3ebdSchin #ifndef FIORDCHK
58da2e3ebdSchin #   define NTICKS	5		/* number of ticks for typeahead */
59da2e3ebdSchin #endif /* FIORDCHK */
60da2e3ebdSchin 
61da2e3ebdSchin #define	MAXCHAR	MAXLINE-2		/* max char per line */
62da2e3ebdSchin 
63da2e3ebdSchin #if SHOPT_MULTIBYTE
64da2e3ebdSchin #   include	"lexstates.h"
65da2e3ebdSchin #   define gencpy(a,b)	ed_gencpy(a,b)
66da2e3ebdSchin #   define genncpy(a,b,n)	ed_genncpy(a,b,n)
67da2e3ebdSchin #   define genlen(str)	ed_genlen(str)
68da2e3ebdSchin #   define digit(c)	((c&~STRIP)==0 && isdigit(c))
69da2e3ebdSchin #   define is_print(c)	((c&~STRIP) || isprint(c))
70da2e3ebdSchin #   if !_lib_iswprint && !defined(iswprint)
71da2e3ebdSchin #	define iswprint(c)	((c&~0177) || isprint(c))
72da2e3ebdSchin #   endif
73da2e3ebdSchin     static int _isalph(int);
74da2e3ebdSchin     static int _ismetach(int);
75da2e3ebdSchin     static int _isblank(int);
76da2e3ebdSchin #   undef  isblank
77da2e3ebdSchin #   define isblank(v)	_isblank(virtual[v])
78da2e3ebdSchin #   define isalph(v)	_isalph(virtual[v])
79da2e3ebdSchin #   define ismetach(v)	_ismetach(virtual[v])
80da2e3ebdSchin #else
81da2e3ebdSchin     static genchar	_c;
82da2e3ebdSchin #   define gencpy(a,b)	strcpy((char*)(a),(char*)(b))
83da2e3ebdSchin #   define genncpy(a,b,n) strncpy((char*)(a),(char*)(b),n)
84da2e3ebdSchin #   define genlen(str)	strlen(str)
85da2e3ebdSchin #   define isalph(v)	((_c=virtual[v])=='_'||isalnum(_c))
86da2e3ebdSchin #   undef  isblank
87da2e3ebdSchin #   define isblank(v)	isspace(virtual[v])
88da2e3ebdSchin #   define ismetach(v)	ismeta(virtual[v])
89da2e3ebdSchin #   define digit(c)	isdigit(c)
90da2e3ebdSchin #   define is_print(c)	isprint(c)
91da2e3ebdSchin #endif	/* SHOPT_MULTIBYTE */
92da2e3ebdSchin 
93da2e3ebdSchin #if ( 'a' == 97) /* ASCII? */
94da2e3ebdSchin #   define fold(c)	((c)&~040)	/* lower and uppercase equivalent */
95da2e3ebdSchin #else
96da2e3ebdSchin #   define fold(c)	((c)|0100)	/* lower and uppercase equivalent */
97da2e3ebdSchin #endif
98da2e3ebdSchin 
99da2e3ebdSchin #ifndef iswascii
100da2e3ebdSchin #define iswascii(c)	(!((c)&(~0177)))
101da2e3ebdSchin #endif
102da2e3ebdSchin 
103da2e3ebdSchin typedef struct _vi_
104da2e3ebdSchin {
105da2e3ebdSchin 	int direction;
106da2e3ebdSchin 	int lastmacro;
107da2e3ebdSchin 	char addnl;		/* boolean - add newline flag */
108da2e3ebdSchin 	char last_find;		/* last find command */
109da2e3ebdSchin 	char last_cmd;		/* last command */
110da2e3ebdSchin 	char repeat_set;
111da2e3ebdSchin 	char nonewline;
112da2e3ebdSchin 	int findchar;		/* last find char */
113da2e3ebdSchin 	genchar *lastline;
114da2e3ebdSchin 	int first_wind;		/* first column of window */
115da2e3ebdSchin 	int last_wind;		/* last column in window */
116da2e3ebdSchin 	int lastmotion;		/* last motion */
117da2e3ebdSchin 	int long_char; 		/* line bigger than window */
118da2e3ebdSchin 	int long_line;		/* line bigger than window */
119da2e3ebdSchin 	int ocur_phys;		/* old current physical position */
120da2e3ebdSchin 	int ocur_virt;		/* old last virtual position */
121da2e3ebdSchin 	int ofirst_wind;	/* old window first col */
122da2e3ebdSchin 	int o_v_char;		/* prev virtual[ocur_virt] */
123da2e3ebdSchin 	int repeat;		/* repeat count for motion cmds */
124da2e3ebdSchin 	int lastrepeat;		/* last repeat count for motion cmds */
125da2e3ebdSchin 	int u_column;		/* undo current column */
126da2e3ebdSchin 	int U_saved;		/* original virtual saved */
127da2e3ebdSchin 	genchar *U_space;	/* used for U command */
128da2e3ebdSchin 	genchar *u_space;	/* used for u command */
129da2e3ebdSchin #ifdef FIORDCHK
130da2e3ebdSchin 	clock_t typeahead;	/* typeahead occurred */
131da2e3ebdSchin #else
132da2e3ebdSchin 	int typeahead;		/* typeahead occurred */
133da2e3ebdSchin #endif	/* FIORDCHK */
134da2e3ebdSchin #if SHOPT_MULTIBYTE
135da2e3ebdSchin 	int bigvi;
136da2e3ebdSchin #endif
137da2e3ebdSchin 	Edit_t	*ed;		/* pointer to edit data */
138da2e3ebdSchin } Vi_t;
139da2e3ebdSchin 
140da2e3ebdSchin #define editb	(*vp->ed)
141da2e3ebdSchin 
142da2e3ebdSchin #undef putchar
143da2e3ebdSchin #define putchar(c)	ed_putchar(vp->ed,c)
144da2e3ebdSchin 
145da2e3ebdSchin #define crallowed	editb.e_crlf
146da2e3ebdSchin #define cur_virt	editb.e_cur		/* current virtual column */
147da2e3ebdSchin #define cur_phys	editb.e_pcur	/* current phys column cursor is at */
148da2e3ebdSchin #define curhline	editb.e_hline		/* current history line */
149da2e3ebdSchin #define first_virt	editb.e_fcol		/* first allowable column */
150da2e3ebdSchin #define	globals		editb.e_globals		/* local global variables */
151da2e3ebdSchin #define histmin		editb.e_hismin
152da2e3ebdSchin #define histmax		editb.e_hismax
153da2e3ebdSchin #define last_phys	editb.e_peol		/* last column in physical */
154da2e3ebdSchin #define last_virt	editb.e_eol		/* last column */
155da2e3ebdSchin #define lsearch		editb.e_search		/* last search string */
156da2e3ebdSchin #define lookahead	editb.e_lookahead	/* characters in buffer */
157da2e3ebdSchin #define previous	editb.e_lbuf		/* lookahead buffer */
158da2e3ebdSchin #define max_col		editb.e_llimit		/* maximum column */
159da2e3ebdSchin #define Prompt		editb.e_prompt		/* pointer to prompt */
160da2e3ebdSchin #define plen		editb.e_plen		/* length of prompt */
161da2e3ebdSchin #define physical	editb.e_physbuf		/* physical image */
162da2e3ebdSchin #define usreof		editb.e_eof		/* user defined eof char */
163da2e3ebdSchin #define usrerase	editb.e_erase		/* user defined erase char */
164da2e3ebdSchin #define usrlnext	editb.e_lnext		/* user defined next literal */
165da2e3ebdSchin #define usrkill		editb.e_kill		/* user defined kill char */
166da2e3ebdSchin #define virtual		editb.e_inbuf	/* pointer to virtual image buffer */
167da2e3ebdSchin #define	window		editb.e_window		/* window buffer */
168da2e3ebdSchin #define	w_size		editb.e_wsize		/* window size */
169da2e3ebdSchin #define	inmacro		editb.e_inmacro		/* true when in macro */
170da2e3ebdSchin #define yankbuf		editb.e_killbuf		/* yank/delete buffer */
171da2e3ebdSchin 
172da2e3ebdSchin 
173da2e3ebdSchin #define	ABORT	-2			/* user abort */
174da2e3ebdSchin #define	APPEND	-10			/* append chars */
175da2e3ebdSchin #define	BAD	-1			/* failure flag */
176da2e3ebdSchin #define	BIGVI	-15			/* user wants real vi */
177da2e3ebdSchin #define	CONTROL	-20			/* control mode */
178da2e3ebdSchin #define	ENTER	-25			/* enter flag */
179da2e3ebdSchin #define	GOOD	0			/* success flag */
180da2e3ebdSchin #define	INPUT	-30			/* input mode */
181da2e3ebdSchin #define	INSERT	-35			/* insert mode */
182da2e3ebdSchin #define	REPLACE	-40			/* replace chars */
183da2e3ebdSchin #define	SEARCH	-45			/* search flag */
184da2e3ebdSchin #define	TRANSLATE	-50		/* translate virt to phys only */
185da2e3ebdSchin 
186da2e3ebdSchin #define	INVALID	(-1)			/* invalid column */
187da2e3ebdSchin 
188da2e3ebdSchin static const char paren_chars[] = "([{)]}";   /* for % command */
189da2e3ebdSchin 
190da2e3ebdSchin static void	cursor(Vi_t*, int);
191da2e3ebdSchin static void	del_line(Vi_t*,int);
192da2e3ebdSchin static int	getcount(Vi_t*,int);
193da2e3ebdSchin static void	getline(Vi_t*,int);
194da2e3ebdSchin static int	getrchar(Vi_t*);
195da2e3ebdSchin static int	mvcursor(Vi_t*,int);
196da2e3ebdSchin static void	pr_string(Vi_t*,const char*);
197da2e3ebdSchin static void	putstring(Vi_t*,int, int);
198da2e3ebdSchin static void	refresh(Vi_t*,int);
199da2e3ebdSchin static void	replace(Vi_t*,int, int);
200da2e3ebdSchin static void	restore_v(Vi_t*);
201da2e3ebdSchin static void	save_last(Vi_t*);
202da2e3ebdSchin static void	save_v(Vi_t*);
203da2e3ebdSchin static int	search(Vi_t*,int);
204da2e3ebdSchin static void	sync_cursor(Vi_t*);
205da2e3ebdSchin static int	textmod(Vi_t*,int,int);
206da2e3ebdSchin 
207da2e3ebdSchin /*+	VI_READ( fd, shbuf, nchar )
208da2e3ebdSchin  *
209da2e3ebdSchin  *	This routine implements a one line version of vi and is
210da2e3ebdSchin  * called by _filbuf.c
211da2e3ebdSchin  *
212da2e3ebdSchin -*/
213da2e3ebdSchin 
214da2e3ebdSchin /*
215da2e3ebdSchin  * if reedit is non-zero, initialize edit buffer with reedit chars
216da2e3ebdSchin  */
ed_viread(void * context,int fd,register char * shbuf,int nchar,int reedit)217da2e3ebdSchin int ed_viread(void *context, int fd, register char *shbuf, int nchar, int reedit)
218da2e3ebdSchin {
219da2e3ebdSchin 	Edit_t *ed = (Edit_t*)context;
220da2e3ebdSchin 	register int i;			/* general variable */
221da2e3ebdSchin 	register int term_char;		/* read() termination character */
222da2e3ebdSchin 	register Vi_t *vp = ed->e_vi;
223da2e3ebdSchin 	char prompt[PRSIZE+2];		/* prompt */
224da2e3ebdSchin 	genchar Physical[2*MAXLINE];	/* physical image */
225da2e3ebdSchin 	genchar Ubuf[MAXLINE];	/* used for U command */
226da2e3ebdSchin 	genchar ubuf[MAXLINE];	/* used for u command */
227da2e3ebdSchin 	genchar Window[MAXLINE];	/* window image */
228da2e3ebdSchin 	int Globals[9];			/* local global variables */
229da2e3ebdSchin 	int esc_or_hang=0;		/* <ESC> or hangup */
230da2e3ebdSchin 	char cntl_char=0;		/* TRUE if control character present */
231da2e3ebdSchin #if SHOPT_RAWONLY
232da2e3ebdSchin #   define viraw	1
233da2e3ebdSchin #else
234da2e3ebdSchin 	int viraw = (sh_isoption(SH_VIRAW) || sh.st.trap[SH_KEYTRAP]);
235da2e3ebdSchin #   ifndef FIORDCHK
236da2e3ebdSchin 	clock_t oldtime, newtime;
237da2e3ebdSchin 	struct tms dummy;
238da2e3ebdSchin #   endif /* FIORDCHK */
239da2e3ebdSchin #endif /* SHOPT_RAWONLY */
240da2e3ebdSchin 	if(!vp)
241da2e3ebdSchin 	{
242da2e3ebdSchin 		ed->e_vi = vp =  newof(0,Vi_t,1,0);
243da2e3ebdSchin 		vp->lastline = (genchar*)malloc(MAXLINE*CHARSIZE);
244da2e3ebdSchin 		vp->direction = -1;
245da2e3ebdSchin 		vp->ed = ed;
246da2e3ebdSchin 	}
247da2e3ebdSchin 
248da2e3ebdSchin 	/*** setup prompt ***/
249da2e3ebdSchin 
250da2e3ebdSchin 	Prompt = prompt;
251da2e3ebdSchin 	ed_setup(vp->ed,fd, reedit);
252da2e3ebdSchin 	shbuf[reedit] = 0;
253da2e3ebdSchin 
254da2e3ebdSchin #if !SHOPT_RAWONLY
255da2e3ebdSchin 	if(!viraw)
256da2e3ebdSchin 	{
257da2e3ebdSchin 		/*** Change the eol characters to '\r' and eof  ***/
258da2e3ebdSchin 		/* in addition to '\n' and make eof an ESC	*/
259da2e3ebdSchin 		if(tty_alt(ERRIO) < 0)
260da2e3ebdSchin 			return(reexit?reedit:ed_read(context, fd, shbuf, nchar,0));
261da2e3ebdSchin 
262da2e3ebdSchin #ifdef FIORDCHK
263da2e3ebdSchin 		ioctl(fd,FIORDCHK,&vp->typeahead);
264da2e3ebdSchin #else
265da2e3ebdSchin 		/* time the current line to determine typeahead */
266da2e3ebdSchin 		oldtime = times(&dummy);
267da2e3ebdSchin #endif /* FIORDCHK */
268da2e3ebdSchin #if KSHELL
269da2e3ebdSchin 		/* abort of interrupt has occurred */
270da2e3ebdSchin 		if(sh.trapnote&SH_SIGSET)
271da2e3ebdSchin 			i = -1;
272da2e3ebdSchin 		else
273da2e3ebdSchin #endif /* KSHELL */
274da2e3ebdSchin 		/*** Read the line ***/
275da2e3ebdSchin 		i = ed_read(context, fd, shbuf, nchar, 0);
276da2e3ebdSchin #ifndef FIORDCHK
277da2e3ebdSchin 		newtime = times(&dummy);
278da2e3ebdSchin 		vp->typeahead = ((newtime-oldtime) < NTICKS);
279da2e3ebdSchin #endif /* FIORDCHK */
280da2e3ebdSchin 	    if(echoctl)
281da2e3ebdSchin 	    {
282da2e3ebdSchin 		if( i <= 0 )
283da2e3ebdSchin 		{
284da2e3ebdSchin 			/*** read error or eof typed ***/
285da2e3ebdSchin 			tty_cooked(ERRIO);
286da2e3ebdSchin 			return(i);
287da2e3ebdSchin 		}
288da2e3ebdSchin 		term_char = shbuf[--i];
289da2e3ebdSchin 		if( term_char == '\r' )
290da2e3ebdSchin 			term_char = '\n';
291da2e3ebdSchin 		if( term_char=='\n' || term_char==ESC )
292da2e3ebdSchin 			shbuf[i--] = '\0';
293da2e3ebdSchin 		else
294da2e3ebdSchin 			shbuf[i+1] = '\0';
295da2e3ebdSchin 	    }
296da2e3ebdSchin 	    else
297da2e3ebdSchin 	    {
298da2e3ebdSchin 		register int c = shbuf[0];
299da2e3ebdSchin 
300da2e3ebdSchin 		/*** Save and remove the last character if its an eol, ***/
301da2e3ebdSchin 		/* changing '\r' to '\n' */
302da2e3ebdSchin 
303da2e3ebdSchin 		if( i == 0 )
304da2e3ebdSchin 		{
305da2e3ebdSchin 			/*** ESC was typed as first char of line ***/
306da2e3ebdSchin 			esc_or_hang = 1;
307da2e3ebdSchin 			term_char = ESC;
308da2e3ebdSchin 			shbuf[i--] = '\0';	/* null terminate line */
309da2e3ebdSchin 		}
310da2e3ebdSchin 		else if( i<0 || c==usreof )
311da2e3ebdSchin 		{
312da2e3ebdSchin 			/*** read error or eof typed ***/
313da2e3ebdSchin 			tty_cooked(ERRIO);
314da2e3ebdSchin 			if( c == usreof )
315da2e3ebdSchin 				i = 0;
316da2e3ebdSchin 			return(i);
317da2e3ebdSchin 		}
318da2e3ebdSchin 		else
319da2e3ebdSchin 		{
320da2e3ebdSchin 			term_char = shbuf[--i];
321da2e3ebdSchin 			if( term_char == '\r' )
322da2e3ebdSchin 				term_char = '\n';
323da2e3ebdSchin #if !defined(VEOL2) && !defined(ECHOCTL)
324da2e3ebdSchin 			if(term_char=='\n')
325da2e3ebdSchin 			{
326da2e3ebdSchin 				tty_cooked(ERRIO);
327da2e3ebdSchin 				return(i+1);
328da2e3ebdSchin 			}
329da2e3ebdSchin #endif
330da2e3ebdSchin 			if( term_char=='\n' || term_char==usreof )
331da2e3ebdSchin 			{
332da2e3ebdSchin 				/*** remove terminator & null terminate ***/
333da2e3ebdSchin 				shbuf[i--] = '\0';
334da2e3ebdSchin 			}
335da2e3ebdSchin 			else
336da2e3ebdSchin 			{
337da2e3ebdSchin 				/** terminator was ESC, which is not xmitted **/
338da2e3ebdSchin 				term_char = ESC;
339da2e3ebdSchin 				shbuf[i+1] = '\0';
340da2e3ebdSchin 			}
341da2e3ebdSchin 		}
342da2e3ebdSchin 	    }
343da2e3ebdSchin 	}
344da2e3ebdSchin 	else
345da2e3ebdSchin #endif /* SHOPT_RAWONLY */
346da2e3ebdSchin 	{
347da2e3ebdSchin 		/*** Set raw mode ***/
348da2e3ebdSchin 
349da2e3ebdSchin #if !SHOPT_RAWONLY
350da2e3ebdSchin 		if( editb.e_ttyspeed == 0 )
351da2e3ebdSchin 		{
352da2e3ebdSchin 			/*** never did TCGETA, so do it ***/
353da2e3ebdSchin 			/* avoids problem if user does 'sh -o viraw' */
354da2e3ebdSchin 			tty_alt(ERRIO);
355da2e3ebdSchin 		}
356da2e3ebdSchin #endif /* SHOPT_RAWONLY */
357da2e3ebdSchin 		if(tty_raw(ERRIO,0) < 0 )
358da2e3ebdSchin 			return(reedit?reedit:ed_read(context, fd, shbuf, nchar,0));
359da2e3ebdSchin 		i = last_virt-1;
360da2e3ebdSchin 	}
361da2e3ebdSchin 
362da2e3ebdSchin 	/*** Initialize some things ***/
363da2e3ebdSchin 
364da2e3ebdSchin 	virtual = (genchar*)shbuf;
365da2e3ebdSchin #if SHOPT_MULTIBYTE
366da2e3ebdSchin 	virtual = (genchar*)roundof((char*)virtual-(char*)0,sizeof(genchar));
367da2e3ebdSchin 	shbuf[i+1] = 0;
368da2e3ebdSchin 	i = ed_internal(shbuf,virtual)-1;
369da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
370da2e3ebdSchin 	globals = Globals;
371da2e3ebdSchin 	cur_phys = i + 1;
372da2e3ebdSchin 	cur_virt = i;
373da2e3ebdSchin 	first_virt = 0;
374da2e3ebdSchin 	vp->first_wind = 0;
375da2e3ebdSchin 	last_virt = i;
376da2e3ebdSchin 	last_phys = i;
377da2e3ebdSchin 	vp->last_wind = i;
378da2e3ebdSchin 	vp->long_line = ' ';
379da2e3ebdSchin 	vp->long_char = ' ';
380da2e3ebdSchin 	vp->o_v_char = '\0';
381da2e3ebdSchin 	vp->ocur_phys = 0;
382da2e3ebdSchin 	vp->ocur_virt = MAXCHAR;
383da2e3ebdSchin 	vp->ofirst_wind = 0;
384da2e3ebdSchin 	physical = Physical;
385da2e3ebdSchin 	vp->u_column = INVALID - 1;
386da2e3ebdSchin 	vp->U_space = Ubuf;
387da2e3ebdSchin 	vp->u_space = ubuf;
388da2e3ebdSchin 	window = Window;
389da2e3ebdSchin 	window[0] = '\0';
390da2e3ebdSchin 
391da2e3ebdSchin 	if(!yankbuf)
392da2e3ebdSchin 		yankbuf = (genchar*)malloc(MAXLINE*CHARSIZE);
393da2e3ebdSchin 	if( vp->last_cmd == '\0' )
394da2e3ebdSchin 	{
395da2e3ebdSchin 		/*** first time for this shell ***/
396da2e3ebdSchin 
397da2e3ebdSchin 		vp->last_cmd = 'i';
398da2e3ebdSchin 		vp->findchar = INVALID;
399da2e3ebdSchin 		vp->lastmotion = '\0';
400da2e3ebdSchin 		vp->lastrepeat = 1;
401da2e3ebdSchin 		vp->repeat = 1;
402da2e3ebdSchin 		*yankbuf = 0;
403da2e3ebdSchin 	}
404da2e3ebdSchin 
405da2e3ebdSchin 	/*** fiddle around with prompt length ***/
406da2e3ebdSchin 	if( nchar+plen > MAXCHAR )
407da2e3ebdSchin 		nchar = MAXCHAR - plen;
408da2e3ebdSchin 	max_col = nchar - 2;
409da2e3ebdSchin 
410da2e3ebdSchin 	if( !viraw )
411da2e3ebdSchin 	{
412da2e3ebdSchin 		int kill_erase = 0;
413da2e3ebdSchin 		for(i=(echoctl?last_virt:0); i<last_virt; ++i )
414da2e3ebdSchin 		{
415da2e3ebdSchin 			/*** change \r to \n, check for control characters, ***/
416da2e3ebdSchin 			/* delete appropriate ^Vs,			*/
417da2e3ebdSchin 			/* and estimate last physical column */
418da2e3ebdSchin 
419da2e3ebdSchin 			if( virtual[i] == '\r' )
420da2e3ebdSchin 				virtual[i] = '\n';
421da2e3ebdSchin 		    if(!echoctl)
422da2e3ebdSchin 		    {
423da2e3ebdSchin 			register int c = virtual[i];
424da2e3ebdSchin 			if( c<=usrerase)
425da2e3ebdSchin 			{
426da2e3ebdSchin 				/*** user typed escaped erase or kill char ***/
427da2e3ebdSchin 				cntl_char = 1;
428da2e3ebdSchin 				if(is_print(c))
429da2e3ebdSchin 					kill_erase++;
430da2e3ebdSchin 			}
431da2e3ebdSchin 			else if( !is_print(c) )
432da2e3ebdSchin 			{
433da2e3ebdSchin 				cntl_char = 1;
434da2e3ebdSchin 
435da2e3ebdSchin 				if( c == usrlnext )
436da2e3ebdSchin 				{
437da2e3ebdSchin 					if( i == last_virt )
438da2e3ebdSchin 					{
439da2e3ebdSchin 						/*** eol/eof was escaped ***/
440da2e3ebdSchin 						/* so replace ^V with it */
441da2e3ebdSchin 						virtual[i] = term_char;
442da2e3ebdSchin 						break;
443da2e3ebdSchin 					}
444da2e3ebdSchin 
445da2e3ebdSchin 					/*** delete ^V ***/
446da2e3ebdSchin 					gencpy((&virtual[i]), (&virtual[i+1]));
447da2e3ebdSchin 					--cur_virt;
448da2e3ebdSchin 					--last_virt;
449da2e3ebdSchin 				}
450da2e3ebdSchin 			}
451da2e3ebdSchin 		    }
452da2e3ebdSchin 		}
453da2e3ebdSchin 
454da2e3ebdSchin 		/*** copy virtual image to window ***/
455da2e3ebdSchin 		if(last_virt > 0)
456da2e3ebdSchin 			last_phys = ed_virt_to_phys(vp->ed,virtual,physical,last_virt,0,0);
457da2e3ebdSchin 		if( last_phys >= w_size )
458da2e3ebdSchin 		{
459da2e3ebdSchin 			/*** line longer than window ***/
460da2e3ebdSchin 			vp->last_wind = w_size - 1;
461da2e3ebdSchin 		}
462da2e3ebdSchin 		else
463da2e3ebdSchin 			vp->last_wind = last_phys;
464da2e3ebdSchin 		genncpy(window, virtual, vp->last_wind+1);
465da2e3ebdSchin 
466da2e3ebdSchin 		if( term_char!=ESC  && (last_virt==INVALID
467da2e3ebdSchin 			|| virtual[last_virt]!=term_char) )
468da2e3ebdSchin 		{
469da2e3ebdSchin 			/*** Line not terminated with ESC or escaped (^V) ***/
470da2e3ebdSchin 			/* eol, so return after doing a total update */
471da2e3ebdSchin 			/* if( (speed is greater or equal to 1200 */
472da2e3ebdSchin 			/* and something was typed) and */
473da2e3ebdSchin 			/* (control character present */
474da2e3ebdSchin 			/* or typeahead occurred) ) */
475da2e3ebdSchin 
476da2e3ebdSchin 			tty_cooked(ERRIO);
477da2e3ebdSchin 			if( editb.e_ttyspeed==FAST && last_virt!=INVALID
478da2e3ebdSchin 				&& (vp->typeahead || cntl_char) )
479da2e3ebdSchin 			{
480da2e3ebdSchin 				refresh(vp,TRANSLATE);
481da2e3ebdSchin 				pr_string(vp,Prompt);
482da2e3ebdSchin 				putstring(vp,0, last_phys+1);
483da2e3ebdSchin 				if(echoctl)
484da2e3ebdSchin 					ed_crlf(vp->ed);
485da2e3ebdSchin 				else
486da2e3ebdSchin 					while(kill_erase-- > 0)
487da2e3ebdSchin 						putchar(' ');
488da2e3ebdSchin 			}
489da2e3ebdSchin 
490da2e3ebdSchin 			if( term_char=='\n' )
491da2e3ebdSchin 			{
492da2e3ebdSchin 				if(!echoctl)
493da2e3ebdSchin 					ed_crlf(vp->ed);
494da2e3ebdSchin 				virtual[++last_virt] = '\n';
495da2e3ebdSchin 			}
496da2e3ebdSchin 			vp->last_cmd = 'i';
497da2e3ebdSchin 			save_last(vp);
498da2e3ebdSchin #if SHOPT_MULTIBYTE
499da2e3ebdSchin 			virtual[last_virt+1] = 0;
500da2e3ebdSchin 			last_virt = ed_external(virtual,shbuf);
501da2e3ebdSchin 			return(last_virt);
502da2e3ebdSchin #else
503da2e3ebdSchin 			return(++last_virt);
504da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
505da2e3ebdSchin 		}
506da2e3ebdSchin 
507da2e3ebdSchin 		/*** Line terminated with escape, or escaped eol/eof, ***/
508da2e3ebdSchin 		/*  so set raw mode */
509da2e3ebdSchin 
510da2e3ebdSchin 		if( tty_raw(ERRIO,0) < 0 )
511da2e3ebdSchin 		{
512da2e3ebdSchin 			tty_cooked(ERRIO);
513da2e3ebdSchin 			/*
514da2e3ebdSchin 			 * The following prevents drivers that return 0 on
515da2e3ebdSchin 			 * causing an infinite loop
516da2e3ebdSchin 			 */
517da2e3ebdSchin 			if(esc_or_hang)
518da2e3ebdSchin 				return(-1);
519da2e3ebdSchin 			virtual[++last_virt] = '\n';
520da2e3ebdSchin #if SHOPT_MULTIBYTE
521da2e3ebdSchin 			virtual[last_virt+1] = 0;
522da2e3ebdSchin 			last_virt = ed_external(virtual,shbuf);
523da2e3ebdSchin 			return(last_virt);
524da2e3ebdSchin #else
525da2e3ebdSchin 			return(++last_virt);
526da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
527da2e3ebdSchin 		}
528da2e3ebdSchin 
529da2e3ebdSchin 		if(echoctl) /*** for cntl-echo erase the ^[ ***/
530da2e3ebdSchin 			pr_string(vp,"\b\b\b\b      \b\b");
531da2e3ebdSchin 
532da2e3ebdSchin 
533da2e3ebdSchin 		if(crallowed)
534da2e3ebdSchin 		{
535da2e3ebdSchin 			/*** start over since there may be ***/
536da2e3ebdSchin 			/*** a control char, or cursor might not ***/
537da2e3ebdSchin 			/*** be at left margin (this lets us know ***/
538da2e3ebdSchin 			/*** where we are ***/
539da2e3ebdSchin 			cur_phys = 0;
540da2e3ebdSchin 			window[0] = '\0';
541da2e3ebdSchin 			pr_string(vp,Prompt);
542da2e3ebdSchin 			if( term_char==ESC && (last_virt<0 || virtual[last_virt]!=ESC))
543da2e3ebdSchin 				refresh(vp,CONTROL);
544da2e3ebdSchin 			else
545da2e3ebdSchin 				refresh(vp,INPUT);
546da2e3ebdSchin 		}
547da2e3ebdSchin 		else
548da2e3ebdSchin 		{
549da2e3ebdSchin 			/*** just update everything internally ***/
550da2e3ebdSchin 			refresh(vp,TRANSLATE);
551da2e3ebdSchin 		}
552da2e3ebdSchin 	}
553da2e3ebdSchin 
554da2e3ebdSchin 	/*** Handle usrintr, usrquit, or EOF ***/
555da2e3ebdSchin 
556da2e3ebdSchin 	i = sigsetjmp(editb.e_env,0);
557da2e3ebdSchin 	if( i != 0 )
558da2e3ebdSchin 	{
5597c2fbfb3SApril Chin 		if(vp->ed->e_multiline)
5607c2fbfb3SApril Chin 		{
5617c2fbfb3SApril Chin 			cur_virt = last_virt;
5627c2fbfb3SApril Chin 			sync_cursor(vp);
5637c2fbfb3SApril Chin 		}
564da2e3ebdSchin 		virtual[0] = '\0';
565da2e3ebdSchin 		tty_cooked(ERRIO);
566da2e3ebdSchin 
567da2e3ebdSchin 		switch(i)
568da2e3ebdSchin 		{
569da2e3ebdSchin 		case UEOF:
570da2e3ebdSchin 			/*** EOF ***/
571da2e3ebdSchin 			return(0);
572da2e3ebdSchin 
573da2e3ebdSchin 		case UINTR:
574da2e3ebdSchin 			/** interrupt **/
575da2e3ebdSchin 			return(-1);
576da2e3ebdSchin 		}
577da2e3ebdSchin 		return(-1);
578da2e3ebdSchin 	}
579da2e3ebdSchin 
580da2e3ebdSchin 	/*** Get a line from the terminal ***/
581da2e3ebdSchin 
582da2e3ebdSchin 	vp->U_saved = 0;
583da2e3ebdSchin 	if(reedit)
58434f9b3eeSRoland Mainz 	{
58534f9b3eeSRoland Mainz 		cur_phys = vp->first_wind;
58634f9b3eeSRoland Mainz 		vp->ofirst_wind = INVALID;
587da2e3ebdSchin 		refresh(vp,INPUT);
58834f9b3eeSRoland Mainz 	}
589da2e3ebdSchin 	if(viraw)
590da2e3ebdSchin 		getline(vp,APPEND);
591da2e3ebdSchin 	else if(last_virt>=0 && virtual[last_virt]==term_char)
592da2e3ebdSchin 		getline(vp,APPEND);
593da2e3ebdSchin 	else
594da2e3ebdSchin 		getline(vp,ESC);
595da2e3ebdSchin 	if(vp->ed->e_multiline)
596da2e3ebdSchin 		cursor(vp, last_phys);
597da2e3ebdSchin 	/*** add a new line if user typed unescaped \n ***/
598da2e3ebdSchin 	/* to cause the shell to process the line */
599da2e3ebdSchin 	tty_cooked(ERRIO);
600da2e3ebdSchin 	if(ed->e_nlist)
601da2e3ebdSchin 	{
602da2e3ebdSchin 		ed->e_nlist = 0;
603da2e3ebdSchin 		stakset(ed->e_stkptr,ed->e_stkoff);
604da2e3ebdSchin 	}
605da2e3ebdSchin 	if( vp->addnl )
606da2e3ebdSchin 	{
607da2e3ebdSchin 		virtual[++last_virt] = '\n';
608da2e3ebdSchin 		ed_crlf(vp->ed);
609da2e3ebdSchin 	}
610da2e3ebdSchin 	if( ++last_virt >= 0 )
611da2e3ebdSchin 	{
612da2e3ebdSchin #if SHOPT_MULTIBYTE
613da2e3ebdSchin 		if(vp->bigvi)
614da2e3ebdSchin 		{
615da2e3ebdSchin 			vp->bigvi = 0;
616da2e3ebdSchin 			shbuf[last_virt-1] = '\n';
617da2e3ebdSchin 		}
618da2e3ebdSchin 		else
619da2e3ebdSchin 		{
620da2e3ebdSchin 			virtual[last_virt] = 0;
621da2e3ebdSchin 			last_virt = ed_external(virtual,shbuf);
622da2e3ebdSchin 		}
623da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
624da2e3ebdSchin 		return(last_virt);
625da2e3ebdSchin 	}
626da2e3ebdSchin 	else
627da2e3ebdSchin 		return(-1);
628da2e3ebdSchin }
629da2e3ebdSchin 
630da2e3ebdSchin 
631da2e3ebdSchin /*{	APPEND( char, mode )
632da2e3ebdSchin  *
633da2e3ebdSchin  *	This routine will append char after cur_virt in the virtual image.
634da2e3ebdSchin  * mode	=	APPEND, shift chars right before appending
635da2e3ebdSchin  *		REPLACE, replace char if possible
636da2e3ebdSchin  *
637da2e3ebdSchin }*/
638da2e3ebdSchin 
append(Vi_t * vp,int c,int mode)639da2e3ebdSchin static void append(Vi_t *vp,int c, int mode)
640da2e3ebdSchin {
641da2e3ebdSchin 	register int i,j;
642da2e3ebdSchin 
643da2e3ebdSchin 	if( last_virt<max_col && last_phys<max_col )
644da2e3ebdSchin 	{
645da2e3ebdSchin 		if( mode==APPEND || (cur_virt==last_virt  && last_virt>=0))
646da2e3ebdSchin 		{
647da2e3ebdSchin 			j = (cur_virt>=0?cur_virt:0);
648da2e3ebdSchin 			for(i = ++last_virt;  i > j; --i)
649da2e3ebdSchin 				virtual[i] = virtual[i-1];
650da2e3ebdSchin 		}
651da2e3ebdSchin 		virtual[++cur_virt] = c;
652da2e3ebdSchin 	}
653da2e3ebdSchin 	else
654da2e3ebdSchin 		ed_ringbell();
655da2e3ebdSchin 	return;
656da2e3ebdSchin }
657da2e3ebdSchin 
658da2e3ebdSchin /*{	BACKWORD( nwords, cmd )
659da2e3ebdSchin  *
660da2e3ebdSchin  *	This routine will position cur_virt at the nth previous word.
661da2e3ebdSchin  *
662da2e3ebdSchin }*/
663da2e3ebdSchin 
backword(Vi_t * vp,int nwords,register int cmd)664da2e3ebdSchin static void backword(Vi_t *vp,int nwords, register int cmd)
665da2e3ebdSchin {
666da2e3ebdSchin 	register int tcur_virt = cur_virt;
667da2e3ebdSchin 	while( nwords-- && tcur_virt > first_virt )
668da2e3ebdSchin 	{
669da2e3ebdSchin 		if( !isblank(tcur_virt) && isblank(tcur_virt-1)
670da2e3ebdSchin 			&& tcur_virt>first_virt )
671da2e3ebdSchin 			--tcur_virt;
672da2e3ebdSchin 		else if(cmd != 'B')
673da2e3ebdSchin 		{
674da2e3ebdSchin 			register int last = isalph(tcur_virt-1);
675da2e3ebdSchin 			register int cur = isalph(tcur_virt);
676da2e3ebdSchin 			if((!cur && last) || (cur && !last))
677da2e3ebdSchin 				--tcur_virt;
678da2e3ebdSchin 		}
679da2e3ebdSchin 		while( isblank(tcur_virt) && tcur_virt>=first_virt )
680da2e3ebdSchin 			--tcur_virt;
681da2e3ebdSchin 		if( cmd == 'B' )
682da2e3ebdSchin 		{
683da2e3ebdSchin 			while( !isblank(tcur_virt) && tcur_virt>=first_virt )
684da2e3ebdSchin 				--tcur_virt;
685da2e3ebdSchin 		}
686da2e3ebdSchin 		else
687da2e3ebdSchin 		{
688da2e3ebdSchin 			if(isalph(tcur_virt))
689da2e3ebdSchin 				while( isalph(tcur_virt) && tcur_virt>=first_virt )
690da2e3ebdSchin 					--tcur_virt;
691da2e3ebdSchin 			else
692da2e3ebdSchin 				while( !isalph(tcur_virt) && !isblank(tcur_virt)
693da2e3ebdSchin 					&& tcur_virt>=first_virt )
694da2e3ebdSchin 					--tcur_virt;
695da2e3ebdSchin 		}
696da2e3ebdSchin 		cur_virt = ++tcur_virt;
697da2e3ebdSchin 	}
698da2e3ebdSchin 	return;
699da2e3ebdSchin }
700da2e3ebdSchin 
701da2e3ebdSchin /*{	CNTLMODE()
702da2e3ebdSchin  *
703da2e3ebdSchin  *	This routine implements the vi command subset.
704da2e3ebdSchin  *	The cursor will always be positioned at the char of interest.
705da2e3ebdSchin  *
706da2e3ebdSchin }*/
707da2e3ebdSchin 
cntlmode(Vi_t * vp)708da2e3ebdSchin static int cntlmode(Vi_t *vp)
709da2e3ebdSchin {
710da2e3ebdSchin 	register int c;
711da2e3ebdSchin 	register int i;
712da2e3ebdSchin 	genchar tmp_u_space[MAXLINE];	/* temporary u_space */
713da2e3ebdSchin 	genchar *real_u_space;		/* points to real u_space */
714da2e3ebdSchin 	int tmp_u_column = INVALID;	/* temporary u_column */
715da2e3ebdSchin 	int was_inmacro;
716da2e3ebdSchin 
717da2e3ebdSchin 	if(!vp->U_saved)
718da2e3ebdSchin 	{
719da2e3ebdSchin 		/*** save virtual image if never done before ***/
720da2e3ebdSchin 		virtual[last_virt+1] = '\0';
721da2e3ebdSchin 		gencpy(vp->U_space, virtual);
722da2e3ebdSchin 		vp->U_saved = 1;
723da2e3ebdSchin 	}
724da2e3ebdSchin 
725da2e3ebdSchin 	save_last(vp);
726da2e3ebdSchin 
727da2e3ebdSchin 	real_u_space = vp->u_space;
728da2e3ebdSchin 	curhline = histmax;
729da2e3ebdSchin 	first_virt = 0;
730da2e3ebdSchin 	vp->repeat = 1;
731da2e3ebdSchin 	if( cur_virt > INVALID )
732da2e3ebdSchin 	{
733da2e3ebdSchin 		/*** make sure cursor is at the last char ***/
734da2e3ebdSchin 		sync_cursor(vp);
735da2e3ebdSchin 	}
736da2e3ebdSchin 
737da2e3ebdSchin 	/*** Read control char until something happens to cause a ***/
738da2e3ebdSchin 	/* return to APPEND/REPLACE mode	*/
739da2e3ebdSchin 
740da2e3ebdSchin 	while( c=ed_getchar(vp->ed,-1) )
741da2e3ebdSchin 	{
742da2e3ebdSchin 		vp->repeat_set = 0;
743da2e3ebdSchin 		was_inmacro = inmacro;
744da2e3ebdSchin 		if( c == '0' )
745da2e3ebdSchin 		{
746da2e3ebdSchin 			/*** move to leftmost column ***/
747da2e3ebdSchin 			cur_virt = 0;
748da2e3ebdSchin 			sync_cursor(vp);
749da2e3ebdSchin 			continue;
750da2e3ebdSchin 		}
751da2e3ebdSchin 
752da2e3ebdSchin 		if( digit(c) )
753da2e3ebdSchin 		{
754da2e3ebdSchin 			c = getcount(vp,c);
755da2e3ebdSchin 			if( c == '.' )
756da2e3ebdSchin 				vp->lastrepeat = vp->repeat;
757da2e3ebdSchin 		}
758da2e3ebdSchin 
759da2e3ebdSchin 		/*** see if it's a move cursor command ***/
760da2e3ebdSchin 
761da2e3ebdSchin 		if(mvcursor(vp,c))
762da2e3ebdSchin 		{
763da2e3ebdSchin 			sync_cursor(vp);
764da2e3ebdSchin 			vp->repeat = 1;
765da2e3ebdSchin 			continue;
766da2e3ebdSchin 		}
767da2e3ebdSchin 
768da2e3ebdSchin 		/*** see if it's a repeat of the last command ***/
769da2e3ebdSchin 
770da2e3ebdSchin 		if( c == '.' )
771da2e3ebdSchin 		{
772da2e3ebdSchin 			c = vp->last_cmd;
773da2e3ebdSchin 			vp->repeat = vp->lastrepeat;
774da2e3ebdSchin 			i = textmod(vp,c, c);
775da2e3ebdSchin 		}
776da2e3ebdSchin 		else
777da2e3ebdSchin 		{
778da2e3ebdSchin 			i = textmod(vp,c, 0);
779da2e3ebdSchin 		}
780da2e3ebdSchin 
781da2e3ebdSchin 		/*** see if it's a text modification command ***/
782da2e3ebdSchin 
783da2e3ebdSchin 		switch(i)
784da2e3ebdSchin 		{
785da2e3ebdSchin 		case BAD:
786da2e3ebdSchin 			break;
787da2e3ebdSchin 
788da2e3ebdSchin 		default:		/** input mode **/
789da2e3ebdSchin 			if(!was_inmacro)
790da2e3ebdSchin 			{
791da2e3ebdSchin 				vp->last_cmd = c;
792da2e3ebdSchin 				vp->lastrepeat = vp->repeat;
793da2e3ebdSchin 			}
794da2e3ebdSchin 			vp->repeat = 1;
795da2e3ebdSchin 			if( i == GOOD )
796da2e3ebdSchin 				continue;
797da2e3ebdSchin 			return(i);
798da2e3ebdSchin 		}
799da2e3ebdSchin 
800da2e3ebdSchin 		switch( c )
801da2e3ebdSchin 		{
802da2e3ebdSchin 			/***** Other stuff *****/
803da2e3ebdSchin 
804da2e3ebdSchin 		case cntl('L'):		/** Redraw line **/
805da2e3ebdSchin 			/*** print the prompt and ***/
806da2e3ebdSchin 			/* force a total refresh */
8077c2fbfb3SApril Chin 			if(vp->nonewline==0 && !vp->ed->e_nocrnl)
808da2e3ebdSchin 				putchar('\n');
809da2e3ebdSchin 			vp->nonewline = 0;
810da2e3ebdSchin 			pr_string(vp,Prompt);
811da2e3ebdSchin 			window[0] = '\0';
812da2e3ebdSchin 			cur_phys = vp->first_wind;
813da2e3ebdSchin 			vp->ofirst_wind = INVALID;
814da2e3ebdSchin 			vp->long_line = ' ';
815da2e3ebdSchin 			break;
816da2e3ebdSchin 
817da2e3ebdSchin 		case cntl('V'):
818da2e3ebdSchin 		{
819da2e3ebdSchin 			register const char *p = fmtident(e_version);
820da2e3ebdSchin 			save_v(vp);
821da2e3ebdSchin 			del_line(vp,BAD);
822da2e3ebdSchin 			while(c = *p++)
823da2e3ebdSchin 				append(vp,c,APPEND);
824da2e3ebdSchin 			refresh(vp,CONTROL);
825da2e3ebdSchin 			ed_getchar(vp->ed,-1);
826da2e3ebdSchin 			restore_v(vp);
827da2e3ebdSchin 			break;
828da2e3ebdSchin 		}
829da2e3ebdSchin 
830da2e3ebdSchin 		case '/':		/** Search **/
831da2e3ebdSchin 		case '?':
832da2e3ebdSchin 		case 'N':
833da2e3ebdSchin 		case 'n':
834da2e3ebdSchin 			save_v(vp);
835da2e3ebdSchin 			switch( search(vp,c) )
836da2e3ebdSchin 			{
837da2e3ebdSchin 			case GOOD:
838da2e3ebdSchin 				/*** force a total refresh ***/
839da2e3ebdSchin 				window[0] = '\0';
840da2e3ebdSchin 				goto newhist;
841da2e3ebdSchin 
842da2e3ebdSchin 			case BAD:
843da2e3ebdSchin 				/*** no match ***/
844da2e3ebdSchin 					ed_ringbell();
845da2e3ebdSchin 
846da2e3ebdSchin 			default:
847da2e3ebdSchin 				if( vp->u_column == INVALID )
848da2e3ebdSchin 					del_line(vp,BAD);
849da2e3ebdSchin 				else
850da2e3ebdSchin 					restore_v(vp);
851da2e3ebdSchin 				break;
852da2e3ebdSchin 			}
853da2e3ebdSchin 			break;
854da2e3ebdSchin 
855da2e3ebdSchin 		case 'j':		/** get next command **/
856da2e3ebdSchin 		case '+':		/** get next command **/
857da2e3ebdSchin 			curhline += vp->repeat;
858da2e3ebdSchin 			if( curhline > histmax )
859da2e3ebdSchin 			{
860da2e3ebdSchin 				curhline = histmax;
861da2e3ebdSchin 				goto ringbell;
862da2e3ebdSchin 			}
863da2e3ebdSchin 			else if(curhline==histmax && tmp_u_column!=INVALID )
864da2e3ebdSchin 			{
865da2e3ebdSchin 				vp->u_space = tmp_u_space;
866da2e3ebdSchin 				vp->u_column = tmp_u_column;
867da2e3ebdSchin 				restore_v(vp);
868da2e3ebdSchin 				vp->u_space = real_u_space;
869da2e3ebdSchin 				break;
870da2e3ebdSchin 			}
871da2e3ebdSchin 			save_v(vp);
872da2e3ebdSchin 			cur_virt = INVALID;
873da2e3ebdSchin 			goto newhist;
874da2e3ebdSchin 
875da2e3ebdSchin 		case 'k':		/** get previous command **/
876da2e3ebdSchin 		case '-':		/** get previous command **/
877da2e3ebdSchin 			if( curhline == histmax )
878da2e3ebdSchin 			{
879da2e3ebdSchin 				vp->u_space = tmp_u_space;
880da2e3ebdSchin 				i = vp->u_column;
881da2e3ebdSchin 				save_v(vp);
882da2e3ebdSchin 				vp->u_space = real_u_space;
883da2e3ebdSchin 				tmp_u_column = vp->u_column;
884da2e3ebdSchin 				vp->u_column = i;
885da2e3ebdSchin 			}
886da2e3ebdSchin 
887da2e3ebdSchin 			curhline -= vp->repeat;
888da2e3ebdSchin 			if( curhline <= histmin )
889da2e3ebdSchin 			{
890da2e3ebdSchin 				curhline += vp->repeat;
891da2e3ebdSchin 				goto ringbell;
892da2e3ebdSchin 			}
893da2e3ebdSchin 			save_v(vp);
894da2e3ebdSchin 			cur_virt = INVALID;
895da2e3ebdSchin 		newhist:
896da2e3ebdSchin 			if(curhline!=histmax || cur_virt==INVALID)
897da2e3ebdSchin 				hist_copy((char*)virtual, MAXLINE, curhline,-1);
898da2e3ebdSchin 			else
899da2e3ebdSchin 			{
900da2e3ebdSchin 				strcpy((char*)virtual,(char*)vp->u_space);
901da2e3ebdSchin #if SHOPT_MULTIBYTE
902da2e3ebdSchin 				ed_internal((char*)vp->u_space,vp->u_space);
903da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
904da2e3ebdSchin 			}
905da2e3ebdSchin #if SHOPT_MULTIBYTE
906da2e3ebdSchin 			ed_internal((char*)virtual,virtual);
907da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
908da2e3ebdSchin 			if((last_virt=genlen(virtual)-1) >= 0  && cur_virt == INVALID)
909da2e3ebdSchin 				cur_virt = 0;
910da2e3ebdSchin 			break;
911da2e3ebdSchin 
912da2e3ebdSchin 
913da2e3ebdSchin 		case 'u':		/** undo the last thing done **/
914da2e3ebdSchin 			restore_v(vp);
915da2e3ebdSchin 			break;
916da2e3ebdSchin 
917da2e3ebdSchin 		case 'U':		/** Undo everything **/
918da2e3ebdSchin 			save_v(vp);
919da2e3ebdSchin 			if( virtual[0] == '\0' )
920da2e3ebdSchin 				goto ringbell;
921da2e3ebdSchin 			else
922da2e3ebdSchin 			{
923da2e3ebdSchin 				gencpy(virtual, vp->U_space);
924da2e3ebdSchin 				last_virt = genlen(vp->U_space) - 1;
925da2e3ebdSchin 				cur_virt = 0;
926da2e3ebdSchin 			}
927da2e3ebdSchin 			break;
928da2e3ebdSchin 
929da2e3ebdSchin #if KSHELL
930da2e3ebdSchin 		case 'v':
931da2e3ebdSchin 			if(vp->repeat_set==0)
932da2e3ebdSchin 				goto vcommand;
933da2e3ebdSchin #endif /* KSHELL */
934da2e3ebdSchin 
935da2e3ebdSchin 		case 'G':		/** goto command repeat **/
936da2e3ebdSchin 			if(vp->repeat_set==0)
937da2e3ebdSchin 				vp->repeat = histmin+1;
938da2e3ebdSchin 			if( vp->repeat <= histmin || vp->repeat > histmax )
939da2e3ebdSchin 			{
940da2e3ebdSchin 				goto ringbell;
941da2e3ebdSchin 			}
942da2e3ebdSchin 			curhline = vp->repeat;
943da2e3ebdSchin 			save_v(vp);
944da2e3ebdSchin 			if(c == 'G')
945da2e3ebdSchin 			{
946da2e3ebdSchin 				cur_virt = INVALID;
947da2e3ebdSchin 				goto newhist;
948da2e3ebdSchin 			}
949da2e3ebdSchin 
950da2e3ebdSchin #if KSHELL
951da2e3ebdSchin 		vcommand:
952da2e3ebdSchin 			if(ed_fulledit(vp->ed)==GOOD)
953da2e3ebdSchin 				return(BIGVI);
954da2e3ebdSchin 			else
955da2e3ebdSchin 				goto ringbell;
956da2e3ebdSchin #endif	/* KSHELL */
957da2e3ebdSchin 
958da2e3ebdSchin 		case '#':	/** insert(delete) # to (no)comment command **/
959da2e3ebdSchin 			if( cur_virt != INVALID )
960da2e3ebdSchin 			{
961da2e3ebdSchin 				register genchar *p = &virtual[last_virt+1];
962da2e3ebdSchin 				*p = 0;
963da2e3ebdSchin 				/*** see whether first char is comment char ***/
964da2e3ebdSchin 				c = (virtual[0]=='#');
965da2e3ebdSchin 				while(p-- >= virtual)
966da2e3ebdSchin 				{
967da2e3ebdSchin 					if(*p=='\n' || p<virtual)
968da2e3ebdSchin 					{
969da2e3ebdSchin 						if(c) /* delete '#' */
970da2e3ebdSchin 						{
971da2e3ebdSchin 							if(p[1]=='#')
972da2e3ebdSchin 							{
973da2e3ebdSchin 								last_virt--;
974da2e3ebdSchin 								gencpy(p+1,p+2);
975da2e3ebdSchin 							}
976da2e3ebdSchin 						}
977da2e3ebdSchin 						else
978da2e3ebdSchin 						{
979da2e3ebdSchin 							cur_virt = p-virtual;
980da2e3ebdSchin 							append(vp,'#', APPEND);
981da2e3ebdSchin 						}
982da2e3ebdSchin 					}
983da2e3ebdSchin 				}
984da2e3ebdSchin 				if(c)
985da2e3ebdSchin 				{
986da2e3ebdSchin 					curhline = histmax;
987da2e3ebdSchin 					cur_virt = 0;
988da2e3ebdSchin 					break;
989da2e3ebdSchin 				}
990da2e3ebdSchin 				refresh(vp,INPUT);
991da2e3ebdSchin 			}
992da2e3ebdSchin 
993da2e3ebdSchin 		case '\n':		/** send to shell **/
994da2e3ebdSchin 			return(ENTER);
995da2e3ebdSchin 
996da2e3ebdSchin 	        case ESC:
997da2e3ebdSchin 			/* don't ring bell if next char is '[' */
998da2e3ebdSchin 			if(!lookahead)
999da2e3ebdSchin 			{
1000da2e3ebdSchin 				char x;
1001da2e3ebdSchin 				if(sfpkrd(editb.e_fd,&x,1,'\r',400L,-1)>0)
1002da2e3ebdSchin 					ed_ungetchar(vp->ed,x);
1003da2e3ebdSchin 			}
1004da2e3ebdSchin 			if(lookahead)
1005da2e3ebdSchin 			{
1006da2e3ebdSchin 				ed_ungetchar(vp->ed,c=ed_getchar(vp->ed,1));
1007da2e3ebdSchin 				if(c=='[')
1008da2e3ebdSchin 				{
1009da2e3ebdSchin 					vp->repeat = 1;
1010da2e3ebdSchin 					continue;
1011da2e3ebdSchin 				}
1012da2e3ebdSchin 			}
1013da2e3ebdSchin 		default:
1014da2e3ebdSchin 		ringbell:
1015da2e3ebdSchin 			ed_ringbell();
1016da2e3ebdSchin 			vp->repeat = 1;
1017da2e3ebdSchin 			continue;
1018da2e3ebdSchin 		}
1019da2e3ebdSchin 
1020da2e3ebdSchin 		refresh(vp,CONTROL);
1021da2e3ebdSchin 		vp->repeat = 1;
1022da2e3ebdSchin 	}
1023da2e3ebdSchin /* NOTREACHED */
1024da2e3ebdSchin 	return(0);
1025da2e3ebdSchin }
1026da2e3ebdSchin 
1027da2e3ebdSchin /*{	CURSOR( new_current_physical )
1028da2e3ebdSchin  *
1029da2e3ebdSchin  *	This routine will position the virtual cursor at
1030da2e3ebdSchin  * physical column x in the window.
1031da2e3ebdSchin  *
1032da2e3ebdSchin }*/
1033da2e3ebdSchin 
cursor(Vi_t * vp,register int x)1034da2e3ebdSchin static void cursor(Vi_t *vp,register int x)
1035da2e3ebdSchin {
1036da2e3ebdSchin #if SHOPT_MULTIBYTE
1037da2e3ebdSchin 	while(physical[x]==MARKER)
1038da2e3ebdSchin 		x++;
1039da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
1040da2e3ebdSchin 	cur_phys = ed_setcursor(vp->ed, physical, cur_phys,x,vp->first_wind);
1041da2e3ebdSchin }
1042da2e3ebdSchin 
1043da2e3ebdSchin /*{	DELETE( nchars, mode )
1044da2e3ebdSchin  *
1045da2e3ebdSchin  *	Delete nchars from the virtual space and leave cur_virt positioned
1046da2e3ebdSchin  * at cur_virt-1.
1047da2e3ebdSchin  *
1048da2e3ebdSchin  *	If mode	= 'c', do not save the characters deleted
1049da2e3ebdSchin  *		= 'd', save them in yankbuf and delete.
1050da2e3ebdSchin  *		= 'y', save them in yankbuf but do not delete.
1051da2e3ebdSchin  *
1052da2e3ebdSchin }*/
1053da2e3ebdSchin 
cdelete(Vi_t * vp,register int nchars,int mode)1054da2e3ebdSchin static void cdelete(Vi_t *vp,register int nchars, int mode)
1055da2e3ebdSchin {
1056da2e3ebdSchin 	register int i;
1057da2e3ebdSchin 	register genchar *cp;
1058da2e3ebdSchin 
1059da2e3ebdSchin 	if( cur_virt < first_virt )
1060da2e3ebdSchin 	{
1061da2e3ebdSchin 		ed_ringbell();
1062da2e3ebdSchin 		return;
1063da2e3ebdSchin 	}
1064da2e3ebdSchin 	if( nchars > 0 )
1065da2e3ebdSchin 	{
1066da2e3ebdSchin 		cp = virtual+cur_virt;
1067da2e3ebdSchin 		vp->o_v_char = cp[0];
1068da2e3ebdSchin 		if( (cur_virt-- + nchars) > last_virt )
1069da2e3ebdSchin 		{
1070da2e3ebdSchin 			/*** set nchars to number actually deleted ***/
1071da2e3ebdSchin 			nchars = last_virt - cur_virt;
1072da2e3ebdSchin 		}
1073da2e3ebdSchin 
1074da2e3ebdSchin 		/*** save characters to be deleted ***/
1075da2e3ebdSchin 
1076da2e3ebdSchin 		if( mode != 'c' )
1077da2e3ebdSchin 		{
1078da2e3ebdSchin 			i = cp[nchars];
1079da2e3ebdSchin 			cp[nchars] = 0;
1080da2e3ebdSchin 			gencpy(yankbuf,cp);
1081da2e3ebdSchin 			cp[nchars] = i;
1082da2e3ebdSchin 		}
1083da2e3ebdSchin 
1084da2e3ebdSchin 		/*** now delete these characters ***/
1085da2e3ebdSchin 
1086da2e3ebdSchin 		if( mode != 'y' )
1087da2e3ebdSchin 		{
1088da2e3ebdSchin 			gencpy(cp,cp+nchars);
1089da2e3ebdSchin 			last_virt -= nchars;
1090da2e3ebdSchin 		}
1091da2e3ebdSchin 	}
1092da2e3ebdSchin 	return;
1093da2e3ebdSchin }
1094da2e3ebdSchin 
1095da2e3ebdSchin /*{	DEL_LINE( mode )
1096da2e3ebdSchin  *
1097da2e3ebdSchin  *	This routine will delete the line.
1098da2e3ebdSchin  *	mode = GOOD, do a save_v()
1099da2e3ebdSchin  *
1100da2e3ebdSchin }*/
del_line(register Vi_t * vp,int mode)1101da2e3ebdSchin static void del_line(register Vi_t *vp, int mode)
1102da2e3ebdSchin {
1103da2e3ebdSchin 	if( last_virt == INVALID )
1104da2e3ebdSchin 		return;
1105da2e3ebdSchin 
1106da2e3ebdSchin 	if( mode == GOOD )
1107da2e3ebdSchin 		save_v(vp);
1108da2e3ebdSchin 
1109da2e3ebdSchin 	cur_virt = 0;
1110da2e3ebdSchin 	first_virt = 0;
1111da2e3ebdSchin 	cdelete(vp,last_virt+1, BAD);
1112da2e3ebdSchin 	refresh(vp,CONTROL);
1113da2e3ebdSchin 
1114da2e3ebdSchin 	cur_virt = INVALID;
1115da2e3ebdSchin 	cur_phys = 0;
1116da2e3ebdSchin 	vp->findchar = INVALID;
1117da2e3ebdSchin 	last_phys = INVALID;
1118da2e3ebdSchin 	last_virt = INVALID;
1119da2e3ebdSchin 	vp->last_wind = INVALID;
1120da2e3ebdSchin 	vp->first_wind = 0;
1121da2e3ebdSchin 	vp->o_v_char = '\0';
1122da2e3ebdSchin 	vp->ocur_phys = 0;
1123da2e3ebdSchin 	vp->ocur_virt = MAXCHAR;
1124da2e3ebdSchin 	vp->ofirst_wind = 0;
1125da2e3ebdSchin 	window[0] = '\0';
1126da2e3ebdSchin 	return;
1127da2e3ebdSchin }
1128da2e3ebdSchin 
1129da2e3ebdSchin /*{	DELMOTION( motion, mode )
1130da2e3ebdSchin  *
1131da2e3ebdSchin  *	Delete thru motion.
1132da2e3ebdSchin  *
1133da2e3ebdSchin  *	mode	= 'd', save deleted characters, delete
1134da2e3ebdSchin  *		= 'c', do not save characters, change
1135da2e3ebdSchin  *		= 'y', save characters, yank
1136da2e3ebdSchin  *
1137da2e3ebdSchin  *	Returns 1 if operation successful; else 0.
1138da2e3ebdSchin  *
1139da2e3ebdSchin }*/
1140da2e3ebdSchin 
delmotion(Vi_t * vp,int motion,int mode)1141da2e3ebdSchin static int delmotion(Vi_t *vp,int motion, int mode)
1142da2e3ebdSchin {
1143da2e3ebdSchin 	register int begin, end, delta;
1144da2e3ebdSchin 	/* the following saves a register */
1145da2e3ebdSchin 
1146da2e3ebdSchin 	if( cur_virt == INVALID )
1147da2e3ebdSchin 		return(0);
1148da2e3ebdSchin 	if( mode != 'y' )
1149da2e3ebdSchin 		save_v(vp);
1150da2e3ebdSchin 	begin = cur_virt;
1151da2e3ebdSchin 
1152da2e3ebdSchin 	/*** fake out the motion routines by appending a blank ***/
1153da2e3ebdSchin 
1154da2e3ebdSchin 	virtual[++last_virt] = ' ';
1155da2e3ebdSchin 	end = mvcursor(vp,motion);
1156da2e3ebdSchin 	virtual[last_virt--] = 0;
1157da2e3ebdSchin 	if(!end)
1158da2e3ebdSchin 		return(0);
1159da2e3ebdSchin 
1160da2e3ebdSchin 	end = cur_virt;
1161da2e3ebdSchin 	if( mode=='c' && end>begin && strchr("wW", motion) )
1162da2e3ebdSchin 	{
1163da2e3ebdSchin 		/*** called by change operation, user really expects ***/
1164da2e3ebdSchin 		/* the effect of the eE commands, so back up to end of word */
1165da2e3ebdSchin 		while( end>begin && isblank(end-1) )
1166da2e3ebdSchin 			--end;
1167da2e3ebdSchin 		if( end == begin )
1168da2e3ebdSchin 			++end;
1169da2e3ebdSchin 	}
1170da2e3ebdSchin 
1171da2e3ebdSchin 	delta = end - begin;
1172da2e3ebdSchin 	if( delta >= 0 )
1173da2e3ebdSchin 	{
1174da2e3ebdSchin 		cur_virt = begin;
1175da2e3ebdSchin 		if( strchr("eE;,TtFf%", motion) )
1176da2e3ebdSchin 			++delta;
1177da2e3ebdSchin 	}
1178da2e3ebdSchin 	else
1179da2e3ebdSchin 	{
1180da2e3ebdSchin 		delta = -delta + (motion=='%');
1181da2e3ebdSchin 	}
1182da2e3ebdSchin 
1183da2e3ebdSchin 	cdelete(vp,delta, mode);
1184da2e3ebdSchin 	if( mode == 'y' )
1185da2e3ebdSchin 		cur_virt = begin;
1186da2e3ebdSchin 	return(1);
1187da2e3ebdSchin }
1188da2e3ebdSchin 
1189da2e3ebdSchin 
1190da2e3ebdSchin /*{	ENDWORD( nwords, cmd )
1191da2e3ebdSchin  *
1192da2e3ebdSchin  *	This routine will move cur_virt to the end of the nth word.
1193da2e3ebdSchin  *
1194da2e3ebdSchin }*/
1195da2e3ebdSchin 
endword(Vi_t * vp,int nwords,register int cmd)1196da2e3ebdSchin static void endword(Vi_t *vp, int nwords, register int cmd)
1197da2e3ebdSchin {
1198da2e3ebdSchin 	register int tcur_virt = cur_virt;
1199da2e3ebdSchin 	while( nwords-- )
1200da2e3ebdSchin 	{
1201da2e3ebdSchin 		if( !isblank(tcur_virt) && tcur_virt<=last_virt )
1202da2e3ebdSchin 			++tcur_virt;
1203da2e3ebdSchin 		while( isblank(tcur_virt) && tcur_virt<=last_virt )
1204da2e3ebdSchin 			++tcur_virt;
1205da2e3ebdSchin 		if( cmd == 'E' )
1206da2e3ebdSchin 		{
1207da2e3ebdSchin 			while( !isblank(tcur_virt) && tcur_virt<=last_virt )
1208da2e3ebdSchin 				++tcur_virt;
1209da2e3ebdSchin 		}
1210da2e3ebdSchin 		else
1211da2e3ebdSchin 		{
1212da2e3ebdSchin 			if( isalph(tcur_virt) )
1213da2e3ebdSchin 				while( isalph(tcur_virt) && tcur_virt<=last_virt )
1214da2e3ebdSchin 					++tcur_virt;
1215da2e3ebdSchin 			else
1216da2e3ebdSchin 				while( !isalph(tcur_virt) && !isblank(tcur_virt)
1217da2e3ebdSchin 					&& tcur_virt<=last_virt )
1218da2e3ebdSchin 					++tcur_virt;
1219da2e3ebdSchin 		}
1220da2e3ebdSchin 		if( tcur_virt > first_virt )
1221da2e3ebdSchin 			tcur_virt--;
1222da2e3ebdSchin 	}
1223da2e3ebdSchin 	cur_virt = tcur_virt;
1224da2e3ebdSchin 	return;
1225da2e3ebdSchin }
1226da2e3ebdSchin 
1227da2e3ebdSchin /*{	FORWARD( nwords, cmd )
1228da2e3ebdSchin  *
1229da2e3ebdSchin  *	This routine will move cur_virt forward to the next nth word.
1230da2e3ebdSchin  *
1231da2e3ebdSchin }*/
1232da2e3ebdSchin 
forward(Vi_t * vp,register int nwords,int cmd)1233da2e3ebdSchin static void forward(Vi_t *vp,register int nwords, int cmd)
1234da2e3ebdSchin {
1235da2e3ebdSchin 	register int tcur_virt = cur_virt;
1236da2e3ebdSchin 	while( nwords-- )
1237da2e3ebdSchin 	{
1238da2e3ebdSchin 		if( cmd == 'W' )
1239da2e3ebdSchin 		{
1240da2e3ebdSchin 			while( !isblank(tcur_virt) && tcur_virt < last_virt )
1241da2e3ebdSchin 				++tcur_virt;
1242da2e3ebdSchin 		}
1243da2e3ebdSchin 		else
1244da2e3ebdSchin 		{
1245da2e3ebdSchin 			if( isalph(tcur_virt) )
1246da2e3ebdSchin 			{
1247da2e3ebdSchin 				while( isalph(tcur_virt) && tcur_virt<last_virt )
1248da2e3ebdSchin 					++tcur_virt;
1249da2e3ebdSchin 			}
1250da2e3ebdSchin 			else
1251da2e3ebdSchin 			{
1252da2e3ebdSchin 				while( !isalph(tcur_virt) && !isblank(tcur_virt)
1253da2e3ebdSchin 					&& tcur_virt < last_virt )
1254da2e3ebdSchin 					++tcur_virt;
1255da2e3ebdSchin 			}
1256da2e3ebdSchin 		}
1257da2e3ebdSchin 		while( isblank(tcur_virt) && tcur_virt < last_virt )
1258da2e3ebdSchin 			++tcur_virt;
1259da2e3ebdSchin 	}
1260da2e3ebdSchin 	cur_virt = tcur_virt;
1261da2e3ebdSchin 	return;
1262da2e3ebdSchin }
1263da2e3ebdSchin 
1264da2e3ebdSchin 
1265da2e3ebdSchin 
1266da2e3ebdSchin /*{	GETCOUNT(c)
1267da2e3ebdSchin  *
1268da2e3ebdSchin  *	Set repeat to the user typed number and return the terminating
1269da2e3ebdSchin  * character.
1270da2e3ebdSchin  *
1271da2e3ebdSchin }*/
1272da2e3ebdSchin 
getcount(register Vi_t * vp,register int c)1273da2e3ebdSchin static int getcount(register Vi_t *vp,register int c)
1274da2e3ebdSchin {
1275da2e3ebdSchin 	register int i;
1276da2e3ebdSchin 
1277da2e3ebdSchin 	/*** get any repeat count ***/
1278da2e3ebdSchin 
1279da2e3ebdSchin 	if( c == '0' )
1280da2e3ebdSchin 		return(c);
1281da2e3ebdSchin 
1282da2e3ebdSchin 	vp->repeat_set++;
1283da2e3ebdSchin 	i = 0;
1284da2e3ebdSchin 	while( digit(c) )
1285da2e3ebdSchin 	{
1286da2e3ebdSchin 		i = i*10 + c - '0';
1287da2e3ebdSchin 		c = ed_getchar(vp->ed,-1);
1288da2e3ebdSchin 	}
1289da2e3ebdSchin 
1290da2e3ebdSchin 	if( i > 0 )
1291da2e3ebdSchin 		vp->repeat *= i;
1292da2e3ebdSchin 	return(c);
1293da2e3ebdSchin }
1294da2e3ebdSchin 
1295da2e3ebdSchin 
1296da2e3ebdSchin /*{	GETLINE( mode )
1297da2e3ebdSchin  *
1298da2e3ebdSchin  *	This routine will fetch a line.
1299da2e3ebdSchin  *	mode	= APPEND, allow escape to cntlmode subroutine
1300da2e3ebdSchin  *		  appending characters.
1301da2e3ebdSchin  *		= REPLACE, allow escape to cntlmode subroutine
1302da2e3ebdSchin  *		  replacing characters.
1303da2e3ebdSchin  *		= SEARCH, no escape allowed
1304da2e3ebdSchin  *		= ESC, enter control mode immediately
1305da2e3ebdSchin  *
1306da2e3ebdSchin  *	The cursor will always be positioned after the last
1307da2e3ebdSchin  * char printed.
1308da2e3ebdSchin  *
1309da2e3ebdSchin  *	This routine returns when cr, nl, or (eof in column 0) is
1310da2e3ebdSchin  * received (column 0 is the first char position).
1311da2e3ebdSchin  *
1312da2e3ebdSchin }*/
1313da2e3ebdSchin 
getline(register Vi_t * vp,register int mode)1314da2e3ebdSchin static void getline(register Vi_t* vp,register int mode)
1315da2e3ebdSchin {
1316da2e3ebdSchin 	register int c;
1317da2e3ebdSchin 	register int tmp;
1318da2e3ebdSchin 	int	max_virt=0, last_save=0;
1319da2e3ebdSchin 	genchar saveline[MAXLINE];
1320da2e3ebdSchin 
1321da2e3ebdSchin 	vp->addnl = 1;
1322da2e3ebdSchin 
1323da2e3ebdSchin 	if( mode == ESC )
1324da2e3ebdSchin 	{
1325da2e3ebdSchin 		/*** go directly to control mode ***/
1326da2e3ebdSchin 		goto escape;
1327da2e3ebdSchin 	}
1328da2e3ebdSchin 
1329da2e3ebdSchin 	for(;;)
1330da2e3ebdSchin 	{
1331da2e3ebdSchin 		if( (c=ed_getchar(vp->ed,mode==SEARCH?1:-2)) == usreof )
1332da2e3ebdSchin 			c = UEOF;
1333da2e3ebdSchin 		else if( c == usrerase )
1334da2e3ebdSchin 			c = UERASE;
1335da2e3ebdSchin 		else if( c == usrkill )
1336da2e3ebdSchin 			c = UKILL;
1337da2e3ebdSchin 		else if( c == editb.e_werase )
1338da2e3ebdSchin 			c = UWERASE;
1339da2e3ebdSchin 		else if( c == usrlnext )
1340da2e3ebdSchin 			c = ULNEXT;
1341da2e3ebdSchin 
1342da2e3ebdSchin 		if( c == ULNEXT)
1343da2e3ebdSchin 		{
1344da2e3ebdSchin 			/*** implement ^V to escape next char ***/
1345da2e3ebdSchin 			c = ed_getchar(vp->ed,2);
1346da2e3ebdSchin 			append(vp,c, mode);
1347da2e3ebdSchin 			refresh(vp,INPUT);
1348da2e3ebdSchin 			continue;
1349da2e3ebdSchin 		}
1350da2e3ebdSchin 
1351da2e3ebdSchin 		switch( c )
1352da2e3ebdSchin 		{
1353da2e3ebdSchin 		case ESC:		/** enter control mode **/
1354da2e3ebdSchin 			if(!sh_isoption(SH_VI))
1355da2e3ebdSchin 			{
1356da2e3ebdSchin 				append(vp,c, mode);
1357da2e3ebdSchin 				break;
1358da2e3ebdSchin 			}
1359da2e3ebdSchin 			if( mode == SEARCH )
1360da2e3ebdSchin 			{
1361da2e3ebdSchin 				ed_ringbell();
1362da2e3ebdSchin 				continue;
1363da2e3ebdSchin 			}
1364da2e3ebdSchin 			else
1365da2e3ebdSchin 			{
1366da2e3ebdSchin 	escape:
1367da2e3ebdSchin 				if( mode == REPLACE )
1368da2e3ebdSchin 				{
1369da2e3ebdSchin 					c = max_virt-cur_virt;
1370da2e3ebdSchin 					if(c > 0 && last_save>=cur_virt)
1371da2e3ebdSchin 					{
1372da2e3ebdSchin 						genncpy((&virtual[cur_virt]),&saveline[cur_virt],c);
1373da2e3ebdSchin 						if(last_virt>=last_save)
1374da2e3ebdSchin 							last_virt=last_save-1;
1375da2e3ebdSchin 						refresh(vp,INPUT);
1376da2e3ebdSchin 					}
1377da2e3ebdSchin 					--cur_virt;
1378da2e3ebdSchin 				}
1379da2e3ebdSchin 				tmp = cntlmode(vp);
1380da2e3ebdSchin 				if( tmp == ENTER || tmp == BIGVI )
1381da2e3ebdSchin 				{
1382da2e3ebdSchin #if SHOPT_MULTIBYTE
1383da2e3ebdSchin 					vp->bigvi = (tmp==BIGVI);
1384da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
1385da2e3ebdSchin 					return;
1386da2e3ebdSchin 				}
1387da2e3ebdSchin 				if( tmp == INSERT )
1388da2e3ebdSchin 				{
1389da2e3ebdSchin 					mode = APPEND;
1390da2e3ebdSchin 					continue;
1391da2e3ebdSchin 				}
1392da2e3ebdSchin 				mode = tmp;
1393da2e3ebdSchin 				if(mode==REPLACE)
1394da2e3ebdSchin 				{
1395da2e3ebdSchin 					c = last_save = last_virt+1;
1396da2e3ebdSchin 					if(c >= MAXLINE)
1397da2e3ebdSchin 						c = MAXLINE-1;
1398da2e3ebdSchin 					genncpy(saveline, virtual, c);
1399da2e3ebdSchin 				}
1400da2e3ebdSchin 			}
1401da2e3ebdSchin 			break;
1402da2e3ebdSchin 
1403da2e3ebdSchin 		case UERASE:		/** user erase char **/
1404da2e3ebdSchin 				/*** treat as backspace ***/
1405da2e3ebdSchin 
1406da2e3ebdSchin 		case '\b':		/** backspace **/
1407da2e3ebdSchin 			if( virtual[cur_virt] == '\\' )
1408da2e3ebdSchin 			{
1409da2e3ebdSchin 				cdelete(vp,1, BAD);
1410da2e3ebdSchin 				append(vp,usrerase, mode);
1411da2e3ebdSchin 			}
1412da2e3ebdSchin 			else
1413da2e3ebdSchin 			{
1414da2e3ebdSchin 				if( mode==SEARCH && cur_virt==0 )
1415da2e3ebdSchin 				{
1416da2e3ebdSchin 					first_virt = 0;
1417da2e3ebdSchin 					cdelete(vp,1, BAD);
1418da2e3ebdSchin 					return;
1419da2e3ebdSchin 				}
1420da2e3ebdSchin 				if(mode==REPLACE || (last_save>0 && last_virt<=last_save))
1421da2e3ebdSchin 				{
1422da2e3ebdSchin 					if(cur_virt<=first_virt)
1423da2e3ebdSchin 						ed_ringbell();
1424da2e3ebdSchin 					else if(mode==REPLACE)
1425da2e3ebdSchin 						--cur_virt;
1426da2e3ebdSchin 					mode = REPLACE;
1427da2e3ebdSchin 					sync_cursor(vp);
1428da2e3ebdSchin 					continue;
1429da2e3ebdSchin 				}
1430da2e3ebdSchin 				else
1431da2e3ebdSchin 					cdelete(vp,1, BAD);
1432da2e3ebdSchin 			}
1433da2e3ebdSchin 			break;
1434da2e3ebdSchin 
1435da2e3ebdSchin 		case UWERASE:		/** delete back word **/
1436da2e3ebdSchin 			if( cur_virt > first_virt &&
1437da2e3ebdSchin 				!isblank(cur_virt) &&
1438da2e3ebdSchin 				!ispunct(virtual[cur_virt]) &&
1439da2e3ebdSchin 				isblank(cur_virt-1) )
1440da2e3ebdSchin 			{
1441da2e3ebdSchin 				cdelete(vp,1, BAD);
1442da2e3ebdSchin 			}
1443da2e3ebdSchin 			else
1444da2e3ebdSchin 			{
1445da2e3ebdSchin 				tmp = cur_virt;
1446da2e3ebdSchin 				backword(vp,1, 'W');
1447da2e3ebdSchin 				cdelete(vp,tmp - cur_virt + 1, BAD);
1448da2e3ebdSchin 			}
1449da2e3ebdSchin 			break;
1450da2e3ebdSchin 
1451da2e3ebdSchin 		case UKILL:		/** user kill line char **/
1452da2e3ebdSchin 			if( virtual[cur_virt] == '\\' )
1453da2e3ebdSchin 			{
1454da2e3ebdSchin 				cdelete(vp,1, BAD);
1455da2e3ebdSchin 				append(vp,usrkill, mode);
1456da2e3ebdSchin 			}
1457da2e3ebdSchin 			else
1458da2e3ebdSchin 			{
1459da2e3ebdSchin 				if( mode == SEARCH )
1460da2e3ebdSchin 				{
1461da2e3ebdSchin 					cur_virt = 1;
1462da2e3ebdSchin 					delmotion(vp, '$', BAD);
1463da2e3ebdSchin 				}
1464da2e3ebdSchin 				else if(first_virt)
1465da2e3ebdSchin 				{
1466da2e3ebdSchin 					tmp = cur_virt;
1467da2e3ebdSchin 					cur_virt = first_virt;
1468da2e3ebdSchin 					cdelete(vp,tmp - cur_virt + 1, BAD);
1469da2e3ebdSchin 				}
1470da2e3ebdSchin 				else
1471da2e3ebdSchin 					del_line(vp,GOOD);
1472da2e3ebdSchin 			}
1473da2e3ebdSchin 			break;
1474da2e3ebdSchin 
1475da2e3ebdSchin 		case UEOF:		/** eof char **/
1476da2e3ebdSchin 			if( cur_virt != INVALID )
1477da2e3ebdSchin 				continue;
1478da2e3ebdSchin 			vp->addnl = 0;
1479da2e3ebdSchin 
1480da2e3ebdSchin 		case '\n':		/** newline or return **/
1481da2e3ebdSchin 			if( mode != SEARCH )
1482da2e3ebdSchin 				save_last(vp);
1483da2e3ebdSchin 			refresh(vp,INPUT);
14847c2fbfb3SApril Chin 			last_phys++;
1485da2e3ebdSchin 			return;
1486da2e3ebdSchin 
1487da2e3ebdSchin 		case '\t':		/** command completion **/
1488da2e3ebdSchin 			if(mode!=SEARCH && last_virt>=0 && (vp->ed->e_tabcount|| !isblank(cur_virt)) && vp->ed->sh->nextprompt)
1489da2e3ebdSchin 			{
1490da2e3ebdSchin 				if(vp->ed->e_tabcount==0)
1491da2e3ebdSchin 				{
1492da2e3ebdSchin 					ed_ungetchar(vp->ed,'\\');
1493da2e3ebdSchin 					vp->ed->e_tabcount=1;
1494da2e3ebdSchin 					goto escape;
1495da2e3ebdSchin 				}
1496da2e3ebdSchin 				else if(vp->ed->e_tabcount==1)
1497da2e3ebdSchin 				{
1498da2e3ebdSchin 					ed_ungetchar(vp->ed,'=');
1499da2e3ebdSchin 					goto escape;
1500da2e3ebdSchin 				}
1501da2e3ebdSchin 				vp->ed->e_tabcount = 0;
1502da2e3ebdSchin 			}
1503da2e3ebdSchin 			/* FALL THRU*/
1504da2e3ebdSchin 		default:
1505da2e3ebdSchin 			if( mode == REPLACE )
1506da2e3ebdSchin 			{
1507da2e3ebdSchin 				if( cur_virt < last_virt )
1508da2e3ebdSchin 				{
1509da2e3ebdSchin 					replace(vp,c, 1);
1510da2e3ebdSchin 					if(cur_virt>max_virt)
1511da2e3ebdSchin 						max_virt = cur_virt;
1512da2e3ebdSchin 					continue;
1513da2e3ebdSchin 				}
1514da2e3ebdSchin 				cdelete(vp,1, BAD);
1515da2e3ebdSchin 				mode = APPEND;
1516da2e3ebdSchin 				max_virt = last_virt+3;
1517da2e3ebdSchin 			}
1518da2e3ebdSchin 			append(vp,c, mode);
1519da2e3ebdSchin 			break;
1520da2e3ebdSchin 		}
1521da2e3ebdSchin 		refresh(vp,INPUT);
1522da2e3ebdSchin 
1523da2e3ebdSchin 	}
1524da2e3ebdSchin }
1525da2e3ebdSchin 
1526da2e3ebdSchin /*{	MVCURSOR( motion )
1527da2e3ebdSchin  *
1528da2e3ebdSchin  *	This routine will move the virtual cursor according to motion
1529da2e3ebdSchin  * for repeat times.
1530da2e3ebdSchin  *
1531da2e3ebdSchin  * It returns GOOD if successful; else BAD.
1532da2e3ebdSchin  *
1533da2e3ebdSchin }*/
1534da2e3ebdSchin 
mvcursor(register Vi_t * vp,register int motion)1535da2e3ebdSchin static int mvcursor(register Vi_t* vp,register int motion)
1536da2e3ebdSchin {
1537da2e3ebdSchin 	register int count;
1538da2e3ebdSchin 	register int tcur_virt;
1539da2e3ebdSchin 	register int incr = -1;
1540da2e3ebdSchin 	register int bound = 0;
1541da2e3ebdSchin 
1542da2e3ebdSchin 	switch(motion)
1543da2e3ebdSchin 	{
1544da2e3ebdSchin 		/***** Cursor move commands *****/
1545da2e3ebdSchin 
1546da2e3ebdSchin 	case '0':		/** First column **/
1547da2e3ebdSchin 		tcur_virt = 0;
1548da2e3ebdSchin 		break;
1549da2e3ebdSchin 
1550da2e3ebdSchin 	case '^':		/** First nonblank character **/
1551da2e3ebdSchin 		tcur_virt = first_virt;
1552da2e3ebdSchin 		while( isblank(tcur_virt) && tcur_virt < last_virt )
1553da2e3ebdSchin 			++tcur_virt;
1554da2e3ebdSchin 		break;
1555da2e3ebdSchin 
1556da2e3ebdSchin 	case '|':
1557da2e3ebdSchin 		tcur_virt = vp->repeat-1;
1558da2e3ebdSchin 		if(tcur_virt <= last_virt)
1559da2e3ebdSchin 			break;
1560da2e3ebdSchin 		/* fall through */
1561da2e3ebdSchin 
1562da2e3ebdSchin 	case '$':		/** End of line **/
1563da2e3ebdSchin 		tcur_virt = last_virt;
1564da2e3ebdSchin 		break;
1565da2e3ebdSchin 
1566da2e3ebdSchin 	case '[':
1567da2e3ebdSchin 		switch(motion=getcount(vp,ed_getchar(vp->ed,-1)))
1568da2e3ebdSchin 		{
1569da2e3ebdSchin 		    case 'A':
15707c2fbfb3SApril Chin 			if(cur_virt>=0  && cur_virt<(SEARCHSIZE-2) && cur_virt == last_virt)
15717c2fbfb3SApril Chin 			{
15727c2fbfb3SApril Chin 				virtual[last_virt + 1] = '\0';
15737c2fbfb3SApril Chin #if SHOPT_MULTIBYTE
157434f9b3eeSRoland Mainz 				ed_external(virtual,lsearch+1);
157534f9b3eeSRoland Mainz #else
157634f9b3eeSRoland Mainz 				strcpy(lsearch+1,virtual);
15777c2fbfb3SApril Chin #endif /* SHOPT_MULTIBYTE */
15787c2fbfb3SApril Chin 				*lsearch = '^';
15797c2fbfb3SApril Chin 				vp->direction = -2;
15807c2fbfb3SApril Chin 				ed_ungetchar(vp->ed,'n');
15817c2fbfb3SApril Chin 			}
15827c2fbfb3SApril Chin 			else if(cur_virt==0 && vp->direction == -2)
15837c2fbfb3SApril Chin 				ed_ungetchar(vp->ed,'n');
15847c2fbfb3SApril Chin 			else
1585da2e3ebdSchin 				ed_ungetchar(vp->ed,'k');
1586da2e3ebdSchin 			return(1);
1587da2e3ebdSchin 		    case 'B':
1588da2e3ebdSchin 			ed_ungetchar(vp->ed,'j');
1589da2e3ebdSchin 			return(1);
1590da2e3ebdSchin 		    case 'C':
1591da2e3ebdSchin 			motion = last_virt;
1592da2e3ebdSchin 			incr = 1;
1593da2e3ebdSchin 			goto walk;
1594da2e3ebdSchin 		    case 'D':
1595da2e3ebdSchin 			motion = first_virt;
1596da2e3ebdSchin 			goto walk;
1597da2e3ebdSchin 		    case 'H':
1598da2e3ebdSchin 			tcur_virt = 0;
1599da2e3ebdSchin 			break;
1600da2e3ebdSchin 		    case 'Y':
1601da2e3ebdSchin 			tcur_virt = last_virt;
1602da2e3ebdSchin 			break;
1603da2e3ebdSchin 		    default:
1604da2e3ebdSchin 			ed_ungetchar(vp->ed,motion);
1605da2e3ebdSchin 			return(0);
1606da2e3ebdSchin 		}
1607da2e3ebdSchin 		break;
1608da2e3ebdSchin 
1609da2e3ebdSchin 	case 'h':		/** Left one **/
1610da2e3ebdSchin 	case '\b':
1611da2e3ebdSchin 		motion = first_virt;
1612da2e3ebdSchin 		goto walk;
1613da2e3ebdSchin 
1614da2e3ebdSchin 	case ' ':
1615da2e3ebdSchin 	case 'l':		/** Right one **/
1616da2e3ebdSchin 		motion = last_virt;
1617da2e3ebdSchin 		incr = 1;
1618da2e3ebdSchin 	walk:
1619da2e3ebdSchin 		tcur_virt = cur_virt;
1620da2e3ebdSchin 		if( incr*tcur_virt < motion)
1621da2e3ebdSchin 		{
1622da2e3ebdSchin 			tcur_virt += vp->repeat*incr;
1623da2e3ebdSchin 			if( incr*tcur_virt > motion)
1624da2e3ebdSchin 				tcur_virt = motion;
1625da2e3ebdSchin 		}
1626da2e3ebdSchin 		else
1627da2e3ebdSchin 			return(0);
1628da2e3ebdSchin 		break;
1629da2e3ebdSchin 
1630da2e3ebdSchin 	case 'B':
1631da2e3ebdSchin 	case 'b':		/** back word **/
1632da2e3ebdSchin 		tcur_virt = cur_virt;
1633da2e3ebdSchin 		backword(vp,vp->repeat, motion);
1634da2e3ebdSchin 		if( cur_virt == tcur_virt )
1635da2e3ebdSchin 			return(0);
1636da2e3ebdSchin 		return(1);
1637da2e3ebdSchin 
1638da2e3ebdSchin 	case 'E':
1639da2e3ebdSchin 	case 'e':		/** end of word **/
1640da2e3ebdSchin 		tcur_virt = cur_virt;
1641da2e3ebdSchin 		if(tcur_virt >=0)
1642da2e3ebdSchin 			endword(vp, vp->repeat, motion);
1643da2e3ebdSchin 		if( cur_virt == tcur_virt )
1644da2e3ebdSchin 			return(0);
1645da2e3ebdSchin 		return(1);
1646da2e3ebdSchin 
1647da2e3ebdSchin 	case ',':		/** reverse find old char **/
1648da2e3ebdSchin 	case ';':		/** find old char **/
1649da2e3ebdSchin 		switch(vp->last_find)
1650da2e3ebdSchin 		{
1651da2e3ebdSchin 		case 't':
1652da2e3ebdSchin 		case 'f':
1653da2e3ebdSchin 			if(motion==';')
1654da2e3ebdSchin 			{
1655da2e3ebdSchin 				bound = last_virt;
1656da2e3ebdSchin 				incr = 1;
1657da2e3ebdSchin 			}
1658da2e3ebdSchin 			goto find_b;
1659da2e3ebdSchin 
1660da2e3ebdSchin 		case 'T':
1661da2e3ebdSchin 		case 'F':
1662da2e3ebdSchin 			if(motion==',')
1663da2e3ebdSchin 			{
1664da2e3ebdSchin 				bound = last_virt;
1665da2e3ebdSchin 				incr = 1;
1666da2e3ebdSchin 			}
1667da2e3ebdSchin 			goto find_b;
1668da2e3ebdSchin 
1669da2e3ebdSchin 		default:
1670da2e3ebdSchin 			return(0);
1671da2e3ebdSchin 		}
1672da2e3ebdSchin 
1673da2e3ebdSchin 
1674da2e3ebdSchin 	case 't':		/** find up to new char forward **/
1675da2e3ebdSchin 	case 'f':		/** find new char forward **/
1676da2e3ebdSchin 		bound = last_virt;
1677da2e3ebdSchin 		incr = 1;
1678da2e3ebdSchin 
1679da2e3ebdSchin 	case 'T':		/** find up to new char backward **/
1680da2e3ebdSchin 	case 'F':		/** find new char backward **/
1681da2e3ebdSchin 		vp->last_find = motion;
1682da2e3ebdSchin 		if((vp->findchar=getrchar(vp))==ESC)
1683da2e3ebdSchin 			return(1);
1684da2e3ebdSchin find_b:
1685da2e3ebdSchin 		tcur_virt = cur_virt;
1686da2e3ebdSchin 		count = vp->repeat;
1687da2e3ebdSchin 		while( count-- )
1688da2e3ebdSchin 		{
1689da2e3ebdSchin 			while( incr*(tcur_virt+=incr) <= bound
1690da2e3ebdSchin 				&& virtual[tcur_virt] != vp->findchar );
1691da2e3ebdSchin 			if( incr*tcur_virt > bound )
1692da2e3ebdSchin 			{
1693da2e3ebdSchin 				return(0);
1694da2e3ebdSchin 			}
1695da2e3ebdSchin 		}
1696da2e3ebdSchin 		if( fold(vp->last_find) == 'T' )
1697da2e3ebdSchin 			tcur_virt -= incr;
1698da2e3ebdSchin 		break;
1699da2e3ebdSchin 
1700da2e3ebdSchin         case '%':
1701da2e3ebdSchin 	{
1702da2e3ebdSchin 		int nextmotion;
1703da2e3ebdSchin 		int nextc;
1704da2e3ebdSchin 		tcur_virt = cur_virt;
1705da2e3ebdSchin 		while( tcur_virt <= last_virt
1706da2e3ebdSchin 			&& strchr(paren_chars,virtual[tcur_virt])==(char*)0)
1707da2e3ebdSchin 				tcur_virt++;
1708da2e3ebdSchin 		if(tcur_virt > last_virt )
1709da2e3ebdSchin 			return(0);
1710da2e3ebdSchin 		nextc = virtual[tcur_virt];
1711da2e3ebdSchin 		count = strchr(paren_chars,nextc)-paren_chars;
1712da2e3ebdSchin 		if(count < 3)
1713da2e3ebdSchin 		{
1714da2e3ebdSchin 			incr = 1;
1715da2e3ebdSchin 			bound = last_virt;
1716da2e3ebdSchin 			nextmotion = paren_chars[count+3];
1717da2e3ebdSchin 		}
1718da2e3ebdSchin 		else
1719da2e3ebdSchin 			nextmotion = paren_chars[count-3];
1720da2e3ebdSchin 		count = 1;
1721da2e3ebdSchin 		while(count >0 &&  incr*(tcur_virt+=incr) <= bound)
1722da2e3ebdSchin 		{
1723da2e3ebdSchin 		        if(virtual[tcur_virt] == nextmotion)
1724da2e3ebdSchin 		        	count--;
1725da2e3ebdSchin 		        else if(virtual[tcur_virt]==nextc)
1726da2e3ebdSchin 		        	count++;
1727da2e3ebdSchin 		}
1728da2e3ebdSchin 		if(count)
1729da2e3ebdSchin 			return(0);
1730da2e3ebdSchin 		break;
1731da2e3ebdSchin 	}
1732da2e3ebdSchin 
1733da2e3ebdSchin 	case 'W':
1734da2e3ebdSchin 	case 'w':		/** forward word **/
1735da2e3ebdSchin 		tcur_virt = cur_virt;
1736da2e3ebdSchin 		forward(vp,vp->repeat, motion);
1737da2e3ebdSchin 		if( tcur_virt == cur_virt )
1738da2e3ebdSchin 			return(0);
1739da2e3ebdSchin 		return(1);
1740da2e3ebdSchin 
1741da2e3ebdSchin 	default:
1742da2e3ebdSchin 		return(0);
1743da2e3ebdSchin 	}
1744da2e3ebdSchin 	cur_virt = tcur_virt;
1745da2e3ebdSchin 
1746da2e3ebdSchin 	return(1);
1747da2e3ebdSchin }
1748da2e3ebdSchin 
1749da2e3ebdSchin /*
1750da2e3ebdSchin  * print a string
1751da2e3ebdSchin  */
1752da2e3ebdSchin 
pr_string(register Vi_t * vp,register const char * sp)1753da2e3ebdSchin static void pr_string(register Vi_t *vp, register const char *sp)
1754da2e3ebdSchin {
1755da2e3ebdSchin 	/*** copy string sp ***/
1756da2e3ebdSchin 	register char *ptr = editb.e_outptr;
1757da2e3ebdSchin 	while(*sp)
1758da2e3ebdSchin 		*ptr++ = *sp++;
1759da2e3ebdSchin 	editb.e_outptr = ptr;
1760da2e3ebdSchin 	return;
1761da2e3ebdSchin }
1762da2e3ebdSchin 
1763da2e3ebdSchin /*{	PUTSTRING( column, nchars )
1764da2e3ebdSchin  *
1765da2e3ebdSchin  *	Put nchars starting at column of physical into the workspace
1766da2e3ebdSchin  * to be printed.
1767da2e3ebdSchin  *
1768da2e3ebdSchin }*/
1769da2e3ebdSchin 
putstring(register Vi_t * vp,register int col,register int nchars)1770da2e3ebdSchin static void putstring(register Vi_t *vp,register int col, register int nchars)
1771da2e3ebdSchin {
1772da2e3ebdSchin 	while( nchars-- )
1773da2e3ebdSchin 		putchar(physical[col++]);
1774da2e3ebdSchin 	return;
1775da2e3ebdSchin }
1776da2e3ebdSchin 
1777da2e3ebdSchin /*{	REFRESH( mode )
1778da2e3ebdSchin  *
1779da2e3ebdSchin  *	This routine will refresh the crt so the physical image matches
1780da2e3ebdSchin  * the virtual image and display the proper window.
1781da2e3ebdSchin  *
1782da2e3ebdSchin  *	mode	= CONTROL, refresh in control mode, ie. leave cursor
1783da2e3ebdSchin  *			positioned at last char printed.
1784da2e3ebdSchin  *		= INPUT, refresh in input mode; leave cursor positioned
1785da2e3ebdSchin  *			after last char printed.
1786da2e3ebdSchin  *		= TRANSLATE, perform virtual to physical translation
1787da2e3ebdSchin  *			and adjust left margin only.
1788da2e3ebdSchin  *
1789da2e3ebdSchin  *		+-------------------------------+
1790da2e3ebdSchin  *		|   | |    virtual	  | |   |
1791da2e3ebdSchin  *		+-------------------------------+
1792da2e3ebdSchin  *		  cur_virt		last_virt
1793da2e3ebdSchin  *
1794da2e3ebdSchin  *		+-----------------------------------------------+
1795da2e3ebdSchin  *		|	  | |	        physical	 | |    |
1796da2e3ebdSchin  *		+-----------------------------------------------+
1797da2e3ebdSchin  *			cur_phys			last_phys
1798da2e3ebdSchin  *
1799da2e3ebdSchin  *				0			w_size - 1
1800da2e3ebdSchin  *				+-----------------------+
1801da2e3ebdSchin  *				| | |  window		|
1802da2e3ebdSchin  *				+-----------------------+
1803da2e3ebdSchin  *				cur_window = cur_phys - first_wind
1804da2e3ebdSchin }*/
1805da2e3ebdSchin 
refresh(register Vi_t * vp,int mode)1806da2e3ebdSchin static void refresh(register Vi_t* vp, int mode)
1807da2e3ebdSchin {
1808da2e3ebdSchin 	register int p;
1809da2e3ebdSchin 	register int regb;
1810da2e3ebdSchin 	register int first_w = vp->first_wind;
1811da2e3ebdSchin 	int p_differ;
1812da2e3ebdSchin 	int new_lw;
1813da2e3ebdSchin 	int ncur_phys;
1814da2e3ebdSchin 	int opflag;			/* search optimize flag */
1815da2e3ebdSchin 
1816da2e3ebdSchin #	define	w	regb
1817da2e3ebdSchin #	define	v	regb
1818da2e3ebdSchin 
1819da2e3ebdSchin 	/*** find out if it's necessary to start translating at beginning ***/
1820da2e3ebdSchin 
1821da2e3ebdSchin 	if(lookahead>0)
1822da2e3ebdSchin 	{
1823da2e3ebdSchin 		p = previous[lookahead-1];
1824da2e3ebdSchin 		if(p != ESC && p != '\n' && p != '\r')
1825da2e3ebdSchin 			mode = TRANSLATE;
1826da2e3ebdSchin 	}
1827da2e3ebdSchin 	v = cur_virt;
1828da2e3ebdSchin 	if( v<vp->ocur_virt || vp->ocur_virt==INVALID
1829da2e3ebdSchin 		|| ( v==vp->ocur_virt
1830da2e3ebdSchin 			&& (!is_print(virtual[v]) || !is_print(vp->o_v_char))) )
1831da2e3ebdSchin 	{
1832da2e3ebdSchin 		opflag = 0;
1833da2e3ebdSchin 		p = 0;
1834da2e3ebdSchin 		v = 0;
1835da2e3ebdSchin 	}
1836da2e3ebdSchin 	else
1837da2e3ebdSchin 	{
1838da2e3ebdSchin 		opflag = 1;
1839da2e3ebdSchin 		p = vp->ocur_phys;
1840da2e3ebdSchin 		v = vp->ocur_virt;
1841da2e3ebdSchin 		if( !is_print(virtual[v]) )
1842da2e3ebdSchin 		{
1843da2e3ebdSchin 			/*** avoid double ^'s ***/
1844da2e3ebdSchin 			++p;
1845da2e3ebdSchin 			++v;
1846da2e3ebdSchin 		}
1847da2e3ebdSchin 	}
1848da2e3ebdSchin 	virtual[last_virt+1] = 0;
1849da2e3ebdSchin 	ncur_phys = ed_virt_to_phys(vp->ed,virtual,physical,cur_virt,v,p);
1850da2e3ebdSchin 	p = genlen(physical);
1851da2e3ebdSchin 	if( --p < 0 )
1852da2e3ebdSchin 		last_phys = 0;
1853da2e3ebdSchin 	else
1854da2e3ebdSchin 		last_phys = p;
1855da2e3ebdSchin 
1856da2e3ebdSchin 	/*** see if this was a translate only ***/
1857da2e3ebdSchin 
1858da2e3ebdSchin 	if( mode == TRANSLATE )
1859da2e3ebdSchin 		return;
1860da2e3ebdSchin 
1861da2e3ebdSchin 	/*** adjust left margin if necessary ***/
1862da2e3ebdSchin 
1863da2e3ebdSchin 	if( ncur_phys<first_w || ncur_phys>=(first_w + w_size) )
1864da2e3ebdSchin 	{
1865da2e3ebdSchin 		cursor(vp,first_w);
1866da2e3ebdSchin 		first_w = ncur_phys - (w_size>>1);
1867da2e3ebdSchin 		if( first_w < 0 )
1868da2e3ebdSchin 			first_w = 0;
1869da2e3ebdSchin 		vp->first_wind = cur_phys = first_w;
1870da2e3ebdSchin 	}
1871da2e3ebdSchin 
1872da2e3ebdSchin 	/*** attempt to optimize search somewhat to find ***/
1873da2e3ebdSchin 	/*** out where physical and window images differ ***/
1874da2e3ebdSchin 
1875da2e3ebdSchin 	if( first_w==vp->ofirst_wind && ncur_phys>=vp->ocur_phys && opflag==1 )
1876da2e3ebdSchin 	{
1877da2e3ebdSchin 		p = vp->ocur_phys;
1878da2e3ebdSchin 		w = p - first_w;
1879da2e3ebdSchin 	}
1880da2e3ebdSchin 	else
1881da2e3ebdSchin 	{
1882da2e3ebdSchin 		p = first_w;
1883da2e3ebdSchin 		w = 0;
1884da2e3ebdSchin 	}
1885da2e3ebdSchin 
1886da2e3ebdSchin 	for(; (p<=last_phys && w<=vp->last_wind); ++p, ++w)
1887da2e3ebdSchin 	{
1888da2e3ebdSchin 		if( window[w] != physical[p] )
1889da2e3ebdSchin 			break;
1890da2e3ebdSchin 	}
1891da2e3ebdSchin 	p_differ = p;
1892da2e3ebdSchin 
1893da2e3ebdSchin 	if( (p>last_phys || p>=first_w+w_size) && w>vp->last_wind
1894da2e3ebdSchin 		&& cur_virt==vp->ocur_virt )
1895da2e3ebdSchin 	{
1896da2e3ebdSchin 		/*** images are identical ***/
1897da2e3ebdSchin 		return;
1898da2e3ebdSchin 	}
1899da2e3ebdSchin 
1900da2e3ebdSchin 	/*** copy the physical image to the window image ***/
1901da2e3ebdSchin 
1902da2e3ebdSchin 	if( last_virt != INVALID )
1903da2e3ebdSchin 	{
1904da2e3ebdSchin 		while( p <= last_phys && w < w_size )
1905da2e3ebdSchin 			window[w++] = physical[p++];
1906da2e3ebdSchin 	}
1907da2e3ebdSchin 	new_lw = w;
1908da2e3ebdSchin 
1909da2e3ebdSchin 	/*** erase trailing characters if needed ***/
1910da2e3ebdSchin 
1911da2e3ebdSchin 	while( w <= vp->last_wind )
1912da2e3ebdSchin 		window[w++] = ' ';
1913da2e3ebdSchin 	vp->last_wind = --w;
1914da2e3ebdSchin 
1915da2e3ebdSchin 	p = p_differ;
1916da2e3ebdSchin 
1917da2e3ebdSchin 	/*** move cursor to start of difference ***/
1918da2e3ebdSchin 
1919da2e3ebdSchin 	cursor(vp,p);
1920da2e3ebdSchin 
1921da2e3ebdSchin 	/*** and output difference ***/
1922da2e3ebdSchin 
1923da2e3ebdSchin 	w = p - first_w;
1924da2e3ebdSchin 	while( w <= vp->last_wind )
1925da2e3ebdSchin 		putchar(window[w++]);
1926da2e3ebdSchin 
1927da2e3ebdSchin 	cur_phys = w + first_w;
1928da2e3ebdSchin 	vp->last_wind = --new_lw;
1929da2e3ebdSchin 
1930da2e3ebdSchin 	if( last_phys >= w_size )
1931da2e3ebdSchin 	{
1932da2e3ebdSchin 		if( first_w == 0 )
1933da2e3ebdSchin 			vp->long_char = '>';
1934da2e3ebdSchin 		else if( last_phys < (first_w+w_size) )
1935da2e3ebdSchin 			vp->long_char = '<';
1936da2e3ebdSchin 		else
1937da2e3ebdSchin 			vp->long_char = '*';
1938da2e3ebdSchin 	}
1939da2e3ebdSchin 	else
1940da2e3ebdSchin 		vp->long_char = ' ';
1941da2e3ebdSchin 
1942da2e3ebdSchin 	if( vp->long_line != vp->long_char )
1943da2e3ebdSchin 	{
1944da2e3ebdSchin 		/*** indicate lines longer than window ***/
1945da2e3ebdSchin 		while( w++ < w_size )
1946da2e3ebdSchin 		{
1947da2e3ebdSchin 			putchar(' ');
1948da2e3ebdSchin 			++cur_phys;
1949da2e3ebdSchin 		}
1950da2e3ebdSchin 		putchar(vp->long_char);
1951da2e3ebdSchin 		++cur_phys;
1952da2e3ebdSchin 		vp->long_line = vp->long_char;
1953da2e3ebdSchin 	}
1954da2e3ebdSchin 
19557c2fbfb3SApril Chin 	if(vp->ed->e_multiline &&  vp->ofirst_wind==INVALID && !vp->ed->e_nocrnl)
19567c2fbfb3SApril Chin 		ed_setcursor(vp->ed, physical, last_phys+1, last_phys+1, -1);
19577c2fbfb3SApril Chin 	vp->ed->e_nocrnl = 0;
1958da2e3ebdSchin 	vp->ocur_phys = ncur_phys;
1959da2e3ebdSchin 	vp->ocur_virt = cur_virt;
1960da2e3ebdSchin 	vp->ofirst_wind = first_w;
1961da2e3ebdSchin 
1962da2e3ebdSchin 	if( mode==INPUT && cur_virt>INVALID )
1963da2e3ebdSchin 		++ncur_phys;
1964da2e3ebdSchin 
1965da2e3ebdSchin 	cursor(vp,ncur_phys);
1966da2e3ebdSchin 	ed_flush(vp->ed);
1967da2e3ebdSchin 	return;
1968da2e3ebdSchin }
1969da2e3ebdSchin 
1970da2e3ebdSchin /*{	REPLACE( char, increment )
1971da2e3ebdSchin  *
1972da2e3ebdSchin  *	Replace the cur_virt character with char.  This routine attempts
1973da2e3ebdSchin  * to avoid using refresh().
1974da2e3ebdSchin  *
1975da2e3ebdSchin  *	increment	= 1, increment cur_virt after replacement.
1976da2e3ebdSchin  *			= 0, leave cur_virt where it is.
1977da2e3ebdSchin  *
1978da2e3ebdSchin }*/
1979da2e3ebdSchin 
replace(register Vi_t * vp,register int c,register int increment)1980da2e3ebdSchin static void replace(register Vi_t *vp, register int c, register int increment)
1981da2e3ebdSchin {
1982da2e3ebdSchin 	register int cur_window;
1983da2e3ebdSchin 
1984da2e3ebdSchin 	if( cur_virt == INVALID )
1985da2e3ebdSchin 	{
1986da2e3ebdSchin 		/*** can't replace invalid cursor ***/
1987da2e3ebdSchin 		ed_ringbell();
1988da2e3ebdSchin 		return;
1989da2e3ebdSchin 	}
1990da2e3ebdSchin 	cur_window = cur_phys - vp->first_wind;
1991da2e3ebdSchin 	if( vp->ocur_virt == INVALID || !is_print(c)
1992da2e3ebdSchin 		|| !is_print(virtual[cur_virt])
1993da2e3ebdSchin 		|| !is_print(vp->o_v_char)
1994da2e3ebdSchin #if SHOPT_MULTIBYTE
1995da2e3ebdSchin 		|| !iswascii(c) || mbwidth(vp->o_v_char)>1
1996da2e3ebdSchin 		|| !iswascii(virtual[cur_virt])
1997da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
1998da2e3ebdSchin 		|| (increment && (cur_window==w_size-1)
1999da2e3ebdSchin 			|| !is_print(virtual[cur_virt+1])) )
2000da2e3ebdSchin 	{
2001da2e3ebdSchin 		/*** must use standard refresh routine ***/
2002da2e3ebdSchin 
2003da2e3ebdSchin 		cdelete(vp,1, BAD);
2004da2e3ebdSchin 		append(vp,c, APPEND);
2005da2e3ebdSchin 		if( increment && cur_virt<last_virt )
2006da2e3ebdSchin 			++cur_virt;
2007da2e3ebdSchin 		refresh(vp,CONTROL);
2008da2e3ebdSchin 	}
2009da2e3ebdSchin 	else
2010da2e3ebdSchin 	{
2011da2e3ebdSchin 		virtual[cur_virt] = c;
2012da2e3ebdSchin 		physical[cur_phys] = c;
2013da2e3ebdSchin 		window[cur_window] = c;
2014da2e3ebdSchin 		putchar(c);
2015da2e3ebdSchin 		if(increment)
2016da2e3ebdSchin 		{
2017da2e3ebdSchin 			c = virtual[++cur_virt];
2018da2e3ebdSchin 			++cur_phys;
2019da2e3ebdSchin 		}
2020da2e3ebdSchin 		else
2021da2e3ebdSchin 		{
2022da2e3ebdSchin 			putchar('\b');
2023da2e3ebdSchin 		}
2024da2e3ebdSchin 		vp->o_v_char = c;
2025da2e3ebdSchin 		ed_flush(vp->ed);
2026da2e3ebdSchin 	}
2027da2e3ebdSchin 	return;
2028da2e3ebdSchin }
2029da2e3ebdSchin 
2030da2e3ebdSchin /*{	RESTORE_V()
2031da2e3ebdSchin  *
2032da2e3ebdSchin  *	Restore the contents of virtual space from u_space.
2033da2e3ebdSchin  *
2034da2e3ebdSchin }*/
2035da2e3ebdSchin 
restore_v(register Vi_t * vp)2036da2e3ebdSchin static void restore_v(register Vi_t *vp)
2037da2e3ebdSchin {
2038da2e3ebdSchin 	register int tmpcol;
2039da2e3ebdSchin 	genchar tmpspace[MAXLINE];
2040da2e3ebdSchin 
2041da2e3ebdSchin 	if( vp->u_column == INVALID-1 )
2042da2e3ebdSchin 	{
2043da2e3ebdSchin 		/*** never saved anything ***/
2044da2e3ebdSchin 		ed_ringbell();
2045da2e3ebdSchin 		return;
2046da2e3ebdSchin 	}
2047da2e3ebdSchin 	gencpy(tmpspace, vp->u_space);
2048da2e3ebdSchin 	tmpcol = vp->u_column;
2049da2e3ebdSchin 	save_v(vp);
2050da2e3ebdSchin 	gencpy(virtual, tmpspace);
2051da2e3ebdSchin 	cur_virt = tmpcol;
2052da2e3ebdSchin 	last_virt = genlen(tmpspace) - 1;
2053da2e3ebdSchin 	vp->ocur_virt = MAXCHAR;	/** invalidate refresh optimization **/
2054da2e3ebdSchin 	return;
2055da2e3ebdSchin }
2056da2e3ebdSchin 
2057da2e3ebdSchin /*{	SAVE_LAST()
2058da2e3ebdSchin  *
2059da2e3ebdSchin  *	If the user has typed something, save it in last line.
2060da2e3ebdSchin  *
2061da2e3ebdSchin }*/
2062da2e3ebdSchin 
save_last(register Vi_t * vp)2063da2e3ebdSchin static void save_last(register Vi_t* vp)
2064da2e3ebdSchin {
2065da2e3ebdSchin 	register int i;
2066da2e3ebdSchin 
2067da2e3ebdSchin 	if( (i = cur_virt - first_virt + 1) > 0 )
2068da2e3ebdSchin 	{
2069da2e3ebdSchin 		/*** save last thing user typed ***/
2070da2e3ebdSchin 		if(i >= MAXLINE)
2071da2e3ebdSchin 			i = MAXLINE-1;
2072da2e3ebdSchin 		genncpy(vp->lastline, (&virtual[first_virt]), i);
2073da2e3ebdSchin 		vp->lastline[i] = '\0';
2074da2e3ebdSchin 	}
2075da2e3ebdSchin 	return;
2076da2e3ebdSchin }
2077da2e3ebdSchin 
2078da2e3ebdSchin /*{	SAVE_V()
2079da2e3ebdSchin  *
2080da2e3ebdSchin  *	This routine will save the contents of virtual in u_space.
2081da2e3ebdSchin  *
2082da2e3ebdSchin }*/
2083da2e3ebdSchin 
save_v(register Vi_t * vp)2084da2e3ebdSchin static void save_v(register Vi_t *vp)
2085da2e3ebdSchin {
2086da2e3ebdSchin 	if(!inmacro)
2087da2e3ebdSchin 	{
2088da2e3ebdSchin 		virtual[last_virt + 1] = '\0';
2089da2e3ebdSchin 		gencpy(vp->u_space, virtual);
2090da2e3ebdSchin 		vp->u_column = cur_virt;
2091da2e3ebdSchin 	}
2092da2e3ebdSchin 	return;
2093da2e3ebdSchin }
2094da2e3ebdSchin 
2095da2e3ebdSchin /*{	SEARCH( mode )
2096da2e3ebdSchin  *
2097da2e3ebdSchin  *	Search history file for regular expression.
2098da2e3ebdSchin  *
2099da2e3ebdSchin  *	mode	= '/'	require search string and search new to old
2100da2e3ebdSchin  *	mode	= '?'	require search string and search old to new
2101da2e3ebdSchin  *	mode	= 'N'	repeat last search in reverse direction
2102da2e3ebdSchin  *	mode	= 'n'	repeat last search
2103da2e3ebdSchin  *
2104da2e3ebdSchin }*/
2105da2e3ebdSchin 
2106da2e3ebdSchin /*
2107da2e3ebdSchin  * search for <string> in the current command
2108da2e3ebdSchin  */
curline_search(Vi_t * vp,const char * string)2109da2e3ebdSchin static int curline_search(Vi_t *vp, const char *string)
2110da2e3ebdSchin {
2111da2e3ebdSchin 	register int len=strlen(string);
2112da2e3ebdSchin 	register const char *dp,*cp=string, *dpmax;
2113da2e3ebdSchin #if SHOPT_MULTIBYTE
2114da2e3ebdSchin 	ed_external(vp->u_space,(char*)vp->u_space);
2115da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
2116da2e3ebdSchin 	for(dp=(char*)vp->u_space,dpmax=dp+strlen(dp)-len; dp<=dpmax; dp++)
2117da2e3ebdSchin 	{
2118da2e3ebdSchin 		if(*dp==*cp && memcmp(cp,dp,len)==0)
2119da2e3ebdSchin 			return(dp-(char*)vp->u_space);
2120da2e3ebdSchin 	}
2121da2e3ebdSchin #if SHOPT_MULTIBYTE
2122da2e3ebdSchin 	ed_internal((char*)vp->u_space,vp->u_space);
2123da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
2124da2e3ebdSchin 	return(-1);
2125da2e3ebdSchin }
2126da2e3ebdSchin 
search(register Vi_t * vp,register int mode)2127da2e3ebdSchin static int search(register Vi_t* vp,register int mode)
2128da2e3ebdSchin {
2129da2e3ebdSchin 	register int new_direction;
2130da2e3ebdSchin 	register int oldcurhline;
2131da2e3ebdSchin 	register int i;
2132da2e3ebdSchin 	Histloc_t  location;
2133da2e3ebdSchin 
21347c2fbfb3SApril Chin 	if( vp->direction == -2 && mode != 'n')
21357c2fbfb3SApril Chin 		vp->direction = -1;
2136da2e3ebdSchin 	if( mode == '/' || mode == '?')
2137da2e3ebdSchin 	{
2138da2e3ebdSchin 		/*** new search expression ***/
2139da2e3ebdSchin 		del_line(vp,BAD);
2140da2e3ebdSchin 		append(vp,mode, APPEND);
2141da2e3ebdSchin 		refresh(vp,INPUT);
2142da2e3ebdSchin 		first_virt = 1;
2143da2e3ebdSchin 		getline(vp,SEARCH);
2144da2e3ebdSchin 		first_virt = 0;
2145da2e3ebdSchin 		virtual[last_virt + 1] = '\0';	/*** make null terminated ***/
2146da2e3ebdSchin 		vp->direction = mode=='/' ? -1 : 1;
2147da2e3ebdSchin 	}
2148da2e3ebdSchin 
2149da2e3ebdSchin 	if( cur_virt == INVALID )
2150da2e3ebdSchin 	{
2151da2e3ebdSchin 		/*** no operation ***/
2152da2e3ebdSchin 		return(ABORT);
2153da2e3ebdSchin 	}
2154da2e3ebdSchin 
2155da2e3ebdSchin 	if( cur_virt==0 ||  fold(mode)=='N' )
2156da2e3ebdSchin 	{
2157da2e3ebdSchin 		/*** user wants repeat of last search ***/
2158da2e3ebdSchin 		del_line(vp,BAD);
2159da2e3ebdSchin 		strcpy( ((char*)virtual)+1, lsearch);
2160da2e3ebdSchin #if SHOPT_MULTIBYTE
2161da2e3ebdSchin 		*((char*)virtual) = '/';
2162da2e3ebdSchin 		ed_internal((char*)virtual,virtual);
2163da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
2164da2e3ebdSchin 	}
2165da2e3ebdSchin 
2166da2e3ebdSchin 	if( mode == 'N' )
2167da2e3ebdSchin 		new_direction = -vp->direction;
2168da2e3ebdSchin 	else
2169da2e3ebdSchin 		new_direction = vp->direction;
2170da2e3ebdSchin 
2171da2e3ebdSchin 
2172da2e3ebdSchin 	/*** now search ***/
2173da2e3ebdSchin 
2174da2e3ebdSchin 	oldcurhline = curhline;
2175da2e3ebdSchin #if SHOPT_MULTIBYTE
2176da2e3ebdSchin 	ed_external(virtual,(char*)virtual);
2177da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
2178da2e3ebdSchin 	if(mode=='?' && (i=curline_search(vp,((char*)virtual)+1))>=0)
2179da2e3ebdSchin 	{
2180da2e3ebdSchin 		location.hist_command = curhline;
2181da2e3ebdSchin 		location.hist_char = i;
2182da2e3ebdSchin 	}
2183da2e3ebdSchin 	else
2184da2e3ebdSchin 	{
2185da2e3ebdSchin 		i = INVALID;
2186da2e3ebdSchin 		if( new_direction==1 && curhline >= histmax )
2187da2e3ebdSchin 			curhline = histmin + 1;
2188da2e3ebdSchin 		location = hist_find(sh.hist_ptr,((char*)virtual)+1, curhline, 1, new_direction);
2189da2e3ebdSchin 	}
2190da2e3ebdSchin 	cur_virt = i;
2191da2e3ebdSchin 	strncpy(lsearch, ((char*)virtual)+1, SEARCHSIZE);
2192da2e3ebdSchin 	if( (curhline=location.hist_command) >=0 )
2193da2e3ebdSchin 	{
2194da2e3ebdSchin 		vp->ocur_virt = INVALID;
2195da2e3ebdSchin 		return(GOOD);
2196da2e3ebdSchin 	}
2197da2e3ebdSchin 
2198da2e3ebdSchin 	/*** could not find matching line ***/
2199da2e3ebdSchin 
2200da2e3ebdSchin 	curhline = oldcurhline;
2201da2e3ebdSchin 	return(BAD);
2202da2e3ebdSchin }
2203da2e3ebdSchin 
2204da2e3ebdSchin /*{	SYNC_CURSOR()
2205da2e3ebdSchin  *
2206da2e3ebdSchin  *	This routine will move the physical cursor to the same
2207da2e3ebdSchin  * column as the virtual cursor.
2208da2e3ebdSchin  *
2209da2e3ebdSchin }*/
2210da2e3ebdSchin 
sync_cursor(register Vi_t * vp)2211da2e3ebdSchin static void sync_cursor(register Vi_t *vp)
2212da2e3ebdSchin {
2213da2e3ebdSchin 	register int p;
2214da2e3ebdSchin 	register int v;
2215da2e3ebdSchin 	register int c;
2216da2e3ebdSchin 	int new_phys;
2217da2e3ebdSchin 
2218da2e3ebdSchin 	if( cur_virt == INVALID )
2219da2e3ebdSchin 		return;
2220da2e3ebdSchin 
2221da2e3ebdSchin 	/*** find physical col that corresponds to virtual col ***/
2222da2e3ebdSchin 
2223da2e3ebdSchin 	new_phys = 0;
2224da2e3ebdSchin 	if(vp->first_wind==vp->ofirst_wind && cur_virt>vp->ocur_virt && vp->ocur_virt!=INVALID)
2225da2e3ebdSchin 	{
2226da2e3ebdSchin 		/*** try to optimize search a little ***/
2227da2e3ebdSchin 		p = vp->ocur_phys + 1;
2228da2e3ebdSchin #if SHOPT_MULTIBYTE
2229da2e3ebdSchin 		while(physical[p]==MARKER)
2230da2e3ebdSchin 			p++;
2231da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
2232da2e3ebdSchin 		v = vp->ocur_virt + 1;
2233da2e3ebdSchin 	}
2234da2e3ebdSchin 	else
2235da2e3ebdSchin 	{
2236da2e3ebdSchin 		p = 0;
2237da2e3ebdSchin 		v = 0;
2238da2e3ebdSchin 	}
2239da2e3ebdSchin 	for(; v <= last_virt; ++p, ++v)
2240da2e3ebdSchin 	{
2241da2e3ebdSchin #if SHOPT_MULTIBYTE
2242da2e3ebdSchin 		int d;
2243da2e3ebdSchin 		c = virtual[v];
2244da2e3ebdSchin 		if((d = mbwidth(c)) > 1)
2245da2e3ebdSchin 		{
2246da2e3ebdSchin 			if( v != cur_virt )
2247da2e3ebdSchin 				p += (d-1);
2248da2e3ebdSchin 		}
2249da2e3ebdSchin 		else if(!iswprint(c))
2250da2e3ebdSchin #else
2251da2e3ebdSchin 		c = virtual[v];
2252da2e3ebdSchin 		if(!isprint(c))
2253da2e3ebdSchin #endif	/* SHOPT_MULTIBYTE */
2254da2e3ebdSchin 		{
2255da2e3ebdSchin 			if( c == '\t' )
2256da2e3ebdSchin 			{
2257da2e3ebdSchin 				p -= ((p+editb.e_plen)%TABSIZE);
2258da2e3ebdSchin 				p += (TABSIZE-1);
2259da2e3ebdSchin 			}
2260da2e3ebdSchin 			else
2261da2e3ebdSchin 			{
2262da2e3ebdSchin 				++p;
2263da2e3ebdSchin 			}
2264da2e3ebdSchin 		}
2265da2e3ebdSchin 		if( v == cur_virt )
2266da2e3ebdSchin 		{
2267da2e3ebdSchin 			new_phys = p;
2268da2e3ebdSchin 			break;
2269da2e3ebdSchin 		}
2270da2e3ebdSchin 	}
2271da2e3ebdSchin 
2272da2e3ebdSchin 	if( new_phys < vp->first_wind || new_phys >= vp->first_wind + w_size )
2273da2e3ebdSchin 	{
2274da2e3ebdSchin 		/*** asked to move outside of window ***/
2275da2e3ebdSchin 
2276da2e3ebdSchin 		window[0] = '\0';
2277da2e3ebdSchin 		refresh(vp,CONTROL);
2278da2e3ebdSchin 		return;
2279da2e3ebdSchin 	}
2280da2e3ebdSchin 
2281da2e3ebdSchin 	cursor(vp,new_phys);
2282da2e3ebdSchin 	ed_flush(vp->ed);
2283da2e3ebdSchin 	vp->ocur_phys = cur_phys;
2284da2e3ebdSchin 	vp->ocur_virt = cur_virt;
2285da2e3ebdSchin 	vp->o_v_char = virtual[vp->ocur_virt];
2286da2e3ebdSchin 
2287da2e3ebdSchin 	return;
2288da2e3ebdSchin }
2289da2e3ebdSchin 
2290da2e3ebdSchin /*{	TEXTMOD( command, mode )
2291da2e3ebdSchin  *
2292da2e3ebdSchin  *	Modify text operations.
2293da2e3ebdSchin  *
2294da2e3ebdSchin  *	mode != 0, repeat previous operation
2295da2e3ebdSchin  *
2296da2e3ebdSchin }*/
2297da2e3ebdSchin 
textmod(register Vi_t * vp,register int c,int mode)2298da2e3ebdSchin static int textmod(register Vi_t *vp,register int c, int mode)
2299da2e3ebdSchin {
2300da2e3ebdSchin 	register int i;
2301da2e3ebdSchin 	register genchar *p = vp->lastline;
2302da2e3ebdSchin 	register int trepeat = vp->repeat;
2303da2e3ebdSchin 	genchar *savep;
2304da2e3ebdSchin 
2305da2e3ebdSchin 	if(mode && (fold(vp->lastmotion)=='F' || fold(vp->lastmotion)=='T'))
2306da2e3ebdSchin 		vp->lastmotion = ';';
2307da2e3ebdSchin 
2308da2e3ebdSchin 	if( fold(c) == 'P' )
2309da2e3ebdSchin 	{
2310da2e3ebdSchin 		/*** change p from lastline to yankbuf ***/
2311da2e3ebdSchin 		p = yankbuf;
2312da2e3ebdSchin 	}
2313da2e3ebdSchin 
2314da2e3ebdSchin addin:
2315da2e3ebdSchin 	switch( c )
2316da2e3ebdSchin 	{
2317da2e3ebdSchin 			/***** Input commands *****/
2318da2e3ebdSchin 
2319da2e3ebdSchin #if KSHELL
2320da2e3ebdSchin         case '\t':
2321da2e3ebdSchin 		if(vp->ed->e_tabcount!=1)
2322da2e3ebdSchin 			return(BAD);
2323da2e3ebdSchin 		c = '=';
2324da2e3ebdSchin 	case '*':		/** do file name expansion in place **/
2325da2e3ebdSchin 	case '\\':		/** do file name completion in place **/
2326da2e3ebdSchin 		if( cur_virt == INVALID )
2327da2e3ebdSchin 			return(BAD);
2328da2e3ebdSchin 	case '=':		/** list file name expansions **/
2329da2e3ebdSchin 		save_v(vp);
2330da2e3ebdSchin 		i = last_virt;
2331da2e3ebdSchin 		++last_virt;
2332da2e3ebdSchin 		mode = cur_virt-1;
2333da2e3ebdSchin 		virtual[last_virt] = 0;
2334da2e3ebdSchin 		if(ed_expand(vp->ed,(char*)virtual, &cur_virt, &last_virt, c, vp->repeat_set?vp->repeat:-1)<0)
2335da2e3ebdSchin 		{
2336da2e3ebdSchin 			if(vp->ed->e_tabcount)
2337da2e3ebdSchin 			{
2338da2e3ebdSchin 				vp->ed->e_tabcount=2;
2339da2e3ebdSchin 				ed_ungetchar(vp->ed,'\t');
2340da2e3ebdSchin 				--last_virt;
2341da2e3ebdSchin 				return(APPEND);
2342da2e3ebdSchin 			}
2343da2e3ebdSchin 			last_virt = i;
2344da2e3ebdSchin 			ed_ringbell();
2345da2e3ebdSchin 		}
2346da2e3ebdSchin 		else if(c == '=' && !vp->repeat_set)
2347da2e3ebdSchin 		{
2348da2e3ebdSchin 			last_virt = i;
2349da2e3ebdSchin 			vp->nonewline++;
2350da2e3ebdSchin 			ed_ungetchar(vp->ed,cntl('L'));
2351da2e3ebdSchin 			return(GOOD);
2352da2e3ebdSchin 		}
2353da2e3ebdSchin 		else
2354da2e3ebdSchin 		{
2355da2e3ebdSchin 			--cur_virt;
2356da2e3ebdSchin 			--last_virt;
2357da2e3ebdSchin 			vp->ocur_virt = MAXCHAR;
2358da2e3ebdSchin 			if(c=='=' || (mode<cur_virt && (virtual[cur_virt]==' ' || virtual[cur_virt]=='/')))
2359da2e3ebdSchin 				vp->ed->e_tabcount = 0;
2360da2e3ebdSchin 			return(APPEND);
2361da2e3ebdSchin 		}
2362da2e3ebdSchin 		break;
2363da2e3ebdSchin 
2364da2e3ebdSchin 	case '@':		/** macro expansion **/
2365da2e3ebdSchin 		if( mode )
2366da2e3ebdSchin 			c = vp->lastmacro;
2367da2e3ebdSchin 		else
2368da2e3ebdSchin 			if((c=getrchar(vp))==ESC)
2369da2e3ebdSchin 				return(GOOD);
2370da2e3ebdSchin 		if(!inmacro)
2371da2e3ebdSchin 			vp->lastmacro = c;
2372da2e3ebdSchin 		if(ed_macro(vp->ed,c))
2373da2e3ebdSchin 		{
2374da2e3ebdSchin 			save_v(vp);
2375da2e3ebdSchin 			inmacro++;
2376da2e3ebdSchin 			return(GOOD);
2377da2e3ebdSchin 		}
2378da2e3ebdSchin 		ed_ringbell();
2379da2e3ebdSchin 		return(BAD);
2380da2e3ebdSchin 
2381da2e3ebdSchin #endif	/* KSHELL */
2382da2e3ebdSchin 	case '_':		/** append last argument of prev command **/
2383da2e3ebdSchin 		save_v(vp);
2384da2e3ebdSchin 		{
2385da2e3ebdSchin 			genchar tmpbuf[MAXLINE];
2386da2e3ebdSchin 			if(vp->repeat_set==0)
2387da2e3ebdSchin 				vp->repeat = -1;
2388da2e3ebdSchin 			p = (genchar*)hist_word((char*)tmpbuf,MAXLINE,vp->repeat);
2389da2e3ebdSchin 			if(p==0)
2390da2e3ebdSchin 			{
2391da2e3ebdSchin 				ed_ringbell();
2392da2e3ebdSchin 				break;
2393da2e3ebdSchin 			}
2394da2e3ebdSchin #if SHOPT_MULTIBYTE
2395da2e3ebdSchin 			ed_internal((char*)p,tmpbuf);
2396da2e3ebdSchin 			p = tmpbuf;
2397da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
2398da2e3ebdSchin 			i = ' ';
2399da2e3ebdSchin 			do
2400da2e3ebdSchin 			{
2401da2e3ebdSchin 				append(vp,i,APPEND);
2402da2e3ebdSchin 			}
2403da2e3ebdSchin 			while(i = *p++);
2404da2e3ebdSchin 			return(APPEND);
2405da2e3ebdSchin 		}
2406da2e3ebdSchin 
2407da2e3ebdSchin 	case 'A':		/** append to end of line **/
2408da2e3ebdSchin 		cur_virt = last_virt;
2409da2e3ebdSchin 		sync_cursor(vp);
2410da2e3ebdSchin 
2411da2e3ebdSchin 	case 'a':		/** append **/
2412da2e3ebdSchin 		if( fold(mode) == 'A' )
2413da2e3ebdSchin 		{
2414da2e3ebdSchin 			c = 'p';
2415da2e3ebdSchin 			goto addin;
2416da2e3ebdSchin 		}
2417da2e3ebdSchin 		save_v(vp);
2418da2e3ebdSchin 		if( cur_virt != INVALID )
2419da2e3ebdSchin 		{
2420da2e3ebdSchin 			first_virt = cur_virt + 1;
2421da2e3ebdSchin 			cursor(vp,cur_phys + 1);
2422da2e3ebdSchin 			ed_flush(vp->ed);
2423da2e3ebdSchin 		}
2424da2e3ebdSchin 		return(APPEND);
2425da2e3ebdSchin 
2426da2e3ebdSchin 	case 'I':		/** insert at beginning of line **/
2427da2e3ebdSchin 		cur_virt = first_virt;
2428da2e3ebdSchin 		sync_cursor(vp);
2429da2e3ebdSchin 
2430da2e3ebdSchin 	case 'i':		/** insert **/
2431da2e3ebdSchin 		if( fold(mode) == 'I' )
2432da2e3ebdSchin 		{
2433da2e3ebdSchin 			c = 'P';
2434da2e3ebdSchin 			goto addin;
2435da2e3ebdSchin 		}
2436da2e3ebdSchin 		save_v(vp);
2437da2e3ebdSchin 		if( cur_virt != INVALID )
2438da2e3ebdSchin  		{
2439da2e3ebdSchin  			vp->o_v_char = virtual[cur_virt];
2440da2e3ebdSchin 			first_virt = cur_virt--;
2441da2e3ebdSchin   		}
2442da2e3ebdSchin 		return(INSERT);
2443da2e3ebdSchin 
2444da2e3ebdSchin 	case 'C':		/** change to eol **/
2445da2e3ebdSchin 		c = '$';
2446da2e3ebdSchin 		goto chgeol;
2447da2e3ebdSchin 
2448da2e3ebdSchin 	case 'c':		/** change **/
2449da2e3ebdSchin 		if( mode )
2450da2e3ebdSchin 			c = vp->lastmotion;
2451da2e3ebdSchin 		else
2452da2e3ebdSchin 			c = getcount(vp,ed_getchar(vp->ed,-1));
2453da2e3ebdSchin chgeol:
2454da2e3ebdSchin 		vp->lastmotion = c;
2455da2e3ebdSchin 		if( c == 'c' )
2456da2e3ebdSchin 		{
2457da2e3ebdSchin 			del_line(vp,GOOD);
2458da2e3ebdSchin 			return(APPEND);
2459da2e3ebdSchin 		}
2460da2e3ebdSchin 
2461da2e3ebdSchin 		if(!delmotion(vp, c, 'c'))
2462da2e3ebdSchin 			return(BAD);
2463da2e3ebdSchin 
2464da2e3ebdSchin 		if( mode == 'c' )
2465da2e3ebdSchin 		{
2466da2e3ebdSchin 			c = 'p';
2467da2e3ebdSchin 			trepeat = 1;
2468da2e3ebdSchin 			goto addin;
2469da2e3ebdSchin 		}
2470da2e3ebdSchin 		first_virt = cur_virt + 1;
2471da2e3ebdSchin 		return(APPEND);
2472da2e3ebdSchin 
2473da2e3ebdSchin 	case 'D':		/** delete to eol **/
2474da2e3ebdSchin 		c = '$';
2475da2e3ebdSchin 		goto deleol;
2476da2e3ebdSchin 
2477da2e3ebdSchin 	case 'd':		/** delete **/
2478da2e3ebdSchin 		if( mode )
2479da2e3ebdSchin 			c = vp->lastmotion;
2480da2e3ebdSchin 		else
2481da2e3ebdSchin 			c = getcount(vp,ed_getchar(vp->ed,-1));
2482da2e3ebdSchin deleol:
2483da2e3ebdSchin 		vp->lastmotion = c;
2484da2e3ebdSchin 		if( c == 'd' )
2485da2e3ebdSchin 		{
2486da2e3ebdSchin 			del_line(vp,GOOD);
2487da2e3ebdSchin 			break;
2488da2e3ebdSchin 		}
2489da2e3ebdSchin 		if(!delmotion(vp, c, 'd'))
2490da2e3ebdSchin 			return(BAD);
2491da2e3ebdSchin 		if( cur_virt < last_virt )
2492da2e3ebdSchin 			++cur_virt;
2493da2e3ebdSchin 		break;
2494da2e3ebdSchin 
2495da2e3ebdSchin 	case 'P':
2496da2e3ebdSchin 		if( p[0] == '\0' )
2497da2e3ebdSchin 			return(BAD);
2498da2e3ebdSchin 		if( cur_virt != INVALID )
2499da2e3ebdSchin 		{
2500da2e3ebdSchin 			i = virtual[cur_virt];
2501da2e3ebdSchin 			if(!is_print(i))
2502da2e3ebdSchin 				vp->ocur_virt = INVALID;
2503da2e3ebdSchin 			--cur_virt;
2504da2e3ebdSchin 		}
2505da2e3ebdSchin 
2506da2e3ebdSchin 	case 'p':		/** print **/
2507da2e3ebdSchin 		if( p[0] == '\0' )
2508da2e3ebdSchin 			return(BAD);
2509da2e3ebdSchin 
2510da2e3ebdSchin 		if( mode != 's' && mode != 'c' )
2511da2e3ebdSchin 		{
2512da2e3ebdSchin 			save_v(vp);
2513da2e3ebdSchin 			if( c == 'P' )
2514da2e3ebdSchin 			{
2515da2e3ebdSchin 				/*** fix stored cur_virt ***/
2516da2e3ebdSchin 				++vp->u_column;
2517da2e3ebdSchin 			}
2518da2e3ebdSchin 		}
2519da2e3ebdSchin 		if( mode == 'R' )
2520da2e3ebdSchin 			mode = REPLACE;
2521da2e3ebdSchin 		else
2522da2e3ebdSchin 			mode = APPEND;
2523da2e3ebdSchin 		savep = p;
2524da2e3ebdSchin 		for(i=0; i<trepeat; ++i)
2525da2e3ebdSchin 		{
2526da2e3ebdSchin 			while(c= *p++)
2527da2e3ebdSchin 				append(vp,c,mode);
2528da2e3ebdSchin 			p = savep;
2529da2e3ebdSchin 		}
2530da2e3ebdSchin 		break;
2531da2e3ebdSchin 
2532da2e3ebdSchin 	case 'R':		/* Replace many chars **/
2533da2e3ebdSchin 		if( mode == 'R' )
2534da2e3ebdSchin 		{
2535da2e3ebdSchin 			c = 'P';
2536da2e3ebdSchin 			goto addin;
2537da2e3ebdSchin 		}
2538da2e3ebdSchin 		save_v(vp);
2539da2e3ebdSchin 		if( cur_virt != INVALID )
2540da2e3ebdSchin 			first_virt = cur_virt;
2541da2e3ebdSchin 		return(REPLACE);
2542da2e3ebdSchin 
2543da2e3ebdSchin 	case 'r':		/** replace **/
2544da2e3ebdSchin 		if( mode )
2545da2e3ebdSchin 			c = *p;
2546da2e3ebdSchin 		else
2547da2e3ebdSchin 			if((c=getrchar(vp))==ESC)
2548da2e3ebdSchin 				return(GOOD);
2549da2e3ebdSchin 		*p = c;
2550da2e3ebdSchin 		save_v(vp);
2551da2e3ebdSchin 		while(trepeat--)
2552da2e3ebdSchin 			replace(vp,c, trepeat!=0);
2553da2e3ebdSchin 		return(GOOD);
2554da2e3ebdSchin 
2555da2e3ebdSchin 	case 'S':		/** Substitute line - cc **/
2556da2e3ebdSchin 		c = 'c';
2557da2e3ebdSchin 		goto chgeol;
2558da2e3ebdSchin 
2559da2e3ebdSchin 	case 's':		/** substitute **/
2560da2e3ebdSchin 		save_v(vp);
2561da2e3ebdSchin 		cdelete(vp,vp->repeat, BAD);
2562da2e3ebdSchin 		if( mode )
2563da2e3ebdSchin 		{
2564da2e3ebdSchin 			c = 'p';
2565da2e3ebdSchin 			trepeat = 1;
2566da2e3ebdSchin 			goto addin;
2567da2e3ebdSchin 		}
2568da2e3ebdSchin 		first_virt = cur_virt + 1;
2569da2e3ebdSchin 		return(APPEND);
2570da2e3ebdSchin 
2571da2e3ebdSchin 	case 'Y':		/** Yank to end of line **/
2572da2e3ebdSchin 		c = '$';
2573da2e3ebdSchin 		goto yankeol;
2574da2e3ebdSchin 
2575da2e3ebdSchin 	case 'y':		/** yank thru motion **/
2576da2e3ebdSchin 		if( mode )
2577da2e3ebdSchin 			c = vp->lastmotion;
2578da2e3ebdSchin 		else
2579da2e3ebdSchin 			c = getcount(vp,ed_getchar(vp->ed,-1));
2580da2e3ebdSchin yankeol:
2581da2e3ebdSchin 		vp->lastmotion = c;
2582da2e3ebdSchin 		if( c == 'y' )
2583da2e3ebdSchin 		{
2584da2e3ebdSchin 			gencpy(yankbuf, virtual);
2585da2e3ebdSchin 		}
2586da2e3ebdSchin 		else if(!delmotion(vp, c, 'y'))
2587da2e3ebdSchin 		{
2588da2e3ebdSchin 			return(BAD);
2589da2e3ebdSchin 		}
2590da2e3ebdSchin 		break;
2591da2e3ebdSchin 
2592da2e3ebdSchin 	case 'x':		/** delete repeat chars forward - dl **/
2593da2e3ebdSchin 		c = 'l';
2594da2e3ebdSchin 		goto deleol;
2595da2e3ebdSchin 
2596da2e3ebdSchin 	case 'X':		/** delete repeat chars backward - dh **/
2597da2e3ebdSchin 		c = 'h';
2598da2e3ebdSchin 		goto deleol;
2599da2e3ebdSchin 
2600da2e3ebdSchin 	case '~':		/** invert case and advance **/
2601da2e3ebdSchin 		if( cur_virt != INVALID )
2602da2e3ebdSchin 		{
2603da2e3ebdSchin 			save_v(vp);
2604da2e3ebdSchin 			i = INVALID;
2605da2e3ebdSchin 			while(trepeat-->0 && i!=cur_virt)
2606da2e3ebdSchin 			{
2607da2e3ebdSchin 				i = cur_virt;
2608da2e3ebdSchin 				c = virtual[cur_virt];
2609da2e3ebdSchin #if SHOPT_MULTIBYTE
2610da2e3ebdSchin 				if((c&~STRIP)==0)
2611da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
2612da2e3ebdSchin 				if( isupper(c) )
2613da2e3ebdSchin 					c = tolower(c);
2614da2e3ebdSchin 				else if( islower(c) )
2615da2e3ebdSchin 					c = toupper(c);
2616da2e3ebdSchin 				replace(vp,c, 1);
2617da2e3ebdSchin 			}
2618da2e3ebdSchin 			return(GOOD);
2619da2e3ebdSchin 		}
2620da2e3ebdSchin 		else
2621da2e3ebdSchin 			return(BAD);
2622da2e3ebdSchin 
2623da2e3ebdSchin 	default:
2624da2e3ebdSchin 		return(BAD);
2625da2e3ebdSchin 	}
2626da2e3ebdSchin 	refresh(vp,CONTROL);
2627da2e3ebdSchin 	return(GOOD);
2628da2e3ebdSchin }
2629da2e3ebdSchin 
2630da2e3ebdSchin 
2631da2e3ebdSchin #if SHOPT_MULTIBYTE
_isalph(register int v)2632da2e3ebdSchin     static int _isalph(register int v)
2633da2e3ebdSchin     {
2634da2e3ebdSchin #ifdef _lib_iswalnum
2635da2e3ebdSchin 	return(iswalnum(v) || v=='_');
2636da2e3ebdSchin #else
2637da2e3ebdSchin 	return((v&~STRIP) || isalnum(v) || v=='_');
2638da2e3ebdSchin #endif
2639da2e3ebdSchin     }
2640da2e3ebdSchin 
2641da2e3ebdSchin 
_isblank(register int v)2642da2e3ebdSchin     static int _isblank(register int v)
2643da2e3ebdSchin     {
2644da2e3ebdSchin 	return((v&~STRIP)==0 && isspace(v));
2645da2e3ebdSchin     }
2646da2e3ebdSchin 
_ismetach(register int v)2647da2e3ebdSchin     static int _ismetach(register int v)
2648da2e3ebdSchin     {
2649da2e3ebdSchin 	return((v&~STRIP)==0 && ismeta(v));
2650da2e3ebdSchin     }
2651da2e3ebdSchin 
2652da2e3ebdSchin #endif	/* SHOPT_MULTIBYTE */
2653da2e3ebdSchin 
2654da2e3ebdSchin /*
2655da2e3ebdSchin  * get a character, after ^V processing
2656da2e3ebdSchin  */
getrchar(register Vi_t * vp)2657da2e3ebdSchin static int getrchar(register Vi_t *vp)
2658da2e3ebdSchin {
2659da2e3ebdSchin 	register int c;
2660da2e3ebdSchin 	if((c=ed_getchar(vp->ed,1))== usrlnext)
2661da2e3ebdSchin 		c = ed_getchar(vp->ed,2);
2662da2e3ebdSchin 	return(c);
2663da2e3ebdSchin }
2664