xref: /titanic_50/usr/src/lib/libshell/common/edit/edit.c (revision 3e14f97f673e8a630f076077de35afdd43dc1587)
1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin *                                                                      *
3da2e3ebdSchin *               This software is part of the ast package               *
4*3e14f97fSRoger A. Faulkner *          Copyright (c) 1982-2010 AT&T Intellectual Property          *
5da2e3ebdSchin *                      and is licensed under the                       *
6da2e3ebdSchin *                  Common Public License, Version 1.0                  *
77c2fbfb3SApril Chin *                    by AT&T Intellectual Property                     *
8da2e3ebdSchin *                                                                      *
9da2e3ebdSchin *                A copy of the License is available at                 *
10da2e3ebdSchin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11da2e3ebdSchin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12da2e3ebdSchin *                                                                      *
13da2e3ebdSchin *              Information and Software Systems Research               *
14da2e3ebdSchin *                            AT&T Research                             *
15da2e3ebdSchin *                           Florham Park NJ                            *
16da2e3ebdSchin *                                                                      *
17da2e3ebdSchin *                  David Korn <dgk@research.att.com>                   *
18da2e3ebdSchin *                                                                      *
19da2e3ebdSchin ***********************************************************************/
20da2e3ebdSchin #pragma prototyped
21da2e3ebdSchin /*
22da2e3ebdSchin  *  edit.c - common routines for vi and emacs one line editors in shell
23da2e3ebdSchin  *
24da2e3ebdSchin  *   David Korn				P.D. Sullivan
25da2e3ebdSchin  *   AT&T Labs
26da2e3ebdSchin  *
27da2e3ebdSchin  *   Coded April 1983.
28da2e3ebdSchin  */
29da2e3ebdSchin 
30da2e3ebdSchin #include	<ast.h>
31da2e3ebdSchin #include	<errno.h>
32da2e3ebdSchin #include	<ccode.h>
33da2e3ebdSchin #include	"FEATURE/options"
34da2e3ebdSchin #include	"FEATURE/time"
35da2e3ebdSchin #include	"FEATURE/cmds"
36da2e3ebdSchin #ifdef _hdr_utime
37da2e3ebdSchin #   include	<utime.h>
38da2e3ebdSchin #   include	<ls.h>
39da2e3ebdSchin #endif
40da2e3ebdSchin 
41da2e3ebdSchin #if KSHELL
42da2e3ebdSchin #   include	"defs.h"
43da2e3ebdSchin #   include	"variables.h"
44da2e3ebdSchin #else
4534f9b3eeSRoland Mainz #   include	<ctype.h>
46da2e3ebdSchin     extern char ed_errbuf[];
47da2e3ebdSchin     char e_version[] = "\n@(#)$Id: Editlib version 1993-12-28 r $\0\n";
48da2e3ebdSchin #endif	/* KSHELL */
49da2e3ebdSchin #include	"io.h"
50da2e3ebdSchin #include	"terminal.h"
51da2e3ebdSchin #include	"history.h"
52da2e3ebdSchin #include	"edit.h"
53da2e3ebdSchin 
54da2e3ebdSchin static char CURSOR_UP[20] = { ESC, '[', 'A', 0 };
55da2e3ebdSchin 
567c2fbfb3SApril Chin 
577c2fbfb3SApril Chin 
58da2e3ebdSchin #if SHOPT_MULTIBYTE
59da2e3ebdSchin #   define is_cntrl(c)	((c<=STRIP) && iscntrl(c))
60da2e3ebdSchin #   define is_print(c)	((c&~STRIP) || isprint(c))
61da2e3ebdSchin #else
62da2e3ebdSchin #   define is_cntrl(c)	iscntrl(c)
63da2e3ebdSchin #   define is_print(c)	isprint(c)
64da2e3ebdSchin #endif
65da2e3ebdSchin 
66da2e3ebdSchin #if	(CC_NATIVE == CC_ASCII)
67da2e3ebdSchin #   define printchar(c)	((c) ^ ('A'-cntl('A')))
68da2e3ebdSchin #else
printchar(int c)69da2e3ebdSchin     static int printchar(int c)
70da2e3ebdSchin     {
71da2e3ebdSchin 	switch(c)
72da2e3ebdSchin 	{
73da2e3ebdSchin 
74da2e3ebdSchin 	    case cntl('A'): return('A');
75da2e3ebdSchin 	    case cntl('B'): return('B');
76da2e3ebdSchin 	    case cntl('C'): return('C');
77da2e3ebdSchin 	    case cntl('D'): return('D');
78da2e3ebdSchin 	    case cntl('E'): return('E');
79da2e3ebdSchin 	    case cntl('F'): return('F');
80da2e3ebdSchin 	    case cntl('G'): return('G');
81da2e3ebdSchin 	    case cntl('H'): return('H');
82da2e3ebdSchin 	    case cntl('I'): return('I');
83da2e3ebdSchin 	    case cntl('J'): return('J');
84da2e3ebdSchin 	    case cntl('K'): return('K');
85da2e3ebdSchin 	    case cntl('L'): return('L');
86da2e3ebdSchin 	    case cntl('M'): return('M');
87da2e3ebdSchin 	    case cntl('N'): return('N');
88da2e3ebdSchin 	    case cntl('O'): return('O');
89da2e3ebdSchin 	    case cntl('P'): return('P');
90da2e3ebdSchin 	    case cntl('Q'): return('Q');
91da2e3ebdSchin 	    case cntl('R'): return('R');
92da2e3ebdSchin 	    case cntl('S'): return('S');
93da2e3ebdSchin 	    case cntl('T'): return('T');
94da2e3ebdSchin 	    case cntl('U'): return('U');
95da2e3ebdSchin 	    case cntl('V'): return('V');
96da2e3ebdSchin 	    case cntl('W'): return('W');
97da2e3ebdSchin 	    case cntl('X'): return('X');
98da2e3ebdSchin 	    case cntl('Y'): return('Y');
99da2e3ebdSchin 	    case cntl('Z'): return('Z');
100da2e3ebdSchin 	    case cntl(']'): return(']');
101da2e3ebdSchin 	    case cntl('['): return('[');
102da2e3ebdSchin 	}
103da2e3ebdSchin 	return('?');
104da2e3ebdSchin     }
105da2e3ebdSchin #endif
106da2e3ebdSchin #define MINWINDOW	15	/* minimum width window */
107da2e3ebdSchin #define DFLTWINDOW	80	/* default window width */
108da2e3ebdSchin #define RAWMODE		1
109da2e3ebdSchin #define ALTMODE		2
110da2e3ebdSchin #define ECHOMODE	3
111da2e3ebdSchin #define	SYSERR	-1
112da2e3ebdSchin 
113da2e3ebdSchin #if SHOPT_OLDTERMIO
114da2e3ebdSchin #   undef tcgetattr
115da2e3ebdSchin #   undef tcsetattr
116da2e3ebdSchin #endif /* SHOPT_OLDTERMIO */
117da2e3ebdSchin 
118da2e3ebdSchin #ifdef RT
119da2e3ebdSchin #   define VENIX 1
120da2e3ebdSchin #endif	/* RT */
121da2e3ebdSchin 
122da2e3ebdSchin 
123da2e3ebdSchin #ifdef _hdr_sgtty
124da2e3ebdSchin #   ifdef TIOCGETP
125da2e3ebdSchin 	static int l_mask;
126da2e3ebdSchin 	static struct tchars l_ttychars;
127da2e3ebdSchin 	static struct ltchars l_chars;
128da2e3ebdSchin 	static  char  l_changed;	/* set if mode bits changed */
129da2e3ebdSchin #	define L_CHARS	4
130da2e3ebdSchin #	define T_CHARS	2
131da2e3ebdSchin #	define L_MASK	1
132da2e3ebdSchin #   endif /* TIOCGETP */
133da2e3ebdSchin #endif /* _hdr_sgtty */
134da2e3ebdSchin 
135da2e3ebdSchin #if KSHELL
136da2e3ebdSchin      static int keytrap(Edit_t *,char*, int, int, int);
137da2e3ebdSchin #else
138da2e3ebdSchin      Edit_t editb;
139da2e3ebdSchin #endif	/* KSHELL */
140da2e3ebdSchin 
141da2e3ebdSchin 
142da2e3ebdSchin #ifndef _POSIX_DISABLE
143da2e3ebdSchin #   define _POSIX_DISABLE	0
144da2e3ebdSchin #endif
145da2e3ebdSchin 
146da2e3ebdSchin #ifdef future
147da2e3ebdSchin     static int compare(const char*, const char*, int);
148da2e3ebdSchin #endif  /* future */
149da2e3ebdSchin #if SHOPT_VSH || SHOPT_ESH
150da2e3ebdSchin #   define ttyparm	(ep->e_ttyparm)
151da2e3ebdSchin #   define nttyparm	(ep->e_nttyparm)
152da2e3ebdSchin     static const char bellchr[] = "\a";	/* bell char */
153da2e3ebdSchin #endif /* SHOPT_VSH || SHOPT_ESH */
154da2e3ebdSchin 
155da2e3ebdSchin 
156da2e3ebdSchin /*
157da2e3ebdSchin  * This routine returns true if fd refers to a terminal
158da2e3ebdSchin  * This should be equivalent to isatty
159da2e3ebdSchin  */
tty_check(int fd)160da2e3ebdSchin int tty_check(int fd)
161da2e3ebdSchin {
162da2e3ebdSchin 	register Edit_t *ep = (Edit_t*)(sh_getinterp()->ed_context);
163da2e3ebdSchin 	struct termios tty;
164da2e3ebdSchin 	ep->e_savefd = -1;
165da2e3ebdSchin 	return(tty_get(fd,&tty)==0);
166da2e3ebdSchin }
167da2e3ebdSchin 
168da2e3ebdSchin /*
169da2e3ebdSchin  * Get the current terminal attributes
170da2e3ebdSchin  * This routine remembers the attributes and just returns them if it
171da2e3ebdSchin  *   is called again without an intervening tty_set()
172da2e3ebdSchin  */
173da2e3ebdSchin 
tty_get(register int fd,register struct termios * tty)174da2e3ebdSchin int tty_get(register int fd, register struct termios *tty)
175da2e3ebdSchin {
176da2e3ebdSchin 	register Edit_t *ep = (Edit_t*)(sh_getinterp()->ed_context);
177da2e3ebdSchin 	if(fd == ep->e_savefd)
178da2e3ebdSchin 		*tty = ep->e_savetty;
179da2e3ebdSchin 	else
180da2e3ebdSchin 	{
181da2e3ebdSchin 		while(tcgetattr(fd,tty) == SYSERR)
182da2e3ebdSchin 		{
183da2e3ebdSchin 			if(errno !=EINTR)
184da2e3ebdSchin 				return(SYSERR);
185da2e3ebdSchin 			errno = 0;
186da2e3ebdSchin 		}
187da2e3ebdSchin 		/* save terminal settings if in cannonical state */
188da2e3ebdSchin 		if(ep->e_raw==0)
189da2e3ebdSchin 		{
190da2e3ebdSchin 			ep->e_savetty = *tty;
191da2e3ebdSchin 			ep->e_savefd = fd;
192da2e3ebdSchin 		}
193da2e3ebdSchin 	}
194da2e3ebdSchin 	return(0);
195da2e3ebdSchin }
196da2e3ebdSchin 
197da2e3ebdSchin /*
198da2e3ebdSchin  * Set the terminal attributes
199da2e3ebdSchin  * If fd<0, then current attributes are invalidated
200da2e3ebdSchin  */
201da2e3ebdSchin 
tty_set(int fd,int action,struct termios * tty)202da2e3ebdSchin int tty_set(int fd, int action, struct termios *tty)
203da2e3ebdSchin {
204da2e3ebdSchin 	register Edit_t *ep = (Edit_t*)(sh_getinterp()->ed_context);
205da2e3ebdSchin 	if(fd >=0)
206da2e3ebdSchin 	{
207da2e3ebdSchin #ifdef future
208da2e3ebdSchin 		if(ep->e_savefd>=0 && compare(&ep->e_savetty,tty,sizeof(struct termios)))
209da2e3ebdSchin 			return(0);
210da2e3ebdSchin #endif
211da2e3ebdSchin 		while(tcsetattr(fd, action, tty) == SYSERR)
212da2e3ebdSchin 		{
213da2e3ebdSchin 			if(errno !=EINTR)
214da2e3ebdSchin 				return(SYSERR);
215da2e3ebdSchin 			errno = 0;
216da2e3ebdSchin 		}
217da2e3ebdSchin 		ep->e_savetty = *tty;
218da2e3ebdSchin 	}
219da2e3ebdSchin 	ep->e_savefd = fd;
220da2e3ebdSchin 	return(0);
221da2e3ebdSchin }
222da2e3ebdSchin 
223da2e3ebdSchin #if SHOPT_ESH || SHOPT_VSH
224da2e3ebdSchin /*{	TTY_COOKED( fd )
225da2e3ebdSchin  *
226da2e3ebdSchin  *	This routine will set the tty in cooked mode.
227da2e3ebdSchin  *	It is also called by error.done().
228da2e3ebdSchin  *
229da2e3ebdSchin }*/
230da2e3ebdSchin 
tty_cooked(register int fd)231da2e3ebdSchin void tty_cooked(register int fd)
232da2e3ebdSchin {
233da2e3ebdSchin 	register Edit_t *ep = (Edit_t*)(sh_getinterp()->ed_context);
234da2e3ebdSchin 	if(ep->e_raw==0)
235da2e3ebdSchin 		return;
236da2e3ebdSchin 	if(fd < 0)
237da2e3ebdSchin 		fd = ep->e_savefd;
238da2e3ebdSchin #ifdef L_MASK
239da2e3ebdSchin 	/* restore flags */
240da2e3ebdSchin 	if(l_changed&L_MASK)
241da2e3ebdSchin 		ioctl(fd,TIOCLSET,&l_mask);
242da2e3ebdSchin 	if(l_changed&T_CHARS)
243da2e3ebdSchin 		/* restore alternate break character */
244da2e3ebdSchin 		ioctl(fd,TIOCSETC,&l_ttychars);
245da2e3ebdSchin 	if(l_changed&L_CHARS)
246da2e3ebdSchin 		/* restore alternate break character */
247da2e3ebdSchin 		ioctl(fd,TIOCSLTC,&l_chars);
248da2e3ebdSchin 	l_changed = 0;
249da2e3ebdSchin #endif	/* L_MASK */
250da2e3ebdSchin 	/*** don't do tty_set unless ttyparm has valid data ***/
251da2e3ebdSchin 	if(tty_set(fd, TCSANOW, &ttyparm) == SYSERR)
252da2e3ebdSchin 		return;
253da2e3ebdSchin 	ep->e_raw = 0;
254da2e3ebdSchin 	return;
255da2e3ebdSchin }
256da2e3ebdSchin 
257da2e3ebdSchin /*{	TTY_RAW( fd )
258da2e3ebdSchin  *
259da2e3ebdSchin  *	This routine will set the tty in raw mode.
260da2e3ebdSchin  *
261da2e3ebdSchin }*/
262da2e3ebdSchin 
tty_raw(register int fd,int echomode)263da2e3ebdSchin int tty_raw(register int fd, int echomode)
264da2e3ebdSchin {
265da2e3ebdSchin 	int echo = echomode;
266da2e3ebdSchin #ifdef L_MASK
267da2e3ebdSchin 	struct ltchars lchars;
268da2e3ebdSchin #endif	/* L_MASK */
269da2e3ebdSchin 	register Edit_t *ep = (Edit_t*)(sh_getinterp()->ed_context);
270da2e3ebdSchin 	if(ep->e_raw==RAWMODE)
271da2e3ebdSchin 		return(echo?-1:0);
272da2e3ebdSchin 	else if(ep->e_raw==ECHOMODE)
273da2e3ebdSchin 		return(echo?0:-1);
274da2e3ebdSchin #if !SHOPT_RAWONLY
275da2e3ebdSchin 	if(ep->e_raw != ALTMODE)
276da2e3ebdSchin #endif /* SHOPT_RAWONLY */
277da2e3ebdSchin 	{
278da2e3ebdSchin 		if(tty_get(fd,&ttyparm) == SYSERR)
279da2e3ebdSchin 			return(-1);
280da2e3ebdSchin 	}
281da2e3ebdSchin #if  L_MASK || VENIX
282da2e3ebdSchin 	if(ttyparm.sg_flags&LCASE)
283da2e3ebdSchin 		return(-1);
284da2e3ebdSchin 	if(!(ttyparm.sg_flags&ECHO))
285da2e3ebdSchin 	{
286da2e3ebdSchin 		if(!echomode)
287da2e3ebdSchin 			return(-1);
288da2e3ebdSchin 		echo = 0;
289da2e3ebdSchin 	}
290da2e3ebdSchin 	nttyparm = ttyparm;
291da2e3ebdSchin 	if(!echo)
292da2e3ebdSchin 		nttyparm.sg_flags &= ~(ECHO | TBDELAY);
293da2e3ebdSchin #   ifdef CBREAK
294da2e3ebdSchin 	nttyparm.sg_flags |= CBREAK;
295da2e3ebdSchin #   else
296da2e3ebdSchin 	nttyparm.sg_flags |= RAW;
297da2e3ebdSchin #   endif /* CBREAK */
298da2e3ebdSchin 	ep->e_erase = ttyparm.sg_erase;
299da2e3ebdSchin 	ep->e_kill = ttyparm.sg_kill;
300da2e3ebdSchin 	ep->e_eof = cntl('D');
301da2e3ebdSchin 	ep->e_werase = cntl('W');
302da2e3ebdSchin 	ep->e_lnext = cntl('V');
303da2e3ebdSchin 	if( tty_set(fd, TCSADRAIN, &nttyparm) == SYSERR )
304da2e3ebdSchin 		return(-1);
305da2e3ebdSchin 	ep->e_ttyspeed = (ttyparm.sg_ospeed>=B1200?FAST:SLOW);
306da2e3ebdSchin #   ifdef TIOCGLTC
307da2e3ebdSchin 	/* try to remove effect of ^V  and ^Y and ^O */
308da2e3ebdSchin 	if(ioctl(fd,TIOCGLTC,&l_chars) != SYSERR)
309da2e3ebdSchin 	{
310da2e3ebdSchin 		lchars = l_chars;
311da2e3ebdSchin 		lchars.t_lnextc = -1;
312da2e3ebdSchin 		lchars.t_flushc = -1;
313da2e3ebdSchin 		lchars.t_dsuspc = -1;	/* no delayed stop process signal */
314da2e3ebdSchin 		if(ioctl(fd,TIOCSLTC,&lchars) != SYSERR)
315da2e3ebdSchin 			l_changed |= L_CHARS;
316da2e3ebdSchin 	}
317da2e3ebdSchin #   endif	/* TIOCGLTC */
318da2e3ebdSchin #else
319da2e3ebdSchin 	if (!(ttyparm.c_lflag & ECHO ))
320da2e3ebdSchin 	{
321da2e3ebdSchin 		if(!echomode)
322da2e3ebdSchin 			return(-1);
323da2e3ebdSchin 		echo = 0;
324da2e3ebdSchin 	}
325da2e3ebdSchin #   ifdef FLUSHO
326da2e3ebdSchin 	ttyparm.c_lflag &= ~FLUSHO;
327da2e3ebdSchin #   endif /* FLUSHO */
328da2e3ebdSchin 	nttyparm = ttyparm;
329da2e3ebdSchin #  ifndef u370
330da2e3ebdSchin 	nttyparm.c_iflag &= ~(IGNPAR|PARMRK|INLCR|IGNCR|ICRNL);
331da2e3ebdSchin 	nttyparm.c_iflag |= BRKINT;
332da2e3ebdSchin #   else
333da2e3ebdSchin 	nttyparm.c_iflag &=
334da2e3ebdSchin 			~(IGNBRK|PARMRK|INLCR|IGNCR|ICRNL|INPCK);
335da2e3ebdSchin 	nttyparm.c_iflag |= (BRKINT|IGNPAR);
336da2e3ebdSchin #   endif	/* u370 */
337da2e3ebdSchin 	if(echo)
338da2e3ebdSchin 		nttyparm.c_lflag &= ~ICANON;
339da2e3ebdSchin 	else
340da2e3ebdSchin 		nttyparm.c_lflag &= ~(ICANON|ECHO|ECHOK);
341da2e3ebdSchin 	nttyparm.c_cc[VTIME] = 0;
342da2e3ebdSchin 	nttyparm.c_cc[VMIN] = 1;
343da2e3ebdSchin #   ifdef VREPRINT
344da2e3ebdSchin 	nttyparm.c_cc[VREPRINT] = _POSIX_DISABLE;
345da2e3ebdSchin #   endif /* VREPRINT */
346da2e3ebdSchin #   ifdef VDISCARD
347da2e3ebdSchin 	nttyparm.c_cc[VDISCARD] = _POSIX_DISABLE;
348da2e3ebdSchin #   endif /* VDISCARD */
349da2e3ebdSchin #   ifdef VDSUSP
350da2e3ebdSchin 	nttyparm.c_cc[VDSUSP] = _POSIX_DISABLE;
351da2e3ebdSchin #   endif /* VDSUSP */
352da2e3ebdSchin #   ifdef VWERASE
353da2e3ebdSchin 	if(ttyparm.c_cc[VWERASE] == _POSIX_DISABLE)
354da2e3ebdSchin 		ep->e_werase = cntl('W');
355da2e3ebdSchin 	else
356da2e3ebdSchin 		ep->e_werase = nttyparm.c_cc[VWERASE];
357da2e3ebdSchin 	nttyparm.c_cc[VWERASE] = _POSIX_DISABLE;
358da2e3ebdSchin #   else
359da2e3ebdSchin 	    ep->e_werase = cntl('W');
360da2e3ebdSchin #   endif /* VWERASE */
361da2e3ebdSchin #   ifdef VLNEXT
362da2e3ebdSchin 	if(ttyparm.c_cc[VLNEXT] == _POSIX_DISABLE )
363da2e3ebdSchin 		ep->e_lnext = cntl('V');
364da2e3ebdSchin 	else
365da2e3ebdSchin 		ep->e_lnext = nttyparm.c_cc[VLNEXT];
366da2e3ebdSchin 	nttyparm.c_cc[VLNEXT] = _POSIX_DISABLE;
367da2e3ebdSchin #   else
368da2e3ebdSchin 	ep->e_lnext = cntl('V');
369da2e3ebdSchin #   endif /* VLNEXT */
370da2e3ebdSchin 	ep->e_eof = ttyparm.c_cc[VEOF];
371da2e3ebdSchin 	ep->e_erase = ttyparm.c_cc[VERASE];
372da2e3ebdSchin 	ep->e_kill = ttyparm.c_cc[VKILL];
373da2e3ebdSchin 	if( tty_set(fd, TCSADRAIN, &nttyparm) == SYSERR )
374da2e3ebdSchin 		return(-1);
375da2e3ebdSchin 	ep->e_ttyspeed = (cfgetospeed(&ttyparm)>=B1200?FAST:SLOW);
376da2e3ebdSchin #endif
377da2e3ebdSchin 	ep->e_raw = (echomode?ECHOMODE:RAWMODE);
378da2e3ebdSchin 	return(0);
379da2e3ebdSchin }
380da2e3ebdSchin 
381da2e3ebdSchin #if !SHOPT_RAWONLY
382da2e3ebdSchin 
383da2e3ebdSchin /*
384da2e3ebdSchin  *
385da2e3ebdSchin  *	Get tty parameters and make ESC and '\r' wakeup characters.
386da2e3ebdSchin  *
387da2e3ebdSchin  */
388da2e3ebdSchin 
389da2e3ebdSchin #   ifdef TIOCGETC
tty_alt(register int fd)390da2e3ebdSchin int tty_alt(register int fd)
391da2e3ebdSchin {
392da2e3ebdSchin 	register Edit_t *ep = (Edit_t*)(sh_getinterp()->ed_context);
393da2e3ebdSchin 	int mask;
394da2e3ebdSchin 	struct tchars ttychars;
395da2e3ebdSchin 	switch(ep->e_raw)
396da2e3ebdSchin 	{
397da2e3ebdSchin 	    case ECHOMODE:
398da2e3ebdSchin 		return(-1);
399da2e3ebdSchin 	    case ALTMODE:
400da2e3ebdSchin 		return(0);
401da2e3ebdSchin 	    case RAWMODE:
402da2e3ebdSchin 		tty_cooked(fd);
403da2e3ebdSchin 	}
404da2e3ebdSchin 	l_changed = 0;
405da2e3ebdSchin 	if( ep->e_ttyspeed == 0)
406da2e3ebdSchin 	{
407da2e3ebdSchin 		if((tty_get(fd,&ttyparm) != SYSERR))
408da2e3ebdSchin 			ep->e_ttyspeed = (ttyparm.sg_ospeed>=B1200?FAST:SLOW);
409da2e3ebdSchin 		ep->e_raw = ALTMODE;
410da2e3ebdSchin 	}
411da2e3ebdSchin 	if(ioctl(fd,TIOCGETC,&l_ttychars) == SYSERR)
412da2e3ebdSchin 		return(-1);
413da2e3ebdSchin 	if(ioctl(fd,TIOCLGET,&l_mask)==SYSERR)
414da2e3ebdSchin 		return(-1);
415da2e3ebdSchin 	ttychars = l_ttychars;
416da2e3ebdSchin 	mask =  LCRTBS|LCRTERA|LCTLECH|LPENDIN|LCRTKIL;
417da2e3ebdSchin 	if((l_mask|mask) != l_mask)
418da2e3ebdSchin 		l_changed = L_MASK;
419da2e3ebdSchin 	if(ioctl(fd,TIOCLBIS,&mask)==SYSERR)
420da2e3ebdSchin 		return(-1);
421da2e3ebdSchin 	if(ttychars.t_brkc!=ESC)
422da2e3ebdSchin 	{
423da2e3ebdSchin 		ttychars.t_brkc = ESC;
424da2e3ebdSchin 		l_changed |= T_CHARS;
425da2e3ebdSchin 		if(ioctl(fd,TIOCSETC,&ttychars) == SYSERR)
426da2e3ebdSchin 			return(-1);
427da2e3ebdSchin 	}
428da2e3ebdSchin 	return(0);
429da2e3ebdSchin }
430da2e3ebdSchin #   else
431da2e3ebdSchin #	ifndef PENDIN
432da2e3ebdSchin #	    define PENDIN	0
433da2e3ebdSchin #	endif /* PENDIN */
434da2e3ebdSchin #	ifndef IEXTEN
435da2e3ebdSchin #	    define IEXTEN	0
436da2e3ebdSchin #	endif /* IEXTEN */
437da2e3ebdSchin 
tty_alt(register int fd)438da2e3ebdSchin int tty_alt(register int fd)
439da2e3ebdSchin {
440da2e3ebdSchin 	register Edit_t *ep = (Edit_t*)(sh_getinterp()->ed_context);
441da2e3ebdSchin 	switch(ep->e_raw)
442da2e3ebdSchin 	{
443da2e3ebdSchin 	    case ECHOMODE:
444da2e3ebdSchin 		return(-1);
445da2e3ebdSchin 	    case ALTMODE:
446da2e3ebdSchin 		return(0);
447da2e3ebdSchin 	    case RAWMODE:
448da2e3ebdSchin 		tty_cooked(fd);
449da2e3ebdSchin 	}
450da2e3ebdSchin 	if((tty_get(fd, &ttyparm)==SYSERR) || (!(ttyparm.c_lflag&ECHO)))
451da2e3ebdSchin 		return(-1);
452da2e3ebdSchin #	ifdef FLUSHO
453da2e3ebdSchin 	    ttyparm.c_lflag &= ~FLUSHO;
454da2e3ebdSchin #	endif /* FLUSHO */
455da2e3ebdSchin 	nttyparm = ttyparm;
456da2e3ebdSchin 	ep->e_eof = ttyparm.c_cc[VEOF];
457da2e3ebdSchin #	ifdef ECHOCTL
458da2e3ebdSchin 	    /* escape character echos as ^[ */
459da2e3ebdSchin 	    nttyparm.c_lflag |= (ECHOE|ECHOK|ECHOCTL|PENDIN|IEXTEN);
460da2e3ebdSchin 	    nttyparm.c_cc[VEOL] = ESC;
461da2e3ebdSchin #	else
462da2e3ebdSchin 	    /* switch VEOL2 and EOF, since EOF isn't echo'd by driver */
463da2e3ebdSchin 	    nttyparm.c_lflag |= (ECHOE|ECHOK);
464da2e3ebdSchin 	    nttyparm.c_cc[VEOF] = ESC;	/* make ESC the eof char */
465da2e3ebdSchin #	    ifdef VEOL2
466da2e3ebdSchin 		nttyparm.c_iflag &= ~(IGNCR|ICRNL);
467da2e3ebdSchin 		nttyparm.c_iflag |= INLCR;
468da2e3ebdSchin 		nttyparm.c_cc[VEOL] = '\r';	/* make CR an eol char */
469da2e3ebdSchin 		nttyparm.c_cc[VEOL2] = ep->e_eof; /* make EOF an eol char */
470da2e3ebdSchin #	    else
471da2e3ebdSchin 		nttyparm.c_cc[VEOL] = ep->e_eof; /* make EOF an eol char */
472da2e3ebdSchin #	    endif /* VEOL2 */
473da2e3ebdSchin #	endif /* ECHOCTL */
474da2e3ebdSchin #	ifdef VREPRINT
475da2e3ebdSchin 		nttyparm.c_cc[VREPRINT] = _POSIX_DISABLE;
476da2e3ebdSchin #	endif /* VREPRINT */
477da2e3ebdSchin #	ifdef VDISCARD
478da2e3ebdSchin 		nttyparm.c_cc[VDISCARD] = _POSIX_DISABLE;
479da2e3ebdSchin #	endif /* VDISCARD */
480da2e3ebdSchin #	ifdef VWERASE
481da2e3ebdSchin 	    if(ttyparm.c_cc[VWERASE] == _POSIX_DISABLE)
482da2e3ebdSchin 		    nttyparm.c_cc[VWERASE] = cntl('W');
483da2e3ebdSchin 	    ep->e_werase = nttyparm.c_cc[VWERASE];
484da2e3ebdSchin #	else
485da2e3ebdSchin 	    ep->e_werase = cntl('W');
486da2e3ebdSchin #	endif /* VWERASE */
487da2e3ebdSchin #	ifdef VLNEXT
488da2e3ebdSchin 	    if(ttyparm.c_cc[VLNEXT] == _POSIX_DISABLE )
489da2e3ebdSchin 		    nttyparm.c_cc[VLNEXT] = cntl('V');
490da2e3ebdSchin 	    ep->e_lnext = nttyparm.c_cc[VLNEXT];
491da2e3ebdSchin #	else
492da2e3ebdSchin 	    ep->e_lnext = cntl('V');
493da2e3ebdSchin #	endif /* VLNEXT */
494da2e3ebdSchin 	ep->e_erase = ttyparm.c_cc[VERASE];
495da2e3ebdSchin 	ep->e_kill = ttyparm.c_cc[VKILL];
496da2e3ebdSchin 	if( tty_set(fd, TCSADRAIN, &nttyparm) == SYSERR )
497da2e3ebdSchin 		return(-1);
498da2e3ebdSchin 	ep->e_ttyspeed = (cfgetospeed(&ttyparm)>=B1200?FAST:SLOW);
499da2e3ebdSchin 	ep->e_raw = ALTMODE;
500da2e3ebdSchin 	return(0);
501da2e3ebdSchin }
502da2e3ebdSchin 
503da2e3ebdSchin #   endif /* TIOCGETC */
504da2e3ebdSchin #endif	/* SHOPT_RAWONLY */
505da2e3ebdSchin 
506da2e3ebdSchin /*
507da2e3ebdSchin  *	ED_WINDOW()
508da2e3ebdSchin  *
509da2e3ebdSchin  *	return the window size
510da2e3ebdSchin  */
ed_window(void)511da2e3ebdSchin int ed_window(void)
512da2e3ebdSchin {
513da2e3ebdSchin 	int	rows,cols;
514da2e3ebdSchin 	register char *cp = nv_getval(COLUMNS);
515da2e3ebdSchin 	if(cp)
516da2e3ebdSchin 		cols = (int)strtol(cp, (char**)0, 10)-1;
517da2e3ebdSchin 	else
518da2e3ebdSchin 	{
519da2e3ebdSchin 		astwinsize(2,&rows,&cols);
520da2e3ebdSchin 		if(--cols <0)
521da2e3ebdSchin 			cols = DFLTWINDOW-1;
522da2e3ebdSchin 	}
523da2e3ebdSchin 	if(cols < MINWINDOW)
524da2e3ebdSchin 		cols = MINWINDOW;
525da2e3ebdSchin 	else if(cols > MAXWINDOW)
526da2e3ebdSchin 		cols = MAXWINDOW;
527da2e3ebdSchin 	return(cols);
528da2e3ebdSchin }
529da2e3ebdSchin 
530da2e3ebdSchin /*	E_FLUSH()
531da2e3ebdSchin  *
532da2e3ebdSchin  *	Flush the output buffer.
533da2e3ebdSchin  *
534da2e3ebdSchin  */
535da2e3ebdSchin 
ed_flush(Edit_t * ep)536da2e3ebdSchin void ed_flush(Edit_t *ep)
537da2e3ebdSchin {
538da2e3ebdSchin 	register int n = ep->e_outptr-ep->e_outbase;
539da2e3ebdSchin 	register int fd = ERRIO;
540da2e3ebdSchin 	if(n<=0)
541da2e3ebdSchin 		return;
542da2e3ebdSchin 	write(fd,ep->e_outbase,(unsigned)n);
543da2e3ebdSchin 	ep->e_outptr = ep->e_outbase;
544da2e3ebdSchin }
545da2e3ebdSchin 
546da2e3ebdSchin /*
547da2e3ebdSchin  * send the bell character ^G to the terminal
548da2e3ebdSchin  */
549da2e3ebdSchin 
ed_ringbell(void)550da2e3ebdSchin void ed_ringbell(void)
551da2e3ebdSchin {
552da2e3ebdSchin 	write(ERRIO,bellchr,1);
553da2e3ebdSchin }
554da2e3ebdSchin 
555da2e3ebdSchin /*
556da2e3ebdSchin  * send a carriage return line feed to the terminal
557da2e3ebdSchin  */
558da2e3ebdSchin 
ed_crlf(register Edit_t * ep)559da2e3ebdSchin void ed_crlf(register Edit_t *ep)
560da2e3ebdSchin {
561da2e3ebdSchin #ifdef cray
562da2e3ebdSchin 	ed_putchar(ep,'\r');
563da2e3ebdSchin #endif /* cray */
564da2e3ebdSchin #ifdef u370
565da2e3ebdSchin 	ed_putchar(ep,'\r');
566da2e3ebdSchin #endif	/* u370 */
567da2e3ebdSchin #ifdef VENIX
568da2e3ebdSchin 	ed_putchar(ep,'\r');
569da2e3ebdSchin #endif /* VENIX */
570da2e3ebdSchin 	ed_putchar(ep,'\n');
571da2e3ebdSchin 	ed_flush(ep);
572da2e3ebdSchin }
573da2e3ebdSchin 
574da2e3ebdSchin /*	ED_SETUP( max_prompt_size )
575da2e3ebdSchin  *
576da2e3ebdSchin  *	This routine sets up the prompt string
577da2e3ebdSchin  *	The following is an unadvertised feature.
578da2e3ebdSchin  *	  Escape sequences in the prompt can be excluded from the calculated
579da2e3ebdSchin  *	  prompt length.  This is accomplished as follows:
580da2e3ebdSchin  *	  - if the prompt string starts with "%\r, or contains \r%\r", where %
581da2e3ebdSchin  *	    represents any char, then % is taken to be the quote character.
582da2e3ebdSchin  *	  - strings enclosed by this quote character, and the quote character,
583da2e3ebdSchin  *	    are not counted as part of the prompt length.
584da2e3ebdSchin  */
585da2e3ebdSchin 
ed_setup(register Edit_t * ep,int fd,int reedit)586da2e3ebdSchin void	ed_setup(register Edit_t *ep, int fd, int reedit)
587da2e3ebdSchin {
5887c2fbfb3SApril Chin 	Shell_t *shp = ep->sh;
589da2e3ebdSchin 	register char *pp;
5907c2fbfb3SApril Chin 	register char *last, *prev;
591da2e3ebdSchin 	char *ppmax;
592da2e3ebdSchin 	int myquote = 0, n;
5937c2fbfb3SApril Chin 	register int qlen = 1, qwid;
594da2e3ebdSchin 	char inquote = 0;
595da2e3ebdSchin 	ep->e_fd = fd;
596da2e3ebdSchin 	ep->e_multiline = sh_isoption(SH_MULTILINE)!=0;
597da2e3ebdSchin #ifdef SIGWINCH
5987c2fbfb3SApril Chin 	if(!(shp->sigflag[SIGWINCH]&SH_SIGFAULT))
599da2e3ebdSchin 	{
600da2e3ebdSchin 		signal(SIGWINCH,sh_fault);
6017c2fbfb3SApril Chin 		shp->sigflag[SIGWINCH] |= SH_SIGFAULT;
602da2e3ebdSchin 	}
6037c2fbfb3SApril Chin 	pp = shp->st.trapcom[SIGWINCH];
6047c2fbfb3SApril Chin 	shp->st.trapcom[SIGWINCH] = 0;
605da2e3ebdSchin 	sh_fault(SIGWINCH);
6067c2fbfb3SApril Chin 	shp->st.trapcom[SIGWINCH] = pp;
6077c2fbfb3SApril Chin 	ep->sh->winch = 0;
608da2e3ebdSchin #endif
609da2e3ebdSchin #if KSHELL
610da2e3ebdSchin 	ep->e_stkptr = stakptr(0);
611da2e3ebdSchin 	ep->e_stkoff = staktell();
6127c2fbfb3SApril Chin 	if(!(last = shp->prompt))
613da2e3ebdSchin 		last = "";
6147c2fbfb3SApril Chin 	shp->prompt = 0;
615da2e3ebdSchin #else
616da2e3ebdSchin 	last = ep->e_prbuff;
617da2e3ebdSchin #endif /* KSHELL */
6187c2fbfb3SApril Chin 	if(shp->hist_ptr)
619da2e3ebdSchin 	{
6207c2fbfb3SApril Chin 		register History_t *hp = shp->hist_ptr;
621da2e3ebdSchin 		ep->e_hismax = hist_max(hp);
622da2e3ebdSchin 		ep->e_hismin = hist_min(hp);
623da2e3ebdSchin 	}
624da2e3ebdSchin 	else
625da2e3ebdSchin 	{
626da2e3ebdSchin 		ep->e_hismax = ep->e_hismin = ep->e_hloff = 0;
627da2e3ebdSchin 	}
628da2e3ebdSchin 	ep->e_hline = ep->e_hismax;
629da2e3ebdSchin 	if(!sh_isoption(SH_VI) && !sh_isoption(SH_EMACS) && !sh_isoption(SH_GMACS))
630da2e3ebdSchin 		ep->e_wsize = MAXLINE;
631da2e3ebdSchin 	else
632da2e3ebdSchin 		ep->e_wsize = ed_window()-2;
633da2e3ebdSchin 	ep->e_winsz = ep->e_wsize+2;
634da2e3ebdSchin 	ep->e_crlf = 1;
635da2e3ebdSchin 	ep->e_plen = 0;
636da2e3ebdSchin 	pp = ep->e_prompt;
637da2e3ebdSchin 	ppmax = pp+PRSIZE-1;
638da2e3ebdSchin 	*pp++ = '\r';
639da2e3ebdSchin 	{
640da2e3ebdSchin 		register int c;
6417c2fbfb3SApril Chin 		while(prev = last, c = mbchar(last)) switch(c)
642da2e3ebdSchin 		{
643da2e3ebdSchin 			case ESC:
644da2e3ebdSchin 			{
645da2e3ebdSchin 				int skip=0;
646da2e3ebdSchin 				ep->e_crlf = 0;
647da2e3ebdSchin 				*pp++ = c;
648da2e3ebdSchin 				for(n=1; c = *last++; n++)
649da2e3ebdSchin 				{
650da2e3ebdSchin 					if(pp < ppmax)
651da2e3ebdSchin 						*pp++ = c;
6527c2fbfb3SApril Chin 					if(c=='\a' || c==ESC || c=='\r')
653da2e3ebdSchin 						break;
654da2e3ebdSchin 					if(skip || (c>='0' && c<='9'))
655da2e3ebdSchin 						continue;
656da2e3ebdSchin 					if(n>1 && c==';')
657da2e3ebdSchin 						skip = 1;
658da2e3ebdSchin 					else if(n>2 || (c!= '[' &&  c!= ']'))
659da2e3ebdSchin 						break;
660da2e3ebdSchin 				}
6617c2fbfb3SApril Chin 				if(c==0 || c==ESC || c=='\r')
6627c2fbfb3SApril Chin 					last--;
663da2e3ebdSchin 				qlen += (n+1);
664da2e3ebdSchin 				break;
665da2e3ebdSchin 			}
666da2e3ebdSchin 			case '\b':
667da2e3ebdSchin 				if(pp>ep->e_prompt+1)
668da2e3ebdSchin 					pp--;
669da2e3ebdSchin 				break;
670da2e3ebdSchin 			case '\r':
671da2e3ebdSchin 				if(pp == (ep->e_prompt+2)) /* quote char */
672da2e3ebdSchin 					myquote = *(pp-1);
673da2e3ebdSchin 				/*FALLTHROUGH*/
674da2e3ebdSchin 
675da2e3ebdSchin 			case '\n':
676da2e3ebdSchin 				/* start again */
677da2e3ebdSchin 				ep->e_crlf = 1;
678da2e3ebdSchin 				qlen = 1;
679da2e3ebdSchin 				inquote = 0;
680da2e3ebdSchin 				pp = ep->e_prompt+1;
681da2e3ebdSchin 				break;
682da2e3ebdSchin 
683da2e3ebdSchin 			case '\t':
684da2e3ebdSchin 				/* expand tabs */
685da2e3ebdSchin 				while((pp-ep->e_prompt)%TABSIZE)
686da2e3ebdSchin 				{
687da2e3ebdSchin 					if(pp >= ppmax)
688da2e3ebdSchin 						break;
689da2e3ebdSchin 					*pp++ = ' ';
690da2e3ebdSchin 				}
691da2e3ebdSchin 				break;
692da2e3ebdSchin 
693da2e3ebdSchin 			case '\a':
694da2e3ebdSchin 				/* cut out bells */
695da2e3ebdSchin 				break;
696da2e3ebdSchin 
697da2e3ebdSchin 			default:
698da2e3ebdSchin 				if(c==myquote)
699da2e3ebdSchin 				{
700da2e3ebdSchin 					qlen += inquote;
701da2e3ebdSchin 					inquote ^= 1;
702da2e3ebdSchin 				}
703da2e3ebdSchin 				if(pp < ppmax)
704da2e3ebdSchin 				{
7057c2fbfb3SApril Chin 					if(inquote)
7067c2fbfb3SApril Chin 						qlen++;
7077c2fbfb3SApril Chin 					else if(!is_print(c))
708da2e3ebdSchin 						ep->e_crlf = 0;
7097c2fbfb3SApril Chin 					if((qwid = last - prev) > 1)
7107c2fbfb3SApril Chin 						qlen += qwid - mbwidth(c);
7117c2fbfb3SApril Chin 					while(prev < last && pp < ppmax)
7127c2fbfb3SApril Chin 						*pp++ = *prev++;
713da2e3ebdSchin 				}
7147c2fbfb3SApril Chin 				break;
715da2e3ebdSchin 		}
716da2e3ebdSchin 	}
717da2e3ebdSchin 	if(pp-ep->e_prompt > qlen)
718da2e3ebdSchin 		ep->e_plen = pp - ep->e_prompt - qlen;
719da2e3ebdSchin 	*pp = 0;
7207c2fbfb3SApril Chin 	if(!ep->e_multiline && (ep->e_wsize -= ep->e_plen) < 7)
721da2e3ebdSchin 	{
722da2e3ebdSchin 		register int shift = 7-ep->e_wsize;
723da2e3ebdSchin 		ep->e_wsize = 7;
724da2e3ebdSchin 		pp = ep->e_prompt+1;
725da2e3ebdSchin 		strcpy(pp,pp+shift);
726da2e3ebdSchin 		ep->e_plen -= shift;
727da2e3ebdSchin 		last[-ep->e_plen-2] = '\r';
728da2e3ebdSchin 	}
729da2e3ebdSchin 	sfsync(sfstderr);
730da2e3ebdSchin 	if(fd == sffileno(sfstderr))
731da2e3ebdSchin 	{
732da2e3ebdSchin 		/* can't use output buffer when reading from stderr */
733da2e3ebdSchin 		static char *buff;
734da2e3ebdSchin 		if(!buff)
735da2e3ebdSchin 			buff = (char*)malloc(MAXLINE);
736da2e3ebdSchin 		ep->e_outbase = ep->e_outptr = buff;
737da2e3ebdSchin 		ep->e_outlast = ep->e_outptr + MAXLINE;
738da2e3ebdSchin 		return;
739da2e3ebdSchin 	}
740da2e3ebdSchin 	qlen = sfset(sfstderr,SF_READ,0);
741da2e3ebdSchin 	/* make sure SF_READ not on */
742da2e3ebdSchin 	ep->e_outbase = ep->e_outptr = (char*)sfreserve(sfstderr,SF_UNBOUND,SF_LOCKR);
743da2e3ebdSchin 	ep->e_outlast = ep->e_outptr + sfvalue(sfstderr);
744da2e3ebdSchin 	if(qlen)
745da2e3ebdSchin 		sfset(sfstderr,SF_READ,1);
746da2e3ebdSchin 	sfwrite(sfstderr,ep->e_outptr,0);
747da2e3ebdSchin 	ep->e_eol = reedit;
748da2e3ebdSchin 	if(ep->e_multiline)
749da2e3ebdSchin 	{
750da2e3ebdSchin #ifdef _cmd_tput
751da2e3ebdSchin 		char *term;
752da2e3ebdSchin 		if(!ep->e_term)
7537c2fbfb3SApril Chin 			ep->e_term = nv_search("TERM",shp->var_tree,0);
754da2e3ebdSchin 		if(ep->e_term && (term=nv_getval(ep->e_term)) && strlen(term)<sizeof(ep->e_termname) && strcmp(term,ep->e_termname))
755da2e3ebdSchin 		{
756da2e3ebdSchin 			sh_trap(".sh.subscript=$(tput cuu1 2>/dev/null)",0);
757da2e3ebdSchin 			if(pp=nv_getval(SH_SUBSCRNOD))
758da2e3ebdSchin 				strncpy(CURSOR_UP,pp,sizeof(CURSOR_UP)-1);
759da2e3ebdSchin 			nv_unset(SH_SUBSCRNOD);
760da2e3ebdSchin 			strcpy(ep->e_termname,term);
761da2e3ebdSchin 		}
762da2e3ebdSchin #endif
7637c2fbfb3SApril Chin 		ep->e_wsize = MAXLINE - (ep->e_plen+1);
764da2e3ebdSchin 	}
765da2e3ebdSchin 	if(ep->e_default && (pp = nv_getval(ep->e_default)))
766da2e3ebdSchin 	{
767da2e3ebdSchin 		n = strlen(pp);
768da2e3ebdSchin 		if(n > LOOKAHEAD)
769da2e3ebdSchin 			n = LOOKAHEAD;
770da2e3ebdSchin 		ep->e_lookahead = n;
771da2e3ebdSchin 		while(n-- > 0)
772da2e3ebdSchin 			ep->e_lbuf[n] = *pp++;
773da2e3ebdSchin 		ep->e_default = 0;
774da2e3ebdSchin 	}
775da2e3ebdSchin }
776da2e3ebdSchin 
ed_putstring(register Edit_t * ep,const char * str)7777c2fbfb3SApril Chin static void ed_putstring(register Edit_t *ep, const char *str)
7787c2fbfb3SApril Chin {
7797c2fbfb3SApril Chin 	register int c;
7807c2fbfb3SApril Chin 	while(c = *str++)
7817c2fbfb3SApril Chin 		ed_putchar(ep,c);
7827c2fbfb3SApril Chin }
7837c2fbfb3SApril Chin 
ed_nputchar(register Edit_t * ep,int n,int c)7847c2fbfb3SApril Chin static void ed_nputchar(register Edit_t *ep, int n, int c)
7857c2fbfb3SApril Chin {
7867c2fbfb3SApril Chin 	while(n-->0)
7877c2fbfb3SApril Chin 		ed_putchar(ep,c);
7887c2fbfb3SApril Chin }
7897c2fbfb3SApril Chin 
790da2e3ebdSchin /*
791da2e3ebdSchin  * Do read, restart on interrupt unless SH_SIGSET or SH_SIGTRAP is set
792da2e3ebdSchin  * Use sfpkrd() to poll() or select() to wait for input if possible
793da2e3ebdSchin  * Unfortunately, systems that get interrupted from slow reads update
794da2e3ebdSchin  * this access time for for the terminal (in violation of POSIX).
795da2e3ebdSchin  * The fixtime() macro, resets the time to the time at entry in
796da2e3ebdSchin  * this case.  This is not necessary for systems that can handle
797da2e3ebdSchin  * sfpkrd() correctly (i,e., those that support poll() or select()
798da2e3ebdSchin  */
ed_read(void * context,int fd,char * buff,int size,int reedit)799da2e3ebdSchin int ed_read(void *context, int fd, char *buff, int size, int reedit)
800da2e3ebdSchin {
801da2e3ebdSchin 	register Edit_t *ep = (Edit_t*)context;
802da2e3ebdSchin 	register int rv= -1;
803da2e3ebdSchin 	register int delim = (ep->e_raw==RAWMODE?'\r':'\n');
8047c2fbfb3SApril Chin 	Shell_t *shp = ep->sh;
805da2e3ebdSchin 	int mode = -1;
8067c2fbfb3SApril Chin 	int (*waitevent)(int,long,int) = shp->waitevent;
807da2e3ebdSchin 	if(ep->e_raw==ALTMODE)
808da2e3ebdSchin 		mode = 1;
809da2e3ebdSchin 	if(size < 0)
810da2e3ebdSchin 	{
811da2e3ebdSchin 		mode = 1;
812da2e3ebdSchin 		size = -size;
813da2e3ebdSchin 	}
814da2e3ebdSchin 	sh_onstate(SH_TTYWAIT);
815da2e3ebdSchin 	errno = EINTR;
8167c2fbfb3SApril Chin 	shp->waitevent = 0;
817da2e3ebdSchin 	while(rv<0 && errno==EINTR)
818da2e3ebdSchin 	{
8197c2fbfb3SApril Chin 		if(shp->trapnote&(SH_SIGSET|SH_SIGTRAP))
820da2e3ebdSchin 			goto done;
82134f9b3eeSRoland Mainz 		if(ep->sh->winch && sh_isstate(SH_INTERACTIVE) && (sh_isoption(SH_VI) || sh_isoption(SH_EMACS)))
8227c2fbfb3SApril Chin 		{
8237c2fbfb3SApril Chin 			Edpos_t	lastpos;
8247c2fbfb3SApril Chin 			int	n, rows, newsize;
8257c2fbfb3SApril Chin 			/* move cursor to start of first line */
8267c2fbfb3SApril Chin 			ed_putchar(ep,'\r');
8277c2fbfb3SApril Chin 			ed_flush(ep);
8287c2fbfb3SApril Chin 			astwinsize(2,&rows,&newsize);
8297c2fbfb3SApril Chin 			n = (ep->e_plen+ep->e_cur)/++ep->e_winsz;
8307c2fbfb3SApril Chin 			while(n--)
8317c2fbfb3SApril Chin 				ed_putstring(ep,CURSOR_UP);
8327c2fbfb3SApril Chin 			if(ep->e_multiline && newsize>ep->e_winsz && (lastpos.line=(ep->e_plen+ep->e_peol)/ep->e_winsz))
8337c2fbfb3SApril Chin 			{
8347c2fbfb3SApril Chin 				/* clear the current command line */
8357c2fbfb3SApril Chin 				n = lastpos.line;
8367c2fbfb3SApril Chin 				while(lastpos.line--)
8377c2fbfb3SApril Chin 				{
8387c2fbfb3SApril Chin 					ed_nputchar(ep,ep->e_winsz,' ');
8397c2fbfb3SApril Chin 					ed_putchar(ep,'\n');
8407c2fbfb3SApril Chin 				}
8417c2fbfb3SApril Chin 				ed_nputchar(ep,ep->e_winsz,' ');
8427c2fbfb3SApril Chin 				while(n--)
8437c2fbfb3SApril Chin 					ed_putstring(ep,CURSOR_UP);
8447c2fbfb3SApril Chin 			}
8457c2fbfb3SApril Chin 	                ep->sh->winch = 0;
8467c2fbfb3SApril Chin 			ed_flush(ep);
8477c2fbfb3SApril Chin 			sh_delay(.05);
8487c2fbfb3SApril Chin 			astwinsize(2,&rows,&newsize);
8497c2fbfb3SApril Chin 			ep->e_winsz = newsize-1;
8507c2fbfb3SApril Chin 			if(!ep->e_multiline && ep->e_wsize < MAXLINE)
8517c2fbfb3SApril Chin 				ep->e_wsize = ep->e_winsz-2;
8527c2fbfb3SApril Chin 			ep->e_nocrnl=1;
8537c2fbfb3SApril Chin 			if(*ep->e_vi_insert)
8547c2fbfb3SApril Chin 			{
8557c2fbfb3SApril Chin 				buff[0] = ESC;
8567c2fbfb3SApril Chin 				buff[1] = cntl('L');
8577c2fbfb3SApril Chin 				buff[2] = 'a';
8587c2fbfb3SApril Chin 				return(3);
8597c2fbfb3SApril Chin 			}
86034f9b3eeSRoland Mainz 			if(sh_isoption(SH_EMACS) || sh_isoption(SH_VI))
8617c2fbfb3SApril Chin 				buff[0] = cntl('L');
8627c2fbfb3SApril Chin 			return(1);
8637c2fbfb3SApril Chin 		}
86434f9b3eeSRoland Mainz 		else
86534f9b3eeSRoland Mainz 			ep->sh->winch = 0;
866da2e3ebdSchin 		/* an interrupt that should be ignored */
867da2e3ebdSchin 		errno = 0;
868da2e3ebdSchin 		if(!waitevent || (rv=(*waitevent)(fd,-1L,0))>=0)
869da2e3ebdSchin 			rv = sfpkrd(fd,buff,size,delim,-1L,mode);
870da2e3ebdSchin 	}
871da2e3ebdSchin 	if(rv < 0)
872da2e3ebdSchin 	{
873da2e3ebdSchin #ifdef _hdr_utime
874da2e3ebdSchin #		define fixtime()	if(isdevtty)utime(ep->e_tty,&utimes)
875da2e3ebdSchin 		int	isdevtty=0;
876da2e3ebdSchin 		struct stat statb;
877da2e3ebdSchin 		struct utimbuf utimes;
878da2e3ebdSchin 	 	if(errno==0 && !ep->e_tty)
879da2e3ebdSchin 		{
880da2e3ebdSchin 			if((ep->e_tty=ttyname(fd)) && stat(ep->e_tty,&statb)>=0)
881da2e3ebdSchin 			{
882da2e3ebdSchin 				ep->e_tty_ino = statb.st_ino;
883da2e3ebdSchin 				ep->e_tty_dev = statb.st_dev;
884da2e3ebdSchin 			}
885da2e3ebdSchin 		}
886da2e3ebdSchin 		if(ep->e_tty_ino && fstat(fd,&statb)>=0 && statb.st_ino==ep->e_tty_ino && statb.st_dev==ep->e_tty_dev)
887da2e3ebdSchin 		{
888da2e3ebdSchin 			utimes.actime = statb.st_atime;
889da2e3ebdSchin 			utimes.modtime = statb.st_mtime;
890da2e3ebdSchin 			isdevtty=1;
891da2e3ebdSchin 		}
892da2e3ebdSchin #else
893da2e3ebdSchin #		define fixtime()
894da2e3ebdSchin #endif /* _hdr_utime */
895da2e3ebdSchin 		while(1)
896da2e3ebdSchin 		{
897da2e3ebdSchin 			rv = read(fd,buff,size);
898da2e3ebdSchin 			if(rv>=0 || errno!=EINTR)
899da2e3ebdSchin 				break;
9007c2fbfb3SApril Chin 			if(shp->trapnote&(SH_SIGSET|SH_SIGTRAP))
901da2e3ebdSchin 				goto done;
902da2e3ebdSchin 			/* an interrupt that should be ignored */
903da2e3ebdSchin 			fixtime();
904da2e3ebdSchin 		}
905da2e3ebdSchin 	}
906da2e3ebdSchin 	else if(rv>=0 && mode>0)
907da2e3ebdSchin 		rv = read(fd,buff,rv>0?rv:1);
908da2e3ebdSchin done:
9097c2fbfb3SApril Chin 	shp->waitevent = waitevent;
910da2e3ebdSchin 	sh_offstate(SH_TTYWAIT);
911da2e3ebdSchin 	return(rv);
912da2e3ebdSchin }
913da2e3ebdSchin 
914da2e3ebdSchin 
915da2e3ebdSchin /*
916da2e3ebdSchin  * put <string> of length <nbyte> onto lookahead stack
917da2e3ebdSchin  * if <type> is non-zero,  the negation of the character is put
918da2e3ebdSchin  *    onto the stack so that it can be checked for KEYTRAP
919da2e3ebdSchin  * putstack() returns 1 except when in the middle of a multi-byte char
920da2e3ebdSchin  */
921da2e3ebdSchin static int putstack(Edit_t *ep,char string[], register int nbyte, int type)
922da2e3ebdSchin {
923da2e3ebdSchin 	register int c;
924da2e3ebdSchin #if SHOPT_MULTIBYTE
925da2e3ebdSchin 	char *endp, *p=string;
926da2e3ebdSchin 	int size, offset = ep->e_lookahead + nbyte;
927da2e3ebdSchin 	*(endp = &p[nbyte]) = 0;
928da2e3ebdSchin 	endp = &p[nbyte];
929da2e3ebdSchin 	do
930da2e3ebdSchin 	{
931da2e3ebdSchin 		c = (int)((*p) & STRIP);
932da2e3ebdSchin 		if(c< 0x80 && c!='<')
933da2e3ebdSchin 		{
934da2e3ebdSchin 			if (type)
935da2e3ebdSchin 				c = -c;
936da2e3ebdSchin #   ifndef CBREAK
937da2e3ebdSchin 			if(c == '\0')
938da2e3ebdSchin 			{
939da2e3ebdSchin 				/*** user break key ***/
940da2e3ebdSchin 				ep->e_lookahead = 0;
941da2e3ebdSchin #	if KSHELL
942da2e3ebdSchin 				sh_fault(SIGINT);
943da2e3ebdSchin 				siglongjmp(ep->e_env, UINTR);
944da2e3ebdSchin #	endif   /* KSHELL */
945da2e3ebdSchin 			}
946da2e3ebdSchin #   endif /* CBREAK */
947da2e3ebdSchin 
948da2e3ebdSchin 		}
949da2e3ebdSchin 		else
950da2e3ebdSchin 		{
951da2e3ebdSchin 		again:
952da2e3ebdSchin 			if((c=mbchar(p)) >=0)
953da2e3ebdSchin 			{
954da2e3ebdSchin 				p--;	/* incremented below */
955da2e3ebdSchin 				if(type)
956da2e3ebdSchin 					c = -c;
957da2e3ebdSchin 			}
958da2e3ebdSchin #ifdef EILSEQ
959da2e3ebdSchin 			else if(errno == EILSEQ)
960da2e3ebdSchin 				errno = 0;
961da2e3ebdSchin #endif
962da2e3ebdSchin 			else if((endp-p) < mbmax())
963da2e3ebdSchin 			{
964da2e3ebdSchin 				if ((c=ed_read(ep,ep->e_fd,endp, 1,0)) == 1)
965da2e3ebdSchin 				{
966da2e3ebdSchin 					*++endp = 0;
967da2e3ebdSchin 					goto again;
968da2e3ebdSchin 				}
969da2e3ebdSchin 				return(c);
970da2e3ebdSchin 			}
971da2e3ebdSchin 			else
972da2e3ebdSchin 			{
973da2e3ebdSchin 				ed_ringbell();
974da2e3ebdSchin 				c = -(int)((*p) & STRIP);
975da2e3ebdSchin 				offset += mbmax()-1;
976da2e3ebdSchin 			}
977da2e3ebdSchin 		}
978da2e3ebdSchin 		ep->e_lbuf[--offset] = c;
979da2e3ebdSchin 		p++;
980da2e3ebdSchin 	}
981da2e3ebdSchin 	while (p < endp);
982da2e3ebdSchin 	/* shift lookahead buffer if necessary */
983da2e3ebdSchin 	if(offset -= ep->e_lookahead)
984da2e3ebdSchin 	{
985da2e3ebdSchin 		for(size=offset;size < nbyte;size++)
986da2e3ebdSchin 			ep->e_lbuf[ep->e_lookahead+size-offset] = ep->e_lbuf[ep->e_lookahead+size];
987da2e3ebdSchin 	}
988da2e3ebdSchin 	ep->e_lookahead += nbyte-offset;
989da2e3ebdSchin #else
990da2e3ebdSchin 	while (nbyte > 0)
991da2e3ebdSchin 	{
992da2e3ebdSchin 		c = string[--nbyte] & STRIP;
993da2e3ebdSchin 		ep->e_lbuf[ep->e_lookahead++] = (type?-c:c);
994da2e3ebdSchin #   ifndef CBREAK
995da2e3ebdSchin 		if( c == '\0' )
996da2e3ebdSchin 		{
997da2e3ebdSchin 			/*** user break key ***/
998da2e3ebdSchin 			ep->e_lookahead = 0;
999da2e3ebdSchin #	if KSHELL
1000da2e3ebdSchin 			sh_fault(SIGINT);
1001da2e3ebdSchin 			siglongjmp(ep->e_env, UINTR);
1002da2e3ebdSchin #	endif	/* KSHELL */
1003da2e3ebdSchin 		}
1004da2e3ebdSchin #   endif /* CBREAK */
1005da2e3ebdSchin 	}
1006da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
1007da2e3ebdSchin 	return(1);
1008da2e3ebdSchin }
1009da2e3ebdSchin 
1010da2e3ebdSchin /*
1011da2e3ebdSchin  * routine to perform read from terminal for vi and emacs mode
1012da2e3ebdSchin  * <mode> can be one of the following:
1013da2e3ebdSchin  *   -2		vi insert mode - key binding is in effect
1014da2e3ebdSchin  *   -1		vi control mode - key binding is in effect
1015da2e3ebdSchin  *   0		normal command mode - key binding is in effect
1016da2e3ebdSchin  *   1		edit keys not mapped
1017da2e3ebdSchin  *   2		Next key is literal
1018da2e3ebdSchin  */
1019da2e3ebdSchin int ed_getchar(register Edit_t *ep,int mode)
1020da2e3ebdSchin {
1021da2e3ebdSchin 	register int n, c;
1022da2e3ebdSchin 	char readin[LOOKAHEAD+1];
1023da2e3ebdSchin 	if(!ep->e_lookahead)
1024da2e3ebdSchin 	{
1025da2e3ebdSchin 		ed_flush(ep);
1026da2e3ebdSchin 		ep->e_inmacro = 0;
1027da2e3ebdSchin 		/* The while is necessary for reads of partial multbyte chars */
10287c2fbfb3SApril Chin 		*ep->e_vi_insert = (mode==-2);
1029da2e3ebdSchin 		if((n=ed_read(ep,ep->e_fd,readin,-LOOKAHEAD,0)) > 0)
1030da2e3ebdSchin 			n = putstack(ep,readin,n,1);
10317c2fbfb3SApril Chin 		*ep->e_vi_insert = 0;
1032da2e3ebdSchin 	}
1033da2e3ebdSchin 	if(ep->e_lookahead)
1034da2e3ebdSchin 	{
1035da2e3ebdSchin 		/* check for possible key mapping */
1036da2e3ebdSchin 		if((c = ep->e_lbuf[--ep->e_lookahead]) < 0)
1037da2e3ebdSchin 		{
10387c2fbfb3SApril Chin 			if(mode<=0 && ep->sh->st.trap[SH_KEYTRAP])
1039da2e3ebdSchin 			{
1040da2e3ebdSchin 				n=1;
1041da2e3ebdSchin 				if((readin[0]= -c) == ESC)
1042da2e3ebdSchin 				{
1043da2e3ebdSchin 					while(1)
1044da2e3ebdSchin 					{
1045da2e3ebdSchin 						if(!ep->e_lookahead)
1046da2e3ebdSchin 						{
1047da2e3ebdSchin 							if((c=sfpkrd(ep->e_fd,readin+n,1,'\r',(mode?400L:-1L),0))>0)
1048da2e3ebdSchin 								putstack(ep,readin+n,c,1);
1049da2e3ebdSchin 						}
1050da2e3ebdSchin 						if(!ep->e_lookahead)
1051da2e3ebdSchin 							break;
1052da2e3ebdSchin 						if((c=ep->e_lbuf[--ep->e_lookahead])>=0)
1053da2e3ebdSchin 						{
1054da2e3ebdSchin 							ep->e_lookahead++;
1055da2e3ebdSchin 							break;
1056da2e3ebdSchin 						}
1057da2e3ebdSchin 						c = -c;
1058da2e3ebdSchin 						readin[n++] = c;
1059da2e3ebdSchin 						if(c>='0' && c<='9' && n>2)
1060da2e3ebdSchin 							continue;
1061da2e3ebdSchin 						if(n>2 || (c!= '['  &&  c!= 'O'))
1062da2e3ebdSchin 							break;
1063da2e3ebdSchin 					}
1064da2e3ebdSchin 				}
1065da2e3ebdSchin 				if(n=keytrap(ep,readin,n,LOOKAHEAD-n,mode))
1066da2e3ebdSchin 				{
1067da2e3ebdSchin 					putstack(ep,readin,n,0);
1068da2e3ebdSchin 					c = ep->e_lbuf[--ep->e_lookahead];
1069da2e3ebdSchin 				}
1070da2e3ebdSchin 				else
1071da2e3ebdSchin 					c = ed_getchar(ep,mode);
1072da2e3ebdSchin 			}
1073da2e3ebdSchin 			else
1074da2e3ebdSchin 				c = -c;
1075da2e3ebdSchin 		}
1076da2e3ebdSchin 		/*** map '\r' to '\n' ***/
1077da2e3ebdSchin 		if(c == '\r' && mode!=2)
1078da2e3ebdSchin 			c = '\n';
1079da2e3ebdSchin 		if(ep->e_tabcount && !(c=='\t'||c==ESC || c=='\\' || c=='=' || c==cntl('L') || isdigit(c)))
1080da2e3ebdSchin 			ep->e_tabcount = 0;
1081da2e3ebdSchin 	}
1082da2e3ebdSchin 	else
1083da2e3ebdSchin 		siglongjmp(ep->e_env,(n==0?UEOF:UINTR));
1084da2e3ebdSchin 	return(c);
1085da2e3ebdSchin }
1086da2e3ebdSchin 
1087da2e3ebdSchin void ed_ungetchar(Edit_t *ep,register int c)
1088da2e3ebdSchin {
1089da2e3ebdSchin 	if (ep->e_lookahead < LOOKAHEAD)
1090da2e3ebdSchin 		ep->e_lbuf[ep->e_lookahead++] = c;
1091da2e3ebdSchin 	return;
1092da2e3ebdSchin }
1093da2e3ebdSchin 
1094da2e3ebdSchin /*
1095da2e3ebdSchin  * put a character into the output buffer
1096da2e3ebdSchin  */
1097da2e3ebdSchin 
1098da2e3ebdSchin void	ed_putchar(register Edit_t *ep,register int c)
1099da2e3ebdSchin {
1100da2e3ebdSchin 	char buf[8];
1101da2e3ebdSchin 	register char *dp = ep->e_outptr;
1102da2e3ebdSchin 	register int i,size=1;
11037c2fbfb3SApril Chin 	if(!dp)
11047c2fbfb3SApril Chin 		return;
1105da2e3ebdSchin 	buf[0] = c;
1106da2e3ebdSchin #if SHOPT_MULTIBYTE
1107da2e3ebdSchin 	/* check for place holder */
1108da2e3ebdSchin 	if(c == MARKER)
1109da2e3ebdSchin 		return;
1110da2e3ebdSchin 	if((size = mbconv(buf, (wchar_t)c)) > 1)
1111da2e3ebdSchin 	{
1112da2e3ebdSchin 		for (i = 0; i < (size-1); i++)
1113da2e3ebdSchin 			*dp++ = buf[i];
1114da2e3ebdSchin 		c = buf[i];
1115da2e3ebdSchin 	}
1116da2e3ebdSchin 	else
1117da2e3ebdSchin 	{
1118da2e3ebdSchin 		buf[0] = c;
1119da2e3ebdSchin 		size = 1;
1120da2e3ebdSchin 	}
1121da2e3ebdSchin #endif	/* SHOPT_MULTIBYTE */
1122da2e3ebdSchin 	if (buf[0] == '_' && size==1)
1123da2e3ebdSchin 	{
1124da2e3ebdSchin 		*dp++ = ' ';
1125da2e3ebdSchin 		*dp++ = '\b';
1126da2e3ebdSchin 	}
1127da2e3ebdSchin 	*dp++ = c;
1128da2e3ebdSchin 	*dp = '\0';
1129da2e3ebdSchin 	if(dp >= ep->e_outlast)
1130da2e3ebdSchin 		ed_flush(ep);
1131da2e3ebdSchin 	else
1132da2e3ebdSchin 		ep->e_outptr = dp;
1133da2e3ebdSchin }
1134da2e3ebdSchin 
1135da2e3ebdSchin /*
1136da2e3ebdSchin  * returns the line and column corresponding to offset <off> in the physical buffer
1137da2e3ebdSchin  * if <cur> is non-zero and <= <off>, then correspodning <curpos> will start the search
1138da2e3ebdSchin  */
1139da2e3ebdSchin Edpos_t ed_curpos(Edit_t *ep,genchar *phys, int off, int cur, Edpos_t curpos)
1140da2e3ebdSchin {
1141da2e3ebdSchin 	register genchar *sp=phys;
1142da2e3ebdSchin 	register int c=1, col=ep->e_plen;
1143da2e3ebdSchin 	Edpos_t pos;
1144da2e3ebdSchin #if SHOPT_MULTIBYTE
1145da2e3ebdSchin 	char p[16];
1146da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
1147da2e3ebdSchin 	if(cur && off>=cur)
1148da2e3ebdSchin 	{
1149da2e3ebdSchin 		sp += cur;
1150da2e3ebdSchin 		off -= cur;
1151da2e3ebdSchin 		pos = curpos;
1152da2e3ebdSchin 		col = pos.col;
1153da2e3ebdSchin 	}
1154da2e3ebdSchin 	else
11557c2fbfb3SApril Chin 	{
1156da2e3ebdSchin 		pos.line = 0;
11577c2fbfb3SApril Chin 		while(col > ep->e_winsz)
11587c2fbfb3SApril Chin 		{
11597c2fbfb3SApril Chin 			pos.line++;
11607c2fbfb3SApril Chin 			col -= (ep->e_winsz+1);
11617c2fbfb3SApril Chin 		}
11627c2fbfb3SApril Chin 	}
1163da2e3ebdSchin 	while(off-->0)
1164da2e3ebdSchin 	{
1165da2e3ebdSchin 		if(c)
1166da2e3ebdSchin 			c = *sp++;
1167da2e3ebdSchin #if SHOPT_MULTIBYTE
1168da2e3ebdSchin 		if(c && (mbconv(p, (wchar_t)c))==1 && p[0]=='\n')
1169da2e3ebdSchin #else
1170da2e3ebdSchin 		if(c=='\n')
1171da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
1172da2e3ebdSchin 			col = 0;
1173da2e3ebdSchin 		else
1174da2e3ebdSchin 			col++;
1175da2e3ebdSchin 		if(col >  ep->e_winsz)
1176da2e3ebdSchin 			col = 0;
1177da2e3ebdSchin 		if(col==0)
1178da2e3ebdSchin 			pos.line++;
1179da2e3ebdSchin 	}
1180da2e3ebdSchin 	pos.col = col;
1181da2e3ebdSchin 	return(pos);
1182da2e3ebdSchin }
1183da2e3ebdSchin 
1184da2e3ebdSchin int ed_setcursor(register Edit_t *ep,genchar *physical,register int old,register int new,int first)
1185da2e3ebdSchin {
1186da2e3ebdSchin 	static int oldline;
1187da2e3ebdSchin 	register int delta;
11887c2fbfb3SApril Chin 	int clear = 0;
1189da2e3ebdSchin 	Edpos_t newpos;
1190da2e3ebdSchin 
1191da2e3ebdSchin 	delta = new - old;
11927c2fbfb3SApril Chin 	if(first < 0)
11937c2fbfb3SApril Chin 	{
11947c2fbfb3SApril Chin 		first = 0;
11957c2fbfb3SApril Chin 		clear = 1;
11967c2fbfb3SApril Chin 	}
11977c2fbfb3SApril Chin 	if( delta == 0  &&  !clear)
1198da2e3ebdSchin 		return(new);
1199da2e3ebdSchin 	if(ep->e_multiline)
1200da2e3ebdSchin 	{
1201da2e3ebdSchin 		ep->e_curpos = ed_curpos(ep, physical, old,0,ep->e_curpos);
12027c2fbfb3SApril Chin 		if(clear && old>=ep->e_peol && (clear=ep->e_winsz-ep->e_curpos.col)>0)
12037c2fbfb3SApril Chin 		{
12047c2fbfb3SApril Chin 			ed_nputchar(ep,clear,' ');
12057c2fbfb3SApril Chin 			ed_nputchar(ep,clear,'\b');
12067c2fbfb3SApril Chin 			return(new);
12077c2fbfb3SApril Chin 		}
1208da2e3ebdSchin 		newpos =     ed_curpos(ep, physical, new,old,ep->e_curpos);
1209da2e3ebdSchin 		if(ep->e_curpos.col==0 && ep->e_curpos.line>0 && oldline<ep->e_curpos.line && delta<0)
1210da2e3ebdSchin 			ed_putstring(ep,"\r\n");
1211da2e3ebdSchin 		oldline = newpos.line;
1212da2e3ebdSchin 		if(ep->e_curpos.line > newpos.line)
1213da2e3ebdSchin 		{
12147c2fbfb3SApril Chin 			int n,pline,plen=ep->e_plen;
1215da2e3ebdSchin 			for(;ep->e_curpos.line > newpos.line; ep->e_curpos.line--)
1216da2e3ebdSchin 				ed_putstring(ep,CURSOR_UP);
12177c2fbfb3SApril Chin 			pline = plen/(ep->e_winsz+1);
12187c2fbfb3SApril Chin 			if(newpos.line <= pline)
12197c2fbfb3SApril Chin 				plen -= pline*(ep->e_winsz+1);
12207c2fbfb3SApril Chin 			else
12217c2fbfb3SApril Chin 				plen = 0;
12227c2fbfb3SApril Chin 			if((n=plen- ep->e_curpos.col)>0)
1223da2e3ebdSchin 			{
1224da2e3ebdSchin 				ep->e_curpos.col += n;
1225da2e3ebdSchin 				ed_putchar(ep,'\r');
12267c2fbfb3SApril Chin 				if(!ep->e_crlf && pline==0)
1227da2e3ebdSchin 					ed_putstring(ep,ep->e_prompt);
1228da2e3ebdSchin 				else
1229da2e3ebdSchin 				{
12307c2fbfb3SApril Chin 					int m = ep->e_winsz+1-plen;
1231da2e3ebdSchin 					ed_putchar(ep,'\n');
12327c2fbfb3SApril Chin 					n = plen;
1233da2e3ebdSchin 					if(m < ed_genlen(physical))
1234da2e3ebdSchin 					{
1235da2e3ebdSchin 						while(physical[m] && n-->0)
1236da2e3ebdSchin 							ed_putchar(ep,physical[m++]);
1237da2e3ebdSchin 					}
12387c2fbfb3SApril Chin 					ed_nputchar(ep,n,' ');
1239da2e3ebdSchin 					ed_putstring(ep,CURSOR_UP);
1240da2e3ebdSchin 				}
1241da2e3ebdSchin 			}
1242da2e3ebdSchin 		}
1243da2e3ebdSchin 		else if(ep->e_curpos.line < newpos.line)
1244da2e3ebdSchin 		{
12457c2fbfb3SApril Chin 			ed_nputchar(ep, newpos.line-ep->e_curpos.line,'\n');
12467c2fbfb3SApril Chin 			ep->e_curpos.line = newpos.line;
1247da2e3ebdSchin 			ed_putchar(ep,'\r');
1248da2e3ebdSchin 			ep->e_curpos.col = 0;
1249da2e3ebdSchin 		}
1250da2e3ebdSchin 		delta = newpos.col - ep->e_curpos.col;
1251da2e3ebdSchin 		old   =  new - delta;
1252da2e3ebdSchin 	}
1253da2e3ebdSchin 	else
1254da2e3ebdSchin 		newpos.line=0;
1255da2e3ebdSchin 	if(delta<0)
1256da2e3ebdSchin 	{
12577c2fbfb3SApril Chin 		int bs= newpos.line && ep->e_plen>ep->e_winsz;
1258da2e3ebdSchin 		/*** move to left ***/
1259da2e3ebdSchin 		delta = -delta;
1260da2e3ebdSchin 		/*** attempt to optimize cursor movement ***/
12617c2fbfb3SApril Chin 		if(!ep->e_crlf || bs || (2*delta <= ((old-first)+(newpos.line?0:ep->e_plen))) )
1262da2e3ebdSchin 		{
12637c2fbfb3SApril Chin 			ed_nputchar(ep,delta,'\b');
12647c2fbfb3SApril Chin 			delta = 0;
1265da2e3ebdSchin 		}
1266da2e3ebdSchin 		else
1267da2e3ebdSchin 		{
1268da2e3ebdSchin 			if(newpos.line==0)
1269da2e3ebdSchin 				ed_putstring(ep,ep->e_prompt);
12707c2fbfb3SApril Chin 			else
12717c2fbfb3SApril Chin 			{
12727c2fbfb3SApril Chin 				first = 1+(newpos.line*ep->e_winsz - ep->e_plen);
12737c2fbfb3SApril Chin 				ed_putchar(ep,'\r');
12747c2fbfb3SApril Chin 			}
1275da2e3ebdSchin 			old = first;
1276da2e3ebdSchin 			delta = new-first;
1277da2e3ebdSchin 		}
1278da2e3ebdSchin 	}
1279da2e3ebdSchin 	while(delta-->0)
1280da2e3ebdSchin 		ed_putchar(ep,physical[old++]);
1281da2e3ebdSchin 	return(new);
1282da2e3ebdSchin }
1283da2e3ebdSchin 
1284da2e3ebdSchin /*
1285da2e3ebdSchin  * copy virtual to physical and return the index for cursor in physical buffer
1286da2e3ebdSchin  */
1287da2e3ebdSchin int ed_virt_to_phys(Edit_t *ep,genchar *virt,genchar *phys,int cur,int voff,int poff)
1288da2e3ebdSchin {
1289da2e3ebdSchin 	register genchar *sp = virt;
1290da2e3ebdSchin 	register genchar *dp = phys;
1291da2e3ebdSchin 	register int c;
1292da2e3ebdSchin 	genchar *curp = sp + cur;
1293da2e3ebdSchin 	genchar *dpmax = phys+MAXLINE;
1294da2e3ebdSchin 	int d, r;
1295da2e3ebdSchin 	sp += voff;
1296da2e3ebdSchin 	dp += poff;
1297da2e3ebdSchin 	for(r=poff;c= *sp;sp++)
1298da2e3ebdSchin 	{
1299da2e3ebdSchin 		if(curp == sp)
1300da2e3ebdSchin 			r = dp - phys;
1301da2e3ebdSchin #if SHOPT_MULTIBYTE
1302da2e3ebdSchin 		d = mbwidth((wchar_t)c);
1303da2e3ebdSchin 		if(d==1 && is_cntrl(c))
1304da2e3ebdSchin 			d = -1;
1305da2e3ebdSchin 		if(d>1)
1306da2e3ebdSchin 		{
1307da2e3ebdSchin 			/* multiple width character put in place holders */
1308da2e3ebdSchin 			*dp++ = c;
1309da2e3ebdSchin 			while(--d >0)
1310da2e3ebdSchin 				*dp++ = MARKER;
1311da2e3ebdSchin 			/* in vi mode the cursor is at the last character */
1312da2e3ebdSchin 			if(dp>=dpmax)
1313da2e3ebdSchin 				break;
1314da2e3ebdSchin 			continue;
1315da2e3ebdSchin 		}
1316da2e3ebdSchin 		else
1317da2e3ebdSchin #else
1318da2e3ebdSchin 		d = (is_cntrl(c)?-1:1);
1319da2e3ebdSchin #endif	/* SHOPT_MULTIBYTE */
1320da2e3ebdSchin 		if(d<0)
1321da2e3ebdSchin 		{
1322da2e3ebdSchin 			if(c=='\t')
1323da2e3ebdSchin 			{
1324da2e3ebdSchin 				c = dp-phys;
1325da2e3ebdSchin 				if(sh_isoption(SH_VI))
1326da2e3ebdSchin 					c += ep->e_plen;
1327da2e3ebdSchin 				c = TABSIZE - c%TABSIZE;
1328da2e3ebdSchin 				while(--c>0)
1329da2e3ebdSchin 					*dp++ = ' ';
1330da2e3ebdSchin 				c = ' ';
1331da2e3ebdSchin 			}
1332da2e3ebdSchin 			else
1333da2e3ebdSchin 			{
1334da2e3ebdSchin 				*dp++ = '^';
1335da2e3ebdSchin 				c = printchar(c);
1336da2e3ebdSchin 			}
1337da2e3ebdSchin 			/* in vi mode the cursor is at the last character */
1338da2e3ebdSchin 			if(curp == sp && sh_isoption(SH_VI))
1339da2e3ebdSchin 				r = dp - phys;
1340da2e3ebdSchin 		}
1341da2e3ebdSchin 		*dp++ = c;
1342da2e3ebdSchin 		if(dp>=dpmax)
1343da2e3ebdSchin 			break;
1344da2e3ebdSchin 	}
1345da2e3ebdSchin 	*dp = 0;
13467c2fbfb3SApril Chin 	ep->e_peol = dp-phys;
1347da2e3ebdSchin 	return(r);
1348da2e3ebdSchin }
1349da2e3ebdSchin 
1350da2e3ebdSchin #if SHOPT_MULTIBYTE
1351da2e3ebdSchin /*
1352da2e3ebdSchin  * convert external representation <src> to an array of genchars <dest>
1353da2e3ebdSchin  * <src> and <dest> can be the same
1354da2e3ebdSchin  * returns number of chars in dest
1355da2e3ebdSchin  */
1356da2e3ebdSchin 
1357da2e3ebdSchin int	ed_internal(const char *src, genchar *dest)
1358da2e3ebdSchin {
1359da2e3ebdSchin 	register const unsigned char *cp = (unsigned char *)src;
1360da2e3ebdSchin 	register int c;
1361da2e3ebdSchin 	register wchar_t *dp = (wchar_t*)dest;
1362da2e3ebdSchin 	if(dest == (genchar*)roundof(cp-(unsigned char*)0,sizeof(genchar)))
1363da2e3ebdSchin 	{
1364da2e3ebdSchin 		genchar buffer[MAXLINE];
1365da2e3ebdSchin 		c = ed_internal(src,buffer);
1366da2e3ebdSchin 		ed_gencpy((genchar*)dp,buffer);
1367da2e3ebdSchin 		return(c);
1368da2e3ebdSchin 	}
1369da2e3ebdSchin 	while(*cp)
1370da2e3ebdSchin 		*dp++ = mbchar(cp);
1371da2e3ebdSchin 	*dp = 0;
1372da2e3ebdSchin 	return(dp-(wchar_t*)dest);
1373da2e3ebdSchin }
1374da2e3ebdSchin 
1375da2e3ebdSchin /*
1376da2e3ebdSchin  * convert internal representation <src> into character array <dest>.
1377da2e3ebdSchin  * The <src> and <dest> may be the same.
1378da2e3ebdSchin  * returns number of chars in dest.
1379da2e3ebdSchin  */
1380da2e3ebdSchin 
1381da2e3ebdSchin int	ed_external(const genchar *src, char *dest)
1382da2e3ebdSchin {
1383da2e3ebdSchin 	register genchar wc;
1384da2e3ebdSchin 	register int c,size;
1385da2e3ebdSchin 	register char *dp = dest;
1386da2e3ebdSchin 	char *dpmax = dp+sizeof(genchar)*MAXLINE-2;
1387da2e3ebdSchin 	if((char*)src == dp)
1388da2e3ebdSchin 	{
1389da2e3ebdSchin 		char buffer[MAXLINE*sizeof(genchar)];
1390da2e3ebdSchin 		c = ed_external(src,buffer);
1391da2e3ebdSchin 
1392da2e3ebdSchin #ifdef _lib_wcscpy
1393da2e3ebdSchin 		wcscpy((wchar_t *)dest,(const wchar_t *)buffer);
1394da2e3ebdSchin #else
1395da2e3ebdSchin 		strcpy(dest,buffer);
1396da2e3ebdSchin #endif
1397da2e3ebdSchin 		return(c);
1398da2e3ebdSchin 	}
1399da2e3ebdSchin 	while((wc = *src++) && dp<dpmax)
1400da2e3ebdSchin 	{
1401da2e3ebdSchin 		if((size = mbconv(dp, wc)) < 0)
1402da2e3ebdSchin 		{
1403da2e3ebdSchin 			/* copy the character as is */
1404da2e3ebdSchin 			size = 1;
1405da2e3ebdSchin 			*dp = wc;
1406da2e3ebdSchin 		}
1407da2e3ebdSchin 		dp += size;
1408da2e3ebdSchin 	}
1409da2e3ebdSchin 	*dp = 0;
1410da2e3ebdSchin 	return(dp-dest);
1411da2e3ebdSchin }
1412da2e3ebdSchin 
1413da2e3ebdSchin /*
1414da2e3ebdSchin  * copy <sp> to <dp>
1415da2e3ebdSchin  */
1416da2e3ebdSchin 
1417da2e3ebdSchin void	ed_gencpy(genchar *dp,const genchar *sp)
1418da2e3ebdSchin {
1419da2e3ebdSchin 	dp = (genchar*)roundof((char*)dp-(char*)0,sizeof(genchar));
1420da2e3ebdSchin 	sp = (const genchar*)roundof((char*)sp-(char*)0,sizeof(genchar));
1421da2e3ebdSchin 	while(*dp++ = *sp++);
1422da2e3ebdSchin }
1423da2e3ebdSchin 
1424da2e3ebdSchin /*
1425da2e3ebdSchin  * copy at most <n> items from <sp> to <dp>
1426da2e3ebdSchin  */
1427da2e3ebdSchin 
1428da2e3ebdSchin void	ed_genncpy(register genchar *dp,register const genchar *sp, int n)
1429da2e3ebdSchin {
1430da2e3ebdSchin 	dp = (genchar*)roundof((char*)dp-(char*)0,sizeof(genchar));
1431da2e3ebdSchin 	sp = (const genchar*)roundof((char*)sp-(char*)0,sizeof(genchar));
1432da2e3ebdSchin 	while(n-->0 && (*dp++ = *sp++));
1433da2e3ebdSchin }
1434da2e3ebdSchin 
1435da2e3ebdSchin /*
1436da2e3ebdSchin  * find the string length of <str>
1437da2e3ebdSchin  */
1438da2e3ebdSchin 
1439da2e3ebdSchin int	ed_genlen(register const genchar *str)
1440da2e3ebdSchin {
1441da2e3ebdSchin 	register const genchar *sp = str;
1442da2e3ebdSchin 	sp = (const genchar*)roundof((char*)sp-(char*)0,sizeof(genchar));
1443da2e3ebdSchin 	while(*sp++);
1444da2e3ebdSchin 	return(sp-str-1);
1445da2e3ebdSchin }
1446da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
1447da2e3ebdSchin #endif /* SHOPT_ESH || SHOPT_VSH */
1448da2e3ebdSchin 
1449da2e3ebdSchin #ifdef future
1450da2e3ebdSchin /*
1451da2e3ebdSchin  * returns 1 when <n> bytes starting at <a> and <b> are equal
1452da2e3ebdSchin  */
1453da2e3ebdSchin static int compare(register const char *a,register const char *b,register int n)
1454da2e3ebdSchin {
1455da2e3ebdSchin 	while(n-->0)
1456da2e3ebdSchin 	{
1457da2e3ebdSchin 		if(*a++ != *b++)
1458da2e3ebdSchin 			return(0);
1459da2e3ebdSchin 	}
1460da2e3ebdSchin 	return(1);
1461da2e3ebdSchin }
1462da2e3ebdSchin #endif
1463da2e3ebdSchin 
1464da2e3ebdSchin #if SHOPT_OLDTERMIO
1465da2e3ebdSchin 
1466da2e3ebdSchin #   include	<sys/termio.h>
1467da2e3ebdSchin 
1468da2e3ebdSchin #ifndef ECHOCTL
1469da2e3ebdSchin #   define ECHOCTL	0
1470da2e3ebdSchin #endif /* !ECHOCTL */
1471da2e3ebdSchin #define ott	ep->e_ott
1472da2e3ebdSchin 
1473da2e3ebdSchin /*
1474da2e3ebdSchin  * For backward compatibility only
1475da2e3ebdSchin  * This version will use termios when possible, otherwise termio
1476da2e3ebdSchin  */
1477da2e3ebdSchin 
14787c2fbfb3SApril Chin int tcgetattr(int fd, struct termios *tt)
1479da2e3ebdSchin {
1480da2e3ebdSchin 	register Edit_t *ep = (Edit_t*)(sh_getinterp()->ed_context);
1481da2e3ebdSchin 	register int r,i;
1482da2e3ebdSchin 	ep->e_tcgeta = 0;
1483da2e3ebdSchin 	ep->e_echoctl = (ECHOCTL!=0);
1484da2e3ebdSchin 	if((r=ioctl(fd,TCGETS,tt))>=0 ||  errno!=EINVAL)
1485da2e3ebdSchin 		return(r);
1486da2e3ebdSchin 	if((r=ioctl(fd,TCGETA,&ott)) >= 0)
1487da2e3ebdSchin 	{
1488da2e3ebdSchin 		tt->c_lflag = ott.c_lflag;
1489da2e3ebdSchin 		tt->c_oflag = ott.c_oflag;
1490da2e3ebdSchin 		tt->c_iflag = ott.c_iflag;
1491da2e3ebdSchin 		tt->c_cflag = ott.c_cflag;
1492da2e3ebdSchin 		for(i=0; i<NCC; i++)
1493da2e3ebdSchin 			tt->c_cc[i] = ott.c_cc[i];
1494da2e3ebdSchin 		ep->e_tcgeta++;
1495da2e3ebdSchin 		ep->e_echoctl = 0;
1496da2e3ebdSchin 	}
1497da2e3ebdSchin 	return(r);
1498da2e3ebdSchin }
1499da2e3ebdSchin 
15007c2fbfb3SApril Chin int tcsetattr(int fd,int mode,struct termios *tt)
1501da2e3ebdSchin {
1502da2e3ebdSchin 	register Edit_t *ep = (Edit_t*)(sh_getinterp()->ed_context);
1503da2e3ebdSchin 	register int r;
1504da2e3ebdSchin 	if(ep->e_tcgeta)
1505da2e3ebdSchin 	{
1506da2e3ebdSchin 		register int i;
1507da2e3ebdSchin 		ott.c_lflag = tt->c_lflag;
1508da2e3ebdSchin 		ott.c_oflag = tt->c_oflag;
1509da2e3ebdSchin 		ott.c_iflag = tt->c_iflag;
1510da2e3ebdSchin 		ott.c_cflag = tt->c_cflag;
1511da2e3ebdSchin 		for(i=0; i<NCC; i++)
1512da2e3ebdSchin 			ott.c_cc[i] = tt->c_cc[i];
1513da2e3ebdSchin 		if(tt->c_lflag&ECHOCTL)
1514da2e3ebdSchin 		{
1515da2e3ebdSchin 			ott.c_lflag &= ~(ECHOCTL|IEXTEN);
1516da2e3ebdSchin 			ott.c_iflag &= ~(IGNCR|ICRNL);
1517da2e3ebdSchin 			ott.c_iflag |= INLCR;
1518da2e3ebdSchin 			ott.c_cc[VEOF]= ESC;  /* ESC -> eof char */
1519da2e3ebdSchin 			ott.c_cc[VEOL] = '\r'; /* CR -> eol char */
1520da2e3ebdSchin 			ott.c_cc[VEOL2] = tt->c_cc[VEOF]; /* EOF -> eol char */
1521da2e3ebdSchin 		}
1522da2e3ebdSchin 		switch(mode)
1523da2e3ebdSchin 		{
1524da2e3ebdSchin 			case TCSANOW:
1525da2e3ebdSchin 				mode = TCSETA;
1526da2e3ebdSchin 				break;
1527da2e3ebdSchin 			case TCSADRAIN:
1528da2e3ebdSchin 				mode = TCSETAW;
1529da2e3ebdSchin 				break;
1530da2e3ebdSchin 			case TCSAFLUSH:
1531da2e3ebdSchin 				mode = TCSETAF;
1532da2e3ebdSchin 		}
1533da2e3ebdSchin 		return(ioctl(fd,mode,&ott));
1534da2e3ebdSchin 	}
1535da2e3ebdSchin 	return(ioctl(fd,mode,tt));
1536da2e3ebdSchin }
1537da2e3ebdSchin #endif /* SHOPT_OLDTERMIO */
1538da2e3ebdSchin 
1539da2e3ebdSchin #if KSHELL
1540da2e3ebdSchin /*
1541da2e3ebdSchin  * Execute keyboard trap on given buffer <inbuff> of given size <isize>
1542da2e3ebdSchin  * <mode> < 0 for vi insert mode
1543da2e3ebdSchin  */
1544da2e3ebdSchin static int keytrap(Edit_t *ep,char *inbuff,register int insize, int bufsize, int mode)
1545da2e3ebdSchin {
1546da2e3ebdSchin 	register char *cp;
1547da2e3ebdSchin 	int savexit;
15487c2fbfb3SApril Chin 	Shell_t *shp = ep->sh;
1549da2e3ebdSchin #if SHOPT_MULTIBYTE
1550da2e3ebdSchin 	char buff[MAXLINE];
1551da2e3ebdSchin 	ed_external(ep->e_inbuf,cp=buff);
1552da2e3ebdSchin #else
1553da2e3ebdSchin 	cp = ep->e_inbuf;
1554da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
1555da2e3ebdSchin 	inbuff[insize] = 0;
1556da2e3ebdSchin 	ep->e_col = ep->e_cur;
1557da2e3ebdSchin 	if(mode== -2)
1558da2e3ebdSchin 	{
1559da2e3ebdSchin 		ep->e_col++;
1560da2e3ebdSchin 		*ep->e_vi_insert = ESC;
1561da2e3ebdSchin 	}
1562da2e3ebdSchin 	else
1563da2e3ebdSchin 		*ep->e_vi_insert = 0;
1564da2e3ebdSchin 	nv_putval(ED_CHRNOD,inbuff,NV_NOFREE);
1565da2e3ebdSchin 	nv_putval(ED_COLNOD,(char*)&ep->e_col,NV_NOFREE|NV_INTEGER);
1566da2e3ebdSchin 	nv_putval(ED_TXTNOD,(char*)cp,NV_NOFREE);
1567da2e3ebdSchin 	nv_putval(ED_MODENOD,ep->e_vi_insert,NV_NOFREE);
15687c2fbfb3SApril Chin 	savexit = shp->savexit;
15697c2fbfb3SApril Chin 	sh_trap(shp->st.trap[SH_KEYTRAP],0);
15707c2fbfb3SApril Chin 	shp->savexit = savexit;
1571da2e3ebdSchin 	if((cp = nv_getval(ED_CHRNOD)) == inbuff)
1572da2e3ebdSchin 		nv_unset(ED_CHRNOD);
15737c2fbfb3SApril Chin 	else if(bufsize>0)
1574da2e3ebdSchin 	{
1575da2e3ebdSchin 		strncpy(inbuff,cp,bufsize);
15767c2fbfb3SApril Chin 		inbuff[bufsize-1]='\0';
1577da2e3ebdSchin 		insize = strlen(inbuff);
1578da2e3ebdSchin 	}
15797c2fbfb3SApril Chin 	else
15807c2fbfb3SApril Chin 		insize = 0;
1581da2e3ebdSchin 	nv_unset(ED_TXTNOD);
1582da2e3ebdSchin 	return(insize);
1583da2e3ebdSchin }
1584da2e3ebdSchin #endif /* KSHELL */
1585da2e3ebdSchin 
1586da2e3ebdSchin void	*ed_open(Shell_t *shp)
1587da2e3ebdSchin {
1588da2e3ebdSchin 	Edit_t *ed = newof(0,Edit_t,1,0);
1589da2e3ebdSchin 	ed->sh = shp;
1590da2e3ebdSchin 	strcpy(ed->e_macro,"_??");
1591da2e3ebdSchin 	return((void*)ed);
1592da2e3ebdSchin }
1593