xref: /onnv-gate/usr/src/lib/libshell/common/edit/vi.c (revision 12068:08a39a083754)
14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*12068SRoger.Faulkner@Oracle.COM *          Copyright (c) 1982-2010 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
78462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
84887Schin *                                                                      *
94887Schin *                A copy of the License is available at                 *
104887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
114887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
124887Schin *                                                                      *
134887Schin *              Information and Software Systems Research               *
144887Schin *                            AT&T Research                             *
154887Schin *                           Florham Park NJ                            *
164887Schin *                                                                      *
174887Schin *                  David Korn <dgk@research.att.com>                   *
184887Schin *                                                                      *
194887Schin ***********************************************************************/
204887Schin #pragma prototyped
214887Schin /* Adapted for ksh by David Korn */
224887Schin /*+	VI.C			P.D. Sullivan
234887Schin  *
244887Schin  *	One line editor for the shell based on the vi editor.
254887Schin  *
264887Schin  *	Questions to:
274887Schin  *		P.D. Sullivan
284887Schin  *		cbosgd!pds
294887Schin -*/
304887Schin 
314887Schin 
324887Schin #if KSHELL
334887Schin #   include	"defs.h"
344887Schin #else
354887Schin #   include	<ast.h>
364887Schin #   include	"FEATURE/options"
3710898Sroland.mainz@nrubsig.org #   include	<ctype.h>
384887Schin #endif	/* KSHELL */
394887Schin #include	"io.h"
404887Schin 
414887Schin #include	"history.h"
424887Schin #include	"edit.h"
434887Schin #include	"terminal.h"
444887Schin #include	"FEATURE/time"
454887Schin 
464887Schin #if SHOPT_OLDTERMIO
474887Schin #   undef ECHOCTL
484887Schin #   define echoctl	(vp->ed->e_echoctl)
494887Schin #else
504887Schin #   ifdef ECHOCTL
514887Schin #	define echoctl	ECHOCTL
524887Schin #   else
534887Schin #	define echoctl	0
544887Schin #   endif /* ECHOCTL */
554887Schin #endif /*SHOPT_OLDTERMIO */
564887Schin 
574887Schin #ifndef FIORDCHK
584887Schin #   define NTICKS	5		/* number of ticks for typeahead */
594887Schin #endif /* FIORDCHK */
604887Schin 
614887Schin #define	MAXCHAR	MAXLINE-2		/* max char per line */
624887Schin 
634887Schin #if SHOPT_MULTIBYTE
644887Schin #   include	"lexstates.h"
654887Schin #   define gencpy(a,b)	ed_gencpy(a,b)
664887Schin #   define genncpy(a,b,n)	ed_genncpy(a,b,n)
674887Schin #   define genlen(str)	ed_genlen(str)
684887Schin #   define digit(c)	((c&~STRIP)==0 && isdigit(c))
694887Schin #   define is_print(c)	((c&~STRIP) || isprint(c))
704887Schin #   if !_lib_iswprint && !defined(iswprint)
714887Schin #	define iswprint(c)	((c&~0177) || isprint(c))
724887Schin #   endif
734887Schin     static int _isalph(int);
744887Schin     static int _ismetach(int);
754887Schin     static int _isblank(int);
764887Schin #   undef  isblank
774887Schin #   define isblank(v)	_isblank(virtual[v])
784887Schin #   define isalph(v)	_isalph(virtual[v])
794887Schin #   define ismetach(v)	_ismetach(virtual[v])
804887Schin #else
814887Schin     static genchar	_c;
824887Schin #   define gencpy(a,b)	strcpy((char*)(a),(char*)(b))
834887Schin #   define genncpy(a,b,n) strncpy((char*)(a),(char*)(b),n)
844887Schin #   define genlen(str)	strlen(str)
854887Schin #   define isalph(v)	((_c=virtual[v])=='_'||isalnum(_c))
864887Schin #   undef  isblank
874887Schin #   define isblank(v)	isspace(virtual[v])
884887Schin #   define ismetach(v)	ismeta(virtual[v])
894887Schin #   define digit(c)	isdigit(c)
904887Schin #   define is_print(c)	isprint(c)
914887Schin #endif	/* SHOPT_MULTIBYTE */
924887Schin 
934887Schin #if ( 'a' == 97) /* ASCII? */
944887Schin #   define fold(c)	((c)&~040)	/* lower and uppercase equivalent */
954887Schin #else
964887Schin #   define fold(c)	((c)|0100)	/* lower and uppercase equivalent */
974887Schin #endif
984887Schin 
994887Schin #ifndef iswascii
1004887Schin #define iswascii(c)	(!((c)&(~0177)))
1014887Schin #endif
1024887Schin 
1034887Schin typedef struct _vi_
1044887Schin {
1054887Schin 	int direction;
1064887Schin 	int lastmacro;
1074887Schin 	char addnl;		/* boolean - add newline flag */
1084887Schin 	char last_find;		/* last find command */
1094887Schin 	char last_cmd;		/* last command */
1104887Schin 	char repeat_set;
1114887Schin 	char nonewline;
1124887Schin 	int findchar;		/* last find char */
1134887Schin 	genchar *lastline;
1144887Schin 	int first_wind;		/* first column of window */
1154887Schin 	int last_wind;		/* last column in window */
1164887Schin 	int lastmotion;		/* last motion */
1174887Schin 	int long_char; 		/* line bigger than window */
1184887Schin 	int long_line;		/* line bigger than window */
1194887Schin 	int ocur_phys;		/* old current physical position */
1204887Schin 	int ocur_virt;		/* old last virtual position */
1214887Schin 	int ofirst_wind;	/* old window first col */
1224887Schin 	int o_v_char;		/* prev virtual[ocur_virt] */
1234887Schin 	int repeat;		/* repeat count for motion cmds */
1244887Schin 	int lastrepeat;		/* last repeat count for motion cmds */
1254887Schin 	int u_column;		/* undo current column */
1264887Schin 	int U_saved;		/* original virtual saved */
1274887Schin 	genchar *U_space;	/* used for U command */
1284887Schin 	genchar *u_space;	/* used for u command */
1294887Schin #ifdef FIORDCHK
1304887Schin 	clock_t typeahead;	/* typeahead occurred */
1314887Schin #else
1324887Schin 	int typeahead;		/* typeahead occurred */
1334887Schin #endif	/* FIORDCHK */
1344887Schin #if SHOPT_MULTIBYTE
1354887Schin 	int bigvi;
1364887Schin #endif
1374887Schin 	Edit_t	*ed;		/* pointer to edit data */
1384887Schin } Vi_t;
1394887Schin 
1404887Schin #define editb	(*vp->ed)
1414887Schin 
1424887Schin #undef putchar
1434887Schin #define putchar(c)	ed_putchar(vp->ed,c)
1444887Schin 
1454887Schin #define crallowed	editb.e_crlf
1464887Schin #define cur_virt	editb.e_cur		/* current virtual column */
1474887Schin #define cur_phys	editb.e_pcur	/* current phys column cursor is at */
1484887Schin #define curhline	editb.e_hline		/* current history line */
1494887Schin #define first_virt	editb.e_fcol		/* first allowable column */
1504887Schin #define	globals		editb.e_globals		/* local global variables */
1514887Schin #define histmin		editb.e_hismin
1524887Schin #define histmax		editb.e_hismax
1534887Schin #define last_phys	editb.e_peol		/* last column in physical */
1544887Schin #define last_virt	editb.e_eol		/* last column */
1554887Schin #define lsearch		editb.e_search		/* last search string */
1564887Schin #define lookahead	editb.e_lookahead	/* characters in buffer */
1574887Schin #define previous	editb.e_lbuf		/* lookahead buffer */
1584887Schin #define max_col		editb.e_llimit		/* maximum column */
1594887Schin #define Prompt		editb.e_prompt		/* pointer to prompt */
1604887Schin #define plen		editb.e_plen		/* length of prompt */
1614887Schin #define physical	editb.e_physbuf		/* physical image */
1624887Schin #define usreof		editb.e_eof		/* user defined eof char */
1634887Schin #define usrerase	editb.e_erase		/* user defined erase char */
1644887Schin #define usrlnext	editb.e_lnext		/* user defined next literal */
1654887Schin #define usrkill		editb.e_kill		/* user defined kill char */
1664887Schin #define virtual		editb.e_inbuf	/* pointer to virtual image buffer */
1674887Schin #define	window		editb.e_window		/* window buffer */
1684887Schin #define	w_size		editb.e_wsize		/* window size */
1694887Schin #define	inmacro		editb.e_inmacro		/* true when in macro */
1704887Schin #define yankbuf		editb.e_killbuf		/* yank/delete buffer */
1714887Schin 
1724887Schin 
1734887Schin #define	ABORT	-2			/* user abort */
1744887Schin #define	APPEND	-10			/* append chars */
1754887Schin #define	BAD	-1			/* failure flag */
1764887Schin #define	BIGVI	-15			/* user wants real vi */
1774887Schin #define	CONTROL	-20			/* control mode */
1784887Schin #define	ENTER	-25			/* enter flag */
1794887Schin #define	GOOD	0			/* success flag */
1804887Schin #define	INPUT	-30			/* input mode */
1814887Schin #define	INSERT	-35			/* insert mode */
1824887Schin #define	REPLACE	-40			/* replace chars */
1834887Schin #define	SEARCH	-45			/* search flag */
1844887Schin #define	TRANSLATE	-50		/* translate virt to phys only */
1854887Schin 
1864887Schin #define	INVALID	(-1)			/* invalid column */
1874887Schin 
1884887Schin static const char paren_chars[] = "([{)]}";   /* for % command */
1894887Schin 
1904887Schin static void	cursor(Vi_t*, int);
1914887Schin static void	del_line(Vi_t*,int);
1924887Schin static int	getcount(Vi_t*,int);
1934887Schin static void	getline(Vi_t*,int);
1944887Schin static int	getrchar(Vi_t*);
1954887Schin static int	mvcursor(Vi_t*,int);
1964887Schin static void	pr_string(Vi_t*,const char*);
1974887Schin static void	putstring(Vi_t*,int, int);
1984887Schin static void	refresh(Vi_t*,int);
1994887Schin static void	replace(Vi_t*,int, int);
2004887Schin static void	restore_v(Vi_t*);
2014887Schin static void	save_last(Vi_t*);
2024887Schin static void	save_v(Vi_t*);
2034887Schin static int	search(Vi_t*,int);
2044887Schin static void	sync_cursor(Vi_t*);
2054887Schin static int	textmod(Vi_t*,int,int);
2064887Schin 
2074887Schin /*+	VI_READ( fd, shbuf, nchar )
2084887Schin  *
2094887Schin  *	This routine implements a one line version of vi and is
2104887Schin  * called by _filbuf.c
2114887Schin  *
2124887Schin -*/
2134887Schin 
2144887Schin /*
2154887Schin  * if reedit is non-zero, initialize edit buffer with reedit chars
2164887Schin  */
ed_viread(void * context,int fd,register char * shbuf,int nchar,int reedit)2174887Schin int ed_viread(void *context, int fd, register char *shbuf, int nchar, int reedit)
2184887Schin {
2194887Schin 	Edit_t *ed = (Edit_t*)context;
2204887Schin 	register int i;			/* general variable */
2214887Schin 	register int term_char;		/* read() termination character */
2224887Schin 	register Vi_t *vp = ed->e_vi;
2234887Schin 	char prompt[PRSIZE+2];		/* prompt */
2244887Schin 	genchar Physical[2*MAXLINE];	/* physical image */
2254887Schin 	genchar Ubuf[MAXLINE];	/* used for U command */
2264887Schin 	genchar ubuf[MAXLINE];	/* used for u command */
2274887Schin 	genchar Window[MAXLINE];	/* window image */
2284887Schin 	int Globals[9];			/* local global variables */
2294887Schin 	int esc_or_hang=0;		/* <ESC> or hangup */
2304887Schin 	char cntl_char=0;		/* TRUE if control character present */
2314887Schin #if SHOPT_RAWONLY
2324887Schin #   define viraw	1
2334887Schin #else
2344887Schin 	int viraw = (sh_isoption(SH_VIRAW) || sh.st.trap[SH_KEYTRAP]);
2354887Schin #   ifndef FIORDCHK
2364887Schin 	clock_t oldtime, newtime;
2374887Schin 	struct tms dummy;
2384887Schin #   endif /* FIORDCHK */
2394887Schin #endif /* SHOPT_RAWONLY */
2404887Schin 	if(!vp)
2414887Schin 	{
2424887Schin 		ed->e_vi = vp =  newof(0,Vi_t,1,0);
2434887Schin 		vp->lastline = (genchar*)malloc(MAXLINE*CHARSIZE);
2444887Schin 		vp->direction = -1;
2454887Schin 		vp->ed = ed;
2464887Schin 	}
2474887Schin 
2484887Schin 	/*** setup prompt ***/
2494887Schin 
2504887Schin 	Prompt = prompt;
2514887Schin 	ed_setup(vp->ed,fd, reedit);
2524887Schin 	shbuf[reedit] = 0;
2534887Schin 
2544887Schin #if !SHOPT_RAWONLY
2554887Schin 	if(!viraw)
2564887Schin 	{
2574887Schin 		/*** Change the eol characters to '\r' and eof  ***/
2584887Schin 		/* in addition to '\n' and make eof an ESC	*/
2594887Schin 		if(tty_alt(ERRIO) < 0)
2604887Schin 			return(reexit?reedit:ed_read(context, fd, shbuf, nchar,0));
2614887Schin 
2624887Schin #ifdef FIORDCHK
2634887Schin 		ioctl(fd,FIORDCHK,&vp->typeahead);
2644887Schin #else
2654887Schin 		/* time the current line to determine typeahead */
2664887Schin 		oldtime = times(&dummy);
2674887Schin #endif /* FIORDCHK */
2684887Schin #if KSHELL
2694887Schin 		/* abort of interrupt has occurred */
2704887Schin 		if(sh.trapnote&SH_SIGSET)
2714887Schin 			i = -1;
2724887Schin 		else
2734887Schin #endif /* KSHELL */
2744887Schin 		/*** Read the line ***/
2754887Schin 		i = ed_read(context, fd, shbuf, nchar, 0);
2764887Schin #ifndef FIORDCHK
2774887Schin 		newtime = times(&dummy);
2784887Schin 		vp->typeahead = ((newtime-oldtime) < NTICKS);
2794887Schin #endif /* FIORDCHK */
2804887Schin 	    if(echoctl)
2814887Schin 	    {
2824887Schin 		if( i <= 0 )
2834887Schin 		{
2844887Schin 			/*** read error or eof typed ***/
2854887Schin 			tty_cooked(ERRIO);
2864887Schin 			return(i);
2874887Schin 		}
2884887Schin 		term_char = shbuf[--i];
2894887Schin 		if( term_char == '\r' )
2904887Schin 			term_char = '\n';
2914887Schin 		if( term_char=='\n' || term_char==ESC )
2924887Schin 			shbuf[i--] = '\0';
2934887Schin 		else
2944887Schin 			shbuf[i+1] = '\0';
2954887Schin 	    }
2964887Schin 	    else
2974887Schin 	    {
2984887Schin 		register int c = shbuf[0];
2994887Schin 
3004887Schin 		/*** Save and remove the last character if its an eol, ***/
3014887Schin 		/* changing '\r' to '\n' */
3024887Schin 
3034887Schin 		if( i == 0 )
3044887Schin 		{
3054887Schin 			/*** ESC was typed as first char of line ***/
3064887Schin 			esc_or_hang = 1;
3074887Schin 			term_char = ESC;
3084887Schin 			shbuf[i--] = '\0';	/* null terminate line */
3094887Schin 		}
3104887Schin 		else if( i<0 || c==usreof )
3114887Schin 		{
3124887Schin 			/*** read error or eof typed ***/
3134887Schin 			tty_cooked(ERRIO);
3144887Schin 			if( c == usreof )
3154887Schin 				i = 0;
3164887Schin 			return(i);
3174887Schin 		}
3184887Schin 		else
3194887Schin 		{
3204887Schin 			term_char = shbuf[--i];
3214887Schin 			if( term_char == '\r' )
3224887Schin 				term_char = '\n';
3234887Schin #if !defined(VEOL2) && !defined(ECHOCTL)
3244887Schin 			if(term_char=='\n')
3254887Schin 			{
3264887Schin 				tty_cooked(ERRIO);
3274887Schin 				return(i+1);
3284887Schin 			}
3294887Schin #endif
3304887Schin 			if( term_char=='\n' || term_char==usreof )
3314887Schin 			{
3324887Schin 				/*** remove terminator & null terminate ***/
3334887Schin 				shbuf[i--] = '\0';
3344887Schin 			}
3354887Schin 			else
3364887Schin 			{
3374887Schin 				/** terminator was ESC, which is not xmitted **/
3384887Schin 				term_char = ESC;
3394887Schin 				shbuf[i+1] = '\0';
3404887Schin 			}
3414887Schin 		}
3424887Schin 	    }
3434887Schin 	}
3444887Schin 	else
3454887Schin #endif /* SHOPT_RAWONLY */
3464887Schin 	{
3474887Schin 		/*** Set raw mode ***/
3484887Schin 
3494887Schin #if !SHOPT_RAWONLY
3504887Schin 		if( editb.e_ttyspeed == 0 )
3514887Schin 		{
3524887Schin 			/*** never did TCGETA, so do it ***/
3534887Schin 			/* avoids problem if user does 'sh -o viraw' */
3544887Schin 			tty_alt(ERRIO);
3554887Schin 		}
3564887Schin #endif /* SHOPT_RAWONLY */
3574887Schin 		if(tty_raw(ERRIO,0) < 0 )
3584887Schin 			return(reedit?reedit:ed_read(context, fd, shbuf, nchar,0));
3594887Schin 		i = last_virt-1;
3604887Schin 	}
3614887Schin 
3624887Schin 	/*** Initialize some things ***/
3634887Schin 
3644887Schin 	virtual = (genchar*)shbuf;
3654887Schin #if SHOPT_MULTIBYTE
3664887Schin 	virtual = (genchar*)roundof((char*)virtual-(char*)0,sizeof(genchar));
3674887Schin 	shbuf[i+1] = 0;
3684887Schin 	i = ed_internal(shbuf,virtual)-1;
3694887Schin #endif /* SHOPT_MULTIBYTE */
3704887Schin 	globals = Globals;
3714887Schin 	cur_phys = i + 1;
3724887Schin 	cur_virt = i;
3734887Schin 	first_virt = 0;
3744887Schin 	vp->first_wind = 0;
3754887Schin 	last_virt = i;
3764887Schin 	last_phys = i;
3774887Schin 	vp->last_wind = i;
3784887Schin 	vp->long_line = ' ';
3794887Schin 	vp->long_char = ' ';
3804887Schin 	vp->o_v_char = '\0';
3814887Schin 	vp->ocur_phys = 0;
3824887Schin 	vp->ocur_virt = MAXCHAR;
3834887Schin 	vp->ofirst_wind = 0;
3844887Schin 	physical = Physical;
3854887Schin 	vp->u_column = INVALID - 1;
3864887Schin 	vp->U_space = Ubuf;
3874887Schin 	vp->u_space = ubuf;
3884887Schin 	window = Window;
3894887Schin 	window[0] = '\0';
3904887Schin 
3914887Schin 	if(!yankbuf)
3924887Schin 		yankbuf = (genchar*)malloc(MAXLINE*CHARSIZE);
3934887Schin 	if( vp->last_cmd == '\0' )
3944887Schin 	{
3954887Schin 		/*** first time for this shell ***/
3964887Schin 
3974887Schin 		vp->last_cmd = 'i';
3984887Schin 		vp->findchar = INVALID;
3994887Schin 		vp->lastmotion = '\0';
4004887Schin 		vp->lastrepeat = 1;
4014887Schin 		vp->repeat = 1;
4024887Schin 		*yankbuf = 0;
4034887Schin 	}
4044887Schin 
4054887Schin 	/*** fiddle around with prompt length ***/
4064887Schin 	if( nchar+plen > MAXCHAR )
4074887Schin 		nchar = MAXCHAR - plen;
4084887Schin 	max_col = nchar - 2;
4094887Schin 
4104887Schin 	if( !viraw )
4114887Schin 	{
4124887Schin 		int kill_erase = 0;
4134887Schin 		for(i=(echoctl?last_virt:0); i<last_virt; ++i )
4144887Schin 		{
4154887Schin 			/*** change \r to \n, check for control characters, ***/
4164887Schin 			/* delete appropriate ^Vs,			*/
4174887Schin 			/* and estimate last physical column */
4184887Schin 
4194887Schin 			if( virtual[i] == '\r' )
4204887Schin 				virtual[i] = '\n';
4214887Schin 		    if(!echoctl)
4224887Schin 		    {
4234887Schin 			register int c = virtual[i];
4244887Schin 			if( c<=usrerase)
4254887Schin 			{
4264887Schin 				/*** user typed escaped erase or kill char ***/
4274887Schin 				cntl_char = 1;
4284887Schin 				if(is_print(c))
4294887Schin 					kill_erase++;
4304887Schin 			}
4314887Schin 			else if( !is_print(c) )
4324887Schin 			{
4334887Schin 				cntl_char = 1;
4344887Schin 
4354887Schin 				if( c == usrlnext )
4364887Schin 				{
4374887Schin 					if( i == last_virt )
4384887Schin 					{
4394887Schin 						/*** eol/eof was escaped ***/
4404887Schin 						/* so replace ^V with it */
4414887Schin 						virtual[i] = term_char;
4424887Schin 						break;
4434887Schin 					}
4444887Schin 
4454887Schin 					/*** delete ^V ***/
4464887Schin 					gencpy((&virtual[i]), (&virtual[i+1]));
4474887Schin 					--cur_virt;
4484887Schin 					--last_virt;
4494887Schin 				}
4504887Schin 			}
4514887Schin 		    }
4524887Schin 		}
4534887Schin 
4544887Schin 		/*** copy virtual image to window ***/
4554887Schin 		if(last_virt > 0)
4564887Schin 			last_phys = ed_virt_to_phys(vp->ed,virtual,physical,last_virt,0,0);
4574887Schin 		if( last_phys >= w_size )
4584887Schin 		{
4594887Schin 			/*** line longer than window ***/
4604887Schin 			vp->last_wind = w_size - 1;
4614887Schin 		}
4624887Schin 		else
4634887Schin 			vp->last_wind = last_phys;
4644887Schin 		genncpy(window, virtual, vp->last_wind+1);
4654887Schin 
4664887Schin 		if( term_char!=ESC  && (last_virt==INVALID
4674887Schin 			|| virtual[last_virt]!=term_char) )
4684887Schin 		{
4694887Schin 			/*** Line not terminated with ESC or escaped (^V) ***/
4704887Schin 			/* eol, so return after doing a total update */
4714887Schin 			/* if( (speed is greater or equal to 1200 */
4724887Schin 			/* and something was typed) and */
4734887Schin 			/* (control character present */
4744887Schin 			/* or typeahead occurred) ) */
4754887Schin 
4764887Schin 			tty_cooked(ERRIO);
4774887Schin 			if( editb.e_ttyspeed==FAST && last_virt!=INVALID
4784887Schin 				&& (vp->typeahead || cntl_char) )
4794887Schin 			{
4804887Schin 				refresh(vp,TRANSLATE);
4814887Schin 				pr_string(vp,Prompt);
4824887Schin 				putstring(vp,0, last_phys+1);
4834887Schin 				if(echoctl)
4844887Schin 					ed_crlf(vp->ed);
4854887Schin 				else
4864887Schin 					while(kill_erase-- > 0)
4874887Schin 						putchar(' ');
4884887Schin 			}
4894887Schin 
4904887Schin 			if( term_char=='\n' )
4914887Schin 			{
4924887Schin 				if(!echoctl)
4934887Schin 					ed_crlf(vp->ed);
4944887Schin 				virtual[++last_virt] = '\n';
4954887Schin 			}
4964887Schin 			vp->last_cmd = 'i';
4974887Schin 			save_last(vp);
4984887Schin #if SHOPT_MULTIBYTE
4994887Schin 			virtual[last_virt+1] = 0;
5004887Schin 			last_virt = ed_external(virtual,shbuf);
5014887Schin 			return(last_virt);
5024887Schin #else
5034887Schin 			return(++last_virt);
5044887Schin #endif /* SHOPT_MULTIBYTE */
5054887Schin 		}
5064887Schin 
5074887Schin 		/*** Line terminated with escape, or escaped eol/eof, ***/
5084887Schin 		/*  so set raw mode */
5094887Schin 
5104887Schin 		if( tty_raw(ERRIO,0) < 0 )
5114887Schin 		{
5124887Schin 			tty_cooked(ERRIO);
5134887Schin 			/*
5144887Schin 			 * The following prevents drivers that return 0 on
5154887Schin 			 * causing an infinite loop
5164887Schin 			 */
5174887Schin 			if(esc_or_hang)
5184887Schin 				return(-1);
5194887Schin 			virtual[++last_virt] = '\n';
5204887Schin #if SHOPT_MULTIBYTE
5214887Schin 			virtual[last_virt+1] = 0;
5224887Schin 			last_virt = ed_external(virtual,shbuf);
5234887Schin 			return(last_virt);
5244887Schin #else
5254887Schin 			return(++last_virt);
5264887Schin #endif /* SHOPT_MULTIBYTE */
5274887Schin 		}
5284887Schin 
5294887Schin 		if(echoctl) /*** for cntl-echo erase the ^[ ***/
5304887Schin 			pr_string(vp,"\b\b\b\b      \b\b");
5314887Schin 
5324887Schin 
5334887Schin 		if(crallowed)
5344887Schin 		{
5354887Schin 			/*** start over since there may be ***/
5364887Schin 			/*** a control char, or cursor might not ***/
5374887Schin 			/*** be at left margin (this lets us know ***/
5384887Schin 			/*** where we are ***/
5394887Schin 			cur_phys = 0;
5404887Schin 			window[0] = '\0';
5414887Schin 			pr_string(vp,Prompt);
5424887Schin 			if( term_char==ESC && (last_virt<0 || virtual[last_virt]!=ESC))
5434887Schin 				refresh(vp,CONTROL);
5444887Schin 			else
5454887Schin 				refresh(vp,INPUT);
5464887Schin 		}
5474887Schin 		else
5484887Schin 		{
5494887Schin 			/*** just update everything internally ***/
5504887Schin 			refresh(vp,TRANSLATE);
5514887Schin 		}
5524887Schin 	}
5534887Schin 
5544887Schin 	/*** Handle usrintr, usrquit, or EOF ***/
5554887Schin 
5564887Schin 	i = sigsetjmp(editb.e_env,0);
5574887Schin 	if( i != 0 )
5584887Schin 	{
5598462SApril.Chin@Sun.COM 		if(vp->ed->e_multiline)
5608462SApril.Chin@Sun.COM 		{
5618462SApril.Chin@Sun.COM 			cur_virt = last_virt;
5628462SApril.Chin@Sun.COM 			sync_cursor(vp);
5638462SApril.Chin@Sun.COM 		}
5644887Schin 		virtual[0] = '\0';
5654887Schin 		tty_cooked(ERRIO);
5664887Schin 
5674887Schin 		switch(i)
5684887Schin 		{
5694887Schin 		case UEOF:
5704887Schin 			/*** EOF ***/
5714887Schin 			return(0);
5724887Schin 
5734887Schin 		case UINTR:
5744887Schin 			/** interrupt **/
5754887Schin 			return(-1);
5764887Schin 		}
5774887Schin 		return(-1);
5784887Schin 	}
5794887Schin 
5804887Schin 	/*** Get a line from the terminal ***/
5814887Schin 
5824887Schin 	vp->U_saved = 0;
5834887Schin 	if(reedit)
58410898Sroland.mainz@nrubsig.org 	{
58510898Sroland.mainz@nrubsig.org 		cur_phys = vp->first_wind;
58610898Sroland.mainz@nrubsig.org 		vp->ofirst_wind = INVALID;
5874887Schin 		refresh(vp,INPUT);
58810898Sroland.mainz@nrubsig.org 	}
5894887Schin 	if(viraw)
5904887Schin 		getline(vp,APPEND);
5914887Schin 	else if(last_virt>=0 && virtual[last_virt]==term_char)
5924887Schin 		getline(vp,APPEND);
5934887Schin 	else
5944887Schin 		getline(vp,ESC);
5954887Schin 	if(vp->ed->e_multiline)
5964887Schin 		cursor(vp, last_phys);
5974887Schin 	/*** add a new line if user typed unescaped \n ***/
5984887Schin 	/* to cause the shell to process the line */
5994887Schin 	tty_cooked(ERRIO);
6004887Schin 	if(ed->e_nlist)
6014887Schin 	{
6024887Schin 		ed->e_nlist = 0;
6034887Schin 		stakset(ed->e_stkptr,ed->e_stkoff);
6044887Schin 	}
6054887Schin 	if( vp->addnl )
6064887Schin 	{
6074887Schin 		virtual[++last_virt] = '\n';
6084887Schin 		ed_crlf(vp->ed);
6094887Schin 	}
6104887Schin 	if( ++last_virt >= 0 )
6114887Schin 	{
6124887Schin #if SHOPT_MULTIBYTE
6134887Schin 		if(vp->bigvi)
6144887Schin 		{
6154887Schin 			vp->bigvi = 0;
6164887Schin 			shbuf[last_virt-1] = '\n';
6174887Schin 		}
6184887Schin 		else
6194887Schin 		{
6204887Schin 			virtual[last_virt] = 0;
6214887Schin 			last_virt = ed_external(virtual,shbuf);
6224887Schin 		}
6234887Schin #endif /* SHOPT_MULTIBYTE */
6244887Schin 		return(last_virt);
6254887Schin 	}
6264887Schin 	else
6274887Schin 		return(-1);
6284887Schin }
6294887Schin 
6304887Schin 
6314887Schin /*{	APPEND( char, mode )
6324887Schin  *
6334887Schin  *	This routine will append char after cur_virt in the virtual image.
6344887Schin  * mode	=	APPEND, shift chars right before appending
6354887Schin  *		REPLACE, replace char if possible
6364887Schin  *
6374887Schin }*/
6384887Schin 
append(Vi_t * vp,int c,int mode)6394887Schin static void append(Vi_t *vp,int c, int mode)
6404887Schin {
6414887Schin 	register int i,j;
6424887Schin 
6434887Schin 	if( last_virt<max_col && last_phys<max_col )
6444887Schin 	{
6454887Schin 		if( mode==APPEND || (cur_virt==last_virt  && last_virt>=0))
6464887Schin 		{
6474887Schin 			j = (cur_virt>=0?cur_virt:0);
6484887Schin 			for(i = ++last_virt;  i > j; --i)
6494887Schin 				virtual[i] = virtual[i-1];
6504887Schin 		}
6514887Schin 		virtual[++cur_virt] = c;
6524887Schin 	}
6534887Schin 	else
6544887Schin 		ed_ringbell();
6554887Schin 	return;
6564887Schin }
6574887Schin 
6584887Schin /*{	BACKWORD( nwords, cmd )
6594887Schin  *
6604887Schin  *	This routine will position cur_virt at the nth previous word.
6614887Schin  *
6624887Schin }*/
6634887Schin 
backword(Vi_t * vp,int nwords,register int cmd)6644887Schin static void backword(Vi_t *vp,int nwords, register int cmd)
6654887Schin {
6664887Schin 	register int tcur_virt = cur_virt;
6674887Schin 	while( nwords-- && tcur_virt > first_virt )
6684887Schin 	{
6694887Schin 		if( !isblank(tcur_virt) && isblank(tcur_virt-1)
6704887Schin 			&& tcur_virt>first_virt )
6714887Schin 			--tcur_virt;
6724887Schin 		else if(cmd != 'B')
6734887Schin 		{
6744887Schin 			register int last = isalph(tcur_virt-1);
6754887Schin 			register int cur = isalph(tcur_virt);
6764887Schin 			if((!cur && last) || (cur && !last))
6774887Schin 				--tcur_virt;
6784887Schin 		}
6794887Schin 		while( isblank(tcur_virt) && tcur_virt>=first_virt )
6804887Schin 			--tcur_virt;
6814887Schin 		if( cmd == 'B' )
6824887Schin 		{
6834887Schin 			while( !isblank(tcur_virt) && tcur_virt>=first_virt )
6844887Schin 				--tcur_virt;
6854887Schin 		}
6864887Schin 		else
6874887Schin 		{
6884887Schin 			if(isalph(tcur_virt))
6894887Schin 				while( isalph(tcur_virt) && tcur_virt>=first_virt )
6904887Schin 					--tcur_virt;
6914887Schin 			else
6924887Schin 				while( !isalph(tcur_virt) && !isblank(tcur_virt)
6934887Schin 					&& tcur_virt>=first_virt )
6944887Schin 					--tcur_virt;
6954887Schin 		}
6964887Schin 		cur_virt = ++tcur_virt;
6974887Schin 	}
6984887Schin 	return;
6994887Schin }
7004887Schin 
7014887Schin /*{	CNTLMODE()
7024887Schin  *
7034887Schin  *	This routine implements the vi command subset.
7044887Schin  *	The cursor will always be positioned at the char of interest.
7054887Schin  *
7064887Schin }*/
7074887Schin 
cntlmode(Vi_t * vp)7084887Schin static int cntlmode(Vi_t *vp)
7094887Schin {
7104887Schin 	register int c;
7114887Schin 	register int i;
7124887Schin 	genchar tmp_u_space[MAXLINE];	/* temporary u_space */
7134887Schin 	genchar *real_u_space;		/* points to real u_space */
7144887Schin 	int tmp_u_column = INVALID;	/* temporary u_column */
7154887Schin 	int was_inmacro;
7164887Schin 
7174887Schin 	if(!vp->U_saved)
7184887Schin 	{
7194887Schin 		/*** save virtual image if never done before ***/
7204887Schin 		virtual[last_virt+1] = '\0';
7214887Schin 		gencpy(vp->U_space, virtual);
7224887Schin 		vp->U_saved = 1;
7234887Schin 	}
7244887Schin 
7254887Schin 	save_last(vp);
7264887Schin 
7274887Schin 	real_u_space = vp->u_space;
7284887Schin 	curhline = histmax;
7294887Schin 	first_virt = 0;
7304887Schin 	vp->repeat = 1;
7314887Schin 	if( cur_virt > INVALID )
7324887Schin 	{
7334887Schin 		/*** make sure cursor is at the last char ***/
7344887Schin 		sync_cursor(vp);
7354887Schin 	}
7364887Schin 
7374887Schin 	/*** Read control char until something happens to cause a ***/
7384887Schin 	/* return to APPEND/REPLACE mode	*/
7394887Schin 
7404887Schin 	while( c=ed_getchar(vp->ed,-1) )
7414887Schin 	{
7424887Schin 		vp->repeat_set = 0;
7434887Schin 		was_inmacro = inmacro;
7444887Schin 		if( c == '0' )
7454887Schin 		{
7464887Schin 			/*** move to leftmost column ***/
7474887Schin 			cur_virt = 0;
7484887Schin 			sync_cursor(vp);
7494887Schin 			continue;
7504887Schin 		}
7514887Schin 
7524887Schin 		if( digit(c) )
7534887Schin 		{
7544887Schin 			c = getcount(vp,c);
7554887Schin 			if( c == '.' )
7564887Schin 				vp->lastrepeat = vp->repeat;
7574887Schin 		}
7584887Schin 
7594887Schin 		/*** see if it's a move cursor command ***/
7604887Schin 
7614887Schin 		if(mvcursor(vp,c))
7624887Schin 		{
7634887Schin 			sync_cursor(vp);
7644887Schin 			vp->repeat = 1;
7654887Schin 			continue;
7664887Schin 		}
7674887Schin 
7684887Schin 		/*** see if it's a repeat of the last command ***/
7694887Schin 
7704887Schin 		if( c == '.' )
7714887Schin 		{
7724887Schin 			c = vp->last_cmd;
7734887Schin 			vp->repeat = vp->lastrepeat;
7744887Schin 			i = textmod(vp,c, c);
7754887Schin 		}
7764887Schin 		else
7774887Schin 		{
7784887Schin 			i = textmod(vp,c, 0);
7794887Schin 		}
7804887Schin 
7814887Schin 		/*** see if it's a text modification command ***/
7824887Schin 
7834887Schin 		switch(i)
7844887Schin 		{
7854887Schin 		case BAD:
7864887Schin 			break;
7874887Schin 
7884887Schin 		default:		/** input mode **/
7894887Schin 			if(!was_inmacro)
7904887Schin 			{
7914887Schin 				vp->last_cmd = c;
7924887Schin 				vp->lastrepeat = vp->repeat;
7934887Schin 			}
7944887Schin 			vp->repeat = 1;
7954887Schin 			if( i == GOOD )
7964887Schin 				continue;
7974887Schin 			return(i);
7984887Schin 		}
7994887Schin 
8004887Schin 		switch( c )
8014887Schin 		{
8024887Schin 			/***** Other stuff *****/
8034887Schin 
8044887Schin 		case cntl('L'):		/** Redraw line **/
8054887Schin 			/*** print the prompt and ***/
8064887Schin 			/* force a total refresh */
8078462SApril.Chin@Sun.COM 			if(vp->nonewline==0 && !vp->ed->e_nocrnl)
8084887Schin 				putchar('\n');
8094887Schin 			vp->nonewline = 0;
8104887Schin 			pr_string(vp,Prompt);
8114887Schin 			window[0] = '\0';
8124887Schin 			cur_phys = vp->first_wind;
8134887Schin 			vp->ofirst_wind = INVALID;
8144887Schin 			vp->long_line = ' ';
8154887Schin 			break;
8164887Schin 
8174887Schin 		case cntl('V'):
8184887Schin 		{
8194887Schin 			register const char *p = fmtident(e_version);
8204887Schin 			save_v(vp);
8214887Schin 			del_line(vp,BAD);
8224887Schin 			while(c = *p++)
8234887Schin 				append(vp,c,APPEND);
8244887Schin 			refresh(vp,CONTROL);
8254887Schin 			ed_getchar(vp->ed,-1);
8264887Schin 			restore_v(vp);
8274887Schin 			break;
8284887Schin 		}
8294887Schin 
8304887Schin 		case '/':		/** Search **/
8314887Schin 		case '?':
8324887Schin 		case 'N':
8334887Schin 		case 'n':
8344887Schin 			save_v(vp);
8354887Schin 			switch( search(vp,c) )
8364887Schin 			{
8374887Schin 			case GOOD:
8384887Schin 				/*** force a total refresh ***/
8394887Schin 				window[0] = '\0';
8404887Schin 				goto newhist;
8414887Schin 
8424887Schin 			case BAD:
8434887Schin 				/*** no match ***/
8444887Schin 					ed_ringbell();
8454887Schin 
8464887Schin 			default:
8474887Schin 				if( vp->u_column == INVALID )
8484887Schin 					del_line(vp,BAD);
8494887Schin 				else
8504887Schin 					restore_v(vp);
8514887Schin 				break;
8524887Schin 			}
8534887Schin 			break;
8544887Schin 
8554887Schin 		case 'j':		/** get next command **/
8564887Schin 		case '+':		/** get next command **/
8574887Schin 			curhline += vp->repeat;
8584887Schin 			if( curhline > histmax )
8594887Schin 			{
8604887Schin 				curhline = histmax;
8614887Schin 				goto ringbell;
8624887Schin 			}
8634887Schin 			else if(curhline==histmax && tmp_u_column!=INVALID )
8644887Schin 			{
8654887Schin 				vp->u_space = tmp_u_space;
8664887Schin 				vp->u_column = tmp_u_column;
8674887Schin 				restore_v(vp);
8684887Schin 				vp->u_space = real_u_space;
8694887Schin 				break;
8704887Schin 			}
8714887Schin 			save_v(vp);
8724887Schin 			cur_virt = INVALID;
8734887Schin 			goto newhist;
8744887Schin 
8754887Schin 		case 'k':		/** get previous command **/
8764887Schin 		case '-':		/** get previous command **/
8774887Schin 			if( curhline == histmax )
8784887Schin 			{
8794887Schin 				vp->u_space = tmp_u_space;
8804887Schin 				i = vp->u_column;
8814887Schin 				save_v(vp);
8824887Schin 				vp->u_space = real_u_space;
8834887Schin 				tmp_u_column = vp->u_column;
8844887Schin 				vp->u_column = i;
8854887Schin 			}
8864887Schin 
8874887Schin 			curhline -= vp->repeat;
8884887Schin 			if( curhline <= histmin )
8894887Schin 			{
8904887Schin 				curhline += vp->repeat;
8914887Schin 				goto ringbell;
8924887Schin 			}
8934887Schin 			save_v(vp);
8944887Schin 			cur_virt = INVALID;
8954887Schin 		newhist:
8964887Schin 			if(curhline!=histmax || cur_virt==INVALID)
8974887Schin 				hist_copy((char*)virtual, MAXLINE, curhline,-1);
8984887Schin 			else
8994887Schin 			{
9004887Schin 				strcpy((char*)virtual,(char*)vp->u_space);
9014887Schin #if SHOPT_MULTIBYTE
9024887Schin 				ed_internal((char*)vp->u_space,vp->u_space);
9034887Schin #endif /* SHOPT_MULTIBYTE */
9044887Schin 			}
9054887Schin #if SHOPT_MULTIBYTE
9064887Schin 			ed_internal((char*)virtual,virtual);
9074887Schin #endif /* SHOPT_MULTIBYTE */
9084887Schin 			if((last_virt=genlen(virtual)-1) >= 0  && cur_virt == INVALID)
9094887Schin 				cur_virt = 0;
9104887Schin 			break;
9114887Schin 
9124887Schin 
9134887Schin 		case 'u':		/** undo the last thing done **/
9144887Schin 			restore_v(vp);
9154887Schin 			break;
9164887Schin 
9174887Schin 		case 'U':		/** Undo everything **/
9184887Schin 			save_v(vp);
9194887Schin 			if( virtual[0] == '\0' )
9204887Schin 				goto ringbell;
9214887Schin 			else
9224887Schin 			{
9234887Schin 				gencpy(virtual, vp->U_space);
9244887Schin 				last_virt = genlen(vp->U_space) - 1;
9254887Schin 				cur_virt = 0;
9264887Schin 			}
9274887Schin 			break;
9284887Schin 
9294887Schin #if KSHELL
9304887Schin 		case 'v':
9314887Schin 			if(vp->repeat_set==0)
9324887Schin 				goto vcommand;
9334887Schin #endif /* KSHELL */
9344887Schin 
9354887Schin 		case 'G':		/** goto command repeat **/
9364887Schin 			if(vp->repeat_set==0)
9374887Schin 				vp->repeat = histmin+1;
9384887Schin 			if( vp->repeat <= histmin || vp->repeat > histmax )
9394887Schin 			{
9404887Schin 				goto ringbell;
9414887Schin 			}
9424887Schin 			curhline = vp->repeat;
9434887Schin 			save_v(vp);
9444887Schin 			if(c == 'G')
9454887Schin 			{
9464887Schin 				cur_virt = INVALID;
9474887Schin 				goto newhist;
9484887Schin 			}
9494887Schin 
9504887Schin #if KSHELL
9514887Schin 		vcommand:
9524887Schin 			if(ed_fulledit(vp->ed)==GOOD)
9534887Schin 				return(BIGVI);
9544887Schin 			else
9554887Schin 				goto ringbell;
9564887Schin #endif	/* KSHELL */
9574887Schin 
9584887Schin 		case '#':	/** insert(delete) # to (no)comment command **/
9594887Schin 			if( cur_virt != INVALID )
9604887Schin 			{
9614887Schin 				register genchar *p = &virtual[last_virt+1];
9624887Schin 				*p = 0;
9634887Schin 				/*** see whether first char is comment char ***/
9644887Schin 				c = (virtual[0]=='#');
9654887Schin 				while(p-- >= virtual)
9664887Schin 				{
9674887Schin 					if(*p=='\n' || p<virtual)
9684887Schin 					{
9694887Schin 						if(c) /* delete '#' */
9704887Schin 						{
9714887Schin 							if(p[1]=='#')
9724887Schin 							{
9734887Schin 								last_virt--;
9744887Schin 								gencpy(p+1,p+2);
9754887Schin 							}
9764887Schin 						}
9774887Schin 						else
9784887Schin 						{
9794887Schin 							cur_virt = p-virtual;
9804887Schin 							append(vp,'#', APPEND);
9814887Schin 						}
9824887Schin 					}
9834887Schin 				}
9844887Schin 				if(c)
9854887Schin 				{
9864887Schin 					curhline = histmax;
9874887Schin 					cur_virt = 0;
9884887Schin 					break;
9894887Schin 				}
9904887Schin 				refresh(vp,INPUT);
9914887Schin 			}
9924887Schin 
9934887Schin 		case '\n':		/** send to shell **/
9944887Schin 			return(ENTER);
9954887Schin 
9964887Schin 	        case ESC:
9974887Schin 			/* don't ring bell if next char is '[' */
9984887Schin 			if(!lookahead)
9994887Schin 			{
10004887Schin 				char x;
10014887Schin 				if(sfpkrd(editb.e_fd,&x,1,'\r',400L,-1)>0)
10024887Schin 					ed_ungetchar(vp->ed,x);
10034887Schin 			}
10044887Schin 			if(lookahead)
10054887Schin 			{
10064887Schin 				ed_ungetchar(vp->ed,c=ed_getchar(vp->ed,1));
10074887Schin 				if(c=='[')
10084887Schin 				{
10094887Schin 					vp->repeat = 1;
10104887Schin 					continue;
10114887Schin 				}
10124887Schin 			}
10134887Schin 		default:
10144887Schin 		ringbell:
10154887Schin 			ed_ringbell();
10164887Schin 			vp->repeat = 1;
10174887Schin 			continue;
10184887Schin 		}
10194887Schin 
10204887Schin 		refresh(vp,CONTROL);
10214887Schin 		vp->repeat = 1;
10224887Schin 	}
10234887Schin /* NOTREACHED */
10244887Schin 	return(0);
10254887Schin }
10264887Schin 
10274887Schin /*{	CURSOR( new_current_physical )
10284887Schin  *
10294887Schin  *	This routine will position the virtual cursor at
10304887Schin  * physical column x in the window.
10314887Schin  *
10324887Schin }*/
10334887Schin 
cursor(Vi_t * vp,register int x)10344887Schin static void cursor(Vi_t *vp,register int x)
10354887Schin {
10364887Schin #if SHOPT_MULTIBYTE
10374887Schin 	while(physical[x]==MARKER)
10384887Schin 		x++;
10394887Schin #endif /* SHOPT_MULTIBYTE */
10404887Schin 	cur_phys = ed_setcursor(vp->ed, physical, cur_phys,x,vp->first_wind);
10414887Schin }
10424887Schin 
10434887Schin /*{	DELETE( nchars, mode )
10444887Schin  *
10454887Schin  *	Delete nchars from the virtual space and leave cur_virt positioned
10464887Schin  * at cur_virt-1.
10474887Schin  *
10484887Schin  *	If mode	= 'c', do not save the characters deleted
10494887Schin  *		= 'd', save them in yankbuf and delete.
10504887Schin  *		= 'y', save them in yankbuf but do not delete.
10514887Schin  *
10524887Schin }*/
10534887Schin 
cdelete(Vi_t * vp,register int nchars,int mode)10544887Schin static void cdelete(Vi_t *vp,register int nchars, int mode)
10554887Schin {
10564887Schin 	register int i;
10574887Schin 	register genchar *cp;
10584887Schin 
10594887Schin 	if( cur_virt < first_virt )
10604887Schin 	{
10614887Schin 		ed_ringbell();
10624887Schin 		return;
10634887Schin 	}
10644887Schin 	if( nchars > 0 )
10654887Schin 	{
10664887Schin 		cp = virtual+cur_virt;
10674887Schin 		vp->o_v_char = cp[0];
10684887Schin 		if( (cur_virt-- + nchars) > last_virt )
10694887Schin 		{
10704887Schin 			/*** set nchars to number actually deleted ***/
10714887Schin 			nchars = last_virt - cur_virt;
10724887Schin 		}
10734887Schin 
10744887Schin 		/*** save characters to be deleted ***/
10754887Schin 
10764887Schin 		if( mode != 'c' )
10774887Schin 		{
10784887Schin 			i = cp[nchars];
10794887Schin 			cp[nchars] = 0;
10804887Schin 			gencpy(yankbuf,cp);
10814887Schin 			cp[nchars] = i;
10824887Schin 		}
10834887Schin 
10844887Schin 		/*** now delete these characters ***/
10854887Schin 
10864887Schin 		if( mode != 'y' )
10874887Schin 		{
10884887Schin 			gencpy(cp,cp+nchars);
10894887Schin 			last_virt -= nchars;
10904887Schin 		}
10914887Schin 	}
10924887Schin 	return;
10934887Schin }
10944887Schin 
10954887Schin /*{	DEL_LINE( mode )
10964887Schin  *
10974887Schin  *	This routine will delete the line.
10984887Schin  *	mode = GOOD, do a save_v()
10994887Schin  *
11004887Schin }*/
del_line(register Vi_t * vp,int mode)11014887Schin static void del_line(register Vi_t *vp, int mode)
11024887Schin {
11034887Schin 	if( last_virt == INVALID )
11044887Schin 		return;
11054887Schin 
11064887Schin 	if( mode == GOOD )
11074887Schin 		save_v(vp);
11084887Schin 
11094887Schin 	cur_virt = 0;
11104887Schin 	first_virt = 0;
11114887Schin 	cdelete(vp,last_virt+1, BAD);
11124887Schin 	refresh(vp,CONTROL);
11134887Schin 
11144887Schin 	cur_virt = INVALID;
11154887Schin 	cur_phys = 0;
11164887Schin 	vp->findchar = INVALID;
11174887Schin 	last_phys = INVALID;
11184887Schin 	last_virt = INVALID;
11194887Schin 	vp->last_wind = INVALID;
11204887Schin 	vp->first_wind = 0;
11214887Schin 	vp->o_v_char = '\0';
11224887Schin 	vp->ocur_phys = 0;
11234887Schin 	vp->ocur_virt = MAXCHAR;
11244887Schin 	vp->ofirst_wind = 0;
11254887Schin 	window[0] = '\0';
11264887Schin 	return;
11274887Schin }
11284887Schin 
11294887Schin /*{	DELMOTION( motion, mode )
11304887Schin  *
11314887Schin  *	Delete thru motion.
11324887Schin  *
11334887Schin  *	mode	= 'd', save deleted characters, delete
11344887Schin  *		= 'c', do not save characters, change
11354887Schin  *		= 'y', save characters, yank
11364887Schin  *
11374887Schin  *	Returns 1 if operation successful; else 0.
11384887Schin  *
11394887Schin }*/
11404887Schin 
delmotion(Vi_t * vp,int motion,int mode)11414887Schin static int delmotion(Vi_t *vp,int motion, int mode)
11424887Schin {
11434887Schin 	register int begin, end, delta;
11444887Schin 	/* the following saves a register */
11454887Schin 
11464887Schin 	if( cur_virt == INVALID )
11474887Schin 		return(0);
11484887Schin 	if( mode != 'y' )
11494887Schin 		save_v(vp);
11504887Schin 	begin = cur_virt;
11514887Schin 
11524887Schin 	/*** fake out the motion routines by appending a blank ***/
11534887Schin 
11544887Schin 	virtual[++last_virt] = ' ';
11554887Schin 	end = mvcursor(vp,motion);
11564887Schin 	virtual[last_virt--] = 0;
11574887Schin 	if(!end)
11584887Schin 		return(0);
11594887Schin 
11604887Schin 	end = cur_virt;
11614887Schin 	if( mode=='c' && end>begin && strchr("wW", motion) )
11624887Schin 	{
11634887Schin 		/*** called by change operation, user really expects ***/
11644887Schin 		/* the effect of the eE commands, so back up to end of word */
11654887Schin 		while( end>begin && isblank(end-1) )
11664887Schin 			--end;
11674887Schin 		if( end == begin )
11684887Schin 			++end;
11694887Schin 	}
11704887Schin 
11714887Schin 	delta = end - begin;
11724887Schin 	if( delta >= 0 )
11734887Schin 	{
11744887Schin 		cur_virt = begin;
11754887Schin 		if( strchr("eE;,TtFf%", motion) )
11764887Schin 			++delta;
11774887Schin 	}
11784887Schin 	else
11794887Schin 	{
11804887Schin 		delta = -delta + (motion=='%');
11814887Schin 	}
11824887Schin 
11834887Schin 	cdelete(vp,delta, mode);
11844887Schin 	if( mode == 'y' )
11854887Schin 		cur_virt = begin;
11864887Schin 	return(1);
11874887Schin }
11884887Schin 
11894887Schin 
11904887Schin /*{	ENDWORD( nwords, cmd )
11914887Schin  *
11924887Schin  *	This routine will move cur_virt to the end of the nth word.
11934887Schin  *
11944887Schin }*/
11954887Schin 
endword(Vi_t * vp,int nwords,register int cmd)11964887Schin static void endword(Vi_t *vp, int nwords, register int cmd)
11974887Schin {
11984887Schin 	register int tcur_virt = cur_virt;
11994887Schin 	while( nwords-- )
12004887Schin 	{
12014887Schin 		if( !isblank(tcur_virt) && tcur_virt<=last_virt )
12024887Schin 			++tcur_virt;
12034887Schin 		while( isblank(tcur_virt) && tcur_virt<=last_virt )
12044887Schin 			++tcur_virt;
12054887Schin 		if( cmd == 'E' )
12064887Schin 		{
12074887Schin 			while( !isblank(tcur_virt) && tcur_virt<=last_virt )
12084887Schin 				++tcur_virt;
12094887Schin 		}
12104887Schin 		else
12114887Schin 		{
12124887Schin 			if( isalph(tcur_virt) )
12134887Schin 				while( isalph(tcur_virt) && tcur_virt<=last_virt )
12144887Schin 					++tcur_virt;
12154887Schin 			else
12164887Schin 				while( !isalph(tcur_virt) && !isblank(tcur_virt)
12174887Schin 					&& tcur_virt<=last_virt )
12184887Schin 					++tcur_virt;
12194887Schin 		}
12204887Schin 		if( tcur_virt > first_virt )
12214887Schin 			tcur_virt--;
12224887Schin 	}
12234887Schin 	cur_virt = tcur_virt;
12244887Schin 	return;
12254887Schin }
12264887Schin 
12274887Schin /*{	FORWARD( nwords, cmd )
12284887Schin  *
12294887Schin  *	This routine will move cur_virt forward to the next nth word.
12304887Schin  *
12314887Schin }*/
12324887Schin 
forward(Vi_t * vp,register int nwords,int cmd)12334887Schin static void forward(Vi_t *vp,register int nwords, int cmd)
12344887Schin {
12354887Schin 	register int tcur_virt = cur_virt;
12364887Schin 	while( nwords-- )
12374887Schin 	{
12384887Schin 		if( cmd == 'W' )
12394887Schin 		{
12404887Schin 			while( !isblank(tcur_virt) && tcur_virt < last_virt )
12414887Schin 				++tcur_virt;
12424887Schin 		}
12434887Schin 		else
12444887Schin 		{
12454887Schin 			if( isalph(tcur_virt) )
12464887Schin 			{
12474887Schin 				while( isalph(tcur_virt) && tcur_virt<last_virt )
12484887Schin 					++tcur_virt;
12494887Schin 			}
12504887Schin 			else
12514887Schin 			{
12524887Schin 				while( !isalph(tcur_virt) && !isblank(tcur_virt)
12534887Schin 					&& tcur_virt < last_virt )
12544887Schin 					++tcur_virt;
12554887Schin 			}
12564887Schin 		}
12574887Schin 		while( isblank(tcur_virt) && tcur_virt < last_virt )
12584887Schin 			++tcur_virt;
12594887Schin 	}
12604887Schin 	cur_virt = tcur_virt;
12614887Schin 	return;
12624887Schin }
12634887Schin 
12644887Schin 
12654887Schin 
12664887Schin /*{	GETCOUNT(c)
12674887Schin  *
12684887Schin  *	Set repeat to the user typed number and return the terminating
12694887Schin  * character.
12704887Schin  *
12714887Schin }*/
12724887Schin 
getcount(register Vi_t * vp,register int c)12734887Schin static int getcount(register Vi_t *vp,register int c)
12744887Schin {
12754887Schin 	register int i;
12764887Schin 
12774887Schin 	/*** get any repeat count ***/
12784887Schin 
12794887Schin 	if( c == '0' )
12804887Schin 		return(c);
12814887Schin 
12824887Schin 	vp->repeat_set++;
12834887Schin 	i = 0;
12844887Schin 	while( digit(c) )
12854887Schin 	{
12864887Schin 		i = i*10 + c - '0';
12874887Schin 		c = ed_getchar(vp->ed,-1);
12884887Schin 	}
12894887Schin 
12904887Schin 	if( i > 0 )
12914887Schin 		vp->repeat *= i;
12924887Schin 	return(c);
12934887Schin }
12944887Schin 
12954887Schin 
12964887Schin /*{	GETLINE( mode )
12974887Schin  *
12984887Schin  *	This routine will fetch a line.
12994887Schin  *	mode	= APPEND, allow escape to cntlmode subroutine
13004887Schin  *		  appending characters.
13014887Schin  *		= REPLACE, allow escape to cntlmode subroutine
13024887Schin  *		  replacing characters.
13034887Schin  *		= SEARCH, no escape allowed
13044887Schin  *		= ESC, enter control mode immediately
13054887Schin  *
13064887Schin  *	The cursor will always be positioned after the last
13074887Schin  * char printed.
13084887Schin  *
13094887Schin  *	This routine returns when cr, nl, or (eof in column 0) is
13104887Schin  * received (column 0 is the first char position).
13114887Schin  *
13124887Schin }*/
13134887Schin 
getline(register Vi_t * vp,register int mode)13144887Schin static void getline(register Vi_t* vp,register int mode)
13154887Schin {
13164887Schin 	register int c;
13174887Schin 	register int tmp;
13184887Schin 	int	max_virt=0, last_save=0;
13194887Schin 	genchar saveline[MAXLINE];
13204887Schin 
13214887Schin 	vp->addnl = 1;
13224887Schin 
13234887Schin 	if( mode == ESC )
13244887Schin 	{
13254887Schin 		/*** go directly to control mode ***/
13264887Schin 		goto escape;
13274887Schin 	}
13284887Schin 
13294887Schin 	for(;;)
13304887Schin 	{
13314887Schin 		if( (c=ed_getchar(vp->ed,mode==SEARCH?1:-2)) == usreof )
13324887Schin 			c = UEOF;
13334887Schin 		else if( c == usrerase )
13344887Schin 			c = UERASE;
13354887Schin 		else if( c == usrkill )
13364887Schin 			c = UKILL;
13374887Schin 		else if( c == editb.e_werase )
13384887Schin 			c = UWERASE;
13394887Schin 		else if( c == usrlnext )
13404887Schin 			c = ULNEXT;
13414887Schin 
13424887Schin 		if( c == ULNEXT)
13434887Schin 		{
13444887Schin 			/*** implement ^V to escape next char ***/
13454887Schin 			c = ed_getchar(vp->ed,2);
13464887Schin 			append(vp,c, mode);
13474887Schin 			refresh(vp,INPUT);
13484887Schin 			continue;
13494887Schin 		}
13504887Schin 
13514887Schin 		switch( c )
13524887Schin 		{
13534887Schin 		case ESC:		/** enter control mode **/
13544887Schin 			if(!sh_isoption(SH_VI))
13554887Schin 			{
13564887Schin 				append(vp,c, mode);
13574887Schin 				break;
13584887Schin 			}
13594887Schin 			if( mode == SEARCH )
13604887Schin 			{
13614887Schin 				ed_ringbell();
13624887Schin 				continue;
13634887Schin 			}
13644887Schin 			else
13654887Schin 			{
13664887Schin 	escape:
13674887Schin 				if( mode == REPLACE )
13684887Schin 				{
13694887Schin 					c = max_virt-cur_virt;
13704887Schin 					if(c > 0 && last_save>=cur_virt)
13714887Schin 					{
13724887Schin 						genncpy((&virtual[cur_virt]),&saveline[cur_virt],c);
13734887Schin 						if(last_virt>=last_save)
13744887Schin 							last_virt=last_save-1;
13754887Schin 						refresh(vp,INPUT);
13764887Schin 					}
13774887Schin 					--cur_virt;
13784887Schin 				}
13794887Schin 				tmp = cntlmode(vp);
13804887Schin 				if( tmp == ENTER || tmp == BIGVI )
13814887Schin 				{
13824887Schin #if SHOPT_MULTIBYTE
13834887Schin 					vp->bigvi = (tmp==BIGVI);
13844887Schin #endif /* SHOPT_MULTIBYTE */
13854887Schin 					return;
13864887Schin 				}
13874887Schin 				if( tmp == INSERT )
13884887Schin 				{
13894887Schin 					mode = APPEND;
13904887Schin 					continue;
13914887Schin 				}
13924887Schin 				mode = tmp;
13934887Schin 				if(mode==REPLACE)
13944887Schin 				{
13954887Schin 					c = last_save = last_virt+1;
13964887Schin 					if(c >= MAXLINE)
13974887Schin 						c = MAXLINE-1;
13984887Schin 					genncpy(saveline, virtual, c);
13994887Schin 				}
14004887Schin 			}
14014887Schin 			break;
14024887Schin 
14034887Schin 		case UERASE:		/** user erase char **/
14044887Schin 				/*** treat as backspace ***/
14054887Schin 
14064887Schin 		case '\b':		/** backspace **/
14074887Schin 			if( virtual[cur_virt] == '\\' )
14084887Schin 			{
14094887Schin 				cdelete(vp,1, BAD);
14104887Schin 				append(vp,usrerase, mode);
14114887Schin 			}
14124887Schin 			else
14134887Schin 			{
14144887Schin 				if( mode==SEARCH && cur_virt==0 )
14154887Schin 				{
14164887Schin 					first_virt = 0;
14174887Schin 					cdelete(vp,1, BAD);
14184887Schin 					return;
14194887Schin 				}
14204887Schin 				if(mode==REPLACE || (last_save>0 && last_virt<=last_save))
14214887Schin 				{
14224887Schin 					if(cur_virt<=first_virt)
14234887Schin 						ed_ringbell();
14244887Schin 					else if(mode==REPLACE)
14254887Schin 						--cur_virt;
14264887Schin 					mode = REPLACE;
14274887Schin 					sync_cursor(vp);
14284887Schin 					continue;
14294887Schin 				}
14304887Schin 				else
14314887Schin 					cdelete(vp,1, BAD);
14324887Schin 			}
14334887Schin 			break;
14344887Schin 
14354887Schin 		case UWERASE:		/** delete back word **/
14364887Schin 			if( cur_virt > first_virt &&
14374887Schin 				!isblank(cur_virt) &&
14384887Schin 				!ispunct(virtual[cur_virt]) &&
14394887Schin 				isblank(cur_virt-1) )
14404887Schin 			{
14414887Schin 				cdelete(vp,1, BAD);
14424887Schin 			}
14434887Schin 			else
14444887Schin 			{
14454887Schin 				tmp = cur_virt;
14464887Schin 				backword(vp,1, 'W');
14474887Schin 				cdelete(vp,tmp - cur_virt + 1, BAD);
14484887Schin 			}
14494887Schin 			break;
14504887Schin 
14514887Schin 		case UKILL:		/** user kill line char **/
14524887Schin 			if( virtual[cur_virt] == '\\' )
14534887Schin 			{
14544887Schin 				cdelete(vp,1, BAD);
14554887Schin 				append(vp,usrkill, mode);
14564887Schin 			}
14574887Schin 			else
14584887Schin 			{
14594887Schin 				if( mode == SEARCH )
14604887Schin 				{
14614887Schin 					cur_virt = 1;
14624887Schin 					delmotion(vp, '$', BAD);
14634887Schin 				}
14644887Schin 				else if(first_virt)
14654887Schin 				{
14664887Schin 					tmp = cur_virt;
14674887Schin 					cur_virt = first_virt;
14684887Schin 					cdelete(vp,tmp - cur_virt + 1, BAD);
14694887Schin 				}
14704887Schin 				else
14714887Schin 					del_line(vp,GOOD);
14724887Schin 			}
14734887Schin 			break;
14744887Schin 
14754887Schin 		case UEOF:		/** eof char **/
14764887Schin 			if( cur_virt != INVALID )
14774887Schin 				continue;
14784887Schin 			vp->addnl = 0;
14794887Schin 
14804887Schin 		case '\n':		/** newline or return **/
14814887Schin 			if( mode != SEARCH )
14824887Schin 				save_last(vp);
14834887Schin 			refresh(vp,INPUT);
14848462SApril.Chin@Sun.COM 			last_phys++;
14854887Schin 			return;
14864887Schin 
14874887Schin 		case '\t':		/** command completion **/
14884887Schin 			if(mode!=SEARCH && last_virt>=0 && (vp->ed->e_tabcount|| !isblank(cur_virt)) && vp->ed->sh->nextprompt)
14894887Schin 			{
14904887Schin 				if(vp->ed->e_tabcount==0)
14914887Schin 				{
14924887Schin 					ed_ungetchar(vp->ed,'\\');
14934887Schin 					vp->ed->e_tabcount=1;
14944887Schin 					goto escape;
14954887Schin 				}
14964887Schin 				else if(vp->ed->e_tabcount==1)
14974887Schin 				{
14984887Schin 					ed_ungetchar(vp->ed,'=');
14994887Schin 					goto escape;
15004887Schin 				}
15014887Schin 				vp->ed->e_tabcount = 0;
15024887Schin 			}
15034887Schin 			/* FALL THRU*/
15044887Schin 		default:
15054887Schin 			if( mode == REPLACE )
15064887Schin 			{
15074887Schin 				if( cur_virt < last_virt )
15084887Schin 				{
15094887Schin 					replace(vp,c, 1);
15104887Schin 					if(cur_virt>max_virt)
15114887Schin 						max_virt = cur_virt;
15124887Schin 					continue;
15134887Schin 				}
15144887Schin 				cdelete(vp,1, BAD);
15154887Schin 				mode = APPEND;
15164887Schin 				max_virt = last_virt+3;
15174887Schin 			}
15184887Schin 			append(vp,c, mode);
15194887Schin 			break;
15204887Schin 		}
15214887Schin 		refresh(vp,INPUT);
15224887Schin 
15234887Schin 	}
15244887Schin }
15254887Schin 
15264887Schin /*{	MVCURSOR( motion )
15274887Schin  *
15284887Schin  *	This routine will move the virtual cursor according to motion
15294887Schin  * for repeat times.
15304887Schin  *
15314887Schin  * It returns GOOD if successful; else BAD.
15324887Schin  *
15334887Schin }*/
15344887Schin 
mvcursor(register Vi_t * vp,register int motion)15354887Schin static int mvcursor(register Vi_t* vp,register int motion)
15364887Schin {
15374887Schin 	register int count;
15384887Schin 	register int tcur_virt;
15394887Schin 	register int incr = -1;
15404887Schin 	register int bound = 0;
15414887Schin 
15424887Schin 	switch(motion)
15434887Schin 	{
15444887Schin 		/***** Cursor move commands *****/
15454887Schin 
15464887Schin 	case '0':		/** First column **/
15474887Schin 		tcur_virt = 0;
15484887Schin 		break;
15494887Schin 
15504887Schin 	case '^':		/** First nonblank character **/
15514887Schin 		tcur_virt = first_virt;
15524887Schin 		while( isblank(tcur_virt) && tcur_virt < last_virt )
15534887Schin 			++tcur_virt;
15544887Schin 		break;
15554887Schin 
15564887Schin 	case '|':
15574887Schin 		tcur_virt = vp->repeat-1;
15584887Schin 		if(tcur_virt <= last_virt)
15594887Schin 			break;
15604887Schin 		/* fall through */
15614887Schin 
15624887Schin 	case '$':		/** End of line **/
15634887Schin 		tcur_virt = last_virt;
15644887Schin 		break;
15654887Schin 
15664887Schin 	case '[':
15674887Schin 		switch(motion=getcount(vp,ed_getchar(vp->ed,-1)))
15684887Schin 		{
15694887Schin 		    case 'A':
15708462SApril.Chin@Sun.COM 			if(cur_virt>=0  && cur_virt<(SEARCHSIZE-2) && cur_virt == last_virt)
15718462SApril.Chin@Sun.COM 			{
15728462SApril.Chin@Sun.COM 				virtual[last_virt + 1] = '\0';
15738462SApril.Chin@Sun.COM #if SHOPT_MULTIBYTE
157410898Sroland.mainz@nrubsig.org 				ed_external(virtual,lsearch+1);
157510898Sroland.mainz@nrubsig.org #else
157610898Sroland.mainz@nrubsig.org 				strcpy(lsearch+1,virtual);
15778462SApril.Chin@Sun.COM #endif /* SHOPT_MULTIBYTE */
15788462SApril.Chin@Sun.COM 				*lsearch = '^';
15798462SApril.Chin@Sun.COM 				vp->direction = -2;
15808462SApril.Chin@Sun.COM 				ed_ungetchar(vp->ed,'n');
15818462SApril.Chin@Sun.COM 			}
15828462SApril.Chin@Sun.COM 			else if(cur_virt==0 && vp->direction == -2)
15838462SApril.Chin@Sun.COM 				ed_ungetchar(vp->ed,'n');
15848462SApril.Chin@Sun.COM 			else
15858462SApril.Chin@Sun.COM 				ed_ungetchar(vp->ed,'k');
15864887Schin 			return(1);
15874887Schin 		    case 'B':
15884887Schin 			ed_ungetchar(vp->ed,'j');
15894887Schin 			return(1);
15904887Schin 		    case 'C':
15914887Schin 			motion = last_virt;
15924887Schin 			incr = 1;
15934887Schin 			goto walk;
15944887Schin 		    case 'D':
15954887Schin 			motion = first_virt;
15964887Schin 			goto walk;
15974887Schin 		    case 'H':
15984887Schin 			tcur_virt = 0;
15994887Schin 			break;
16004887Schin 		    case 'Y':
16014887Schin 			tcur_virt = last_virt;
16024887Schin 			break;
16034887Schin 		    default:
16044887Schin 			ed_ungetchar(vp->ed,motion);
16054887Schin 			return(0);
16064887Schin 		}
16074887Schin 		break;
16084887Schin 
16094887Schin 	case 'h':		/** Left one **/
16104887Schin 	case '\b':
16114887Schin 		motion = first_virt;
16124887Schin 		goto walk;
16134887Schin 
16144887Schin 	case ' ':
16154887Schin 	case 'l':		/** Right one **/
16164887Schin 		motion = last_virt;
16174887Schin 		incr = 1;
16184887Schin 	walk:
16194887Schin 		tcur_virt = cur_virt;
16204887Schin 		if( incr*tcur_virt < motion)
16214887Schin 		{
16224887Schin 			tcur_virt += vp->repeat*incr;
16234887Schin 			if( incr*tcur_virt > motion)
16244887Schin 				tcur_virt = motion;
16254887Schin 		}
16264887Schin 		else
16274887Schin 			return(0);
16284887Schin 		break;
16294887Schin 
16304887Schin 	case 'B':
16314887Schin 	case 'b':		/** back word **/
16324887Schin 		tcur_virt = cur_virt;
16334887Schin 		backword(vp,vp->repeat, motion);
16344887Schin 		if( cur_virt == tcur_virt )
16354887Schin 			return(0);
16364887Schin 		return(1);
16374887Schin 
16384887Schin 	case 'E':
16394887Schin 	case 'e':		/** end of word **/
16404887Schin 		tcur_virt = cur_virt;
16414887Schin 		if(tcur_virt >=0)
16424887Schin 			endword(vp, vp->repeat, motion);
16434887Schin 		if( cur_virt == tcur_virt )
16444887Schin 			return(0);
16454887Schin 		return(1);
16464887Schin 
16474887Schin 	case ',':		/** reverse find old char **/
16484887Schin 	case ';':		/** find old char **/
16494887Schin 		switch(vp->last_find)
16504887Schin 		{
16514887Schin 		case 't':
16524887Schin 		case 'f':
16534887Schin 			if(motion==';')
16544887Schin 			{
16554887Schin 				bound = last_virt;
16564887Schin 				incr = 1;
16574887Schin 			}
16584887Schin 			goto find_b;
16594887Schin 
16604887Schin 		case 'T':
16614887Schin 		case 'F':
16624887Schin 			if(motion==',')
16634887Schin 			{
16644887Schin 				bound = last_virt;
16654887Schin 				incr = 1;
16664887Schin 			}
16674887Schin 			goto find_b;
16684887Schin 
16694887Schin 		default:
16704887Schin 			return(0);
16714887Schin 		}
16724887Schin 
16734887Schin 
16744887Schin 	case 't':		/** find up to new char forward **/
16754887Schin 	case 'f':		/** find new char forward **/
16764887Schin 		bound = last_virt;
16774887Schin 		incr = 1;
16784887Schin 
16794887Schin 	case 'T':		/** find up to new char backward **/
16804887Schin 	case 'F':		/** find new char backward **/
16814887Schin 		vp->last_find = motion;
16824887Schin 		if((vp->findchar=getrchar(vp))==ESC)
16834887Schin 			return(1);
16844887Schin find_b:
16854887Schin 		tcur_virt = cur_virt;
16864887Schin 		count = vp->repeat;
16874887Schin 		while( count-- )
16884887Schin 		{
16894887Schin 			while( incr*(tcur_virt+=incr) <= bound
16904887Schin 				&& virtual[tcur_virt] != vp->findchar );
16914887Schin 			if( incr*tcur_virt > bound )
16924887Schin 			{
16934887Schin 				return(0);
16944887Schin 			}
16954887Schin 		}
16964887Schin 		if( fold(vp->last_find) == 'T' )
16974887Schin 			tcur_virt -= incr;
16984887Schin 		break;
16994887Schin 
17004887Schin         case '%':
17014887Schin 	{
17024887Schin 		int nextmotion;
17034887Schin 		int nextc;
17044887Schin 		tcur_virt = cur_virt;
17054887Schin 		while( tcur_virt <= last_virt
17064887Schin 			&& strchr(paren_chars,virtual[tcur_virt])==(char*)0)
17074887Schin 				tcur_virt++;
17084887Schin 		if(tcur_virt > last_virt )
17094887Schin 			return(0);
17104887Schin 		nextc = virtual[tcur_virt];
17114887Schin 		count = strchr(paren_chars,nextc)-paren_chars;
17124887Schin 		if(count < 3)
17134887Schin 		{
17144887Schin 			incr = 1;
17154887Schin 			bound = last_virt;
17164887Schin 			nextmotion = paren_chars[count+3];
17174887Schin 		}
17184887Schin 		else
17194887Schin 			nextmotion = paren_chars[count-3];
17204887Schin 		count = 1;
17214887Schin 		while(count >0 &&  incr*(tcur_virt+=incr) <= bound)
17224887Schin 		{
17234887Schin 		        if(virtual[tcur_virt] == nextmotion)
17244887Schin 		        	count--;
17254887Schin 		        else if(virtual[tcur_virt]==nextc)
17264887Schin 		        	count++;
17274887Schin 		}
17284887Schin 		if(count)
17294887Schin 			return(0);
17304887Schin 		break;
17314887Schin 	}
17324887Schin 
17334887Schin 	case 'W':
17344887Schin 	case 'w':		/** forward word **/
17354887Schin 		tcur_virt = cur_virt;
17364887Schin 		forward(vp,vp->repeat, motion);
17374887Schin 		if( tcur_virt == cur_virt )
17384887Schin 			return(0);
17394887Schin 		return(1);
17404887Schin 
17414887Schin 	default:
17424887Schin 		return(0);
17434887Schin 	}
17444887Schin 	cur_virt = tcur_virt;
17454887Schin 
17464887Schin 	return(1);
17474887Schin }
17484887Schin 
17494887Schin /*
17504887Schin  * print a string
17514887Schin  */
17524887Schin 
pr_string(register Vi_t * vp,register const char * sp)17534887Schin static void pr_string(register Vi_t *vp, register const char *sp)
17544887Schin {
17554887Schin 	/*** copy string sp ***/
17564887Schin 	register char *ptr = editb.e_outptr;
17574887Schin 	while(*sp)
17584887Schin 		*ptr++ = *sp++;
17594887Schin 	editb.e_outptr = ptr;
17604887Schin 	return;
17614887Schin }
17624887Schin 
17634887Schin /*{	PUTSTRING( column, nchars )
17644887Schin  *
17654887Schin  *	Put nchars starting at column of physical into the workspace
17664887Schin  * to be printed.
17674887Schin  *
17684887Schin }*/
17694887Schin 
putstring(register Vi_t * vp,register int col,register int nchars)17704887Schin static void putstring(register Vi_t *vp,register int col, register int nchars)
17714887Schin {
17724887Schin 	while( nchars-- )
17734887Schin 		putchar(physical[col++]);
17744887Schin 	return;
17754887Schin }
17764887Schin 
17774887Schin /*{	REFRESH( mode )
17784887Schin  *
17794887Schin  *	This routine will refresh the crt so the physical image matches
17804887Schin  * the virtual image and display the proper window.
17814887Schin  *
17824887Schin  *	mode	= CONTROL, refresh in control mode, ie. leave cursor
17834887Schin  *			positioned at last char printed.
17844887Schin  *		= INPUT, refresh in input mode; leave cursor positioned
17854887Schin  *			after last char printed.
17864887Schin  *		= TRANSLATE, perform virtual to physical translation
17874887Schin  *			and adjust left margin only.
17884887Schin  *
17894887Schin  *		+-------------------------------+
17904887Schin  *		|   | |    virtual	  | |   |
17914887Schin  *		+-------------------------------+
17924887Schin  *		  cur_virt		last_virt
17934887Schin  *
17944887Schin  *		+-----------------------------------------------+
17954887Schin  *		|	  | |	        physical	 | |    |
17964887Schin  *		+-----------------------------------------------+
17974887Schin  *			cur_phys			last_phys
17984887Schin  *
17994887Schin  *				0			w_size - 1
18004887Schin  *				+-----------------------+
18014887Schin  *				| | |  window		|
18024887Schin  *				+-----------------------+
18034887Schin  *				cur_window = cur_phys - first_wind
18044887Schin }*/
18054887Schin 
refresh(register Vi_t * vp,int mode)18064887Schin static void refresh(register Vi_t* vp, int mode)
18074887Schin {
18084887Schin 	register int p;
18094887Schin 	register int regb;
18104887Schin 	register int first_w = vp->first_wind;
18114887Schin 	int p_differ;
18124887Schin 	int new_lw;
18134887Schin 	int ncur_phys;
18144887Schin 	int opflag;			/* search optimize flag */
18154887Schin 
18164887Schin #	define	w	regb
18174887Schin #	define	v	regb
18184887Schin 
18194887Schin 	/*** find out if it's necessary to start translating at beginning ***/
18204887Schin 
18214887Schin 	if(lookahead>0)
18224887Schin 	{
18234887Schin 		p = previous[lookahead-1];
18244887Schin 		if(p != ESC && p != '\n' && p != '\r')
18254887Schin 			mode = TRANSLATE;
18264887Schin 	}
18274887Schin 	v = cur_virt;
18284887Schin 	if( v<vp->ocur_virt || vp->ocur_virt==INVALID
18294887Schin 		|| ( v==vp->ocur_virt
18304887Schin 			&& (!is_print(virtual[v]) || !is_print(vp->o_v_char))) )
18314887Schin 	{
18324887Schin 		opflag = 0;
18334887Schin 		p = 0;
18344887Schin 		v = 0;
18354887Schin 	}
18364887Schin 	else
18374887Schin 	{
18384887Schin 		opflag = 1;
18394887Schin 		p = vp->ocur_phys;
18404887Schin 		v = vp->ocur_virt;
18414887Schin 		if( !is_print(virtual[v]) )
18424887Schin 		{
18434887Schin 			/*** avoid double ^'s ***/
18444887Schin 			++p;
18454887Schin 			++v;
18464887Schin 		}
18474887Schin 	}
18484887Schin 	virtual[last_virt+1] = 0;
18494887Schin 	ncur_phys = ed_virt_to_phys(vp->ed,virtual,physical,cur_virt,v,p);
18504887Schin 	p = genlen(physical);
18514887Schin 	if( --p < 0 )
18524887Schin 		last_phys = 0;
18534887Schin 	else
18544887Schin 		last_phys = p;
18554887Schin 
18564887Schin 	/*** see if this was a translate only ***/
18574887Schin 
18584887Schin 	if( mode == TRANSLATE )
18594887Schin 		return;
18604887Schin 
18614887Schin 	/*** adjust left margin if necessary ***/
18624887Schin 
18634887Schin 	if( ncur_phys<first_w || ncur_phys>=(first_w + w_size) )
18644887Schin 	{
18654887Schin 		cursor(vp,first_w);
18664887Schin 		first_w = ncur_phys - (w_size>>1);
18674887Schin 		if( first_w < 0 )
18684887Schin 			first_w = 0;
18694887Schin 		vp->first_wind = cur_phys = first_w;
18704887Schin 	}
18714887Schin 
18724887Schin 	/*** attempt to optimize search somewhat to find ***/
18734887Schin 	/*** out where physical and window images differ ***/
18744887Schin 
18754887Schin 	if( first_w==vp->ofirst_wind && ncur_phys>=vp->ocur_phys && opflag==1 )
18764887Schin 	{
18774887Schin 		p = vp->ocur_phys;
18784887Schin 		w = p - first_w;
18794887Schin 	}
18804887Schin 	else
18814887Schin 	{
18824887Schin 		p = first_w;
18834887Schin 		w = 0;
18844887Schin 	}
18854887Schin 
18864887Schin 	for(; (p<=last_phys && w<=vp->last_wind); ++p, ++w)
18874887Schin 	{
18884887Schin 		if( window[w] != physical[p] )
18894887Schin 			break;
18904887Schin 	}
18914887Schin 	p_differ = p;
18924887Schin 
18934887Schin 	if( (p>last_phys || p>=first_w+w_size) && w>vp->last_wind
18944887Schin 		&& cur_virt==vp->ocur_virt )
18954887Schin 	{
18964887Schin 		/*** images are identical ***/
18974887Schin 		return;
18984887Schin 	}
18994887Schin 
19004887Schin 	/*** copy the physical image to the window image ***/
19014887Schin 
19024887Schin 	if( last_virt != INVALID )
19034887Schin 	{
19044887Schin 		while( p <= last_phys && w < w_size )
19054887Schin 			window[w++] = physical[p++];
19064887Schin 	}
19074887Schin 	new_lw = w;
19084887Schin 
19094887Schin 	/*** erase trailing characters if needed ***/
19104887Schin 
19114887Schin 	while( w <= vp->last_wind )
19124887Schin 		window[w++] = ' ';
19134887Schin 	vp->last_wind = --w;
19144887Schin 
19154887Schin 	p = p_differ;
19164887Schin 
19174887Schin 	/*** move cursor to start of difference ***/
19184887Schin 
19194887Schin 	cursor(vp,p);
19204887Schin 
19214887Schin 	/*** and output difference ***/
19224887Schin 
19234887Schin 	w = p - first_w;
19244887Schin 	while( w <= vp->last_wind )
19254887Schin 		putchar(window[w++]);
19264887Schin 
19274887Schin 	cur_phys = w + first_w;
19284887Schin 	vp->last_wind = --new_lw;
19294887Schin 
19304887Schin 	if( last_phys >= w_size )
19314887Schin 	{
19324887Schin 		if( first_w == 0 )
19334887Schin 			vp->long_char = '>';
19344887Schin 		else if( last_phys < (first_w+w_size) )
19354887Schin 			vp->long_char = '<';
19364887Schin 		else
19374887Schin 			vp->long_char = '*';
19384887Schin 	}
19394887Schin 	else
19404887Schin 		vp->long_char = ' ';
19414887Schin 
19424887Schin 	if( vp->long_line != vp->long_char )
19434887Schin 	{
19444887Schin 		/*** indicate lines longer than window ***/
19454887Schin 		while( w++ < w_size )
19464887Schin 		{
19474887Schin 			putchar(' ');
19484887Schin 			++cur_phys;
19494887Schin 		}
19504887Schin 		putchar(vp->long_char);
19514887Schin 		++cur_phys;
19524887Schin 		vp->long_line = vp->long_char;
19534887Schin 	}
19544887Schin 
19558462SApril.Chin@Sun.COM 	if(vp->ed->e_multiline &&  vp->ofirst_wind==INVALID && !vp->ed->e_nocrnl)
19568462SApril.Chin@Sun.COM 		ed_setcursor(vp->ed, physical, last_phys+1, last_phys+1, -1);
19578462SApril.Chin@Sun.COM 	vp->ed->e_nocrnl = 0;
19584887Schin 	vp->ocur_phys = ncur_phys;
19594887Schin 	vp->ocur_virt = cur_virt;
19604887Schin 	vp->ofirst_wind = first_w;
19614887Schin 
19624887Schin 	if( mode==INPUT && cur_virt>INVALID )
19634887Schin 		++ncur_phys;
19644887Schin 
19654887Schin 	cursor(vp,ncur_phys);
19664887Schin 	ed_flush(vp->ed);
19674887Schin 	return;
19684887Schin }
19694887Schin 
19704887Schin /*{	REPLACE( char, increment )
19714887Schin  *
19724887Schin  *	Replace the cur_virt character with char.  This routine attempts
19734887Schin  * to avoid using refresh().
19744887Schin  *
19754887Schin  *	increment	= 1, increment cur_virt after replacement.
19764887Schin  *			= 0, leave cur_virt where it is.
19774887Schin  *
19784887Schin }*/
19794887Schin 
replace(register Vi_t * vp,register int c,register int increment)19804887Schin static void replace(register Vi_t *vp, register int c, register int increment)
19814887Schin {
19824887Schin 	register int cur_window;
19834887Schin 
19844887Schin 	if( cur_virt == INVALID )
19854887Schin 	{
19864887Schin 		/*** can't replace invalid cursor ***/
19874887Schin 		ed_ringbell();
19884887Schin 		return;
19894887Schin 	}
19904887Schin 	cur_window = cur_phys - vp->first_wind;
19914887Schin 	if( vp->ocur_virt == INVALID || !is_print(c)
19924887Schin 		|| !is_print(virtual[cur_virt])
19934887Schin 		|| !is_print(vp->o_v_char)
19944887Schin #if SHOPT_MULTIBYTE
19954887Schin 		|| !iswascii(c) || mbwidth(vp->o_v_char)>1
19964887Schin 		|| !iswascii(virtual[cur_virt])
19974887Schin #endif /* SHOPT_MULTIBYTE */
19984887Schin 		|| (increment && (cur_window==w_size-1)
19994887Schin 			|| !is_print(virtual[cur_virt+1])) )
20004887Schin 	{
20014887Schin 		/*** must use standard refresh routine ***/
20024887Schin 
20034887Schin 		cdelete(vp,1, BAD);
20044887Schin 		append(vp,c, APPEND);
20054887Schin 		if( increment && cur_virt<last_virt )
20064887Schin 			++cur_virt;
20074887Schin 		refresh(vp,CONTROL);
20084887Schin 	}
20094887Schin 	else
20104887Schin 	{
20114887Schin 		virtual[cur_virt] = c;
20124887Schin 		physical[cur_phys] = c;
20134887Schin 		window[cur_window] = c;
20144887Schin 		putchar(c);
20154887Schin 		if(increment)
20164887Schin 		{
20174887Schin 			c = virtual[++cur_virt];
20184887Schin 			++cur_phys;
20194887Schin 		}
20204887Schin 		else
20214887Schin 		{
20224887Schin 			putchar('\b');
20234887Schin 		}
20244887Schin 		vp->o_v_char = c;
20254887Schin 		ed_flush(vp->ed);
20264887Schin 	}
20274887Schin 	return;
20284887Schin }
20294887Schin 
20304887Schin /*{	RESTORE_V()
20314887Schin  *
20324887Schin  *	Restore the contents of virtual space from u_space.
20334887Schin  *
20344887Schin }*/
20354887Schin 
restore_v(register Vi_t * vp)20364887Schin static void restore_v(register Vi_t *vp)
20374887Schin {
20384887Schin 	register int tmpcol;
20394887Schin 	genchar tmpspace[MAXLINE];
20404887Schin 
20414887Schin 	if( vp->u_column == INVALID-1 )
20424887Schin 	{
20434887Schin 		/*** never saved anything ***/
20444887Schin 		ed_ringbell();
20454887Schin 		return;
20464887Schin 	}
20474887Schin 	gencpy(tmpspace, vp->u_space);
20484887Schin 	tmpcol = vp->u_column;
20494887Schin 	save_v(vp);
20504887Schin 	gencpy(virtual, tmpspace);
20514887Schin 	cur_virt = tmpcol;
20524887Schin 	last_virt = genlen(tmpspace) - 1;
20534887Schin 	vp->ocur_virt = MAXCHAR;	/** invalidate refresh optimization **/
20544887Schin 	return;
20554887Schin }
20564887Schin 
20574887Schin /*{	SAVE_LAST()
20584887Schin  *
20594887Schin  *	If the user has typed something, save it in last line.
20604887Schin  *
20614887Schin }*/
20624887Schin 
save_last(register Vi_t * vp)20634887Schin static void save_last(register Vi_t* vp)
20644887Schin {
20654887Schin 	register int i;
20664887Schin 
20674887Schin 	if( (i = cur_virt - first_virt + 1) > 0 )
20684887Schin 	{
20694887Schin 		/*** save last thing user typed ***/
20704887Schin 		if(i >= MAXLINE)
20714887Schin 			i = MAXLINE-1;
20724887Schin 		genncpy(vp->lastline, (&virtual[first_virt]), i);
20734887Schin 		vp->lastline[i] = '\0';
20744887Schin 	}
20754887Schin 	return;
20764887Schin }
20774887Schin 
20784887Schin /*{	SAVE_V()
20794887Schin  *
20804887Schin  *	This routine will save the contents of virtual in u_space.
20814887Schin  *
20824887Schin }*/
20834887Schin 
save_v(register Vi_t * vp)20844887Schin static void save_v(register Vi_t *vp)
20854887Schin {
20864887Schin 	if(!inmacro)
20874887Schin 	{
20884887Schin 		virtual[last_virt + 1] = '\0';
20894887Schin 		gencpy(vp->u_space, virtual);
20904887Schin 		vp->u_column = cur_virt;
20914887Schin 	}
20924887Schin 	return;
20934887Schin }
20944887Schin 
20954887Schin /*{	SEARCH( mode )
20964887Schin  *
20974887Schin  *	Search history file for regular expression.
20984887Schin  *
20994887Schin  *	mode	= '/'	require search string and search new to old
21004887Schin  *	mode	= '?'	require search string and search old to new
21014887Schin  *	mode	= 'N'	repeat last search in reverse direction
21024887Schin  *	mode	= 'n'	repeat last search
21034887Schin  *
21044887Schin }*/
21054887Schin 
21064887Schin /*
21074887Schin  * search for <string> in the current command
21084887Schin  */
curline_search(Vi_t * vp,const char * string)21094887Schin static int curline_search(Vi_t *vp, const char *string)
21104887Schin {
21114887Schin 	register int len=strlen(string);
21124887Schin 	register const char *dp,*cp=string, *dpmax;
21134887Schin #if SHOPT_MULTIBYTE
21144887Schin 	ed_external(vp->u_space,(char*)vp->u_space);
21154887Schin #endif /* SHOPT_MULTIBYTE */
21164887Schin 	for(dp=(char*)vp->u_space,dpmax=dp+strlen(dp)-len; dp<=dpmax; dp++)
21174887Schin 	{
21184887Schin 		if(*dp==*cp && memcmp(cp,dp,len)==0)
21194887Schin 			return(dp-(char*)vp->u_space);
21204887Schin 	}
21214887Schin #if SHOPT_MULTIBYTE
21224887Schin 	ed_internal((char*)vp->u_space,vp->u_space);
21234887Schin #endif /* SHOPT_MULTIBYTE */
21244887Schin 	return(-1);
21254887Schin }
21264887Schin 
search(register Vi_t * vp,register int mode)21274887Schin static int search(register Vi_t* vp,register int mode)
21284887Schin {
21294887Schin 	register int new_direction;
21304887Schin 	register int oldcurhline;
21314887Schin 	register int i;
21324887Schin 	Histloc_t  location;
21334887Schin 
21348462SApril.Chin@Sun.COM 	if( vp->direction == -2 && mode != 'n')
21358462SApril.Chin@Sun.COM 		vp->direction = -1;
21364887Schin 	if( mode == '/' || mode == '?')
21374887Schin 	{
21384887Schin 		/*** new search expression ***/
21394887Schin 		del_line(vp,BAD);
21404887Schin 		append(vp,mode, APPEND);
21414887Schin 		refresh(vp,INPUT);
21424887Schin 		first_virt = 1;
21434887Schin 		getline(vp,SEARCH);
21444887Schin 		first_virt = 0;
21454887Schin 		virtual[last_virt + 1] = '\0';	/*** make null terminated ***/
21464887Schin 		vp->direction = mode=='/' ? -1 : 1;
21474887Schin 	}
21484887Schin 
21494887Schin 	if( cur_virt == INVALID )
21504887Schin 	{
21514887Schin 		/*** no operation ***/
21524887Schin 		return(ABORT);
21534887Schin 	}
21544887Schin 
21554887Schin 	if( cur_virt==0 ||  fold(mode)=='N' )
21564887Schin 	{
21574887Schin 		/*** user wants repeat of last search ***/
21584887Schin 		del_line(vp,BAD);
21594887Schin 		strcpy( ((char*)virtual)+1, lsearch);
21604887Schin #if SHOPT_MULTIBYTE
21614887Schin 		*((char*)virtual) = '/';
21624887Schin 		ed_internal((char*)virtual,virtual);
21634887Schin #endif /* SHOPT_MULTIBYTE */
21644887Schin 	}
21654887Schin 
21664887Schin 	if( mode == 'N' )
21674887Schin 		new_direction = -vp->direction;
21684887Schin 	else
21694887Schin 		new_direction = vp->direction;
21704887Schin 
21714887Schin 
21724887Schin 	/*** now search ***/
21734887Schin 
21744887Schin 	oldcurhline = curhline;
21754887Schin #if SHOPT_MULTIBYTE
21764887Schin 	ed_external(virtual,(char*)virtual);
21774887Schin #endif /* SHOPT_MULTIBYTE */
21784887Schin 	if(mode=='?' && (i=curline_search(vp,((char*)virtual)+1))>=0)
21794887Schin 	{
21804887Schin 		location.hist_command = curhline;
21814887Schin 		location.hist_char = i;
21824887Schin 	}
21834887Schin 	else
21844887Schin 	{
21854887Schin 		i = INVALID;
21864887Schin 		if( new_direction==1 && curhline >= histmax )
21874887Schin 			curhline = histmin + 1;
21884887Schin 		location = hist_find(sh.hist_ptr,((char*)virtual)+1, curhline, 1, new_direction);
21894887Schin 	}
21904887Schin 	cur_virt = i;
21914887Schin 	strncpy(lsearch, ((char*)virtual)+1, SEARCHSIZE);
21924887Schin 	if( (curhline=location.hist_command) >=0 )
21934887Schin 	{
21944887Schin 		vp->ocur_virt = INVALID;
21954887Schin 		return(GOOD);
21964887Schin 	}
21974887Schin 
21984887Schin 	/*** could not find matching line ***/
21994887Schin 
22004887Schin 	curhline = oldcurhline;
22014887Schin 	return(BAD);
22024887Schin }
22034887Schin 
22044887Schin /*{	SYNC_CURSOR()
22054887Schin  *
22064887Schin  *	This routine will move the physical cursor to the same
22074887Schin  * column as the virtual cursor.
22084887Schin  *
22094887Schin }*/
22104887Schin 
sync_cursor(register Vi_t * vp)22114887Schin static void sync_cursor(register Vi_t *vp)
22124887Schin {
22134887Schin 	register int p;
22144887Schin 	register int v;
22154887Schin 	register int c;
22164887Schin 	int new_phys;
22174887Schin 
22184887Schin 	if( cur_virt == INVALID )
22194887Schin 		return;
22204887Schin 
22214887Schin 	/*** find physical col that corresponds to virtual col ***/
22224887Schin 
22234887Schin 	new_phys = 0;
22244887Schin 	if(vp->first_wind==vp->ofirst_wind && cur_virt>vp->ocur_virt && vp->ocur_virt!=INVALID)
22254887Schin 	{
22264887Schin 		/*** try to optimize search a little ***/
22274887Schin 		p = vp->ocur_phys + 1;
22284887Schin #if SHOPT_MULTIBYTE
22294887Schin 		while(physical[p]==MARKER)
22304887Schin 			p++;
22314887Schin #endif /* SHOPT_MULTIBYTE */
22324887Schin 		v = vp->ocur_virt + 1;
22334887Schin 	}
22344887Schin 	else
22354887Schin 	{
22364887Schin 		p = 0;
22374887Schin 		v = 0;
22384887Schin 	}
22394887Schin 	for(; v <= last_virt; ++p, ++v)
22404887Schin 	{
22414887Schin #if SHOPT_MULTIBYTE
22424887Schin 		int d;
22434887Schin 		c = virtual[v];
22444887Schin 		if((d = mbwidth(c)) > 1)
22454887Schin 		{
22464887Schin 			if( v != cur_virt )
22474887Schin 				p += (d-1);
22484887Schin 		}
22494887Schin 		else if(!iswprint(c))
22504887Schin #else
22514887Schin 		c = virtual[v];
22524887Schin 		if(!isprint(c))
22534887Schin #endif	/* SHOPT_MULTIBYTE */
22544887Schin 		{
22554887Schin 			if( c == '\t' )
22564887Schin 			{
22574887Schin 				p -= ((p+editb.e_plen)%TABSIZE);
22584887Schin 				p += (TABSIZE-1);
22594887Schin 			}
22604887Schin 			else
22614887Schin 			{
22624887Schin 				++p;
22634887Schin 			}
22644887Schin 		}
22654887Schin 		if( v == cur_virt )
22664887Schin 		{
22674887Schin 			new_phys = p;
22684887Schin 			break;
22694887Schin 		}
22704887Schin 	}
22714887Schin 
22724887Schin 	if( new_phys < vp->first_wind || new_phys >= vp->first_wind + w_size )
22734887Schin 	{
22744887Schin 		/*** asked to move outside of window ***/
22754887Schin 
22764887Schin 		window[0] = '\0';
22774887Schin 		refresh(vp,CONTROL);
22784887Schin 		return;
22794887Schin 	}
22804887Schin 
22814887Schin 	cursor(vp,new_phys);
22824887Schin 	ed_flush(vp->ed);
22834887Schin 	vp->ocur_phys = cur_phys;
22844887Schin 	vp->ocur_virt = cur_virt;
22854887Schin 	vp->o_v_char = virtual[vp->ocur_virt];
22864887Schin 
22874887Schin 	return;
22884887Schin }
22894887Schin 
22904887Schin /*{	TEXTMOD( command, mode )
22914887Schin  *
22924887Schin  *	Modify text operations.
22934887Schin  *
22944887Schin  *	mode != 0, repeat previous operation
22954887Schin  *
22964887Schin }*/
22974887Schin 
textmod(register Vi_t * vp,register int c,int mode)22984887Schin static int textmod(register Vi_t *vp,register int c, int mode)
22994887Schin {
23004887Schin 	register int i;
23014887Schin 	register genchar *p = vp->lastline;
23024887Schin 	register int trepeat = vp->repeat;
23034887Schin 	genchar *savep;
23044887Schin 
23054887Schin 	if(mode && (fold(vp->lastmotion)=='F' || fold(vp->lastmotion)=='T'))
23064887Schin 		vp->lastmotion = ';';
23074887Schin 
23084887Schin 	if( fold(c) == 'P' )
23094887Schin 	{
23104887Schin 		/*** change p from lastline to yankbuf ***/
23114887Schin 		p = yankbuf;
23124887Schin 	}
23134887Schin 
23144887Schin addin:
23154887Schin 	switch( c )
23164887Schin 	{
23174887Schin 			/***** Input commands *****/
23184887Schin 
23194887Schin #if KSHELL
23204887Schin         case '\t':
23214887Schin 		if(vp->ed->e_tabcount!=1)
23224887Schin 			return(BAD);
23234887Schin 		c = '=';
23244887Schin 	case '*':		/** do file name expansion in place **/
23254887Schin 	case '\\':		/** do file name completion in place **/
23264887Schin 		if( cur_virt == INVALID )
23274887Schin 			return(BAD);
23284887Schin 	case '=':		/** list file name expansions **/
23294887Schin 		save_v(vp);
23304887Schin 		i = last_virt;
23314887Schin 		++last_virt;
23324887Schin 		mode = cur_virt-1;
23334887Schin 		virtual[last_virt] = 0;
23344887Schin 		if(ed_expand(vp->ed,(char*)virtual, &cur_virt, &last_virt, c, vp->repeat_set?vp->repeat:-1)<0)
23354887Schin 		{
23364887Schin 			if(vp->ed->e_tabcount)
23374887Schin 			{
23384887Schin 				vp->ed->e_tabcount=2;
23394887Schin 				ed_ungetchar(vp->ed,'\t');
23404887Schin 				--last_virt;
23414887Schin 				return(APPEND);
23424887Schin 			}
23434887Schin 			last_virt = i;
23444887Schin 			ed_ringbell();
23454887Schin 		}
23464887Schin 		else if(c == '=' && !vp->repeat_set)
23474887Schin 		{
23484887Schin 			last_virt = i;
23494887Schin 			vp->nonewline++;
23504887Schin 			ed_ungetchar(vp->ed,cntl('L'));
23514887Schin 			return(GOOD);
23524887Schin 		}
23534887Schin 		else
23544887Schin 		{
23554887Schin 			--cur_virt;
23564887Schin 			--last_virt;
23574887Schin 			vp->ocur_virt = MAXCHAR;
23584887Schin 			if(c=='=' || (mode<cur_virt && (virtual[cur_virt]==' ' || virtual[cur_virt]=='/')))
23594887Schin 				vp->ed->e_tabcount = 0;
23604887Schin 			return(APPEND);
23614887Schin 		}
23624887Schin 		break;
23634887Schin 
23644887Schin 	case '@':		/** macro expansion **/
23654887Schin 		if( mode )
23664887Schin 			c = vp->lastmacro;
23674887Schin 		else
23684887Schin 			if((c=getrchar(vp))==ESC)
23694887Schin 				return(GOOD);
23704887Schin 		if(!inmacro)
23714887Schin 			vp->lastmacro = c;
23724887Schin 		if(ed_macro(vp->ed,c))
23734887Schin 		{
23744887Schin 			save_v(vp);
23754887Schin 			inmacro++;
23764887Schin 			return(GOOD);
23774887Schin 		}
23784887Schin 		ed_ringbell();
23794887Schin 		return(BAD);
23804887Schin 
23814887Schin #endif	/* KSHELL */
23824887Schin 	case '_':		/** append last argument of prev command **/
23834887Schin 		save_v(vp);
23844887Schin 		{
23854887Schin 			genchar tmpbuf[MAXLINE];
23864887Schin 			if(vp->repeat_set==0)
23874887Schin 				vp->repeat = -1;
23884887Schin 			p = (genchar*)hist_word((char*)tmpbuf,MAXLINE,vp->repeat);
23894887Schin 			if(p==0)
23904887Schin 			{
23914887Schin 				ed_ringbell();
23924887Schin 				break;
23934887Schin 			}
23944887Schin #if SHOPT_MULTIBYTE
23954887Schin 			ed_internal((char*)p,tmpbuf);
23964887Schin 			p = tmpbuf;
23974887Schin #endif /* SHOPT_MULTIBYTE */
23984887Schin 			i = ' ';
23994887Schin 			do
24004887Schin 			{
24014887Schin 				append(vp,i,APPEND);
24024887Schin 			}
24034887Schin 			while(i = *p++);
24044887Schin 			return(APPEND);
24054887Schin 		}
24064887Schin 
24074887Schin 	case 'A':		/** append to end of line **/
24084887Schin 		cur_virt = last_virt;
24094887Schin 		sync_cursor(vp);
24104887Schin 
24114887Schin 	case 'a':		/** append **/
24124887Schin 		if( fold(mode) == 'A' )
24134887Schin 		{
24144887Schin 			c = 'p';
24154887Schin 			goto addin;
24164887Schin 		}
24174887Schin 		save_v(vp);
24184887Schin 		if( cur_virt != INVALID )
24194887Schin 		{
24204887Schin 			first_virt = cur_virt + 1;
24214887Schin 			cursor(vp,cur_phys + 1);
24224887Schin 			ed_flush(vp->ed);
24234887Schin 		}
24244887Schin 		return(APPEND);
24254887Schin 
24264887Schin 	case 'I':		/** insert at beginning of line **/
24274887Schin 		cur_virt = first_virt;
24284887Schin 		sync_cursor(vp);
24294887Schin 
24304887Schin 	case 'i':		/** insert **/
24314887Schin 		if( fold(mode) == 'I' )
24324887Schin 		{
24334887Schin 			c = 'P';
24344887Schin 			goto addin;
24354887Schin 		}
24364887Schin 		save_v(vp);
24374887Schin 		if( cur_virt != INVALID )
24384887Schin  		{
24394887Schin  			vp->o_v_char = virtual[cur_virt];
24404887Schin 			first_virt = cur_virt--;
24414887Schin   		}
24424887Schin 		return(INSERT);
24434887Schin 
24444887Schin 	case 'C':		/** change to eol **/
24454887Schin 		c = '$';
24464887Schin 		goto chgeol;
24474887Schin 
24484887Schin 	case 'c':		/** change **/
24494887Schin 		if( mode )
24504887Schin 			c = vp->lastmotion;
24514887Schin 		else
24524887Schin 			c = getcount(vp,ed_getchar(vp->ed,-1));
24534887Schin chgeol:
24544887Schin 		vp->lastmotion = c;
24554887Schin 		if( c == 'c' )
24564887Schin 		{
24574887Schin 			del_line(vp,GOOD);
24584887Schin 			return(APPEND);
24594887Schin 		}
24604887Schin 
24614887Schin 		if(!delmotion(vp, c, 'c'))
24624887Schin 			return(BAD);
24634887Schin 
24644887Schin 		if( mode == 'c' )
24654887Schin 		{
24664887Schin 			c = 'p';
24674887Schin 			trepeat = 1;
24684887Schin 			goto addin;
24694887Schin 		}
24704887Schin 		first_virt = cur_virt + 1;
24714887Schin 		return(APPEND);
24724887Schin 
24734887Schin 	case 'D':		/** delete to eol **/
24744887Schin 		c = '$';
24754887Schin 		goto deleol;
24764887Schin 
24774887Schin 	case 'd':		/** delete **/
24784887Schin 		if( mode )
24794887Schin 			c = vp->lastmotion;
24804887Schin 		else
24814887Schin 			c = getcount(vp,ed_getchar(vp->ed,-1));
24824887Schin deleol:
24834887Schin 		vp->lastmotion = c;
24844887Schin 		if( c == 'd' )
24854887Schin 		{
24864887Schin 			del_line(vp,GOOD);
24874887Schin 			break;
24884887Schin 		}
24894887Schin 		if(!delmotion(vp, c, 'd'))
24904887Schin 			return(BAD);
24914887Schin 		if( cur_virt < last_virt )
24924887Schin 			++cur_virt;
24934887Schin 		break;
24944887Schin 
24954887Schin 	case 'P':
24964887Schin 		if( p[0] == '\0' )
24974887Schin 			return(BAD);
24984887Schin 		if( cur_virt != INVALID )
24994887Schin 		{
25004887Schin 			i = virtual[cur_virt];
25014887Schin 			if(!is_print(i))
25024887Schin 				vp->ocur_virt = INVALID;
25034887Schin 			--cur_virt;
25044887Schin 		}
25054887Schin 
25064887Schin 	case 'p':		/** print **/
25074887Schin 		if( p[0] == '\0' )
25084887Schin 			return(BAD);
25094887Schin 
25104887Schin 		if( mode != 's' && mode != 'c' )
25114887Schin 		{
25124887Schin 			save_v(vp);
25134887Schin 			if( c == 'P' )
25144887Schin 			{
25154887Schin 				/*** fix stored cur_virt ***/
25164887Schin 				++vp->u_column;
25174887Schin 			}
25184887Schin 		}
25194887Schin 		if( mode == 'R' )
25204887Schin 			mode = REPLACE;
25214887Schin 		else
25224887Schin 			mode = APPEND;
25234887Schin 		savep = p;
25244887Schin 		for(i=0; i<trepeat; ++i)
25254887Schin 		{
25264887Schin 			while(c= *p++)
25274887Schin 				append(vp,c,mode);
25284887Schin 			p = savep;
25294887Schin 		}
25304887Schin 		break;
25314887Schin 
25324887Schin 	case 'R':		/* Replace many chars **/
25334887Schin 		if( mode == 'R' )
25344887Schin 		{
25354887Schin 			c = 'P';
25364887Schin 			goto addin;
25374887Schin 		}
25384887Schin 		save_v(vp);
25394887Schin 		if( cur_virt != INVALID )
25404887Schin 			first_virt = cur_virt;
25414887Schin 		return(REPLACE);
25424887Schin 
25434887Schin 	case 'r':		/** replace **/
25444887Schin 		if( mode )
25454887Schin 			c = *p;
25464887Schin 		else
25474887Schin 			if((c=getrchar(vp))==ESC)
25484887Schin 				return(GOOD);
25494887Schin 		*p = c;
25504887Schin 		save_v(vp);
25514887Schin 		while(trepeat--)
25524887Schin 			replace(vp,c, trepeat!=0);
25534887Schin 		return(GOOD);
25544887Schin 
25554887Schin 	case 'S':		/** Substitute line - cc **/
25564887Schin 		c = 'c';
25574887Schin 		goto chgeol;
25584887Schin 
25594887Schin 	case 's':		/** substitute **/
25604887Schin 		save_v(vp);
25614887Schin 		cdelete(vp,vp->repeat, BAD);
25624887Schin 		if( mode )
25634887Schin 		{
25644887Schin 			c = 'p';
25654887Schin 			trepeat = 1;
25664887Schin 			goto addin;
25674887Schin 		}
25684887Schin 		first_virt = cur_virt + 1;
25694887Schin 		return(APPEND);
25704887Schin 
25714887Schin 	case 'Y':		/** Yank to end of line **/
25724887Schin 		c = '$';
25734887Schin 		goto yankeol;
25744887Schin 
25754887Schin 	case 'y':		/** yank thru motion **/
25764887Schin 		if( mode )
25774887Schin 			c = vp->lastmotion;
25784887Schin 		else
25794887Schin 			c = getcount(vp,ed_getchar(vp->ed,-1));
25804887Schin yankeol:
25814887Schin 		vp->lastmotion = c;
25824887Schin 		if( c == 'y' )
25834887Schin 		{
25844887Schin 			gencpy(yankbuf, virtual);
25854887Schin 		}
25864887Schin 		else if(!delmotion(vp, c, 'y'))
25874887Schin 		{
25884887Schin 			return(BAD);
25894887Schin 		}
25904887Schin 		break;
25914887Schin 
25924887Schin 	case 'x':		/** delete repeat chars forward - dl **/
25934887Schin 		c = 'l';
25944887Schin 		goto deleol;
25954887Schin 
25964887Schin 	case 'X':		/** delete repeat chars backward - dh **/
25974887Schin 		c = 'h';
25984887Schin 		goto deleol;
25994887Schin 
26004887Schin 	case '~':		/** invert case and advance **/
26014887Schin 		if( cur_virt != INVALID )
26024887Schin 		{
26034887Schin 			save_v(vp);
26044887Schin 			i = INVALID;
26054887Schin 			while(trepeat-->0 && i!=cur_virt)
26064887Schin 			{
26074887Schin 				i = cur_virt;
26084887Schin 				c = virtual[cur_virt];
26094887Schin #if SHOPT_MULTIBYTE
26104887Schin 				if((c&~STRIP)==0)
26114887Schin #endif /* SHOPT_MULTIBYTE */
26124887Schin 				if( isupper(c) )
26134887Schin 					c = tolower(c);
26144887Schin 				else if( islower(c) )
26154887Schin 					c = toupper(c);
26164887Schin 				replace(vp,c, 1);
26174887Schin 			}
26184887Schin 			return(GOOD);
26194887Schin 		}
26204887Schin 		else
26214887Schin 			return(BAD);
26224887Schin 
26234887Schin 	default:
26244887Schin 		return(BAD);
26254887Schin 	}
26264887Schin 	refresh(vp,CONTROL);
26274887Schin 	return(GOOD);
26284887Schin }
26294887Schin 
26304887Schin 
26314887Schin #if SHOPT_MULTIBYTE
_isalph(register int v)26324887Schin     static int _isalph(register int v)
26334887Schin     {
26344887Schin #ifdef _lib_iswalnum
26354887Schin 	return(iswalnum(v) || v=='_');
26364887Schin #else
26374887Schin 	return((v&~STRIP) || isalnum(v) || v=='_');
26384887Schin #endif
26394887Schin     }
26404887Schin 
26414887Schin 
_isblank(register int v)26424887Schin     static int _isblank(register int v)
26434887Schin     {
26444887Schin 	return((v&~STRIP)==0 && isspace(v));
26454887Schin     }
26464887Schin 
_ismetach(register int v)26474887Schin     static int _ismetach(register int v)
26484887Schin     {
26494887Schin 	return((v&~STRIP)==0 && ismeta(v));
26504887Schin     }
26514887Schin 
26524887Schin #endif	/* SHOPT_MULTIBYTE */
26534887Schin 
26544887Schin /*
26554887Schin  * get a character, after ^V processing
26564887Schin  */
getrchar(register Vi_t * vp)26574887Schin static int getrchar(register Vi_t *vp)
26584887Schin {
26594887Schin 	register int c;
26604887Schin 	if((c=ed_getchar(vp->ed,1))== usrlnext)
26614887Schin 		c = ed_getchar(vp->ed,2);
26624887Schin 	return(c);
26634887Schin }
2664