14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*8462SApril.Chin@Sun.COM *          Copyright (c) 1982-2008 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
7*8462SApril.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	<ctype.h>
344887Schin #include	"FEATURE/options"
354887Schin #include	"FEATURE/time"
364887Schin #include	"FEATURE/cmds"
374887Schin #ifdef _hdr_utime
384887Schin #   include	<utime.h>
394887Schin #   include	<ls.h>
404887Schin #endif
414887Schin 
424887Schin #if KSHELL
434887Schin #   include	"defs.h"
444887Schin #   include	"variables.h"
454887Schin #else
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 
56*8462SApril.Chin@Sun.COM 
57*8462SApril.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
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  */
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 
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 
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 
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 
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
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 
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  */
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 
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 
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 
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 
5864887Schin void	ed_setup(register Edit_t *ep, int fd, int reedit)
5874887Schin {
588*8462SApril.Chin@Sun.COM 	Shell_t *shp = ep->sh;
5894887Schin 	register char *pp;
590*8462SApril.Chin@Sun.COM 	register char *last, *prev;
5914887Schin 	char *ppmax;
5924887Schin 	int myquote = 0, n;
593*8462SApril.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
598*8462SApril.Chin@Sun.COM 	if(!(shp->sigflag[SIGWINCH]&SH_SIGFAULT))
5994887Schin 	{
6004887Schin 		signal(SIGWINCH,sh_fault);
601*8462SApril.Chin@Sun.COM 		shp->sigflag[SIGWINCH] |= SH_SIGFAULT;
6024887Schin 	}
603*8462SApril.Chin@Sun.COM 	pp = shp->st.trapcom[SIGWINCH];
604*8462SApril.Chin@Sun.COM 	shp->st.trapcom[SIGWINCH] = 0;
6054887Schin 	sh_fault(SIGWINCH);
606*8462SApril.Chin@Sun.COM 	shp->st.trapcom[SIGWINCH] = pp;
607*8462SApril.Chin@Sun.COM 	ep->sh->winch = 0;
6084887Schin #endif
6094887Schin #if KSHELL
6104887Schin 	ep->e_stkptr = stakptr(0);
6114887Schin 	ep->e_stkoff = staktell();
612*8462SApril.Chin@Sun.COM 	if(!(last = shp->prompt))
6134887Schin 		last = "";
614*8462SApril.Chin@Sun.COM 	shp->prompt = 0;
6154887Schin #else
6164887Schin 	last = ep->e_prbuff;
6174887Schin #endif /* KSHELL */
618*8462SApril.Chin@Sun.COM 	if(shp->hist_ptr)
6194887Schin 	{
620*8462SApril.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;
641*8462SApril.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;
652*8462SApril.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 				}
661*8462SApril.Chin@Sun.COM 				if(c==0 || c==ESC || c=='\r')
662*8462SApril.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 				{
705*8462SApril.Chin@Sun.COM 					if(inquote)
706*8462SApril.Chin@Sun.COM 						qlen++;
707*8462SApril.Chin@Sun.COM 					else if(!is_print(c))
7084887Schin 						ep->e_crlf = 0;
709*8462SApril.Chin@Sun.COM 					if((qwid = last - prev) > 1)
710*8462SApril.Chin@Sun.COM 						qlen += qwid - mbwidth(c);
711*8462SApril.Chin@Sun.COM 					while(prev < last && pp < ppmax)
712*8462SApril.Chin@Sun.COM 						*pp++ = *prev++;
7134887Schin 				}
714*8462SApril.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;
720*8462SApril.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)
753*8462SApril.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
763*8462SApril.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 
777*8462SApril.Chin@Sun.COM static void ed_putstring(register Edit_t *ep, const char *str)
778*8462SApril.Chin@Sun.COM {
779*8462SApril.Chin@Sun.COM 	register int c;
780*8462SApril.Chin@Sun.COM 	while(c = *str++)
781*8462SApril.Chin@Sun.COM 		ed_putchar(ep,c);
782*8462SApril.Chin@Sun.COM }
783*8462SApril.Chin@Sun.COM 
784*8462SApril.Chin@Sun.COM static void ed_nputchar(register Edit_t *ep, int n, int c)
785*8462SApril.Chin@Sun.COM {
786*8462SApril.Chin@Sun.COM 	while(n-->0)
787*8462SApril.Chin@Sun.COM 		ed_putchar(ep,c);
788*8462SApril.Chin@Sun.COM }
789*8462SApril.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  */
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');
804*8462SApril.Chin@Sun.COM 	Shell_t *shp = ep->sh;
8054887Schin 	int mode = -1;
806*8462SApril.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;
816*8462SApril.Chin@Sun.COM 	shp->waitevent = 0;
8174887Schin 	while(rv<0 && errno==EINTR)
8184887Schin 	{
819*8462SApril.Chin@Sun.COM 		if(shp->trapnote&(SH_SIGSET|SH_SIGTRAP))
8204887Schin 			goto done;
821*8462SApril.Chin@Sun.COM 		if(ep->sh->winch)
822*8462SApril.Chin@Sun.COM 		{
823*8462SApril.Chin@Sun.COM 			Edpos_t	lastpos;
824*8462SApril.Chin@Sun.COM 			int	n, rows, newsize;
825*8462SApril.Chin@Sun.COM 			/* move cursor to start of first line */
826*8462SApril.Chin@Sun.COM 			ed_putchar(ep,'\r');
827*8462SApril.Chin@Sun.COM 			ed_flush(ep);
828*8462SApril.Chin@Sun.COM 			astwinsize(2,&rows,&newsize);
829*8462SApril.Chin@Sun.COM 			n = (ep->e_plen+ep->e_cur)/++ep->e_winsz;
830*8462SApril.Chin@Sun.COM 			while(n--)
831*8462SApril.Chin@Sun.COM 				ed_putstring(ep,CURSOR_UP);
832*8462SApril.Chin@Sun.COM 			if(ep->e_multiline && newsize>ep->e_winsz && (lastpos.line=(ep->e_plen+ep->e_peol)/ep->e_winsz))
833*8462SApril.Chin@Sun.COM 			{
834*8462SApril.Chin@Sun.COM 				/* clear the current command line */
835*8462SApril.Chin@Sun.COM 				n = lastpos.line;
836*8462SApril.Chin@Sun.COM 				while(lastpos.line--)
837*8462SApril.Chin@Sun.COM 				{
838*8462SApril.Chin@Sun.COM 					ed_nputchar(ep,ep->e_winsz,' ');
839*8462SApril.Chin@Sun.COM 					ed_putchar(ep,'\n');
840*8462SApril.Chin@Sun.COM 				}
841*8462SApril.Chin@Sun.COM 				ed_nputchar(ep,ep->e_winsz,' ');
842*8462SApril.Chin@Sun.COM 				while(n--)
843*8462SApril.Chin@Sun.COM 					ed_putstring(ep,CURSOR_UP);
844*8462SApril.Chin@Sun.COM 			}
845*8462SApril.Chin@Sun.COM 	                ep->sh->winch = 0;
846*8462SApril.Chin@Sun.COM 			ed_flush(ep);
847*8462SApril.Chin@Sun.COM 			sh_delay(.05);
848*8462SApril.Chin@Sun.COM 			astwinsize(2,&rows,&newsize);
849*8462SApril.Chin@Sun.COM 			ep->e_winsz = newsize-1;
850*8462SApril.Chin@Sun.COM 			if(!ep->e_multiline && ep->e_wsize < MAXLINE)
851*8462SApril.Chin@Sun.COM 				ep->e_wsize = ep->e_winsz-2;
852*8462SApril.Chin@Sun.COM 			ep->e_nocrnl=1;
853*8462SApril.Chin@Sun.COM 			if(*ep->e_vi_insert)
854*8462SApril.Chin@Sun.COM 			{
855*8462SApril.Chin@Sun.COM 				buff[0] = ESC;
856*8462SApril.Chin@Sun.COM 				buff[1] = cntl('L');
857*8462SApril.Chin@Sun.COM 				buff[2] = 'a';
858*8462SApril.Chin@Sun.COM 				return(3);
859*8462SApril.Chin@Sun.COM 			}
860*8462SApril.Chin@Sun.COM 			buff[0] = cntl('L');
861*8462SApril.Chin@Sun.COM 			return(1);
862*8462SApril.Chin@Sun.COM 		}
8634887Schin 		/* an interrupt that should be ignored */
8644887Schin 		errno = 0;
8654887Schin 		if(!waitevent || (rv=(*waitevent)(fd,-1L,0))>=0)
8664887Schin 			rv = sfpkrd(fd,buff,size,delim,-1L,mode);
8674887Schin 	}
8684887Schin 	if(rv < 0)
8694887Schin 	{
8704887Schin #ifdef _hdr_utime
8714887Schin #		define fixtime()	if(isdevtty)utime(ep->e_tty,&utimes)
8724887Schin 		int	isdevtty=0;
8734887Schin 		struct stat statb;
8744887Schin 		struct utimbuf utimes;
8754887Schin 	 	if(errno==0 && !ep->e_tty)
8764887Schin 		{
8774887Schin 			if((ep->e_tty=ttyname(fd)) && stat(ep->e_tty,&statb)>=0)
8784887Schin 			{
8794887Schin 				ep->e_tty_ino = statb.st_ino;
8804887Schin 				ep->e_tty_dev = statb.st_dev;
8814887Schin 			}
8824887Schin 		}
8834887Schin 		if(ep->e_tty_ino && fstat(fd,&statb)>=0 && statb.st_ino==ep->e_tty_ino && statb.st_dev==ep->e_tty_dev)
8844887Schin 		{
8854887Schin 			utimes.actime = statb.st_atime;
8864887Schin 			utimes.modtime = statb.st_mtime;
8874887Schin 			isdevtty=1;
8884887Schin 		}
8894887Schin #else
8904887Schin #		define fixtime()
8914887Schin #endif /* _hdr_utime */
8924887Schin 		while(1)
8934887Schin 		{
8944887Schin 			rv = read(fd,buff,size);
8954887Schin 			if(rv>=0 || errno!=EINTR)
8964887Schin 				break;
897*8462SApril.Chin@Sun.COM 			if(shp->trapnote&(SH_SIGSET|SH_SIGTRAP))
8984887Schin 				goto done;
8994887Schin 			/* an interrupt that should be ignored */
9004887Schin 			fixtime();
9014887Schin 		}
9024887Schin 	}
9034887Schin 	else if(rv>=0 && mode>0)
9044887Schin 		rv = read(fd,buff,rv>0?rv:1);
9054887Schin done:
906*8462SApril.Chin@Sun.COM 	shp->waitevent = waitevent;
9074887Schin 	sh_offstate(SH_TTYWAIT);
9084887Schin 	return(rv);
9094887Schin }
9104887Schin 
9114887Schin 
9124887Schin /*
9134887Schin  * put <string> of length <nbyte> onto lookahead stack
9144887Schin  * if <type> is non-zero,  the negation of the character is put
9154887Schin  *    onto the stack so that it can be checked for KEYTRAP
9164887Schin  * putstack() returns 1 except when in the middle of a multi-byte char
9174887Schin  */
9184887Schin static int putstack(Edit_t *ep,char string[], register int nbyte, int type)
9194887Schin {
9204887Schin 	register int c;
9214887Schin #if SHOPT_MULTIBYTE
9224887Schin 	char *endp, *p=string;
9234887Schin 	int size, offset = ep->e_lookahead + nbyte;
9244887Schin 	*(endp = &p[nbyte]) = 0;
9254887Schin 	endp = &p[nbyte];
9264887Schin 	do
9274887Schin 	{
9284887Schin 		c = (int)((*p) & STRIP);
9294887Schin 		if(c< 0x80 && c!='<')
9304887Schin 		{
9314887Schin 			if (type)
9324887Schin 				c = -c;
9334887Schin #   ifndef CBREAK
9344887Schin 			if(c == '\0')
9354887Schin 			{
9364887Schin 				/*** user break key ***/
9374887Schin 				ep->e_lookahead = 0;
9384887Schin #	if KSHELL
9394887Schin 				sh_fault(SIGINT);
9404887Schin 				siglongjmp(ep->e_env, UINTR);
9414887Schin #	endif   /* KSHELL */
9424887Schin 			}
9434887Schin #   endif /* CBREAK */
9444887Schin 
9454887Schin 		}
9464887Schin 		else
9474887Schin 		{
9484887Schin 		again:
9494887Schin 			if((c=mbchar(p)) >=0)
9504887Schin 			{
9514887Schin 				p--;	/* incremented below */
9524887Schin 				if(type)
9534887Schin 					c = -c;
9544887Schin 			}
9554887Schin #ifdef EILSEQ
9564887Schin 			else if(errno == EILSEQ)
9574887Schin 				errno = 0;
9584887Schin #endif
9594887Schin 			else if((endp-p) < mbmax())
9604887Schin 			{
9614887Schin 				if ((c=ed_read(ep,ep->e_fd,endp, 1,0)) == 1)
9624887Schin 				{
9634887Schin 					*++endp = 0;
9644887Schin 					goto again;
9654887Schin 				}
9664887Schin 				return(c);
9674887Schin 			}
9684887Schin 			else
9694887Schin 			{
9704887Schin 				ed_ringbell();
9714887Schin 				c = -(int)((*p) & STRIP);
9724887Schin 				offset += mbmax()-1;
9734887Schin 			}
9744887Schin 		}
9754887Schin 		ep->e_lbuf[--offset] = c;
9764887Schin 		p++;
9774887Schin 	}
9784887Schin 	while (p < endp);
9794887Schin 	/* shift lookahead buffer if necessary */
9804887Schin 	if(offset -= ep->e_lookahead)
9814887Schin 	{
9824887Schin 		for(size=offset;size < nbyte;size++)
9834887Schin 			ep->e_lbuf[ep->e_lookahead+size-offset] = ep->e_lbuf[ep->e_lookahead+size];
9844887Schin 	}
9854887Schin 	ep->e_lookahead += nbyte-offset;
9864887Schin #else
9874887Schin 	while (nbyte > 0)
9884887Schin 	{
9894887Schin 		c = string[--nbyte] & STRIP;
9904887Schin 		ep->e_lbuf[ep->e_lookahead++] = (type?-c:c);
9914887Schin #   ifndef CBREAK
9924887Schin 		if( c == '\0' )
9934887Schin 		{
9944887Schin 			/*** user break key ***/
9954887Schin 			ep->e_lookahead = 0;
9964887Schin #	if KSHELL
9974887Schin 			sh_fault(SIGINT);
9984887Schin 			siglongjmp(ep->e_env, UINTR);
9994887Schin #	endif	/* KSHELL */
10004887Schin 		}
10014887Schin #   endif /* CBREAK */
10024887Schin 	}
10034887Schin #endif /* SHOPT_MULTIBYTE */
10044887Schin 	return(1);
10054887Schin }
10064887Schin 
10074887Schin /*
10084887Schin  * routine to perform read from terminal for vi and emacs mode
10094887Schin  * <mode> can be one of the following:
10104887Schin  *   -2		vi insert mode - key binding is in effect
10114887Schin  *   -1		vi control mode - key binding is in effect
10124887Schin  *   0		normal command mode - key binding is in effect
10134887Schin  *   1		edit keys not mapped
10144887Schin  *   2		Next key is literal
10154887Schin  */
10164887Schin int ed_getchar(register Edit_t *ep,int mode)
10174887Schin {
10184887Schin 	register int n, c;
10194887Schin 	char readin[LOOKAHEAD+1];
10204887Schin 	if(!ep->e_lookahead)
10214887Schin 	{
10224887Schin 		ed_flush(ep);
10234887Schin 		ep->e_inmacro = 0;
10244887Schin 		/* The while is necessary for reads of partial multbyte chars */
1025*8462SApril.Chin@Sun.COM 		*ep->e_vi_insert = (mode==-2);
10264887Schin 		if((n=ed_read(ep,ep->e_fd,readin,-LOOKAHEAD,0)) > 0)
10274887Schin 			n = putstack(ep,readin,n,1);
1028*8462SApril.Chin@Sun.COM 		*ep->e_vi_insert = 0;
10294887Schin 	}
10304887Schin 	if(ep->e_lookahead)
10314887Schin 	{
10324887Schin 		/* check for possible key mapping */
10334887Schin 		if((c = ep->e_lbuf[--ep->e_lookahead]) < 0)
10344887Schin 		{
1035*8462SApril.Chin@Sun.COM 			if(mode<=0 && ep->sh->st.trap[SH_KEYTRAP])
10364887Schin 			{
10374887Schin 				n=1;
10384887Schin 				if((readin[0]= -c) == ESC)
10394887Schin 				{
10404887Schin 					while(1)
10414887Schin 					{
10424887Schin 						if(!ep->e_lookahead)
10434887Schin 						{
10444887Schin 							if((c=sfpkrd(ep->e_fd,readin+n,1,'\r',(mode?400L:-1L),0))>0)
10454887Schin 								putstack(ep,readin+n,c,1);
10464887Schin 						}
10474887Schin 						if(!ep->e_lookahead)
10484887Schin 							break;
10494887Schin 						if((c=ep->e_lbuf[--ep->e_lookahead])>=0)
10504887Schin 						{
10514887Schin 							ep->e_lookahead++;
10524887Schin 							break;
10534887Schin 						}
10544887Schin 						c = -c;
10554887Schin 						readin[n++] = c;
10564887Schin 						if(c>='0' && c<='9' && n>2)
10574887Schin 							continue;
10584887Schin 						if(n>2 || (c!= '['  &&  c!= 'O'))
10594887Schin 							break;
10604887Schin 					}
10614887Schin 				}
10624887Schin 				if(n=keytrap(ep,readin,n,LOOKAHEAD-n,mode))
10634887Schin 				{
10644887Schin 					putstack(ep,readin,n,0);
10654887Schin 					c = ep->e_lbuf[--ep->e_lookahead];
10664887Schin 				}
10674887Schin 				else
10684887Schin 					c = ed_getchar(ep,mode);
10694887Schin 			}
10704887Schin 			else
10714887Schin 				c = -c;
10724887Schin 		}
10734887Schin 		/*** map '\r' to '\n' ***/
10744887Schin 		if(c == '\r' && mode!=2)
10754887Schin 			c = '\n';
10764887Schin 		if(ep->e_tabcount && !(c=='\t'||c==ESC || c=='\\' || c=='=' || c==cntl('L') || isdigit(c)))
10774887Schin 			ep->e_tabcount = 0;
10784887Schin 	}
10794887Schin 	else
10804887Schin 		siglongjmp(ep->e_env,(n==0?UEOF:UINTR));
10814887Schin 	return(c);
10824887Schin }
10834887Schin 
10844887Schin void ed_ungetchar(Edit_t *ep,register int c)
10854887Schin {
10864887Schin 	if (ep->e_lookahead < LOOKAHEAD)
10874887Schin 		ep->e_lbuf[ep->e_lookahead++] = c;
10884887Schin 	return;
10894887Schin }
10904887Schin 
10914887Schin /*
10924887Schin  * put a character into the output buffer
10934887Schin  */
10944887Schin 
10954887Schin void	ed_putchar(register Edit_t *ep,register int c)
10964887Schin {
10974887Schin 	char buf[8];
10984887Schin 	register char *dp = ep->e_outptr;
10994887Schin 	register int i,size=1;
1100*8462SApril.Chin@Sun.COM 	if(!dp)
1101*8462SApril.Chin@Sun.COM 		return;
11024887Schin 	buf[0] = c;
11034887Schin #if SHOPT_MULTIBYTE
11044887Schin 	/* check for place holder */
11054887Schin 	if(c == MARKER)
11064887Schin 		return;
11074887Schin 	if((size = mbconv(buf, (wchar_t)c)) > 1)
11084887Schin 	{
11094887Schin 		for (i = 0; i < (size-1); i++)
11104887Schin 			*dp++ = buf[i];
11114887Schin 		c = buf[i];
11124887Schin 	}
11134887Schin 	else
11144887Schin 	{
11154887Schin 		buf[0] = c;
11164887Schin 		size = 1;
11174887Schin 	}
11184887Schin #endif	/* SHOPT_MULTIBYTE */
11194887Schin 	if (buf[0] == '_' && size==1)
11204887Schin 	{
11214887Schin 		*dp++ = ' ';
11224887Schin 		*dp++ = '\b';
11234887Schin 	}
11244887Schin 	*dp++ = c;
11254887Schin 	*dp = '\0';
11264887Schin 	if(dp >= ep->e_outlast)
11274887Schin 		ed_flush(ep);
11284887Schin 	else
11294887Schin 		ep->e_outptr = dp;
11304887Schin }
11314887Schin 
11324887Schin /*
11334887Schin  * returns the line and column corresponding to offset <off> in the physical buffer
11344887Schin  * if <cur> is non-zero and <= <off>, then correspodning <curpos> will start the search
11354887Schin  */
11364887Schin Edpos_t ed_curpos(Edit_t *ep,genchar *phys, int off, int cur, Edpos_t curpos)
11374887Schin {
11384887Schin 	register genchar *sp=phys;
11394887Schin 	register int c=1, col=ep->e_plen;
11404887Schin 	Edpos_t pos;
11414887Schin #if SHOPT_MULTIBYTE
11424887Schin 	char p[16];
11434887Schin #endif /* SHOPT_MULTIBYTE */
11444887Schin 	if(cur && off>=cur)
11454887Schin 	{
11464887Schin 		sp += cur;
11474887Schin 		off -= cur;
11484887Schin 		pos = curpos;
11494887Schin 		col = pos.col;
11504887Schin 	}
11514887Schin 	else
1152*8462SApril.Chin@Sun.COM 	{
11534887Schin 		pos.line = 0;
1154*8462SApril.Chin@Sun.COM 		while(col > ep->e_winsz)
1155*8462SApril.Chin@Sun.COM 		{
1156*8462SApril.Chin@Sun.COM 			pos.line++;
1157*8462SApril.Chin@Sun.COM 			col -= (ep->e_winsz+1);
1158*8462SApril.Chin@Sun.COM 		}
1159*8462SApril.Chin@Sun.COM 	}
11604887Schin 	while(off-->0)
11614887Schin 	{
11624887Schin 		if(c)
11634887Schin 			c = *sp++;
11644887Schin #if SHOPT_MULTIBYTE
11654887Schin 		if(c && (mbconv(p, (wchar_t)c))==1 && p[0]=='\n')
11664887Schin #else
11674887Schin 		if(c=='\n')
11684887Schin #endif /* SHOPT_MULTIBYTE */
11694887Schin 			col = 0;
11704887Schin 		else
11714887Schin 			col++;
11724887Schin 		if(col >  ep->e_winsz)
11734887Schin 			col = 0;
11744887Schin 		if(col==0)
11754887Schin 			pos.line++;
11764887Schin 	}
11774887Schin 	pos.col = col;
11784887Schin 	return(pos);
11794887Schin }
11804887Schin 
11814887Schin int ed_setcursor(register Edit_t *ep,genchar *physical,register int old,register int new,int first)
11824887Schin {
11834887Schin 	static int oldline;
11844887Schin 	register int delta;
1185*8462SApril.Chin@Sun.COM 	int clear = 0;
11864887Schin 	Edpos_t newpos;
11874887Schin 
11884887Schin 	delta = new - old;
1189*8462SApril.Chin@Sun.COM 	if(first < 0)
1190*8462SApril.Chin@Sun.COM 	{
1191*8462SApril.Chin@Sun.COM 		first = 0;
1192*8462SApril.Chin@Sun.COM 		clear = 1;
1193*8462SApril.Chin@Sun.COM 	}
1194*8462SApril.Chin@Sun.COM 	if( delta == 0  &&  !clear)
11954887Schin 		return(new);
11964887Schin 	if(ep->e_multiline)
11974887Schin 	{
11984887Schin 		ep->e_curpos = ed_curpos(ep, physical, old,0,ep->e_curpos);
1199*8462SApril.Chin@Sun.COM 		if(clear && old>=ep->e_peol && (clear=ep->e_winsz-ep->e_curpos.col)>0)
1200*8462SApril.Chin@Sun.COM 		{
1201*8462SApril.Chin@Sun.COM 			ed_nputchar(ep,clear,' ');
1202*8462SApril.Chin@Sun.COM 			ed_nputchar(ep,clear,'\b');
1203*8462SApril.Chin@Sun.COM 			return(new);
1204*8462SApril.Chin@Sun.COM 		}
12054887Schin 		newpos =     ed_curpos(ep, physical, new,old,ep->e_curpos);
12064887Schin 		if(ep->e_curpos.col==0 && ep->e_curpos.line>0 && oldline<ep->e_curpos.line && delta<0)
12074887Schin 			ed_putstring(ep,"\r\n");
12084887Schin 		oldline = newpos.line;
12094887Schin 		if(ep->e_curpos.line > newpos.line)
12104887Schin 		{
1211*8462SApril.Chin@Sun.COM 			int n,pline,plen=ep->e_plen;
12124887Schin 			for(;ep->e_curpos.line > newpos.line; ep->e_curpos.line--)
12134887Schin 				ed_putstring(ep,CURSOR_UP);
1214*8462SApril.Chin@Sun.COM 			pline = plen/(ep->e_winsz+1);
1215*8462SApril.Chin@Sun.COM 			if(newpos.line <= pline)
1216*8462SApril.Chin@Sun.COM 				plen -= pline*(ep->e_winsz+1);
1217*8462SApril.Chin@Sun.COM 			else
1218*8462SApril.Chin@Sun.COM 				plen = 0;
1219*8462SApril.Chin@Sun.COM 			if((n=plen- ep->e_curpos.col)>0)
12204887Schin 			{
12214887Schin 				ep->e_curpos.col += n;
12224887Schin 				ed_putchar(ep,'\r');
1223*8462SApril.Chin@Sun.COM 				if(!ep->e_crlf && pline==0)
12244887Schin 					ed_putstring(ep,ep->e_prompt);
12254887Schin 				else
12264887Schin 				{
1227*8462SApril.Chin@Sun.COM 					int m = ep->e_winsz+1-plen;
12284887Schin 					ed_putchar(ep,'\n');
1229*8462SApril.Chin@Sun.COM 					n = plen;
12304887Schin 					if(m < ed_genlen(physical))
12314887Schin 					{
12324887Schin 						while(physical[m] && n-->0)
12334887Schin 							ed_putchar(ep,physical[m++]);
12344887Schin 					}
1235*8462SApril.Chin@Sun.COM 					ed_nputchar(ep,n,' ');
12364887Schin 					ed_putstring(ep,CURSOR_UP);
12374887Schin 				}
12384887Schin 			}
12394887Schin 		}
12404887Schin 		else if(ep->e_curpos.line < newpos.line)
12414887Schin 		{
1242*8462SApril.Chin@Sun.COM 			ed_nputchar(ep, newpos.line-ep->e_curpos.line,'\n');
1243*8462SApril.Chin@Sun.COM 			ep->e_curpos.line = newpos.line;
12444887Schin 			ed_putchar(ep,'\r');
12454887Schin 			ep->e_curpos.col = 0;
12464887Schin 		}
12474887Schin 		delta = newpos.col - ep->e_curpos.col;
12484887Schin 		old   =  new - delta;
12494887Schin 	}
12504887Schin 	else
12514887Schin 		newpos.line=0;
12524887Schin 	if(delta<0)
12534887Schin 	{
1254*8462SApril.Chin@Sun.COM 		int bs= newpos.line && ep->e_plen>ep->e_winsz;
12554887Schin 		/*** move to left ***/
12564887Schin 		delta = -delta;
12574887Schin 		/*** attempt to optimize cursor movement ***/
1258*8462SApril.Chin@Sun.COM 		if(!ep->e_crlf || bs || (2*delta <= ((old-first)+(newpos.line?0:ep->e_plen))) )
12594887Schin 		{
1260*8462SApril.Chin@Sun.COM 			ed_nputchar(ep,delta,'\b');
1261*8462SApril.Chin@Sun.COM 			delta = 0;
12624887Schin 		}
12634887Schin 		else
12644887Schin 		{
12654887Schin 			if(newpos.line==0)
12664887Schin 				ed_putstring(ep,ep->e_prompt);
1267*8462SApril.Chin@Sun.COM 			else
1268*8462SApril.Chin@Sun.COM 			{
1269*8462SApril.Chin@Sun.COM 				first = 1+(newpos.line*ep->e_winsz - ep->e_plen);
1270*8462SApril.Chin@Sun.COM 				ed_putchar(ep,'\r');
1271*8462SApril.Chin@Sun.COM 			}
12724887Schin 			old = first;
12734887Schin 			delta = new-first;
12744887Schin 		}
12754887Schin 	}
12764887Schin 	while(delta-->0)
12774887Schin 		ed_putchar(ep,physical[old++]);
12784887Schin 	return(new);
12794887Schin }
12804887Schin 
12814887Schin /*
12824887Schin  * copy virtual to physical and return the index for cursor in physical buffer
12834887Schin  */
12844887Schin int ed_virt_to_phys(Edit_t *ep,genchar *virt,genchar *phys,int cur,int voff,int poff)
12854887Schin {
12864887Schin 	register genchar *sp = virt;
12874887Schin 	register genchar *dp = phys;
12884887Schin 	register int c;
12894887Schin 	genchar *curp = sp + cur;
12904887Schin 	genchar *dpmax = phys+MAXLINE;
12914887Schin 	int d, r;
12924887Schin 	sp += voff;
12934887Schin 	dp += poff;
12944887Schin 	for(r=poff;c= *sp;sp++)
12954887Schin 	{
12964887Schin 		if(curp == sp)
12974887Schin 			r = dp - phys;
12984887Schin #if SHOPT_MULTIBYTE
12994887Schin 		d = mbwidth((wchar_t)c);
13004887Schin 		if(d==1 && is_cntrl(c))
13014887Schin 			d = -1;
13024887Schin 		if(d>1)
13034887Schin 		{
13044887Schin 			/* multiple width character put in place holders */
13054887Schin 			*dp++ = c;
13064887Schin 			while(--d >0)
13074887Schin 				*dp++ = MARKER;
13084887Schin 			/* in vi mode the cursor is at the last character */
13094887Schin 			if(dp>=dpmax)
13104887Schin 				break;
13114887Schin 			continue;
13124887Schin 		}
13134887Schin 		else
13144887Schin #else
13154887Schin 		d = (is_cntrl(c)?-1:1);
13164887Schin #endif	/* SHOPT_MULTIBYTE */
13174887Schin 		if(d<0)
13184887Schin 		{
13194887Schin 			if(c=='\t')
13204887Schin 			{
13214887Schin 				c = dp-phys;
13224887Schin 				if(sh_isoption(SH_VI))
13234887Schin 					c += ep->e_plen;
13244887Schin 				c = TABSIZE - c%TABSIZE;
13254887Schin 				while(--c>0)
13264887Schin 					*dp++ = ' ';
13274887Schin 				c = ' ';
13284887Schin 			}
13294887Schin 			else
13304887Schin 			{
13314887Schin 				*dp++ = '^';
13324887Schin 				c = printchar(c);
13334887Schin 			}
13344887Schin 			/* in vi mode the cursor is at the last character */
13354887Schin 			if(curp == sp && sh_isoption(SH_VI))
13364887Schin 				r = dp - phys;
13374887Schin 		}
13384887Schin 		*dp++ = c;
13394887Schin 		if(dp>=dpmax)
13404887Schin 			break;
13414887Schin 	}
13424887Schin 	*dp = 0;
1343*8462SApril.Chin@Sun.COM 	ep->e_peol = dp-phys;
13444887Schin 	return(r);
13454887Schin }
13464887Schin 
13474887Schin #if SHOPT_MULTIBYTE
13484887Schin /*
13494887Schin  * convert external representation <src> to an array of genchars <dest>
13504887Schin  * <src> and <dest> can be the same
13514887Schin  * returns number of chars in dest
13524887Schin  */
13534887Schin 
13544887Schin int	ed_internal(const char *src, genchar *dest)
13554887Schin {
13564887Schin 	register const unsigned char *cp = (unsigned char *)src;
13574887Schin 	register int c;
13584887Schin 	register wchar_t *dp = (wchar_t*)dest;
13594887Schin 	if(dest == (genchar*)roundof(cp-(unsigned char*)0,sizeof(genchar)))
13604887Schin 	{
13614887Schin 		genchar buffer[MAXLINE];
13624887Schin 		c = ed_internal(src,buffer);
13634887Schin 		ed_gencpy((genchar*)dp,buffer);
13644887Schin 		return(c);
13654887Schin 	}
13664887Schin 	while(*cp)
13674887Schin 		*dp++ = mbchar(cp);
13684887Schin 	*dp = 0;
13694887Schin 	return(dp-(wchar_t*)dest);
13704887Schin }
13714887Schin 
13724887Schin /*
13734887Schin  * convert internal representation <src> into character array <dest>.
13744887Schin  * The <src> and <dest> may be the same.
13754887Schin  * returns number of chars in dest.
13764887Schin  */
13774887Schin 
13784887Schin int	ed_external(const genchar *src, char *dest)
13794887Schin {
13804887Schin 	register genchar wc;
13814887Schin 	register int c,size;
13824887Schin 	register char *dp = dest;
13834887Schin 	char *dpmax = dp+sizeof(genchar)*MAXLINE-2;
13844887Schin 	if((char*)src == dp)
13854887Schin 	{
13864887Schin 		char buffer[MAXLINE*sizeof(genchar)];
13874887Schin 		c = ed_external(src,buffer);
13884887Schin 
13894887Schin #ifdef _lib_wcscpy
13904887Schin 		wcscpy((wchar_t *)dest,(const wchar_t *)buffer);
13914887Schin #else
13924887Schin 		strcpy(dest,buffer);
13934887Schin #endif
13944887Schin 		return(c);
13954887Schin 	}
13964887Schin 	while((wc = *src++) && dp<dpmax)
13974887Schin 	{
13984887Schin 		if((size = mbconv(dp, wc)) < 0)
13994887Schin 		{
14004887Schin 			/* copy the character as is */
14014887Schin 			size = 1;
14024887Schin 			*dp = wc;
14034887Schin 		}
14044887Schin 		dp += size;
14054887Schin 	}
14064887Schin 	*dp = 0;
14074887Schin 	return(dp-dest);
14084887Schin }
14094887Schin 
14104887Schin /*
14114887Schin  * copy <sp> to <dp>
14124887Schin  */
14134887Schin 
14144887Schin void	ed_gencpy(genchar *dp,const genchar *sp)
14154887Schin {
14164887Schin 	dp = (genchar*)roundof((char*)dp-(char*)0,sizeof(genchar));
14174887Schin 	sp = (const genchar*)roundof((char*)sp-(char*)0,sizeof(genchar));
14184887Schin 	while(*dp++ = *sp++);
14194887Schin }
14204887Schin 
14214887Schin /*
14224887Schin  * copy at most <n> items from <sp> to <dp>
14234887Schin  */
14244887Schin 
14254887Schin void	ed_genncpy(register genchar *dp,register const genchar *sp, int n)
14264887Schin {
14274887Schin 	dp = (genchar*)roundof((char*)dp-(char*)0,sizeof(genchar));
14284887Schin 	sp = (const genchar*)roundof((char*)sp-(char*)0,sizeof(genchar));
14294887Schin 	while(n-->0 && (*dp++ = *sp++));
14304887Schin }
14314887Schin 
14324887Schin /*
14334887Schin  * find the string length of <str>
14344887Schin  */
14354887Schin 
14364887Schin int	ed_genlen(register const genchar *str)
14374887Schin {
14384887Schin 	register const genchar *sp = str;
14394887Schin 	sp = (const genchar*)roundof((char*)sp-(char*)0,sizeof(genchar));
14404887Schin 	while(*sp++);
14414887Schin 	return(sp-str-1);
14424887Schin }
14434887Schin #endif /* SHOPT_MULTIBYTE */
14444887Schin #endif /* SHOPT_ESH || SHOPT_VSH */
14454887Schin 
14464887Schin #ifdef future
14474887Schin /*
14484887Schin  * returns 1 when <n> bytes starting at <a> and <b> are equal
14494887Schin  */
14504887Schin static int compare(register const char *a,register const char *b,register int n)
14514887Schin {
14524887Schin 	while(n-->0)
14534887Schin 	{
14544887Schin 		if(*a++ != *b++)
14554887Schin 			return(0);
14564887Schin 	}
14574887Schin 	return(1);
14584887Schin }
14594887Schin #endif
14604887Schin 
14614887Schin #if SHOPT_OLDTERMIO
14624887Schin 
14634887Schin #   include	<sys/termio.h>
14644887Schin 
14654887Schin #ifndef ECHOCTL
14664887Schin #   define ECHOCTL	0
14674887Schin #endif /* !ECHOCTL */
14684887Schin #define ott	ep->e_ott
14694887Schin 
14704887Schin /*
14714887Schin  * For backward compatibility only
14724887Schin  * This version will use termios when possible, otherwise termio
14734887Schin  */
14744887Schin 
1475*8462SApril.Chin@Sun.COM int tcgetattr(int fd, struct termios *tt)
14764887Schin {
14774887Schin 	register Edit_t *ep = (Edit_t*)(sh_getinterp()->ed_context);
14784887Schin 	register int r,i;
14794887Schin 	ep->e_tcgeta = 0;
14804887Schin 	ep->e_echoctl = (ECHOCTL!=0);
14814887Schin 	if((r=ioctl(fd,TCGETS,tt))>=0 ||  errno!=EINVAL)
14824887Schin 		return(r);
14834887Schin 	if((r=ioctl(fd,TCGETA,&ott)) >= 0)
14844887Schin 	{
14854887Schin 		tt->c_lflag = ott.c_lflag;
14864887Schin 		tt->c_oflag = ott.c_oflag;
14874887Schin 		tt->c_iflag = ott.c_iflag;
14884887Schin 		tt->c_cflag = ott.c_cflag;
14894887Schin 		for(i=0; i<NCC; i++)
14904887Schin 			tt->c_cc[i] = ott.c_cc[i];
14914887Schin 		ep->e_tcgeta++;
14924887Schin 		ep->e_echoctl = 0;
14934887Schin 	}
14944887Schin 	return(r);
14954887Schin }
14964887Schin 
1497*8462SApril.Chin@Sun.COM int tcsetattr(int fd,int mode,struct termios *tt)
14984887Schin {
14994887Schin 	register Edit_t *ep = (Edit_t*)(sh_getinterp()->ed_context);
15004887Schin 	register int r;
15014887Schin 	if(ep->e_tcgeta)
15024887Schin 	{
15034887Schin 		register int i;
15044887Schin 		ott.c_lflag = tt->c_lflag;
15054887Schin 		ott.c_oflag = tt->c_oflag;
15064887Schin 		ott.c_iflag = tt->c_iflag;
15074887Schin 		ott.c_cflag = tt->c_cflag;
15084887Schin 		for(i=0; i<NCC; i++)
15094887Schin 			ott.c_cc[i] = tt->c_cc[i];
15104887Schin 		if(tt->c_lflag&ECHOCTL)
15114887Schin 		{
15124887Schin 			ott.c_lflag &= ~(ECHOCTL|IEXTEN);
15134887Schin 			ott.c_iflag &= ~(IGNCR|ICRNL);
15144887Schin 			ott.c_iflag |= INLCR;
15154887Schin 			ott.c_cc[VEOF]= ESC;  /* ESC -> eof char */
15164887Schin 			ott.c_cc[VEOL] = '\r'; /* CR -> eol char */
15174887Schin 			ott.c_cc[VEOL2] = tt->c_cc[VEOF]; /* EOF -> eol char */
15184887Schin 		}
15194887Schin 		switch(mode)
15204887Schin 		{
15214887Schin 			case TCSANOW:
15224887Schin 				mode = TCSETA;
15234887Schin 				break;
15244887Schin 			case TCSADRAIN:
15254887Schin 				mode = TCSETAW;
15264887Schin 				break;
15274887Schin 			case TCSAFLUSH:
15284887Schin 				mode = TCSETAF;
15294887Schin 		}
15304887Schin 		return(ioctl(fd,mode,&ott));
15314887Schin 	}
15324887Schin 	return(ioctl(fd,mode,tt));
15334887Schin }
15344887Schin #endif /* SHOPT_OLDTERMIO */
15354887Schin 
15364887Schin #if KSHELL
15374887Schin /*
15384887Schin  * Execute keyboard trap on given buffer <inbuff> of given size <isize>
15394887Schin  * <mode> < 0 for vi insert mode
15404887Schin  */
15414887Schin static int keytrap(Edit_t *ep,char *inbuff,register int insize, int bufsize, int mode)
15424887Schin {
15434887Schin 	register char *cp;
15444887Schin 	int savexit;
1545*8462SApril.Chin@Sun.COM 	Shell_t *shp = ep->sh;
15464887Schin #if SHOPT_MULTIBYTE
15474887Schin 	char buff[MAXLINE];
15484887Schin 	ed_external(ep->e_inbuf,cp=buff);
15494887Schin #else
15504887Schin 	cp = ep->e_inbuf;
15514887Schin #endif /* SHOPT_MULTIBYTE */
15524887Schin 	inbuff[insize] = 0;
15534887Schin 	ep->e_col = ep->e_cur;
15544887Schin 	if(mode== -2)
15554887Schin 	{
15564887Schin 		ep->e_col++;
15574887Schin 		*ep->e_vi_insert = ESC;
15584887Schin 	}
15594887Schin 	else
15604887Schin 		*ep->e_vi_insert = 0;
15614887Schin 	nv_putval(ED_CHRNOD,inbuff,NV_NOFREE);
15624887Schin 	nv_putval(ED_COLNOD,(char*)&ep->e_col,NV_NOFREE|NV_INTEGER);
15634887Schin 	nv_putval(ED_TXTNOD,(char*)cp,NV_NOFREE);
15644887Schin 	nv_putval(ED_MODENOD,ep->e_vi_insert,NV_NOFREE);
1565*8462SApril.Chin@Sun.COM 	savexit = shp->savexit;
1566*8462SApril.Chin@Sun.COM 	sh_trap(shp->st.trap[SH_KEYTRAP],0);
1567*8462SApril.Chin@Sun.COM 	shp->savexit = savexit;
15684887Schin 	if((cp = nv_getval(ED_CHRNOD)) == inbuff)
15694887Schin 		nv_unset(ED_CHRNOD);
1570*8462SApril.Chin@Sun.COM 	else if(bufsize>0)
15714887Schin 	{
15724887Schin 		strncpy(inbuff,cp,bufsize);
1573*8462SApril.Chin@Sun.COM 		inbuff[bufsize-1]='\0';
15744887Schin 		insize = strlen(inbuff);
15754887Schin 	}
1576*8462SApril.Chin@Sun.COM 	else
1577*8462SApril.Chin@Sun.COM 		insize = 0;
15784887Schin 	nv_unset(ED_TXTNOD);
15794887Schin 	return(insize);
15804887Schin }
15814887Schin #endif /* KSHELL */
15824887Schin 
15834887Schin void	*ed_open(Shell_t *shp)
15844887Schin {
15854887Schin 	Edit_t *ed = newof(0,Edit_t,1,0);
15864887Schin 	ed->sh = shp;
15874887Schin 	strcpy(ed->e_macro,"_??");
15884887Schin 	return((void*)ed);
15894887Schin }
1590