xref: /onnv-gate/usr/src/lib/libshell/common/edit/edit.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 /*
224887Schin  *  edit.c - common routines for vi and emacs one line editors in shell
234887Schin  *
244887Schin  *   David Korn				P.D. Sullivan
254887Schin  *   AT&T Labs
264887Schin  *
274887Schin  *   Coded April 1983.
284887Schin  */
294887Schin 
304887Schin #include	<ast.h>
314887Schin #include	<errno.h>
324887Schin #include	<ccode.h>
334887Schin #include	"FEATURE/options"
344887Schin #include	"FEATURE/time"
354887Schin #include	"FEATURE/cmds"
364887Schin #ifdef _hdr_utime
374887Schin #   include	<utime.h>
384887Schin #   include	<ls.h>
394887Schin #endif
404887Schin 
414887Schin #if KSHELL
424887Schin #   include	"defs.h"
434887Schin #   include	"variables.h"
444887Schin #else
4510898Sroland.mainz@nrubsig.org #   include	<ctype.h>
464887Schin     extern char ed_errbuf[];
474887Schin     char e_version[] = "\n@(#)$Id: Editlib version 1993-12-28 r $\0\n";
484887Schin #endif	/* KSHELL */
494887Schin #include	"io.h"
504887Schin #include	"terminal.h"
514887Schin #include	"history.h"
524887Schin #include	"edit.h"
534887Schin 
544887Schin static char CURSOR_UP[20] = { ESC, '[', 'A', 0 };
554887Schin 
568462SApril.Chin@Sun.COM 
578462SApril.Chin@Sun.COM 
584887Schin #if SHOPT_MULTIBYTE
594887Schin #   define is_cntrl(c)	((c<=STRIP) && iscntrl(c))
604887Schin #   define is_print(c)	((c&~STRIP) || isprint(c))
614887Schin #else
624887Schin #   define is_cntrl(c)	iscntrl(c)
634887Schin #   define is_print(c)	isprint(c)
644887Schin #endif
654887Schin 
664887Schin #if	(CC_NATIVE == CC_ASCII)
674887Schin #   define printchar(c)	((c) ^ ('A'-cntl('A')))
684887Schin #else
printchar(int c)694887Schin     static int printchar(int c)
704887Schin     {
714887Schin 	switch(c)
724887Schin 	{
734887Schin 
744887Schin 	    case cntl('A'): return('A');
754887Schin 	    case cntl('B'): return('B');
764887Schin 	    case cntl('C'): return('C');
774887Schin 	    case cntl('D'): return('D');
784887Schin 	    case cntl('E'): return('E');
794887Schin 	    case cntl('F'): return('F');
804887Schin 	    case cntl('G'): return('G');
814887Schin 	    case cntl('H'): return('H');
824887Schin 	    case cntl('I'): return('I');
834887Schin 	    case cntl('J'): return('J');
844887Schin 	    case cntl('K'): return('K');
854887Schin 	    case cntl('L'): return('L');
864887Schin 	    case cntl('M'): return('M');
874887Schin 	    case cntl('N'): return('N');
884887Schin 	    case cntl('O'): return('O');
894887Schin 	    case cntl('P'): return('P');
904887Schin 	    case cntl('Q'): return('Q');
914887Schin 	    case cntl('R'): return('R');
924887Schin 	    case cntl('S'): return('S');
934887Schin 	    case cntl('T'): return('T');
944887Schin 	    case cntl('U'): return('U');
954887Schin 	    case cntl('V'): return('V');
964887Schin 	    case cntl('W'): return('W');
974887Schin 	    case cntl('X'): return('X');
984887Schin 	    case cntl('Y'): return('Y');
994887Schin 	    case cntl('Z'): return('Z');
1004887Schin 	    case cntl(']'): return(']');
1014887Schin 	    case cntl('['): return('[');
1024887Schin 	}
1034887Schin 	return('?');
1044887Schin     }
1054887Schin #endif
1064887Schin #define MINWINDOW	15	/* minimum width window */
1074887Schin #define DFLTWINDOW	80	/* default window width */
1084887Schin #define RAWMODE		1
1094887Schin #define ALTMODE		2
1104887Schin #define ECHOMODE	3
1114887Schin #define	SYSERR	-1
1124887Schin 
1134887Schin #if SHOPT_OLDTERMIO
1144887Schin #   undef tcgetattr
1154887Schin #   undef tcsetattr
1164887Schin #endif /* SHOPT_OLDTERMIO */
1174887Schin 
1184887Schin #ifdef RT
1194887Schin #   define VENIX 1
1204887Schin #endif	/* RT */
1214887Schin 
1224887Schin 
1234887Schin #ifdef _hdr_sgtty
1244887Schin #   ifdef TIOCGETP
1254887Schin 	static int l_mask;
1264887Schin 	static struct tchars l_ttychars;
1274887Schin 	static struct ltchars l_chars;
1284887Schin 	static  char  l_changed;	/* set if mode bits changed */
1294887Schin #	define L_CHARS	4
1304887Schin #	define T_CHARS	2
1314887Schin #	define L_MASK	1
1324887Schin #   endif /* TIOCGETP */
1334887Schin #endif /* _hdr_sgtty */
1344887Schin 
1354887Schin #if KSHELL
1364887Schin      static int keytrap(Edit_t *,char*, int, int, int);
1374887Schin #else
1384887Schin      Edit_t editb;
1394887Schin #endif	/* KSHELL */
1404887Schin 
1414887Schin 
1424887Schin #ifndef _POSIX_DISABLE
1434887Schin #   define _POSIX_DISABLE	0
1444887Schin #endif
1454887Schin 
1464887Schin #ifdef future
1474887Schin     static int compare(const char*, const char*, int);
1484887Schin #endif  /* future */
1494887Schin #if SHOPT_VSH || SHOPT_ESH
1504887Schin #   define ttyparm	(ep->e_ttyparm)
1514887Schin #   define nttyparm	(ep->e_nttyparm)
1524887Schin     static const char bellchr[] = "\a";	/* bell char */
1534887Schin #endif /* SHOPT_VSH || SHOPT_ESH */
1544887Schin 
1554887Schin 
1564887Schin /*
1574887Schin  * This routine returns true if fd refers to a terminal
1584887Schin  * This should be equivalent to isatty
1594887Schin  */
tty_check(int fd)1604887Schin int tty_check(int fd)
1614887Schin {
1624887Schin 	register Edit_t *ep = (Edit_t*)(sh_getinterp()->ed_context);
1634887Schin 	struct termios tty;
1644887Schin 	ep->e_savefd = -1;
1654887Schin 	return(tty_get(fd,&tty)==0);
1664887Schin }
1674887Schin 
1684887Schin /*
1694887Schin  * Get the current terminal attributes
1704887Schin  * This routine remembers the attributes and just returns them if it
1714887Schin  *   is called again without an intervening tty_set()
1724887Schin  */
1734887Schin 
tty_get(register int fd,register struct termios * tty)1744887Schin int tty_get(register int fd, register struct termios *tty)
1754887Schin {
1764887Schin 	register Edit_t *ep = (Edit_t*)(sh_getinterp()->ed_context);
1774887Schin 	if(fd == ep->e_savefd)
1784887Schin 		*tty = ep->e_savetty;
1794887Schin 	else
1804887Schin 	{
1814887Schin 		while(tcgetattr(fd,tty) == SYSERR)
1824887Schin 		{
1834887Schin 			if(errno !=EINTR)
1844887Schin 				return(SYSERR);
1854887Schin 			errno = 0;
1864887Schin 		}
1874887Schin 		/* save terminal settings if in cannonical state */
1884887Schin 		if(ep->e_raw==0)
1894887Schin 		{
1904887Schin 			ep->e_savetty = *tty;
1914887Schin 			ep->e_savefd = fd;
1924887Schin 		}
1934887Schin 	}
1944887Schin 	return(0);
1954887Schin }
1964887Schin 
1974887Schin /*
1984887Schin  * Set the terminal attributes
1994887Schin  * If fd<0, then current attributes are invalidated
2004887Schin  */
2014887Schin 
tty_set(int fd,int action,struct termios * tty)2024887Schin int tty_set(int fd, int action, struct termios *tty)
2034887Schin {
2044887Schin 	register Edit_t *ep = (Edit_t*)(sh_getinterp()->ed_context);
2054887Schin 	if(fd >=0)
2064887Schin 	{
2074887Schin #ifdef future
2084887Schin 		if(ep->e_savefd>=0 && compare(&ep->e_savetty,tty,sizeof(struct termios)))
2094887Schin 			return(0);
2104887Schin #endif
2114887Schin 		while(tcsetattr(fd, action, tty) == SYSERR)
2124887Schin 		{
2134887Schin 			if(errno !=EINTR)
2144887Schin 				return(SYSERR);
2154887Schin 			errno = 0;
2164887Schin 		}
2174887Schin 		ep->e_savetty = *tty;
2184887Schin 	}
2194887Schin 	ep->e_savefd = fd;
2204887Schin 	return(0);
2214887Schin }
2224887Schin 
2234887Schin #if SHOPT_ESH || SHOPT_VSH
2244887Schin /*{	TTY_COOKED( fd )
2254887Schin  *
2264887Schin  *	This routine will set the tty in cooked mode.
2274887Schin  *	It is also called by error.done().
2284887Schin  *
2294887Schin }*/
2304887Schin 
tty_cooked(register int fd)2314887Schin void tty_cooked(register int fd)
2324887Schin {
2334887Schin 	register Edit_t *ep = (Edit_t*)(sh_getinterp()->ed_context);
2344887Schin 	if(ep->e_raw==0)
2354887Schin 		return;
2364887Schin 	if(fd < 0)
2374887Schin 		fd = ep->e_savefd;
2384887Schin #ifdef L_MASK
2394887Schin 	/* restore flags */
2404887Schin 	if(l_changed&L_MASK)
2414887Schin 		ioctl(fd,TIOCLSET,&l_mask);
2424887Schin 	if(l_changed&T_CHARS)
2434887Schin 		/* restore alternate break character */
2444887Schin 		ioctl(fd,TIOCSETC,&l_ttychars);
2454887Schin 	if(l_changed&L_CHARS)
2464887Schin 		/* restore alternate break character */
2474887Schin 		ioctl(fd,TIOCSLTC,&l_chars);
2484887Schin 	l_changed = 0;
2494887Schin #endif	/* L_MASK */
2504887Schin 	/*** don't do tty_set unless ttyparm has valid data ***/
2514887Schin 	if(tty_set(fd, TCSANOW, &ttyparm) == SYSERR)
2524887Schin 		return;
2534887Schin 	ep->e_raw = 0;
2544887Schin 	return;
2554887Schin }
2564887Schin 
2574887Schin /*{	TTY_RAW( fd )
2584887Schin  *
2594887Schin  *	This routine will set the tty in raw mode.
2604887Schin  *
2614887Schin }*/
2624887Schin 
tty_raw(register int fd,int echomode)2634887Schin int tty_raw(register int fd, int echomode)
2644887Schin {
2654887Schin 	int echo = echomode;
2664887Schin #ifdef L_MASK
2674887Schin 	struct ltchars lchars;
2684887Schin #endif	/* L_MASK */
2694887Schin 	register Edit_t *ep = (Edit_t*)(sh_getinterp()->ed_context);
2704887Schin 	if(ep->e_raw==RAWMODE)
2714887Schin 		return(echo?-1:0);
2724887Schin 	else if(ep->e_raw==ECHOMODE)
2734887Schin 		return(echo?0:-1);
2744887Schin #if !SHOPT_RAWONLY
2754887Schin 	if(ep->e_raw != ALTMODE)
2764887Schin #endif /* SHOPT_RAWONLY */
2774887Schin 	{
2784887Schin 		if(tty_get(fd,&ttyparm) == SYSERR)
2794887Schin 			return(-1);
2804887Schin 	}
2814887Schin #if  L_MASK || VENIX
2824887Schin 	if(ttyparm.sg_flags&LCASE)
2834887Schin 		return(-1);
2844887Schin 	if(!(ttyparm.sg_flags&ECHO))
2854887Schin 	{
2864887Schin 		if(!echomode)
2874887Schin 			return(-1);
2884887Schin 		echo = 0;
2894887Schin 	}
2904887Schin 	nttyparm = ttyparm;
2914887Schin 	if(!echo)
2924887Schin 		nttyparm.sg_flags &= ~(ECHO | TBDELAY);
2934887Schin #   ifdef CBREAK
2944887Schin 	nttyparm.sg_flags |= CBREAK;
2954887Schin #   else
2964887Schin 	nttyparm.sg_flags |= RAW;
2974887Schin #   endif /* CBREAK */
2984887Schin 	ep->e_erase = ttyparm.sg_erase;
2994887Schin 	ep->e_kill = ttyparm.sg_kill;
3004887Schin 	ep->e_eof = cntl('D');
3014887Schin 	ep->e_werase = cntl('W');
3024887Schin 	ep->e_lnext = cntl('V');
3034887Schin 	if( tty_set(fd, TCSADRAIN, &nttyparm) == SYSERR )
3044887Schin 		return(-1);
3054887Schin 	ep->e_ttyspeed = (ttyparm.sg_ospeed>=B1200?FAST:SLOW);
3064887Schin #   ifdef TIOCGLTC
3074887Schin 	/* try to remove effect of ^V  and ^Y and ^O */
3084887Schin 	if(ioctl(fd,TIOCGLTC,&l_chars) != SYSERR)
3094887Schin 	{
3104887Schin 		lchars = l_chars;
3114887Schin 		lchars.t_lnextc = -1;
3124887Schin 		lchars.t_flushc = -1;
3134887Schin 		lchars.t_dsuspc = -1;	/* no delayed stop process signal */
3144887Schin 		if(ioctl(fd,TIOCSLTC,&lchars) != SYSERR)
3154887Schin 			l_changed |= L_CHARS;
3164887Schin 	}
3174887Schin #   endif	/* TIOCGLTC */
3184887Schin #else
3194887Schin 	if (!(ttyparm.c_lflag & ECHO ))
3204887Schin 	{
3214887Schin 		if(!echomode)
3224887Schin 			return(-1);
3234887Schin 		echo = 0;
3244887Schin 	}
3254887Schin #   ifdef FLUSHO
3264887Schin 	ttyparm.c_lflag &= ~FLUSHO;
3274887Schin #   endif /* FLUSHO */
3284887Schin 	nttyparm = ttyparm;
3294887Schin #  ifndef u370
3304887Schin 	nttyparm.c_iflag &= ~(IGNPAR|PARMRK|INLCR|IGNCR|ICRNL);
3314887Schin 	nttyparm.c_iflag |= BRKINT;
3324887Schin #   else
3334887Schin 	nttyparm.c_iflag &=
3344887Schin 			~(IGNBRK|PARMRK|INLCR|IGNCR|ICRNL|INPCK);
3354887Schin 	nttyparm.c_iflag |= (BRKINT|IGNPAR);
3364887Schin #   endif	/* u370 */
3374887Schin 	if(echo)
3384887Schin 		nttyparm.c_lflag &= ~ICANON;
3394887Schin 	else
3404887Schin 		nttyparm.c_lflag &= ~(ICANON|ECHO|ECHOK);
3414887Schin 	nttyparm.c_cc[VTIME] = 0;
3424887Schin 	nttyparm.c_cc[VMIN] = 1;
3434887Schin #   ifdef VREPRINT
3444887Schin 	nttyparm.c_cc[VREPRINT] = _POSIX_DISABLE;
3454887Schin #   endif /* VREPRINT */
3464887Schin #   ifdef VDISCARD
3474887Schin 	nttyparm.c_cc[VDISCARD] = _POSIX_DISABLE;
3484887Schin #   endif /* VDISCARD */
3494887Schin #   ifdef VDSUSP
3504887Schin 	nttyparm.c_cc[VDSUSP] = _POSIX_DISABLE;
3514887Schin #   endif /* VDSUSP */
3524887Schin #   ifdef VWERASE
3534887Schin 	if(ttyparm.c_cc[VWERASE] == _POSIX_DISABLE)
3544887Schin 		ep->e_werase = cntl('W');
3554887Schin 	else
3564887Schin 		ep->e_werase = nttyparm.c_cc[VWERASE];
3574887Schin 	nttyparm.c_cc[VWERASE] = _POSIX_DISABLE;
3584887Schin #   else
3594887Schin 	    ep->e_werase = cntl('W');
3604887Schin #   endif /* VWERASE */
3614887Schin #   ifdef VLNEXT
3624887Schin 	if(ttyparm.c_cc[VLNEXT] == _POSIX_DISABLE )
3634887Schin 		ep->e_lnext = cntl('V');
3644887Schin 	else
3654887Schin 		ep->e_lnext = nttyparm.c_cc[VLNEXT];
3664887Schin 	nttyparm.c_cc[VLNEXT] = _POSIX_DISABLE;
3674887Schin #   else
3684887Schin 	ep->e_lnext = cntl('V');
3694887Schin #   endif /* VLNEXT */
3704887Schin 	ep->e_eof = ttyparm.c_cc[VEOF];
3714887Schin 	ep->e_erase = ttyparm.c_cc[VERASE];
3724887Schin 	ep->e_kill = ttyparm.c_cc[VKILL];
3734887Schin 	if( tty_set(fd, TCSADRAIN, &nttyparm) == SYSERR )
3744887Schin 		return(-1);
3754887Schin 	ep->e_ttyspeed = (cfgetospeed(&ttyparm)>=B1200?FAST:SLOW);
3764887Schin #endif
3774887Schin 	ep->e_raw = (echomode?ECHOMODE:RAWMODE);
3784887Schin 	return(0);
3794887Schin }
3804887Schin 
3814887Schin #if !SHOPT_RAWONLY
3824887Schin 
3834887Schin /*
3844887Schin  *
3854887Schin  *	Get tty parameters and make ESC and '\r' wakeup characters.
3864887Schin  *
3874887Schin  */
3884887Schin 
3894887Schin #   ifdef TIOCGETC
tty_alt(register int fd)3904887Schin int tty_alt(register int fd)
3914887Schin {
3924887Schin 	register Edit_t *ep = (Edit_t*)(sh_getinterp()->ed_context);
3934887Schin 	int mask;
3944887Schin 	struct tchars ttychars;
3954887Schin 	switch(ep->e_raw)
3964887Schin 	{
3974887Schin 	    case ECHOMODE:
3984887Schin 		return(-1);
3994887Schin 	    case ALTMODE:
4004887Schin 		return(0);
4014887Schin 	    case RAWMODE:
4024887Schin 		tty_cooked(fd);
4034887Schin 	}
4044887Schin 	l_changed = 0;
4054887Schin 	if( ep->e_ttyspeed == 0)
4064887Schin 	{
4074887Schin 		if((tty_get(fd,&ttyparm) != SYSERR))
4084887Schin 			ep->e_ttyspeed = (ttyparm.sg_ospeed>=B1200?FAST:SLOW);
4094887Schin 		ep->e_raw = ALTMODE;
4104887Schin 	}
4114887Schin 	if(ioctl(fd,TIOCGETC,&l_ttychars) == SYSERR)
4124887Schin 		return(-1);
4134887Schin 	if(ioctl(fd,TIOCLGET,&l_mask)==SYSERR)
4144887Schin 		return(-1);
4154887Schin 	ttychars = l_ttychars;
4164887Schin 	mask =  LCRTBS|LCRTERA|LCTLECH|LPENDIN|LCRTKIL;
4174887Schin 	if((l_mask|mask) != l_mask)
4184887Schin 		l_changed = L_MASK;
4194887Schin 	if(ioctl(fd,TIOCLBIS,&mask)==SYSERR)
4204887Schin 		return(-1);
4214887Schin 	if(ttychars.t_brkc!=ESC)
4224887Schin 	{
4234887Schin 		ttychars.t_brkc = ESC;
4244887Schin 		l_changed |= T_CHARS;
4254887Schin 		if(ioctl(fd,TIOCSETC,&ttychars) == SYSERR)
4264887Schin 			return(-1);
4274887Schin 	}
4284887Schin 	return(0);
4294887Schin }
4304887Schin #   else
4314887Schin #	ifndef PENDIN
4324887Schin #	    define PENDIN	0
4334887Schin #	endif /* PENDIN */
4344887Schin #	ifndef IEXTEN
4354887Schin #	    define IEXTEN	0
4364887Schin #	endif /* IEXTEN */
4374887Schin 
tty_alt(register int fd)4384887Schin int tty_alt(register int fd)
4394887Schin {
4404887Schin 	register Edit_t *ep = (Edit_t*)(sh_getinterp()->ed_context);
4414887Schin 	switch(ep->e_raw)
4424887Schin 	{
4434887Schin 	    case ECHOMODE:
4444887Schin 		return(-1);
4454887Schin 	    case ALTMODE:
4464887Schin 		return(0);
4474887Schin 	    case RAWMODE:
4484887Schin 		tty_cooked(fd);
4494887Schin 	}
4504887Schin 	if((tty_get(fd, &ttyparm)==SYSERR) || (!(ttyparm.c_lflag&ECHO)))
4514887Schin 		return(-1);
4524887Schin #	ifdef FLUSHO
4534887Schin 	    ttyparm.c_lflag &= ~FLUSHO;
4544887Schin #	endif /* FLUSHO */
4554887Schin 	nttyparm = ttyparm;
4564887Schin 	ep->e_eof = ttyparm.c_cc[VEOF];
4574887Schin #	ifdef ECHOCTL
4584887Schin 	    /* escape character echos as ^[ */
4594887Schin 	    nttyparm.c_lflag |= (ECHOE|ECHOK|ECHOCTL|PENDIN|IEXTEN);
4604887Schin 	    nttyparm.c_cc[VEOL] = ESC;
4614887Schin #	else
4624887Schin 	    /* switch VEOL2 and EOF, since EOF isn't echo'd by driver */
4634887Schin 	    nttyparm.c_lflag |= (ECHOE|ECHOK);
4644887Schin 	    nttyparm.c_cc[VEOF] = ESC;	/* make ESC the eof char */
4654887Schin #	    ifdef VEOL2
4664887Schin 		nttyparm.c_iflag &= ~(IGNCR|ICRNL);
4674887Schin 		nttyparm.c_iflag |= INLCR;
4684887Schin 		nttyparm.c_cc[VEOL] = '\r';	/* make CR an eol char */
4694887Schin 		nttyparm.c_cc[VEOL2] = ep->e_eof; /* make EOF an eol char */
4704887Schin #	    else
4714887Schin 		nttyparm.c_cc[VEOL] = ep->e_eof; /* make EOF an eol char */
4724887Schin #	    endif /* VEOL2 */
4734887Schin #	endif /* ECHOCTL */
4744887Schin #	ifdef VREPRINT
4754887Schin 		nttyparm.c_cc[VREPRINT] = _POSIX_DISABLE;
4764887Schin #	endif /* VREPRINT */
4774887Schin #	ifdef VDISCARD
4784887Schin 		nttyparm.c_cc[VDISCARD] = _POSIX_DISABLE;
4794887Schin #	endif /* VDISCARD */
4804887Schin #	ifdef VWERASE
4814887Schin 	    if(ttyparm.c_cc[VWERASE] == _POSIX_DISABLE)
4824887Schin 		    nttyparm.c_cc[VWERASE] = cntl('W');
4834887Schin 	    ep->e_werase = nttyparm.c_cc[VWERASE];
4844887Schin #	else
4854887Schin 	    ep->e_werase = cntl('W');
4864887Schin #	endif /* VWERASE */
4874887Schin #	ifdef VLNEXT
4884887Schin 	    if(ttyparm.c_cc[VLNEXT] == _POSIX_DISABLE )
4894887Schin 		    nttyparm.c_cc[VLNEXT] = cntl('V');
4904887Schin 	    ep->e_lnext = nttyparm.c_cc[VLNEXT];
4914887Schin #	else
4924887Schin 	    ep->e_lnext = cntl('V');
4934887Schin #	endif /* VLNEXT */
4944887Schin 	ep->e_erase = ttyparm.c_cc[VERASE];
4954887Schin 	ep->e_kill = ttyparm.c_cc[VKILL];
4964887Schin 	if( tty_set(fd, TCSADRAIN, &nttyparm) == SYSERR )
4974887Schin 		return(-1);
4984887Schin 	ep->e_ttyspeed = (cfgetospeed(&ttyparm)>=B1200?FAST:SLOW);
4994887Schin 	ep->e_raw = ALTMODE;
5004887Schin 	return(0);
5014887Schin }
5024887Schin 
5034887Schin #   endif /* TIOCGETC */
5044887Schin #endif	/* SHOPT_RAWONLY */
5054887Schin 
5064887Schin /*
5074887Schin  *	ED_WINDOW()
5084887Schin  *
5094887Schin  *	return the window size
5104887Schin  */
ed_window(void)5114887Schin int ed_window(void)
5124887Schin {
5134887Schin 	int	rows,cols;
5144887Schin 	register char *cp = nv_getval(COLUMNS);
5154887Schin 	if(cp)
5164887Schin 		cols = (int)strtol(cp, (char**)0, 10)-1;
5174887Schin 	else
5184887Schin 	{
5194887Schin 		astwinsize(2,&rows,&cols);
5204887Schin 		if(--cols <0)
5214887Schin 			cols = DFLTWINDOW-1;
5224887Schin 	}
5234887Schin 	if(cols < MINWINDOW)
5244887Schin 		cols = MINWINDOW;
5254887Schin 	else if(cols > MAXWINDOW)
5264887Schin 		cols = MAXWINDOW;
5274887Schin 	return(cols);
5284887Schin }
5294887Schin 
5304887Schin /*	E_FLUSH()
5314887Schin  *
5324887Schin  *	Flush the output buffer.
5334887Schin  *
5344887Schin  */
5354887Schin 
ed_flush(Edit_t * ep)5364887Schin void ed_flush(Edit_t *ep)
5374887Schin {
5384887Schin 	register int n = ep->e_outptr-ep->e_outbase;
5394887Schin 	register int fd = ERRIO;
5404887Schin 	if(n<=0)
5414887Schin 		return;
5424887Schin 	write(fd,ep->e_outbase,(unsigned)n);
5434887Schin 	ep->e_outptr = ep->e_outbase;
5444887Schin }
5454887Schin 
5464887Schin /*
5474887Schin  * send the bell character ^G to the terminal
5484887Schin  */
5494887Schin 
ed_ringbell(void)5504887Schin void ed_ringbell(void)
5514887Schin {
5524887Schin 	write(ERRIO,bellchr,1);
5534887Schin }
5544887Schin 
5554887Schin /*
5564887Schin  * send a carriage return line feed to the terminal
5574887Schin  */
5584887Schin 
ed_crlf(register Edit_t * ep)5594887Schin void ed_crlf(register Edit_t *ep)
5604887Schin {
5614887Schin #ifdef cray
5624887Schin 	ed_putchar(ep,'\r');
5634887Schin #endif /* cray */
5644887Schin #ifdef u370
5654887Schin 	ed_putchar(ep,'\r');
5664887Schin #endif	/* u370 */
5674887Schin #ifdef VENIX
5684887Schin 	ed_putchar(ep,'\r');
5694887Schin #endif /* VENIX */
5704887Schin 	ed_putchar(ep,'\n');
5714887Schin 	ed_flush(ep);
5724887Schin }
5734887Schin 
5744887Schin /*	ED_SETUP( max_prompt_size )
5754887Schin  *
5764887Schin  *	This routine sets up the prompt string
5774887Schin  *	The following is an unadvertised feature.
5784887Schin  *	  Escape sequences in the prompt can be excluded from the calculated
5794887Schin  *	  prompt length.  This is accomplished as follows:
5804887Schin  *	  - if the prompt string starts with "%\r, or contains \r%\r", where %
5814887Schin  *	    represents any char, then % is taken to be the quote character.
5824887Schin  *	  - strings enclosed by this quote character, and the quote character,
5834887Schin  *	    are not counted as part of the prompt length.
5844887Schin  */
5854887Schin 
ed_setup(register Edit_t * ep,int fd,int reedit)5864887Schin void	ed_setup(register Edit_t *ep, int fd, int reedit)
5874887Schin {
5888462SApril.Chin@Sun.COM 	Shell_t *shp = ep->sh;
5894887Schin 	register char *pp;
5908462SApril.Chin@Sun.COM 	register char *last, *prev;
5914887Schin 	char *ppmax;
5924887Schin 	int myquote = 0, n;
5938462SApril.Chin@Sun.COM 	register int qlen = 1, qwid;
5944887Schin 	char inquote = 0;
5954887Schin 	ep->e_fd = fd;
5964887Schin 	ep->e_multiline = sh_isoption(SH_MULTILINE)!=0;
5974887Schin #ifdef SIGWINCH
5988462SApril.Chin@Sun.COM 	if(!(shp->sigflag[SIGWINCH]&SH_SIGFAULT))
5994887Schin 	{
6004887Schin 		signal(SIGWINCH,sh_fault);
6018462SApril.Chin@Sun.COM 		shp->sigflag[SIGWINCH] |= SH_SIGFAULT;
6024887Schin 	}
6038462SApril.Chin@Sun.COM 	pp = shp->st.trapcom[SIGWINCH];
6048462SApril.Chin@Sun.COM 	shp->st.trapcom[SIGWINCH] = 0;
6054887Schin 	sh_fault(SIGWINCH);
6068462SApril.Chin@Sun.COM 	shp->st.trapcom[SIGWINCH] = pp;
6078462SApril.Chin@Sun.COM 	ep->sh->winch = 0;
6084887Schin #endif
6094887Schin #if KSHELL
6104887Schin 	ep->e_stkptr = stakptr(0);
6114887Schin 	ep->e_stkoff = staktell();
6128462SApril.Chin@Sun.COM 	if(!(last = shp->prompt))
6134887Schin 		last = "";
6148462SApril.Chin@Sun.COM 	shp->prompt = 0;
6154887Schin #else
6164887Schin 	last = ep->e_prbuff;
6174887Schin #endif /* KSHELL */
6188462SApril.Chin@Sun.COM 	if(shp->hist_ptr)
6194887Schin 	{
6208462SApril.Chin@Sun.COM 		register History_t *hp = shp->hist_ptr;
6214887Schin 		ep->e_hismax = hist_max(hp);
6224887Schin 		ep->e_hismin = hist_min(hp);
6234887Schin 	}
6244887Schin 	else
6254887Schin 	{
6264887Schin 		ep->e_hismax = ep->e_hismin = ep->e_hloff = 0;
6274887Schin 	}
6284887Schin 	ep->e_hline = ep->e_hismax;
6294887Schin 	if(!sh_isoption(SH_VI) && !sh_isoption(SH_EMACS) && !sh_isoption(SH_GMACS))
6304887Schin 		ep->e_wsize = MAXLINE;
6314887Schin 	else
6324887Schin 		ep->e_wsize = ed_window()-2;
6334887Schin 	ep->e_winsz = ep->e_wsize+2;
6344887Schin 	ep->e_crlf = 1;
6354887Schin 	ep->e_plen = 0;
6364887Schin 	pp = ep->e_prompt;
6374887Schin 	ppmax = pp+PRSIZE-1;
6384887Schin 	*pp++ = '\r';
6394887Schin 	{
6404887Schin 		register int c;
6418462SApril.Chin@Sun.COM 		while(prev = last, c = mbchar(last)) switch(c)
6424887Schin 		{
6434887Schin 			case ESC:
6444887Schin 			{
6454887Schin 				int skip=0;
6464887Schin 				ep->e_crlf = 0;
6474887Schin 				*pp++ = c;
6484887Schin 				for(n=1; c = *last++; n++)
6494887Schin 				{
6504887Schin 					if(pp < ppmax)
6514887Schin 						*pp++ = c;
6528462SApril.Chin@Sun.COM 					if(c=='\a' || c==ESC || c=='\r')
6534887Schin 						break;
6544887Schin 					if(skip || (c>='0' && c<='9'))
6554887Schin 						continue;
6564887Schin 					if(n>1 && c==';')
6574887Schin 						skip = 1;
6584887Schin 					else if(n>2 || (c!= '[' &&  c!= ']'))
6594887Schin 						break;
6604887Schin 				}
6618462SApril.Chin@Sun.COM 				if(c==0 || c==ESC || c=='\r')
6628462SApril.Chin@Sun.COM 					last--;
6634887Schin 				qlen += (n+1);
6644887Schin 				break;
6654887Schin 			}
6664887Schin 			case '\b':
6674887Schin 				if(pp>ep->e_prompt+1)
6684887Schin 					pp--;
6694887Schin 				break;
6704887Schin 			case '\r':
6714887Schin 				if(pp == (ep->e_prompt+2)) /* quote char */
6724887Schin 					myquote = *(pp-1);
6734887Schin 				/*FALLTHROUGH*/
6744887Schin 
6754887Schin 			case '\n':
6764887Schin 				/* start again */
6774887Schin 				ep->e_crlf = 1;
6784887Schin 				qlen = 1;
6794887Schin 				inquote = 0;
6804887Schin 				pp = ep->e_prompt+1;
6814887Schin 				break;
6824887Schin 
6834887Schin 			case '\t':
6844887Schin 				/* expand tabs */
6854887Schin 				while((pp-ep->e_prompt)%TABSIZE)
6864887Schin 				{
6874887Schin 					if(pp >= ppmax)
6884887Schin 						break;
6894887Schin 					*pp++ = ' ';
6904887Schin 				}
6914887Schin 				break;
6924887Schin 
6934887Schin 			case '\a':
6944887Schin 				/* cut out bells */
6954887Schin 				break;
6964887Schin 
6974887Schin 			default:
6984887Schin 				if(c==myquote)
6994887Schin 				{
7004887Schin 					qlen += inquote;
7014887Schin 					inquote ^= 1;
7024887Schin 				}
7034887Schin 				if(pp < ppmax)
7044887Schin 				{
7058462SApril.Chin@Sun.COM 					if(inquote)
7068462SApril.Chin@Sun.COM 						qlen++;
7078462SApril.Chin@Sun.COM 					else if(!is_print(c))
7084887Schin 						ep->e_crlf = 0;
7098462SApril.Chin@Sun.COM 					if((qwid = last - prev) > 1)
7108462SApril.Chin@Sun.COM 						qlen += qwid - mbwidth(c);
7118462SApril.Chin@Sun.COM 					while(prev < last && pp < ppmax)
7128462SApril.Chin@Sun.COM 						*pp++ = *prev++;
7134887Schin 				}
7148462SApril.Chin@Sun.COM 				break;
7154887Schin 		}
7164887Schin 	}
7174887Schin 	if(pp-ep->e_prompt > qlen)
7184887Schin 		ep->e_plen = pp - ep->e_prompt - qlen;
7194887Schin 	*pp = 0;
7208462SApril.Chin@Sun.COM 	if(!ep->e_multiline && (ep->e_wsize -= ep->e_plen) < 7)
7214887Schin 	{
7224887Schin 		register int shift = 7-ep->e_wsize;
7234887Schin 		ep->e_wsize = 7;
7244887Schin 		pp = ep->e_prompt+1;
7254887Schin 		strcpy(pp,pp+shift);
7264887Schin 		ep->e_plen -= shift;
7274887Schin 		last[-ep->e_plen-2] = '\r';
7284887Schin 	}
7294887Schin 	sfsync(sfstderr);
7304887Schin 	if(fd == sffileno(sfstderr))
7314887Schin 	{
7324887Schin 		/* can't use output buffer when reading from stderr */
7334887Schin 		static char *buff;
7344887Schin 		if(!buff)
7354887Schin 			buff = (char*)malloc(MAXLINE);
7364887Schin 		ep->e_outbase = ep->e_outptr = buff;
7374887Schin 		ep->e_outlast = ep->e_outptr + MAXLINE;
7384887Schin 		return;
7394887Schin 	}
7404887Schin 	qlen = sfset(sfstderr,SF_READ,0);
7414887Schin 	/* make sure SF_READ not on */
7424887Schin 	ep->e_outbase = ep->e_outptr = (char*)sfreserve(sfstderr,SF_UNBOUND,SF_LOCKR);
7434887Schin 	ep->e_outlast = ep->e_outptr + sfvalue(sfstderr);
7444887Schin 	if(qlen)
7454887Schin 		sfset(sfstderr,SF_READ,1);
7464887Schin 	sfwrite(sfstderr,ep->e_outptr,0);
7474887Schin 	ep->e_eol = reedit;
7484887Schin 	if(ep->e_multiline)
7494887Schin 	{
7504887Schin #ifdef _cmd_tput
7514887Schin 		char *term;
7524887Schin 		if(!ep->e_term)
7538462SApril.Chin@Sun.COM 			ep->e_term = nv_search("TERM",shp->var_tree,0);
7544887Schin 		if(ep->e_term && (term=nv_getval(ep->e_term)) && strlen(term)<sizeof(ep->e_termname) && strcmp(term,ep->e_termname))
7554887Schin 		{
7564887Schin 			sh_trap(".sh.subscript=$(tput cuu1 2>/dev/null)",0);
7574887Schin 			if(pp=nv_getval(SH_SUBSCRNOD))
7584887Schin 				strncpy(CURSOR_UP,pp,sizeof(CURSOR_UP)-1);
7594887Schin 			nv_unset(SH_SUBSCRNOD);
7604887Schin 			strcpy(ep->e_termname,term);
7614887Schin 		}
7624887Schin #endif
7638462SApril.Chin@Sun.COM 		ep->e_wsize = MAXLINE - (ep->e_plen+1);
7644887Schin 	}
7654887Schin 	if(ep->e_default && (pp = nv_getval(ep->e_default)))
7664887Schin 	{
7674887Schin 		n = strlen(pp);
7684887Schin 		if(n > LOOKAHEAD)
7694887Schin 			n = LOOKAHEAD;
7704887Schin 		ep->e_lookahead = n;
7714887Schin 		while(n-- > 0)
7724887Schin 			ep->e_lbuf[n] = *pp++;
7734887Schin 		ep->e_default = 0;
7744887Schin 	}
7754887Schin }
7764887Schin 
ed_putstring(register Edit_t * ep,const char * str)7778462SApril.Chin@Sun.COM static void ed_putstring(register Edit_t *ep, const char *str)
7788462SApril.Chin@Sun.COM {
7798462SApril.Chin@Sun.COM 	register int c;
7808462SApril.Chin@Sun.COM 	while(c = *str++)
7818462SApril.Chin@Sun.COM 		ed_putchar(ep,c);
7828462SApril.Chin@Sun.COM }
7838462SApril.Chin@Sun.COM 
ed_nputchar(register Edit_t * ep,int n,int c)7848462SApril.Chin@Sun.COM static void ed_nputchar(register Edit_t *ep, int n, int c)
7858462SApril.Chin@Sun.COM {
7868462SApril.Chin@Sun.COM 	while(n-->0)
7878462SApril.Chin@Sun.COM 		ed_putchar(ep,c);
7888462SApril.Chin@Sun.COM }
7898462SApril.Chin@Sun.COM 
7904887Schin /*
7914887Schin  * Do read, restart on interrupt unless SH_SIGSET or SH_SIGTRAP is set
7924887Schin  * Use sfpkrd() to poll() or select() to wait for input if possible
7934887Schin  * Unfortunately, systems that get interrupted from slow reads update
7944887Schin  * this access time for for the terminal (in violation of POSIX).
7954887Schin  * The fixtime() macro, resets the time to the time at entry in
7964887Schin  * this case.  This is not necessary for systems that can handle
7974887Schin  * sfpkrd() correctly (i,e., those that support poll() or select()
7984887Schin  */
ed_read(void * context,int fd,char * buff,int size,int reedit)7994887Schin int ed_read(void *context, int fd, char *buff, int size, int reedit)
8004887Schin {
8014887Schin 	register Edit_t *ep = (Edit_t*)context;
8024887Schin 	register int rv= -1;
8034887Schin 	register int delim = (ep->e_raw==RAWMODE?'\r':'\n');
8048462SApril.Chin@Sun.COM 	Shell_t *shp = ep->sh;
8054887Schin 	int mode = -1;
8068462SApril.Chin@Sun.COM 	int (*waitevent)(int,long,int) = shp->waitevent;
8074887Schin 	if(ep->e_raw==ALTMODE)
8084887Schin 		mode = 1;
8094887Schin 	if(size < 0)
8104887Schin 	{
8114887Schin 		mode = 1;
8124887Schin 		size = -size;
8134887Schin 	}
8144887Schin 	sh_onstate(SH_TTYWAIT);
8154887Schin 	errno = EINTR;
8168462SApril.Chin@Sun.COM 	shp->waitevent = 0;
8174887Schin 	while(rv<0 && errno==EINTR)
8184887Schin 	{
8198462SApril.Chin@Sun.COM 		if(shp->trapnote&(SH_SIGSET|SH_SIGTRAP))
8204887Schin 			goto done;
82110898Sroland.mainz@nrubsig.org 		if(ep->sh->winch && sh_isstate(SH_INTERACTIVE) && (sh_isoption(SH_VI) || sh_isoption(SH_EMACS)))
8228462SApril.Chin@Sun.COM 		{
8238462SApril.Chin@Sun.COM 			Edpos_t	lastpos;
8248462SApril.Chin@Sun.COM 			int	n, rows, newsize;
8258462SApril.Chin@Sun.COM 			/* move cursor to start of first line */
8268462SApril.Chin@Sun.COM 			ed_putchar(ep,'\r');
8278462SApril.Chin@Sun.COM 			ed_flush(ep);
8288462SApril.Chin@Sun.COM 			astwinsize(2,&rows,&newsize);
8298462SApril.Chin@Sun.COM 			n = (ep->e_plen+ep->e_cur)/++ep->e_winsz;
8308462SApril.Chin@Sun.COM 			while(n--)
8318462SApril.Chin@Sun.COM 				ed_putstring(ep,CURSOR_UP);
8328462SApril.Chin@Sun.COM 			if(ep->e_multiline && newsize>ep->e_winsz && (lastpos.line=(ep->e_plen+ep->e_peol)/ep->e_winsz))
8338462SApril.Chin@Sun.COM 			{
8348462SApril.Chin@Sun.COM 				/* clear the current command line */
8358462SApril.Chin@Sun.COM 				n = lastpos.line;
8368462SApril.Chin@Sun.COM 				while(lastpos.line--)
8378462SApril.Chin@Sun.COM 				{
8388462SApril.Chin@Sun.COM 					ed_nputchar(ep,ep->e_winsz,' ');
8398462SApril.Chin@Sun.COM 					ed_putchar(ep,'\n');
8408462SApril.Chin@Sun.COM 				}
8418462SApril.Chin@Sun.COM 				ed_nputchar(ep,ep->e_winsz,' ');
8428462SApril.Chin@Sun.COM 				while(n--)
8438462SApril.Chin@Sun.COM 					ed_putstring(ep,CURSOR_UP);
8448462SApril.Chin@Sun.COM 			}
8458462SApril.Chin@Sun.COM 	                ep->sh->winch = 0;
8468462SApril.Chin@Sun.COM 			ed_flush(ep);
8478462SApril.Chin@Sun.COM 			sh_delay(.05);
8488462SApril.Chin@Sun.COM 			astwinsize(2,&rows,&newsize);
8498462SApril.Chin@Sun.COM 			ep->e_winsz = newsize-1;
8508462SApril.Chin@Sun.COM 			if(!ep->e_multiline && ep->e_wsize < MAXLINE)
8518462SApril.Chin@Sun.COM 				ep->e_wsize = ep->e_winsz-2;
8528462SApril.Chin@Sun.COM 			ep->e_nocrnl=1;
8538462SApril.Chin@Sun.COM 			if(*ep->e_vi_insert)
8548462SApril.Chin@Sun.COM 			{
8558462SApril.Chin@Sun.COM 				buff[0] = ESC;
8568462SApril.Chin@Sun.COM 				buff[1] = cntl('L');
8578462SApril.Chin@Sun.COM 				buff[2] = 'a';
8588462SApril.Chin@Sun.COM 				return(3);
8598462SApril.Chin@Sun.COM 			}
86010898Sroland.mainz@nrubsig.org 			if(sh_isoption(SH_EMACS) || sh_isoption(SH_VI))
86110898Sroland.mainz@nrubsig.org 				buff[0] = cntl('L');
8628462SApril.Chin@Sun.COM 			return(1);
8638462SApril.Chin@Sun.COM 		}
86410898Sroland.mainz@nrubsig.org 		else
86510898Sroland.mainz@nrubsig.org 			ep->sh->winch = 0;
8664887Schin 		/* an interrupt that should be ignored */
8674887Schin 		errno = 0;
8684887Schin 		if(!waitevent || (rv=(*waitevent)(fd,-1L,0))>=0)
8694887Schin 			rv = sfpkrd(fd,buff,size,delim,-1L,mode);
8704887Schin 	}
8714887Schin 	if(rv < 0)
8724887Schin 	{
8734887Schin #ifdef _hdr_utime
8744887Schin #		define fixtime()	if(isdevtty)utime(ep->e_tty,&utimes)
8754887Schin 		int	isdevtty=0;
8764887Schin 		struct stat statb;
8774887Schin 		struct utimbuf utimes;
8784887Schin 	 	if(errno==0 && !ep->e_tty)
8794887Schin 		{
8804887Schin 			if((ep->e_tty=ttyname(fd)) && stat(ep->e_tty,&statb)>=0)
8814887Schin 			{
8824887Schin 				ep->e_tty_ino = statb.st_ino;
8834887Schin 				ep->e_tty_dev = statb.st_dev;
8844887Schin 			}
8854887Schin 		}
8864887Schin 		if(ep->e_tty_ino && fstat(fd,&statb)>=0 && statb.st_ino==ep->e_tty_ino && statb.st_dev==ep->e_tty_dev)
8874887Schin 		{
8884887Schin 			utimes.actime = statb.st_atime;
8894887Schin 			utimes.modtime = statb.st_mtime;
8904887Schin 			isdevtty=1;
8914887Schin 		}
8924887Schin #else
8934887Schin #		define fixtime()
8944887Schin #endif /* _hdr_utime */
8954887Schin 		while(1)
8964887Schin 		{
8974887Schin 			rv = read(fd,buff,size);
8984887Schin 			if(rv>=0 || errno!=EINTR)
8994887Schin 				break;
9008462SApril.Chin@Sun.COM 			if(shp->trapnote&(SH_SIGSET|SH_SIGTRAP))
9014887Schin 				goto done;
9024887Schin 			/* an interrupt that should be ignored */
9034887Schin 			fixtime();
9044887Schin 		}
9054887Schin 	}
9064887Schin 	else if(rv>=0 && mode>0)
9074887Schin 		rv = read(fd,buff,rv>0?rv:1);
9084887Schin done:
9098462SApril.Chin@Sun.COM 	shp->waitevent = waitevent;
9104887Schin 	sh_offstate(SH_TTYWAIT);
9114887Schin 	return(rv);
9124887Schin }
9134887Schin 
9144887Schin 
9154887Schin /*
9164887Schin  * put <string> of length <nbyte> onto lookahead stack
9174887Schin  * if <type> is non-zero,  the negation of the character is put
9184887Schin  *    onto the stack so that it can be checked for KEYTRAP
9194887Schin  * putstack() returns 1 except when in the middle of a multi-byte char
9204887Schin  */
9214887Schin static int putstack(Edit_t *ep,char string[], register int nbyte, int type)
9224887Schin {
9234887Schin 	register int c;
9244887Schin #if SHOPT_MULTIBYTE
9254887Schin 	char *endp, *p=string;
9264887Schin 	int size, offset = ep->e_lookahead + nbyte;
9274887Schin 	*(endp = &p[nbyte]) = 0;
9284887Schin 	endp = &p[nbyte];
9294887Schin 	do
9304887Schin 	{
9314887Schin 		c = (int)((*p) & STRIP);
9324887Schin 		if(c< 0x80 && c!='<')
9334887Schin 		{
9344887Schin 			if (type)
9354887Schin 				c = -c;
9364887Schin #   ifndef CBREAK
9374887Schin 			if(c == '\0')
9384887Schin 			{
9394887Schin 				/*** user break key ***/
9404887Schin 				ep->e_lookahead = 0;
9414887Schin #	if KSHELL
9424887Schin 				sh_fault(SIGINT);
9434887Schin 				siglongjmp(ep->e_env, UINTR);
9444887Schin #	endif   /* KSHELL */
9454887Schin 			}
9464887Schin #   endif /* CBREAK */
9474887Schin 
9484887Schin 		}
9494887Schin 		else
9504887Schin 		{
9514887Schin 		again:
9524887Schin 			if((c=mbchar(p)) >=0)
9534887Schin 			{
9544887Schin 				p--;	/* incremented below */
9554887Schin 				if(type)
9564887Schin 					c = -c;
9574887Schin 			}
9584887Schin #ifdef EILSEQ
9594887Schin 			else if(errno == EILSEQ)
9604887Schin 				errno = 0;
9614887Schin #endif
9624887Schin 			else if((endp-p) < mbmax())
9634887Schin 			{
9644887Schin 				if ((c=ed_read(ep,ep->e_fd,endp, 1,0)) == 1)
9654887Schin 				{
9664887Schin 					*++endp = 0;
9674887Schin 					goto again;
9684887Schin 				}
9694887Schin 				return(c);
9704887Schin 			}
9714887Schin 			else
9724887Schin 			{
9734887Schin 				ed_ringbell();
9744887Schin 				c = -(int)((*p) & STRIP);
9754887Schin 				offset += mbmax()-1;
9764887Schin 			}
9774887Schin 		}
9784887Schin 		ep->e_lbuf[--offset] = c;
9794887Schin 		p++;
9804887Schin 	}
9814887Schin 	while (p < endp);
9824887Schin 	/* shift lookahead buffer if necessary */
9834887Schin 	if(offset -= ep->e_lookahead)
9844887Schin 	{
9854887Schin 		for(size=offset;size < nbyte;size++)
9864887Schin 			ep->e_lbuf[ep->e_lookahead+size-offset] = ep->e_lbuf[ep->e_lookahead+size];
9874887Schin 	}
9884887Schin 	ep->e_lookahead += nbyte-offset;
9894887Schin #else
9904887Schin 	while (nbyte > 0)
9914887Schin 	{
9924887Schin 		c = string[--nbyte] & STRIP;
9934887Schin 		ep->e_lbuf[ep->e_lookahead++] = (type?-c:c);
9944887Schin #   ifndef CBREAK
9954887Schin 		if( c == '\0' )
9964887Schin 		{
9974887Schin 			/*** user break key ***/
9984887Schin 			ep->e_lookahead = 0;
9994887Schin #	if KSHELL
10004887Schin 			sh_fault(SIGINT);
10014887Schin 			siglongjmp(ep->e_env, UINTR);
10024887Schin #	endif	/* KSHELL */
10034887Schin 		}
10044887Schin #   endif /* CBREAK */
10054887Schin 	}
10064887Schin #endif /* SHOPT_MULTIBYTE */
10074887Schin 	return(1);
10084887Schin }
10094887Schin 
10104887Schin /*
10114887Schin  * routine to perform read from terminal for vi and emacs mode
10124887Schin  * <mode> can be one of the following:
10134887Schin  *   -2		vi insert mode - key binding is in effect
10144887Schin  *   -1		vi control mode - key binding is in effect
10154887Schin  *   0		normal command mode - key binding is in effect
10164887Schin  *   1		edit keys not mapped
10174887Schin  *   2		Next key is literal
10184887Schin  */
10194887Schin int ed_getchar(register Edit_t *ep,int mode)
10204887Schin {
10214887Schin 	register int n, c;
10224887Schin 	char readin[LOOKAHEAD+1];
10234887Schin 	if(!ep->e_lookahead)
10244887Schin 	{
10254887Schin 		ed_flush(ep);
10264887Schin 		ep->e_inmacro = 0;
10274887Schin 		/* The while is necessary for reads of partial multbyte chars */
10288462SApril.Chin@Sun.COM 		*ep->e_vi_insert = (mode==-2);
10294887Schin 		if((n=ed_read(ep,ep->e_fd,readin,-LOOKAHEAD,0)) > 0)
10304887Schin 			n = putstack(ep,readin,n,1);
10318462SApril.Chin@Sun.COM 		*ep->e_vi_insert = 0;
10324887Schin 	}
10334887Schin 	if(ep->e_lookahead)
10344887Schin 	{
10354887Schin 		/* check for possible key mapping */
10364887Schin 		if((c = ep->e_lbuf[--ep->e_lookahead]) < 0)
10374887Schin 		{
10388462SApril.Chin@Sun.COM 			if(mode<=0 && ep->sh->st.trap[SH_KEYTRAP])
10394887Schin 			{
10404887Schin 				n=1;
10414887Schin 				if((readin[0]= -c) == ESC)
10424887Schin 				{
10434887Schin 					while(1)
10444887Schin 					{
10454887Schin 						if(!ep->e_lookahead)
10464887Schin 						{
10474887Schin 							if((c=sfpkrd(ep->e_fd,readin+n,1,'\r',(mode?400L:-1L),0))>0)
10484887Schin 								putstack(ep,readin+n,c,1);
10494887Schin 						}
10504887Schin 						if(!ep->e_lookahead)
10514887Schin 							break;
10524887Schin 						if((c=ep->e_lbuf[--ep->e_lookahead])>=0)
10534887Schin 						{
10544887Schin 							ep->e_lookahead++;
10554887Schin 							break;
10564887Schin 						}
10574887Schin 						c = -c;
10584887Schin 						readin[n++] = c;
10594887Schin 						if(c>='0' && c<='9' && n>2)
10604887Schin 							continue;
10614887Schin 						if(n>2 || (c!= '['  &&  c!= 'O'))
10624887Schin 							break;
10634887Schin 					}
10644887Schin 				}
10654887Schin 				if(n=keytrap(ep,readin,n,LOOKAHEAD-n,mode))
10664887Schin 				{
10674887Schin 					putstack(ep,readin,n,0);
10684887Schin 					c = ep->e_lbuf[--ep->e_lookahead];
10694887Schin 				}
10704887Schin 				else
10714887Schin 					c = ed_getchar(ep,mode);
10724887Schin 			}
10734887Schin 			else
10744887Schin 				c = -c;
10754887Schin 		}
10764887Schin 		/*** map '\r' to '\n' ***/
10774887Schin 		if(c == '\r' && mode!=2)
10784887Schin 			c = '\n';
10794887Schin 		if(ep->e_tabcount && !(c=='\t'||c==ESC || c=='\\' || c=='=' || c==cntl('L') || isdigit(c)))
10804887Schin 			ep->e_tabcount = 0;
10814887Schin 	}
10824887Schin 	else
10834887Schin 		siglongjmp(ep->e_env,(n==0?UEOF:UINTR));
10844887Schin 	return(c);
10854887Schin }
10864887Schin 
10874887Schin void ed_ungetchar(Edit_t *ep,register int c)
10884887Schin {
10894887Schin 	if (ep->e_lookahead < LOOKAHEAD)
10904887Schin 		ep->e_lbuf[ep->e_lookahead++] = c;
10914887Schin 	return;
10924887Schin }
10934887Schin 
10944887Schin /*
10954887Schin  * put a character into the output buffer
10964887Schin  */
10974887Schin 
10984887Schin void	ed_putchar(register Edit_t *ep,register int c)
10994887Schin {
11004887Schin 	char buf[8];
11014887Schin 	register char *dp = ep->e_outptr;
11024887Schin 	register int i,size=1;
11038462SApril.Chin@Sun.COM 	if(!dp)
11048462SApril.Chin@Sun.COM 		return;
11054887Schin 	buf[0] = c;
11064887Schin #if SHOPT_MULTIBYTE
11074887Schin 	/* check for place holder */
11084887Schin 	if(c == MARKER)
11094887Schin 		return;
11104887Schin 	if((size = mbconv(buf, (wchar_t)c)) > 1)
11114887Schin 	{
11124887Schin 		for (i = 0; i < (size-1); i++)
11134887Schin 			*dp++ = buf[i];
11144887Schin 		c = buf[i];
11154887Schin 	}
11164887Schin 	else
11174887Schin 	{
11184887Schin 		buf[0] = c;
11194887Schin 		size = 1;
11204887Schin 	}
11214887Schin #endif	/* SHOPT_MULTIBYTE */
11224887Schin 	if (buf[0] == '_' && size==1)
11234887Schin 	{
11244887Schin 		*dp++ = ' ';
11254887Schin 		*dp++ = '\b';
11264887Schin 	}
11274887Schin 	*dp++ = c;
11284887Schin 	*dp = '\0';
11294887Schin 	if(dp >= ep->e_outlast)
11304887Schin 		ed_flush(ep);
11314887Schin 	else
11324887Schin 		ep->e_outptr = dp;
11334887Schin }
11344887Schin 
11354887Schin /*
11364887Schin  * returns the line and column corresponding to offset <off> in the physical buffer
11374887Schin  * if <cur> is non-zero and <= <off>, then correspodning <curpos> will start the search
11384887Schin  */
11394887Schin Edpos_t ed_curpos(Edit_t *ep,genchar *phys, int off, int cur, Edpos_t curpos)
11404887Schin {
11414887Schin 	register genchar *sp=phys;
11424887Schin 	register int c=1, col=ep->e_plen;
11434887Schin 	Edpos_t pos;
11444887Schin #if SHOPT_MULTIBYTE
11454887Schin 	char p[16];
11464887Schin #endif /* SHOPT_MULTIBYTE */
11474887Schin 	if(cur && off>=cur)
11484887Schin 	{
11494887Schin 		sp += cur;
11504887Schin 		off -= cur;
11514887Schin 		pos = curpos;
11524887Schin 		col = pos.col;
11534887Schin 	}
11544887Schin 	else
11558462SApril.Chin@Sun.COM 	{
11564887Schin 		pos.line = 0;
11578462SApril.Chin@Sun.COM 		while(col > ep->e_winsz)
11588462SApril.Chin@Sun.COM 		{
11598462SApril.Chin@Sun.COM 			pos.line++;
11608462SApril.Chin@Sun.COM 			col -= (ep->e_winsz+1);
11618462SApril.Chin@Sun.COM 		}
11628462SApril.Chin@Sun.COM 	}
11634887Schin 	while(off-->0)
11644887Schin 	{
11654887Schin 		if(c)
11664887Schin 			c = *sp++;
11674887Schin #if SHOPT_MULTIBYTE
11684887Schin 		if(c && (mbconv(p, (wchar_t)c))==1 && p[0]=='\n')
11694887Schin #else
11704887Schin 		if(c=='\n')
11714887Schin #endif /* SHOPT_MULTIBYTE */
11724887Schin 			col = 0;
11734887Schin 		else
11744887Schin 			col++;
11754887Schin 		if(col >  ep->e_winsz)
11764887Schin 			col = 0;
11774887Schin 		if(col==0)
11784887Schin 			pos.line++;
11794887Schin 	}
11804887Schin 	pos.col = col;
11814887Schin 	return(pos);
11824887Schin }
11834887Schin 
11844887Schin int ed_setcursor(register Edit_t *ep,genchar *physical,register int old,register int new,int first)
11854887Schin {
11864887Schin 	static int oldline;
11874887Schin 	register int delta;
11888462SApril.Chin@Sun.COM 	int clear = 0;
11894887Schin 	Edpos_t newpos;
11904887Schin 
11914887Schin 	delta = new - old;
11928462SApril.Chin@Sun.COM 	if(first < 0)
11938462SApril.Chin@Sun.COM 	{
11948462SApril.Chin@Sun.COM 		first = 0;
11958462SApril.Chin@Sun.COM 		clear = 1;
11968462SApril.Chin@Sun.COM 	}
11978462SApril.Chin@Sun.COM 	if( delta == 0  &&  !clear)
11984887Schin 		return(new);
11994887Schin 	if(ep->e_multiline)
12004887Schin 	{
12014887Schin 		ep->e_curpos = ed_curpos(ep, physical, old,0,ep->e_curpos);
12028462SApril.Chin@Sun.COM 		if(clear && old>=ep->e_peol && (clear=ep->e_winsz-ep->e_curpos.col)>0)
12038462SApril.Chin@Sun.COM 		{
12048462SApril.Chin@Sun.COM 			ed_nputchar(ep,clear,' ');
12058462SApril.Chin@Sun.COM 			ed_nputchar(ep,clear,'\b');
12068462SApril.Chin@Sun.COM 			return(new);
12078462SApril.Chin@Sun.COM 		}
12084887Schin 		newpos =     ed_curpos(ep, physical, new,old,ep->e_curpos);
12094887Schin 		if(ep->e_curpos.col==0 && ep->e_curpos.line>0 && oldline<ep->e_curpos.line && delta<0)
12104887Schin 			ed_putstring(ep,"\r\n");
12114887Schin 		oldline = newpos.line;
12124887Schin 		if(ep->e_curpos.line > newpos.line)
12134887Schin 		{
12148462SApril.Chin@Sun.COM 			int n,pline,plen=ep->e_plen;
12154887Schin 			for(;ep->e_curpos.line > newpos.line; ep->e_curpos.line--)
12164887Schin 				ed_putstring(ep,CURSOR_UP);
12178462SApril.Chin@Sun.COM 			pline = plen/(ep->e_winsz+1);
12188462SApril.Chin@Sun.COM 			if(newpos.line <= pline)
12198462SApril.Chin@Sun.COM 				plen -= pline*(ep->e_winsz+1);
12208462SApril.Chin@Sun.COM 			else
12218462SApril.Chin@Sun.COM 				plen = 0;
12228462SApril.Chin@Sun.COM 			if((n=plen- ep->e_curpos.col)>0)
12234887Schin 			{
12244887Schin 				ep->e_curpos.col += n;
12254887Schin 				ed_putchar(ep,'\r');
12268462SApril.Chin@Sun.COM 				if(!ep->e_crlf && pline==0)
12274887Schin 					ed_putstring(ep,ep->e_prompt);
12284887Schin 				else
12294887Schin 				{
12308462SApril.Chin@Sun.COM 					int m = ep->e_winsz+1-plen;
12314887Schin 					ed_putchar(ep,'\n');
12328462SApril.Chin@Sun.COM 					n = plen;
12334887Schin 					if(m < ed_genlen(physical))
12344887Schin 					{
12354887Schin 						while(physical[m] && n-->0)
12364887Schin 							ed_putchar(ep,physical[m++]);
12374887Schin 					}
12388462SApril.Chin@Sun.COM 					ed_nputchar(ep,n,' ');
12394887Schin 					ed_putstring(ep,CURSOR_UP);
12404887Schin 				}
12414887Schin 			}
12424887Schin 		}
12434887Schin 		else if(ep->e_curpos.line < newpos.line)
12444887Schin 		{
12458462SApril.Chin@Sun.COM 			ed_nputchar(ep, newpos.line-ep->e_curpos.line,'\n');
12468462SApril.Chin@Sun.COM 			ep->e_curpos.line = newpos.line;
12474887Schin 			ed_putchar(ep,'\r');
12484887Schin 			ep->e_curpos.col = 0;
12494887Schin 		}
12504887Schin 		delta = newpos.col - ep->e_curpos.col;
12514887Schin 		old   =  new - delta;
12524887Schin 	}
12534887Schin 	else
12544887Schin 		newpos.line=0;
12554887Schin 	if(delta<0)
12564887Schin 	{
12578462SApril.Chin@Sun.COM 		int bs= newpos.line && ep->e_plen>ep->e_winsz;
12584887Schin 		/*** move to left ***/
12594887Schin 		delta = -delta;
12604887Schin 		/*** attempt to optimize cursor movement ***/
12618462SApril.Chin@Sun.COM 		if(!ep->e_crlf || bs || (2*delta <= ((old-first)+(newpos.line?0:ep->e_plen))) )
12624887Schin 		{
12638462SApril.Chin@Sun.COM 			ed_nputchar(ep,delta,'\b');
12648462SApril.Chin@Sun.COM 			delta = 0;
12654887Schin 		}
12664887Schin 		else
12674887Schin 		{
12684887Schin 			if(newpos.line==0)
12694887Schin 				ed_putstring(ep,ep->e_prompt);
12708462SApril.Chin@Sun.COM 			else
12718462SApril.Chin@Sun.COM 			{
12728462SApril.Chin@Sun.COM 				first = 1+(newpos.line*ep->e_winsz - ep->e_plen);
12738462SApril.Chin@Sun.COM 				ed_putchar(ep,'\r');
12748462SApril.Chin@Sun.COM 			}
12754887Schin 			old = first;
12764887Schin 			delta = new-first;
12774887Schin 		}
12784887Schin 	}
12794887Schin 	while(delta-->0)
12804887Schin 		ed_putchar(ep,physical[old++]);
12814887Schin 	return(new);
12824887Schin }
12834887Schin 
12844887Schin /*
12854887Schin  * copy virtual to physical and return the index for cursor in physical buffer
12864887Schin  */
12874887Schin int ed_virt_to_phys(Edit_t *ep,genchar *virt,genchar *phys,int cur,int voff,int poff)
12884887Schin {
12894887Schin 	register genchar *sp = virt;
12904887Schin 	register genchar *dp = phys;
12914887Schin 	register int c;
12924887Schin 	genchar *curp = sp + cur;
12934887Schin 	genchar *dpmax = phys+MAXLINE;
12944887Schin 	int d, r;
12954887Schin 	sp += voff;
12964887Schin 	dp += poff;
12974887Schin 	for(r=poff;c= *sp;sp++)
12984887Schin 	{
12994887Schin 		if(curp == sp)
13004887Schin 			r = dp - phys;
13014887Schin #if SHOPT_MULTIBYTE
13024887Schin 		d = mbwidth((wchar_t)c);
13034887Schin 		if(d==1 && is_cntrl(c))
13044887Schin 			d = -1;
13054887Schin 		if(d>1)
13064887Schin 		{
13074887Schin 			/* multiple width character put in place holders */
13084887Schin 			*dp++ = c;
13094887Schin 			while(--d >0)
13104887Schin 				*dp++ = MARKER;
13114887Schin 			/* in vi mode the cursor is at the last character */
13124887Schin 			if(dp>=dpmax)
13134887Schin 				break;
13144887Schin 			continue;
13154887Schin 		}
13164887Schin 		else
13174887Schin #else
13184887Schin 		d = (is_cntrl(c)?-1:1);
13194887Schin #endif	/* SHOPT_MULTIBYTE */
13204887Schin 		if(d<0)
13214887Schin 		{
13224887Schin 			if(c=='\t')
13234887Schin 			{
13244887Schin 				c = dp-phys;
13254887Schin 				if(sh_isoption(SH_VI))
13264887Schin 					c += ep->e_plen;
13274887Schin 				c = TABSIZE - c%TABSIZE;
13284887Schin 				while(--c>0)
13294887Schin 					*dp++ = ' ';
13304887Schin 				c = ' ';
13314887Schin 			}
13324887Schin 			else
13334887Schin 			{
13344887Schin 				*dp++ = '^';
13354887Schin 				c = printchar(c);
13364887Schin 			}
13374887Schin 			/* in vi mode the cursor is at the last character */
13384887Schin 			if(curp == sp && sh_isoption(SH_VI))
13394887Schin 				r = dp - phys;
13404887Schin 		}
13414887Schin 		*dp++ = c;
13424887Schin 		if(dp>=dpmax)
13434887Schin 			break;
13444887Schin 	}
13454887Schin 	*dp = 0;
13468462SApril.Chin@Sun.COM 	ep->e_peol = dp-phys;
13474887Schin 	return(r);
13484887Schin }
13494887Schin 
13504887Schin #if SHOPT_MULTIBYTE
13514887Schin /*
13524887Schin  * convert external representation <src> to an array of genchars <dest>
13534887Schin  * <src> and <dest> can be the same
13544887Schin  * returns number of chars in dest
13554887Schin  */
13564887Schin 
13574887Schin int	ed_internal(const char *src, genchar *dest)
13584887Schin {
13594887Schin 	register const unsigned char *cp = (unsigned char *)src;
13604887Schin 	register int c;
13614887Schin 	register wchar_t *dp = (wchar_t*)dest;
13624887Schin 	if(dest == (genchar*)roundof(cp-(unsigned char*)0,sizeof(genchar)))
13634887Schin 	{
13644887Schin 		genchar buffer[MAXLINE];
13654887Schin 		c = ed_internal(src,buffer);
13664887Schin 		ed_gencpy((genchar*)dp,buffer);
13674887Schin 		return(c);
13684887Schin 	}
13694887Schin 	while(*cp)
13704887Schin 		*dp++ = mbchar(cp);
13714887Schin 	*dp = 0;
13724887Schin 	return(dp-(wchar_t*)dest);
13734887Schin }
13744887Schin 
13754887Schin /*
13764887Schin  * convert internal representation <src> into character array <dest>.
13774887Schin  * The <src> and <dest> may be the same.
13784887Schin  * returns number of chars in dest.
13794887Schin  */
13804887Schin 
13814887Schin int	ed_external(const genchar *src, char *dest)
13824887Schin {
13834887Schin 	register genchar wc;
13844887Schin 	register int c,size;
13854887Schin 	register char *dp = dest;
13864887Schin 	char *dpmax = dp+sizeof(genchar)*MAXLINE-2;
13874887Schin 	if((char*)src == dp)
13884887Schin 	{
13894887Schin 		char buffer[MAXLINE*sizeof(genchar)];
13904887Schin 		c = ed_external(src,buffer);
13914887Schin 
13924887Schin #ifdef _lib_wcscpy
13934887Schin 		wcscpy((wchar_t *)dest,(const wchar_t *)buffer);
13944887Schin #else
13954887Schin 		strcpy(dest,buffer);
13964887Schin #endif
13974887Schin 		return(c);
13984887Schin 	}
13994887Schin 	while((wc = *src++) && dp<dpmax)
14004887Schin 	{
14014887Schin 		if((size = mbconv(dp, wc)) < 0)
14024887Schin 		{
14034887Schin 			/* copy the character as is */
14044887Schin 			size = 1;
14054887Schin 			*dp = wc;
14064887Schin 		}
14074887Schin 		dp += size;
14084887Schin 	}
14094887Schin 	*dp = 0;
14104887Schin 	return(dp-dest);
14114887Schin }
14124887Schin 
14134887Schin /*
14144887Schin  * copy <sp> to <dp>
14154887Schin  */
14164887Schin 
14174887Schin void	ed_gencpy(genchar *dp,const genchar *sp)
14184887Schin {
14194887Schin 	dp = (genchar*)roundof((char*)dp-(char*)0,sizeof(genchar));
14204887Schin 	sp = (const genchar*)roundof((char*)sp-(char*)0,sizeof(genchar));
14214887Schin 	while(*dp++ = *sp++);
14224887Schin }
14234887Schin 
14244887Schin /*
14254887Schin  * copy at most <n> items from <sp> to <dp>
14264887Schin  */
14274887Schin 
14284887Schin void	ed_genncpy(register genchar *dp,register const genchar *sp, int n)
14294887Schin {
14304887Schin 	dp = (genchar*)roundof((char*)dp-(char*)0,sizeof(genchar));
14314887Schin 	sp = (const genchar*)roundof((char*)sp-(char*)0,sizeof(genchar));
14324887Schin 	while(n-->0 && (*dp++ = *sp++));
14334887Schin }
14344887Schin 
14354887Schin /*
14364887Schin  * find the string length of <str>
14374887Schin  */
14384887Schin 
14394887Schin int	ed_genlen(register const genchar *str)
14404887Schin {
14414887Schin 	register const genchar *sp = str;
14424887Schin 	sp = (const genchar*)roundof((char*)sp-(char*)0,sizeof(genchar));
14434887Schin 	while(*sp++);
14444887Schin 	return(sp-str-1);
14454887Schin }
14464887Schin #endif /* SHOPT_MULTIBYTE */
14474887Schin #endif /* SHOPT_ESH || SHOPT_VSH */
14484887Schin 
14494887Schin #ifdef future
14504887Schin /*
14514887Schin  * returns 1 when <n> bytes starting at <a> and <b> are equal
14524887Schin  */
14534887Schin static int compare(register const char *a,register const char *b,register int n)
14544887Schin {
14554887Schin 	while(n-->0)
14564887Schin 	{
14574887Schin 		if(*a++ != *b++)
14584887Schin 			return(0);
14594887Schin 	}
14604887Schin 	return(1);
14614887Schin }
14624887Schin #endif
14634887Schin 
14644887Schin #if SHOPT_OLDTERMIO
14654887Schin 
14664887Schin #   include	<sys/termio.h>
14674887Schin 
14684887Schin #ifndef ECHOCTL
14694887Schin #   define ECHOCTL	0
14704887Schin #endif /* !ECHOCTL */
14714887Schin #define ott	ep->e_ott
14724887Schin 
14734887Schin /*
14744887Schin  * For backward compatibility only
14754887Schin  * This version will use termios when possible, otherwise termio
14764887Schin  */
14774887Schin 
14788462SApril.Chin@Sun.COM int tcgetattr(int fd, struct termios *tt)
14794887Schin {
14804887Schin 	register Edit_t *ep = (Edit_t*)(sh_getinterp()->ed_context);
14814887Schin 	register int r,i;
14824887Schin 	ep->e_tcgeta = 0;
14834887Schin 	ep->e_echoctl = (ECHOCTL!=0);
14844887Schin 	if((r=ioctl(fd,TCGETS,tt))>=0 ||  errno!=EINVAL)
14854887Schin 		return(r);
14864887Schin 	if((r=ioctl(fd,TCGETA,&ott)) >= 0)
14874887Schin 	{
14884887Schin 		tt->c_lflag = ott.c_lflag;
14894887Schin 		tt->c_oflag = ott.c_oflag;
14904887Schin 		tt->c_iflag = ott.c_iflag;
14914887Schin 		tt->c_cflag = ott.c_cflag;
14924887Schin 		for(i=0; i<NCC; i++)
14934887Schin 			tt->c_cc[i] = ott.c_cc[i];
14944887Schin 		ep->e_tcgeta++;
14954887Schin 		ep->e_echoctl = 0;
14964887Schin 	}
14974887Schin 	return(r);
14984887Schin }
14994887Schin 
15008462SApril.Chin@Sun.COM int tcsetattr(int fd,int mode,struct termios *tt)
15014887Schin {
15024887Schin 	register Edit_t *ep = (Edit_t*)(sh_getinterp()->ed_context);
15034887Schin 	register int r;
15044887Schin 	if(ep->e_tcgeta)
15054887Schin 	{
15064887Schin 		register int i;
15074887Schin 		ott.c_lflag = tt->c_lflag;
15084887Schin 		ott.c_oflag = tt->c_oflag;
15094887Schin 		ott.c_iflag = tt->c_iflag;
15104887Schin 		ott.c_cflag = tt->c_cflag;
15114887Schin 		for(i=0; i<NCC; i++)
15124887Schin 			ott.c_cc[i] = tt->c_cc[i];
15134887Schin 		if(tt->c_lflag&ECHOCTL)
15144887Schin 		{
15154887Schin 			ott.c_lflag &= ~(ECHOCTL|IEXTEN);
15164887Schin 			ott.c_iflag &= ~(IGNCR|ICRNL);
15174887Schin 			ott.c_iflag |= INLCR;
15184887Schin 			ott.c_cc[VEOF]= ESC;  /* ESC -> eof char */
15194887Schin 			ott.c_cc[VEOL] = '\r'; /* CR -> eol char */
15204887Schin 			ott.c_cc[VEOL2] = tt->c_cc[VEOF]; /* EOF -> eol char */
15214887Schin 		}
15224887Schin 		switch(mode)
15234887Schin 		{
15244887Schin 			case TCSANOW:
15254887Schin 				mode = TCSETA;
15264887Schin 				break;
15274887Schin 			case TCSADRAIN:
15284887Schin 				mode = TCSETAW;
15294887Schin 				break;
15304887Schin 			case TCSAFLUSH:
15314887Schin 				mode = TCSETAF;
15324887Schin 		}
15334887Schin 		return(ioctl(fd,mode,&ott));
15344887Schin 	}
15354887Schin 	return(ioctl(fd,mode,tt));
15364887Schin }
15374887Schin #endif /* SHOPT_OLDTERMIO */
15384887Schin 
15394887Schin #if KSHELL
15404887Schin /*
15414887Schin  * Execute keyboard trap on given buffer <inbuff> of given size <isize>
15424887Schin  * <mode> < 0 for vi insert mode
15434887Schin  */
15444887Schin static int keytrap(Edit_t *ep,char *inbuff,register int insize, int bufsize, int mode)
15454887Schin {
15464887Schin 	register char *cp;
15474887Schin 	int savexit;
15488462SApril.Chin@Sun.COM 	Shell_t *shp = ep->sh;
15494887Schin #if SHOPT_MULTIBYTE
15504887Schin 	char buff[MAXLINE];
15514887Schin 	ed_external(ep->e_inbuf,cp=buff);
15524887Schin #else
15534887Schin 	cp = ep->e_inbuf;
15544887Schin #endif /* SHOPT_MULTIBYTE */
15554887Schin 	inbuff[insize] = 0;
15564887Schin 	ep->e_col = ep->e_cur;
15574887Schin 	if(mode== -2)
15584887Schin 	{
15594887Schin 		ep->e_col++;
15604887Schin 		*ep->e_vi_insert = ESC;
15614887Schin 	}
15624887Schin 	else
15634887Schin 		*ep->e_vi_insert = 0;
15644887Schin 	nv_putval(ED_CHRNOD,inbuff,NV_NOFREE);
15654887Schin 	nv_putval(ED_COLNOD,(char*)&ep->e_col,NV_NOFREE|NV_INTEGER);
15664887Schin 	nv_putval(ED_TXTNOD,(char*)cp,NV_NOFREE);
15674887Schin 	nv_putval(ED_MODENOD,ep->e_vi_insert,NV_NOFREE);
15688462SApril.Chin@Sun.COM 	savexit = shp->savexit;
15698462SApril.Chin@Sun.COM 	sh_trap(shp->st.trap[SH_KEYTRAP],0);
15708462SApril.Chin@Sun.COM 	shp->savexit = savexit;
15714887Schin 	if((cp = nv_getval(ED_CHRNOD)) == inbuff)
15724887Schin 		nv_unset(ED_CHRNOD);
15738462SApril.Chin@Sun.COM 	else if(bufsize>0)
15744887Schin 	{
15754887Schin 		strncpy(inbuff,cp,bufsize);
15768462SApril.Chin@Sun.COM 		inbuff[bufsize-1]='\0';
15774887Schin 		insize = strlen(inbuff);
15784887Schin 	}
15798462SApril.Chin@Sun.COM 	else
15808462SApril.Chin@Sun.COM 		insize = 0;
15814887Schin 	nv_unset(ED_TXTNOD);
15824887Schin 	return(insize);
15834887Schin }
15844887Schin #endif /* KSHELL */
15854887Schin 
15864887Schin void	*ed_open(Shell_t *shp)
15874887Schin {
15884887Schin 	Edit_t *ed = newof(0,Edit_t,1,0);
15894887Schin 	ed->sh = shp;
15904887Schin 	strcpy(ed->e_macro,"_??");
15914887Schin 	return((void*)ed);
15924887Schin }
1593