1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin *                                                                      *
3da2e3ebdSchin *               This software is part of the ast package               *
4*b30d1939SAndy Fiddaman *          Copyright (c) 1982-2012 AT&T Intellectual Property          *
5da2e3ebdSchin *                      and is licensed under the                       *
6*b30d1939SAndy Fiddaman *                 Eclipse Public License, Version 1.0                  *
77c2fbfb3SApril Chin *                    by AT&T Intellectual Property                     *
8da2e3ebdSchin *                                                                      *
9da2e3ebdSchin *                A copy of the License is available at                 *
10*b30d1939SAndy Fiddaman *          http://www.eclipse.org/org/documents/epl-v10.html           *
11*b30d1939SAndy Fiddaman *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
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 };
55*b30d1939SAndy Fiddaman static char KILL_LINE[20] = { ESC, '[', 'J', 0 };
56da2e3ebdSchin 
577c2fbfb3SApril Chin 
587c2fbfb3SApril Chin 
59da2e3ebdSchin #if SHOPT_MULTIBYTE
60da2e3ebdSchin #   define is_cntrl(c)	((c<=STRIP) && iscntrl(c))
61da2e3ebdSchin #   define is_print(c)	((c&~STRIP) || isprint(c))
62da2e3ebdSchin #else
63da2e3ebdSchin #   define is_cntrl(c)	iscntrl(c)
64da2e3ebdSchin #   define is_print(c)	isprint(c)
65da2e3ebdSchin #endif
66da2e3ebdSchin 
67da2e3ebdSchin #if	(CC_NATIVE == CC_ASCII)
68da2e3ebdSchin #   define printchar(c)	((c) ^ ('A'-cntl('A')))
69da2e3ebdSchin #else
printchar(int c)70da2e3ebdSchin     static int printchar(int c)
71da2e3ebdSchin     {
72da2e3ebdSchin 	switch(c)
73da2e3ebdSchin 	{
74da2e3ebdSchin 
75da2e3ebdSchin 	    case cntl('A'): return('A');
76da2e3ebdSchin 	    case cntl('B'): return('B');
77da2e3ebdSchin 	    case cntl('C'): return('C');
78da2e3ebdSchin 	    case cntl('D'): return('D');
79da2e3ebdSchin 	    case cntl('E'): return('E');
80da2e3ebdSchin 	    case cntl('F'): return('F');
81da2e3ebdSchin 	    case cntl('G'): return('G');
82da2e3ebdSchin 	    case cntl('H'): return('H');
83da2e3ebdSchin 	    case cntl('I'): return('I');
84da2e3ebdSchin 	    case cntl('J'): return('J');
85da2e3ebdSchin 	    case cntl('K'): return('K');
86da2e3ebdSchin 	    case cntl('L'): return('L');
87da2e3ebdSchin 	    case cntl('M'): return('M');
88da2e3ebdSchin 	    case cntl('N'): return('N');
89da2e3ebdSchin 	    case cntl('O'): return('O');
90da2e3ebdSchin 	    case cntl('P'): return('P');
91da2e3ebdSchin 	    case cntl('Q'): return('Q');
92da2e3ebdSchin 	    case cntl('R'): return('R');
93da2e3ebdSchin 	    case cntl('S'): return('S');
94da2e3ebdSchin 	    case cntl('T'): return('T');
95da2e3ebdSchin 	    case cntl('U'): return('U');
96da2e3ebdSchin 	    case cntl('V'): return('V');
97da2e3ebdSchin 	    case cntl('W'): return('W');
98da2e3ebdSchin 	    case cntl('X'): return('X');
99da2e3ebdSchin 	    case cntl('Y'): return('Y');
100da2e3ebdSchin 	    case cntl('Z'): return('Z');
101da2e3ebdSchin 	    case cntl(']'): return(']');
102da2e3ebdSchin 	    case cntl('['): return('[');
103da2e3ebdSchin 	}
104da2e3ebdSchin 	return('?');
105da2e3ebdSchin     }
106da2e3ebdSchin #endif
107da2e3ebdSchin #define MINWINDOW	15	/* minimum width window */
108da2e3ebdSchin #define DFLTWINDOW	80	/* default window width */
109da2e3ebdSchin #define RAWMODE		1
110da2e3ebdSchin #define ALTMODE		2
111da2e3ebdSchin #define ECHOMODE	3
112da2e3ebdSchin #define	SYSERR	-1
113da2e3ebdSchin 
114da2e3ebdSchin #if SHOPT_OLDTERMIO
115da2e3ebdSchin #   undef tcgetattr
116da2e3ebdSchin #   undef tcsetattr
117da2e3ebdSchin #endif /* SHOPT_OLDTERMIO */
118da2e3ebdSchin 
119da2e3ebdSchin #ifdef RT
120da2e3ebdSchin #   define VENIX 1
121da2e3ebdSchin #endif	/* RT */
122da2e3ebdSchin 
123da2e3ebdSchin 
124da2e3ebdSchin #ifdef _hdr_sgtty
125da2e3ebdSchin #   ifdef TIOCGETP
126da2e3ebdSchin 	static int l_mask;
127da2e3ebdSchin 	static struct tchars l_ttychars;
128da2e3ebdSchin 	static struct ltchars l_chars;
129da2e3ebdSchin 	static  char  l_changed;	/* set if mode bits changed */
130da2e3ebdSchin #	define L_CHARS	4
131da2e3ebdSchin #	define T_CHARS	2
132da2e3ebdSchin #	define L_MASK	1
133da2e3ebdSchin #   endif /* TIOCGETP */
134da2e3ebdSchin #endif /* _hdr_sgtty */
135da2e3ebdSchin 
136da2e3ebdSchin #if KSHELL
137da2e3ebdSchin      static int keytrap(Edit_t *,char*, int, int, int);
138da2e3ebdSchin #else
139da2e3ebdSchin      Edit_t editb;
140da2e3ebdSchin #endif	/* KSHELL */
141da2e3ebdSchin 
142da2e3ebdSchin 
143da2e3ebdSchin #ifndef _POSIX_DISABLE
144da2e3ebdSchin #   define _POSIX_DISABLE	0
145da2e3ebdSchin #endif
146da2e3ebdSchin 
147da2e3ebdSchin #ifdef future
148da2e3ebdSchin     static int compare(const char*, const char*, int);
149da2e3ebdSchin #endif  /* future */
150da2e3ebdSchin #if SHOPT_VSH || SHOPT_ESH
151da2e3ebdSchin #   define ttyparm	(ep->e_ttyparm)
152da2e3ebdSchin #   define nttyparm	(ep->e_nttyparm)
153da2e3ebdSchin     static const char bellchr[] = "\a";	/* bell char */
154da2e3ebdSchin #endif /* SHOPT_VSH || SHOPT_ESH */
155da2e3ebdSchin 
156da2e3ebdSchin 
157da2e3ebdSchin /*
158da2e3ebdSchin  * This routine returns true if fd refers to a terminal
159da2e3ebdSchin  * This should be equivalent to isatty
160da2e3ebdSchin  */
tty_check(int fd)161da2e3ebdSchin int tty_check(int fd)
162da2e3ebdSchin {
163*b30d1939SAndy Fiddaman 	register Edit_t *ep = (Edit_t*)(shgd->ed_context);
164da2e3ebdSchin 	struct termios tty;
165da2e3ebdSchin 	ep->e_savefd = -1;
166da2e3ebdSchin 	return(tty_get(fd,&tty)==0);
167da2e3ebdSchin }
168da2e3ebdSchin 
169da2e3ebdSchin /*
170da2e3ebdSchin  * Get the current terminal attributes
171da2e3ebdSchin  * This routine remembers the attributes and just returns them if it
172da2e3ebdSchin  *   is called again without an intervening tty_set()
173da2e3ebdSchin  */
174da2e3ebdSchin 
tty_get(register int fd,register struct termios * tty)175da2e3ebdSchin int tty_get(register int fd, register struct termios *tty)
176da2e3ebdSchin {
177*b30d1939SAndy Fiddaman 	register Edit_t *ep = (Edit_t*)(shgd->ed_context);
178da2e3ebdSchin 	if(fd == ep->e_savefd)
179da2e3ebdSchin 		*tty = ep->e_savetty;
180da2e3ebdSchin 	else
181da2e3ebdSchin 	{
182da2e3ebdSchin 		while(tcgetattr(fd,tty) == SYSERR)
183da2e3ebdSchin 		{
184da2e3ebdSchin 			if(errno !=EINTR)
185da2e3ebdSchin 				return(SYSERR);
186da2e3ebdSchin 			errno = 0;
187da2e3ebdSchin 		}
188da2e3ebdSchin 		/* save terminal settings if in cannonical state */
189da2e3ebdSchin 		if(ep->e_raw==0)
190da2e3ebdSchin 		{
191da2e3ebdSchin 			ep->e_savetty = *tty;
192da2e3ebdSchin 			ep->e_savefd = fd;
193da2e3ebdSchin 		}
194da2e3ebdSchin 	}
195da2e3ebdSchin 	return(0);
196da2e3ebdSchin }
197da2e3ebdSchin 
198da2e3ebdSchin /*
199da2e3ebdSchin  * Set the terminal attributes
200da2e3ebdSchin  * If fd<0, then current attributes are invalidated
201da2e3ebdSchin  */
202da2e3ebdSchin 
tty_set(int fd,int action,struct termios * tty)203da2e3ebdSchin int tty_set(int fd, int action, struct termios *tty)
204da2e3ebdSchin {
205*b30d1939SAndy Fiddaman 	register Edit_t *ep = (Edit_t*)(shgd->ed_context);
206da2e3ebdSchin 	if(fd >=0)
207da2e3ebdSchin 	{
208da2e3ebdSchin #ifdef future
209da2e3ebdSchin 		if(ep->e_savefd>=0 && compare(&ep->e_savetty,tty,sizeof(struct termios)))
210da2e3ebdSchin 			return(0);
211da2e3ebdSchin #endif
212da2e3ebdSchin 		while(tcsetattr(fd, action, tty) == SYSERR)
213da2e3ebdSchin 		{
214da2e3ebdSchin 			if(errno !=EINTR)
215da2e3ebdSchin 				return(SYSERR);
216da2e3ebdSchin 			errno = 0;
217da2e3ebdSchin 		}
218da2e3ebdSchin 		ep->e_savetty = *tty;
219da2e3ebdSchin 	}
220da2e3ebdSchin 	ep->e_savefd = fd;
221da2e3ebdSchin 	return(0);
222da2e3ebdSchin }
223da2e3ebdSchin 
224da2e3ebdSchin #if SHOPT_ESH || SHOPT_VSH
225da2e3ebdSchin /*{	TTY_COOKED( fd )
226da2e3ebdSchin  *
227da2e3ebdSchin  *	This routine will set the tty in cooked mode.
228da2e3ebdSchin  *	It is also called by error.done().
229da2e3ebdSchin  *
230da2e3ebdSchin }*/
231da2e3ebdSchin 
tty_cooked(register int fd)232da2e3ebdSchin void tty_cooked(register int fd)
233da2e3ebdSchin {
234*b30d1939SAndy Fiddaman 	register Edit_t *ep = (Edit_t*)(shgd->ed_context);
235*b30d1939SAndy Fiddaman 	ep->e_keytrap = 0;
236da2e3ebdSchin 	if(ep->e_raw==0)
237da2e3ebdSchin 		return;
238da2e3ebdSchin 	if(fd < 0)
239da2e3ebdSchin 		fd = ep->e_savefd;
240da2e3ebdSchin #ifdef L_MASK
241da2e3ebdSchin 	/* restore flags */
242da2e3ebdSchin 	if(l_changed&L_MASK)
243da2e3ebdSchin 		ioctl(fd,TIOCLSET,&l_mask);
244da2e3ebdSchin 	if(l_changed&T_CHARS)
245da2e3ebdSchin 		/* restore alternate break character */
246da2e3ebdSchin 		ioctl(fd,TIOCSETC,&l_ttychars);
247da2e3ebdSchin 	if(l_changed&L_CHARS)
248da2e3ebdSchin 		/* restore alternate break character */
249da2e3ebdSchin 		ioctl(fd,TIOCSLTC,&l_chars);
250da2e3ebdSchin 	l_changed = 0;
251da2e3ebdSchin #endif	/* L_MASK */
252da2e3ebdSchin 	/*** don't do tty_set unless ttyparm has valid data ***/
253da2e3ebdSchin 	if(tty_set(fd, TCSANOW, &ttyparm) == SYSERR)
254da2e3ebdSchin 		return;
255da2e3ebdSchin 	ep->e_raw = 0;
256da2e3ebdSchin 	return;
257da2e3ebdSchin }
258da2e3ebdSchin 
259da2e3ebdSchin /*{	TTY_RAW( fd )
260da2e3ebdSchin  *
261da2e3ebdSchin  *	This routine will set the tty in raw mode.
262da2e3ebdSchin  *
263da2e3ebdSchin }*/
264da2e3ebdSchin 
tty_raw(register int fd,int echomode)265da2e3ebdSchin int tty_raw(register int fd, int echomode)
266da2e3ebdSchin {
267da2e3ebdSchin 	int echo = echomode;
268da2e3ebdSchin #ifdef L_MASK
269da2e3ebdSchin 	struct ltchars lchars;
270da2e3ebdSchin #endif	/* L_MASK */
271*b30d1939SAndy Fiddaman 	register Edit_t *ep = (Edit_t*)(shgd->ed_context);
272da2e3ebdSchin 	if(ep->e_raw==RAWMODE)
273da2e3ebdSchin 		return(echo?-1:0);
274da2e3ebdSchin 	else if(ep->e_raw==ECHOMODE)
275da2e3ebdSchin 		return(echo?0:-1);
276da2e3ebdSchin #if !SHOPT_RAWONLY
277da2e3ebdSchin 	if(ep->e_raw != ALTMODE)
278da2e3ebdSchin #endif /* SHOPT_RAWONLY */
279da2e3ebdSchin 	{
280da2e3ebdSchin 		if(tty_get(fd,&ttyparm) == SYSERR)
281da2e3ebdSchin 			return(-1);
282da2e3ebdSchin 	}
283da2e3ebdSchin #if  L_MASK || VENIX
284da2e3ebdSchin 	if(ttyparm.sg_flags&LCASE)
285da2e3ebdSchin 		return(-1);
286da2e3ebdSchin 	if(!(ttyparm.sg_flags&ECHO))
287da2e3ebdSchin 	{
288da2e3ebdSchin 		if(!echomode)
289da2e3ebdSchin 			return(-1);
290da2e3ebdSchin 		echo = 0;
291da2e3ebdSchin 	}
292da2e3ebdSchin 	nttyparm = ttyparm;
293da2e3ebdSchin 	if(!echo)
294da2e3ebdSchin 		nttyparm.sg_flags &= ~(ECHO | TBDELAY);
295da2e3ebdSchin #   ifdef CBREAK
296da2e3ebdSchin 	nttyparm.sg_flags |= CBREAK;
297da2e3ebdSchin #   else
298da2e3ebdSchin 	nttyparm.sg_flags |= RAW;
299da2e3ebdSchin #   endif /* CBREAK */
300da2e3ebdSchin 	ep->e_erase = ttyparm.sg_erase;
301da2e3ebdSchin 	ep->e_kill = ttyparm.sg_kill;
302da2e3ebdSchin 	ep->e_eof = cntl('D');
303da2e3ebdSchin 	ep->e_werase = cntl('W');
304da2e3ebdSchin 	ep->e_lnext = cntl('V');
305da2e3ebdSchin 	if( tty_set(fd, TCSADRAIN, &nttyparm) == SYSERR )
306da2e3ebdSchin 		return(-1);
307da2e3ebdSchin 	ep->e_ttyspeed = (ttyparm.sg_ospeed>=B1200?FAST:SLOW);
308da2e3ebdSchin #   ifdef TIOCGLTC
309da2e3ebdSchin 	/* try to remove effect of ^V  and ^Y and ^O */
310da2e3ebdSchin 	if(ioctl(fd,TIOCGLTC,&l_chars) != SYSERR)
311da2e3ebdSchin 	{
312da2e3ebdSchin 		lchars = l_chars;
313da2e3ebdSchin 		lchars.t_lnextc = -1;
314da2e3ebdSchin 		lchars.t_flushc = -1;
315da2e3ebdSchin 		lchars.t_dsuspc = -1;	/* no delayed stop process signal */
316da2e3ebdSchin 		if(ioctl(fd,TIOCSLTC,&lchars) != SYSERR)
317da2e3ebdSchin 			l_changed |= L_CHARS;
318da2e3ebdSchin 	}
319da2e3ebdSchin #   endif	/* TIOCGLTC */
320da2e3ebdSchin #else
321da2e3ebdSchin 	if (!(ttyparm.c_lflag & ECHO ))
322da2e3ebdSchin 	{
323da2e3ebdSchin 		if(!echomode)
324da2e3ebdSchin 			return(-1);
325da2e3ebdSchin 		echo = 0;
326da2e3ebdSchin 	}
327da2e3ebdSchin #   ifdef FLUSHO
328da2e3ebdSchin 	ttyparm.c_lflag &= ~FLUSHO;
329da2e3ebdSchin #   endif /* FLUSHO */
330da2e3ebdSchin 	nttyparm = ttyparm;
331da2e3ebdSchin #  ifndef u370
332da2e3ebdSchin 	nttyparm.c_iflag &= ~(IGNPAR|PARMRK|INLCR|IGNCR|ICRNL);
333da2e3ebdSchin 	nttyparm.c_iflag |= BRKINT;
334da2e3ebdSchin #   else
335da2e3ebdSchin 	nttyparm.c_iflag &=
336da2e3ebdSchin 			~(IGNBRK|PARMRK|INLCR|IGNCR|ICRNL|INPCK);
337da2e3ebdSchin 	nttyparm.c_iflag |= (BRKINT|IGNPAR);
338da2e3ebdSchin #   endif	/* u370 */
339da2e3ebdSchin 	if(echo)
340*b30d1939SAndy Fiddaman 		nttyparm.c_lflag &= ~(ICANON);
341da2e3ebdSchin 	else
342*b30d1939SAndy Fiddaman 		nttyparm.c_lflag &= ~(ICANON|ISIG|ECHO|ECHOK);
343da2e3ebdSchin 	nttyparm.c_cc[VTIME] = 0;
344da2e3ebdSchin 	nttyparm.c_cc[VMIN] = 1;
345da2e3ebdSchin #   ifdef VREPRINT
346da2e3ebdSchin 	nttyparm.c_cc[VREPRINT] = _POSIX_DISABLE;
347da2e3ebdSchin #   endif /* VREPRINT */
348da2e3ebdSchin #   ifdef VDISCARD
349da2e3ebdSchin 	nttyparm.c_cc[VDISCARD] = _POSIX_DISABLE;
350da2e3ebdSchin #   endif /* VDISCARD */
351da2e3ebdSchin #   ifdef VDSUSP
352da2e3ebdSchin 	nttyparm.c_cc[VDSUSP] = _POSIX_DISABLE;
353da2e3ebdSchin #   endif /* VDSUSP */
354da2e3ebdSchin #   ifdef VWERASE
355da2e3ebdSchin 	if(ttyparm.c_cc[VWERASE] == _POSIX_DISABLE)
356da2e3ebdSchin 		ep->e_werase = cntl('W');
357da2e3ebdSchin 	else
358da2e3ebdSchin 		ep->e_werase = nttyparm.c_cc[VWERASE];
359da2e3ebdSchin 	nttyparm.c_cc[VWERASE] = _POSIX_DISABLE;
360da2e3ebdSchin #   else
361da2e3ebdSchin 	    ep->e_werase = cntl('W');
362da2e3ebdSchin #   endif /* VWERASE */
363da2e3ebdSchin #   ifdef VLNEXT
364da2e3ebdSchin 	if(ttyparm.c_cc[VLNEXT] == _POSIX_DISABLE )
365da2e3ebdSchin 		ep->e_lnext = cntl('V');
366da2e3ebdSchin 	else
367da2e3ebdSchin 		ep->e_lnext = nttyparm.c_cc[VLNEXT];
368da2e3ebdSchin 	nttyparm.c_cc[VLNEXT] = _POSIX_DISABLE;
369da2e3ebdSchin #   else
370da2e3ebdSchin 	ep->e_lnext = cntl('V');
371da2e3ebdSchin #   endif /* VLNEXT */
372*b30d1939SAndy Fiddaman 	ep->e_intr = ttyparm.c_cc[VINTR];
373da2e3ebdSchin 	ep->e_eof = ttyparm.c_cc[VEOF];
374da2e3ebdSchin 	ep->e_erase = ttyparm.c_cc[VERASE];
375da2e3ebdSchin 	ep->e_kill = ttyparm.c_cc[VKILL];
376da2e3ebdSchin 	if( tty_set(fd, TCSADRAIN, &nttyparm) == SYSERR )
377da2e3ebdSchin 		return(-1);
378da2e3ebdSchin 	ep->e_ttyspeed = (cfgetospeed(&ttyparm)>=B1200?FAST:SLOW);
379da2e3ebdSchin #endif
380da2e3ebdSchin 	ep->e_raw = (echomode?ECHOMODE:RAWMODE);
381da2e3ebdSchin 	return(0);
382da2e3ebdSchin }
383da2e3ebdSchin 
384da2e3ebdSchin #if !SHOPT_RAWONLY
385da2e3ebdSchin 
386da2e3ebdSchin /*
387da2e3ebdSchin  *
388da2e3ebdSchin  *	Get tty parameters and make ESC and '\r' wakeup characters.
389da2e3ebdSchin  *
390da2e3ebdSchin  */
391da2e3ebdSchin 
392da2e3ebdSchin #   ifdef TIOCGETC
tty_alt(register int fd)393da2e3ebdSchin int tty_alt(register int fd)
394da2e3ebdSchin {
395*b30d1939SAndy Fiddaman 	register Edit_t *ep = (Edit_t*)(shgd->ed_context);
396da2e3ebdSchin 	int mask;
397da2e3ebdSchin 	struct tchars ttychars;
398da2e3ebdSchin 	switch(ep->e_raw)
399da2e3ebdSchin 	{
400da2e3ebdSchin 	    case ECHOMODE:
401da2e3ebdSchin 		return(-1);
402da2e3ebdSchin 	    case ALTMODE:
403da2e3ebdSchin 		return(0);
404da2e3ebdSchin 	    case RAWMODE:
405da2e3ebdSchin 		tty_cooked(fd);
406da2e3ebdSchin 	}
407da2e3ebdSchin 	l_changed = 0;
408da2e3ebdSchin 	if( ep->e_ttyspeed == 0)
409da2e3ebdSchin 	{
410da2e3ebdSchin 		if((tty_get(fd,&ttyparm) != SYSERR))
411da2e3ebdSchin 			ep->e_ttyspeed = (ttyparm.sg_ospeed>=B1200?FAST:SLOW);
412da2e3ebdSchin 		ep->e_raw = ALTMODE;
413da2e3ebdSchin 	}
414da2e3ebdSchin 	if(ioctl(fd,TIOCGETC,&l_ttychars) == SYSERR)
415da2e3ebdSchin 		return(-1);
416da2e3ebdSchin 	if(ioctl(fd,TIOCLGET,&l_mask)==SYSERR)
417da2e3ebdSchin 		return(-1);
418da2e3ebdSchin 	ttychars = l_ttychars;
419da2e3ebdSchin 	mask =  LCRTBS|LCRTERA|LCTLECH|LPENDIN|LCRTKIL;
420da2e3ebdSchin 	if((l_mask|mask) != l_mask)
421da2e3ebdSchin 		l_changed = L_MASK;
422da2e3ebdSchin 	if(ioctl(fd,TIOCLBIS,&mask)==SYSERR)
423da2e3ebdSchin 		return(-1);
424da2e3ebdSchin 	if(ttychars.t_brkc!=ESC)
425da2e3ebdSchin 	{
426da2e3ebdSchin 		ttychars.t_brkc = ESC;
427da2e3ebdSchin 		l_changed |= T_CHARS;
428da2e3ebdSchin 		if(ioctl(fd,TIOCSETC,&ttychars) == SYSERR)
429da2e3ebdSchin 			return(-1);
430da2e3ebdSchin 	}
431da2e3ebdSchin 	return(0);
432da2e3ebdSchin }
433da2e3ebdSchin #   else
434da2e3ebdSchin #	ifndef PENDIN
435da2e3ebdSchin #	    define PENDIN	0
436da2e3ebdSchin #	endif /* PENDIN */
437da2e3ebdSchin #	ifndef IEXTEN
438da2e3ebdSchin #	    define IEXTEN	0
439da2e3ebdSchin #	endif /* IEXTEN */
440da2e3ebdSchin 
tty_alt(register int fd)441da2e3ebdSchin int tty_alt(register int fd)
442da2e3ebdSchin {
443*b30d1939SAndy Fiddaman 	register Edit_t *ep = (Edit_t*)(shgd->ed_context);
444da2e3ebdSchin 	switch(ep->e_raw)
445da2e3ebdSchin 	{
446da2e3ebdSchin 	    case ECHOMODE:
447da2e3ebdSchin 		return(-1);
448da2e3ebdSchin 	    case ALTMODE:
449da2e3ebdSchin 		return(0);
450da2e3ebdSchin 	    case RAWMODE:
451da2e3ebdSchin 		tty_cooked(fd);
452da2e3ebdSchin 	}
453da2e3ebdSchin 	if((tty_get(fd, &ttyparm)==SYSERR) || (!(ttyparm.c_lflag&ECHO)))
454da2e3ebdSchin 		return(-1);
455da2e3ebdSchin #	ifdef FLUSHO
456da2e3ebdSchin 	    ttyparm.c_lflag &= ~FLUSHO;
457da2e3ebdSchin #	endif /* FLUSHO */
458da2e3ebdSchin 	nttyparm = ttyparm;
459da2e3ebdSchin 	ep->e_eof = ttyparm.c_cc[VEOF];
460da2e3ebdSchin #	ifdef ECHOCTL
461da2e3ebdSchin 	    /* escape character echos as ^[ */
462da2e3ebdSchin 	    nttyparm.c_lflag |= (ECHOE|ECHOK|ECHOCTL|PENDIN|IEXTEN);
463da2e3ebdSchin 	    nttyparm.c_cc[VEOL] = ESC;
464da2e3ebdSchin #	else
465da2e3ebdSchin 	    /* switch VEOL2 and EOF, since EOF isn't echo'd by driver */
466da2e3ebdSchin 	    nttyparm.c_lflag |= (ECHOE|ECHOK);
467da2e3ebdSchin 	    nttyparm.c_cc[VEOF] = ESC;	/* make ESC the eof char */
468da2e3ebdSchin #	    ifdef VEOL2
469da2e3ebdSchin 		nttyparm.c_iflag &= ~(IGNCR|ICRNL);
470da2e3ebdSchin 		nttyparm.c_iflag |= INLCR;
471da2e3ebdSchin 		nttyparm.c_cc[VEOL] = '\r';	/* make CR an eol char */
472da2e3ebdSchin 		nttyparm.c_cc[VEOL2] = ep->e_eof; /* make EOF an eol char */
473da2e3ebdSchin #	    else
474da2e3ebdSchin 		nttyparm.c_cc[VEOL] = ep->e_eof; /* make EOF an eol char */
475da2e3ebdSchin #	    endif /* VEOL2 */
476da2e3ebdSchin #	endif /* ECHOCTL */
477da2e3ebdSchin #	ifdef VREPRINT
478da2e3ebdSchin 		nttyparm.c_cc[VREPRINT] = _POSIX_DISABLE;
479da2e3ebdSchin #	endif /* VREPRINT */
480da2e3ebdSchin #	ifdef VDISCARD
481da2e3ebdSchin 		nttyparm.c_cc[VDISCARD] = _POSIX_DISABLE;
482da2e3ebdSchin #	endif /* VDISCARD */
483da2e3ebdSchin #	ifdef VWERASE
484da2e3ebdSchin 	    if(ttyparm.c_cc[VWERASE] == _POSIX_DISABLE)
485da2e3ebdSchin 		    nttyparm.c_cc[VWERASE] = cntl('W');
486da2e3ebdSchin 	    ep->e_werase = nttyparm.c_cc[VWERASE];
487da2e3ebdSchin #	else
488da2e3ebdSchin 	    ep->e_werase = cntl('W');
489da2e3ebdSchin #	endif /* VWERASE */
490da2e3ebdSchin #	ifdef VLNEXT
491da2e3ebdSchin 	    if(ttyparm.c_cc[VLNEXT] == _POSIX_DISABLE )
492da2e3ebdSchin 		    nttyparm.c_cc[VLNEXT] = cntl('V');
493da2e3ebdSchin 	    ep->e_lnext = nttyparm.c_cc[VLNEXT];
494da2e3ebdSchin #	else
495da2e3ebdSchin 	    ep->e_lnext = cntl('V');
496da2e3ebdSchin #	endif /* VLNEXT */
497da2e3ebdSchin 	ep->e_erase = ttyparm.c_cc[VERASE];
498da2e3ebdSchin 	ep->e_kill = ttyparm.c_cc[VKILL];
499da2e3ebdSchin 	if( tty_set(fd, TCSADRAIN, &nttyparm) == SYSERR )
500da2e3ebdSchin 		return(-1);
501da2e3ebdSchin 	ep->e_ttyspeed = (cfgetospeed(&ttyparm)>=B1200?FAST:SLOW);
502da2e3ebdSchin 	ep->e_raw = ALTMODE;
503da2e3ebdSchin 	return(0);
504da2e3ebdSchin }
505da2e3ebdSchin 
506da2e3ebdSchin #   endif /* TIOCGETC */
507da2e3ebdSchin #endif	/* SHOPT_RAWONLY */
508da2e3ebdSchin 
509da2e3ebdSchin /*
510da2e3ebdSchin  *	ED_WINDOW()
511da2e3ebdSchin  *
512da2e3ebdSchin  *	return the window size
513da2e3ebdSchin  */
ed_window(void)514da2e3ebdSchin int ed_window(void)
515da2e3ebdSchin {
516da2e3ebdSchin 	int	rows,cols;
517da2e3ebdSchin 	register char *cp = nv_getval(COLUMNS);
518da2e3ebdSchin 	if(cp)
519da2e3ebdSchin 		cols = (int)strtol(cp, (char**)0, 10)-1;
520da2e3ebdSchin 	else
521da2e3ebdSchin 	{
522da2e3ebdSchin 		astwinsize(2,&rows,&cols);
523da2e3ebdSchin 		if(--cols <0)
524da2e3ebdSchin 			cols = DFLTWINDOW-1;
525da2e3ebdSchin 	}
526da2e3ebdSchin 	if(cols < MINWINDOW)
527da2e3ebdSchin 		cols = MINWINDOW;
528da2e3ebdSchin 	else if(cols > MAXWINDOW)
529da2e3ebdSchin 		cols = MAXWINDOW;
530da2e3ebdSchin 	return(cols);
531da2e3ebdSchin }
532da2e3ebdSchin 
533da2e3ebdSchin /*	E_FLUSH()
534da2e3ebdSchin  *
535da2e3ebdSchin  *	Flush the output buffer.
536da2e3ebdSchin  *
537da2e3ebdSchin  */
538da2e3ebdSchin 
ed_flush(Edit_t * ep)539da2e3ebdSchin void ed_flush(Edit_t *ep)
540da2e3ebdSchin {
541da2e3ebdSchin 	register int n = ep->e_outptr-ep->e_outbase;
542da2e3ebdSchin 	register int fd = ERRIO;
543da2e3ebdSchin 	if(n<=0)
544da2e3ebdSchin 		return;
545da2e3ebdSchin 	write(fd,ep->e_outbase,(unsigned)n);
546da2e3ebdSchin 	ep->e_outptr = ep->e_outbase;
547da2e3ebdSchin }
548da2e3ebdSchin 
549da2e3ebdSchin /*
550da2e3ebdSchin  * send the bell character ^G to the terminal
551da2e3ebdSchin  */
552da2e3ebdSchin 
ed_ringbell(void)553da2e3ebdSchin void ed_ringbell(void)
554da2e3ebdSchin {
555da2e3ebdSchin 	write(ERRIO,bellchr,1);
556da2e3ebdSchin }
557da2e3ebdSchin 
558da2e3ebdSchin /*
559da2e3ebdSchin  * send a carriage return line feed to the terminal
560da2e3ebdSchin  */
561da2e3ebdSchin 
ed_crlf(register Edit_t * ep)562da2e3ebdSchin void ed_crlf(register Edit_t *ep)
563da2e3ebdSchin {
564da2e3ebdSchin #ifdef cray
565da2e3ebdSchin 	ed_putchar(ep,'\r');
566da2e3ebdSchin #endif /* cray */
567da2e3ebdSchin #ifdef u370
568da2e3ebdSchin 	ed_putchar(ep,'\r');
569da2e3ebdSchin #endif	/* u370 */
570da2e3ebdSchin #ifdef VENIX
571da2e3ebdSchin 	ed_putchar(ep,'\r');
572da2e3ebdSchin #endif /* VENIX */
573da2e3ebdSchin 	ed_putchar(ep,'\n');
574da2e3ebdSchin 	ed_flush(ep);
575da2e3ebdSchin }
576da2e3ebdSchin 
577da2e3ebdSchin /*	ED_SETUP( max_prompt_size )
578da2e3ebdSchin  *
579da2e3ebdSchin  *	This routine sets up the prompt string
580da2e3ebdSchin  *	The following is an unadvertised feature.
581da2e3ebdSchin  *	  Escape sequences in the prompt can be excluded from the calculated
582da2e3ebdSchin  *	  prompt length.  This is accomplished as follows:
583da2e3ebdSchin  *	  - if the prompt string starts with "%\r, or contains \r%\r", where %
584da2e3ebdSchin  *	    represents any char, then % is taken to be the quote character.
585da2e3ebdSchin  *	  - strings enclosed by this quote character, and the quote character,
586da2e3ebdSchin  *	    are not counted as part of the prompt length.
587da2e3ebdSchin  */
588da2e3ebdSchin 
ed_setup(register Edit_t * ep,int fd,int reedit)589da2e3ebdSchin void	ed_setup(register Edit_t *ep, int fd, int reedit)
590da2e3ebdSchin {
5917c2fbfb3SApril Chin 	Shell_t *shp = ep->sh;
592da2e3ebdSchin 	register char *pp;
5937c2fbfb3SApril Chin 	register char *last, *prev;
594da2e3ebdSchin 	char *ppmax;
595da2e3ebdSchin 	int myquote = 0, n;
5967c2fbfb3SApril Chin 	register int qlen = 1, qwid;
597da2e3ebdSchin 	char inquote = 0;
598da2e3ebdSchin 	ep->e_fd = fd;
599da2e3ebdSchin 	ep->e_multiline = sh_isoption(SH_MULTILINE)!=0;
600da2e3ebdSchin #ifdef SIGWINCH
6017c2fbfb3SApril Chin 	if(!(shp->sigflag[SIGWINCH]&SH_SIGFAULT))
602da2e3ebdSchin 	{
603da2e3ebdSchin 		signal(SIGWINCH,sh_fault);
6047c2fbfb3SApril Chin 		shp->sigflag[SIGWINCH] |= SH_SIGFAULT;
605da2e3ebdSchin 	}
6067c2fbfb3SApril Chin 	pp = shp->st.trapcom[SIGWINCH];
6077c2fbfb3SApril Chin 	shp->st.trapcom[SIGWINCH] = 0;
608da2e3ebdSchin 	sh_fault(SIGWINCH);
6097c2fbfb3SApril Chin 	shp->st.trapcom[SIGWINCH] = pp;
6107c2fbfb3SApril Chin 	ep->sh->winch = 0;
611da2e3ebdSchin #endif
612*b30d1939SAndy Fiddaman #if SHOPT_EDPREDICT
613*b30d1939SAndy Fiddaman 	ep->hlist = 0;
614*b30d1939SAndy Fiddaman 	ep->nhlist = 0;
615*b30d1939SAndy Fiddaman 	ep->hoff = 0;
616*b30d1939SAndy Fiddaman #endif /* SHOPT_EDPREDICT */
617da2e3ebdSchin #if KSHELL
618da2e3ebdSchin 	ep->e_stkptr = stakptr(0);
619da2e3ebdSchin 	ep->e_stkoff = staktell();
6207c2fbfb3SApril Chin 	if(!(last = shp->prompt))
621da2e3ebdSchin 		last = "";
6227c2fbfb3SApril Chin 	shp->prompt = 0;
623da2e3ebdSchin #else
624da2e3ebdSchin 	last = ep->e_prbuff;
625da2e3ebdSchin #endif /* KSHELL */
626*b30d1939SAndy Fiddaman 	if(shp->gd->hist_ptr)
627da2e3ebdSchin 	{
628*b30d1939SAndy Fiddaman 		register History_t *hp = shp->gd->hist_ptr;
629da2e3ebdSchin 		ep->e_hismax = hist_max(hp);
630da2e3ebdSchin 		ep->e_hismin = hist_min(hp);
631da2e3ebdSchin 	}
632da2e3ebdSchin 	else
633da2e3ebdSchin 	{
634da2e3ebdSchin 		ep->e_hismax = ep->e_hismin = ep->e_hloff = 0;
635da2e3ebdSchin 	}
636da2e3ebdSchin 	ep->e_hline = ep->e_hismax;
637da2e3ebdSchin 	if(!sh_isoption(SH_VI) && !sh_isoption(SH_EMACS) && !sh_isoption(SH_GMACS))
638da2e3ebdSchin 		ep->e_wsize = MAXLINE;
639da2e3ebdSchin 	else
640da2e3ebdSchin 		ep->e_wsize = ed_window()-2;
641da2e3ebdSchin 	ep->e_winsz = ep->e_wsize+2;
642da2e3ebdSchin 	ep->e_crlf = 1;
643da2e3ebdSchin 	ep->e_plen = 0;
644da2e3ebdSchin 	pp = ep->e_prompt;
645da2e3ebdSchin 	ppmax = pp+PRSIZE-1;
646da2e3ebdSchin 	*pp++ = '\r';
647da2e3ebdSchin 	{
648da2e3ebdSchin 		register int c;
6497c2fbfb3SApril Chin 		while(prev = last, c = mbchar(last)) switch(c)
650da2e3ebdSchin 		{
651da2e3ebdSchin 			case ESC:
652da2e3ebdSchin 			{
653da2e3ebdSchin 				int skip=0;
654da2e3ebdSchin 				ep->e_crlf = 0;
655*b30d1939SAndy Fiddaman 				if (pp < ppmax)
656*b30d1939SAndy Fiddaman 					*pp++ = c;
657da2e3ebdSchin 				for(n=1; c = *last++; n++)
658da2e3ebdSchin 				{
659da2e3ebdSchin 					if(pp < ppmax)
660da2e3ebdSchin 						*pp++ = c;
6617c2fbfb3SApril Chin 					if(c=='\a' || c==ESC || c=='\r')
662da2e3ebdSchin 						break;
663da2e3ebdSchin 					if(skip || (c>='0' && c<='9'))
664*b30d1939SAndy Fiddaman 					{
665*b30d1939SAndy Fiddaman 						skip = 0;
666da2e3ebdSchin 						continue;
667*b30d1939SAndy Fiddaman 					}
668da2e3ebdSchin 					if(n>1 && c==';')
669da2e3ebdSchin 						skip = 1;
670da2e3ebdSchin 					else if(n>2 || (c!= '[' &&  c!= ']'))
671da2e3ebdSchin 						break;
672da2e3ebdSchin 				}
6737c2fbfb3SApril Chin 				if(c==0 || c==ESC || c=='\r')
6747c2fbfb3SApril Chin 					last--;
675da2e3ebdSchin 				qlen += (n+1);
676da2e3ebdSchin 				break;
677da2e3ebdSchin 			}
678da2e3ebdSchin 			case '\b':
679da2e3ebdSchin 				if(pp>ep->e_prompt+1)
680da2e3ebdSchin 					pp--;
681da2e3ebdSchin 				break;
682da2e3ebdSchin 			case '\r':
683da2e3ebdSchin 				if(pp == (ep->e_prompt+2)) /* quote char */
684da2e3ebdSchin 					myquote = *(pp-1);
685da2e3ebdSchin 				/*FALLTHROUGH*/
686da2e3ebdSchin 
687da2e3ebdSchin 			case '\n':
688da2e3ebdSchin 				/* start again */
689da2e3ebdSchin 				ep->e_crlf = 1;
690da2e3ebdSchin 				qlen = 1;
691da2e3ebdSchin 				inquote = 0;
692da2e3ebdSchin 				pp = ep->e_prompt+1;
693da2e3ebdSchin 				break;
694da2e3ebdSchin 
695da2e3ebdSchin 			case '\t':
696da2e3ebdSchin 				/* expand tabs */
697da2e3ebdSchin 				while((pp-ep->e_prompt)%TABSIZE)
698da2e3ebdSchin 				{
699da2e3ebdSchin 					if(pp >= ppmax)
700da2e3ebdSchin 						break;
701da2e3ebdSchin 					*pp++ = ' ';
702da2e3ebdSchin 				}
703da2e3ebdSchin 				break;
704da2e3ebdSchin 
705da2e3ebdSchin 			case '\a':
706da2e3ebdSchin 				/* cut out bells */
707da2e3ebdSchin 				break;
708da2e3ebdSchin 
709da2e3ebdSchin 			default:
710da2e3ebdSchin 				if(c==myquote)
711da2e3ebdSchin 				{
712da2e3ebdSchin 					qlen += inquote;
713da2e3ebdSchin 					inquote ^= 1;
714da2e3ebdSchin 				}
715da2e3ebdSchin 				if(pp < ppmax)
716da2e3ebdSchin 				{
7177c2fbfb3SApril Chin 					if(inquote)
7187c2fbfb3SApril Chin 						qlen++;
7197c2fbfb3SApril Chin 					else if(!is_print(c))
720da2e3ebdSchin 						ep->e_crlf = 0;
7217c2fbfb3SApril Chin 					if((qwid = last - prev) > 1)
7227c2fbfb3SApril Chin 						qlen += qwid - mbwidth(c);
7237c2fbfb3SApril Chin 					while(prev < last && pp < ppmax)
7247c2fbfb3SApril Chin 						*pp++ = *prev++;
725da2e3ebdSchin 				}
7267c2fbfb3SApril Chin 				break;
727da2e3ebdSchin 		}
728da2e3ebdSchin 	}
729da2e3ebdSchin 	if(pp-ep->e_prompt > qlen)
730da2e3ebdSchin 		ep->e_plen = pp - ep->e_prompt - qlen;
731da2e3ebdSchin 	*pp = 0;
7327c2fbfb3SApril Chin 	if(!ep->e_multiline && (ep->e_wsize -= ep->e_plen) < 7)
733da2e3ebdSchin 	{
734da2e3ebdSchin 		register int shift = 7-ep->e_wsize;
735da2e3ebdSchin 		ep->e_wsize = 7;
736da2e3ebdSchin 		pp = ep->e_prompt+1;
737da2e3ebdSchin 		strcpy(pp,pp+shift);
738da2e3ebdSchin 		ep->e_plen -= shift;
739da2e3ebdSchin 		last[-ep->e_plen-2] = '\r';
740da2e3ebdSchin 	}
741da2e3ebdSchin 	sfsync(sfstderr);
742da2e3ebdSchin 	if(fd == sffileno(sfstderr))
743da2e3ebdSchin 	{
744da2e3ebdSchin 		/* can't use output buffer when reading from stderr */
745da2e3ebdSchin 		static char *buff;
746da2e3ebdSchin 		if(!buff)
747da2e3ebdSchin 			buff = (char*)malloc(MAXLINE);
748da2e3ebdSchin 		ep->e_outbase = ep->e_outptr = buff;
749da2e3ebdSchin 		ep->e_outlast = ep->e_outptr + MAXLINE;
750da2e3ebdSchin 		return;
751da2e3ebdSchin 	}
752da2e3ebdSchin 	qlen = sfset(sfstderr,SF_READ,0);
753da2e3ebdSchin 	/* make sure SF_READ not on */
754da2e3ebdSchin 	ep->e_outbase = ep->e_outptr = (char*)sfreserve(sfstderr,SF_UNBOUND,SF_LOCKR);
755da2e3ebdSchin 	ep->e_outlast = ep->e_outptr + sfvalue(sfstderr);
756da2e3ebdSchin 	if(qlen)
757da2e3ebdSchin 		sfset(sfstderr,SF_READ,1);
758da2e3ebdSchin 	sfwrite(sfstderr,ep->e_outptr,0);
759da2e3ebdSchin 	ep->e_eol = reedit;
760da2e3ebdSchin 	if(ep->e_multiline)
761da2e3ebdSchin 	{
762da2e3ebdSchin #ifdef _cmd_tput
763da2e3ebdSchin 		char *term;
764da2e3ebdSchin 		if(!ep->e_term)
7657c2fbfb3SApril Chin 			ep->e_term = nv_search("TERM",shp->var_tree,0);
766da2e3ebdSchin 		if(ep->e_term && (term=nv_getval(ep->e_term)) && strlen(term)<sizeof(ep->e_termname) && strcmp(term,ep->e_termname))
767da2e3ebdSchin 		{
768da2e3ebdSchin 			sh_trap(".sh.subscript=$(tput cuu1 2>/dev/null)",0);
769da2e3ebdSchin 			if(pp=nv_getval(SH_SUBSCRNOD))
770da2e3ebdSchin 				strncpy(CURSOR_UP,pp,sizeof(CURSOR_UP)-1);
771da2e3ebdSchin 			nv_unset(SH_SUBSCRNOD);
772da2e3ebdSchin 			strcpy(ep->e_termname,term);
773da2e3ebdSchin 		}
774da2e3ebdSchin #endif
7757c2fbfb3SApril Chin 		ep->e_wsize = MAXLINE - (ep->e_plen+1);
776da2e3ebdSchin 	}
777da2e3ebdSchin 	if(ep->e_default && (pp = nv_getval(ep->e_default)))
778da2e3ebdSchin 	{
779da2e3ebdSchin 		n = strlen(pp);
780da2e3ebdSchin 		if(n > LOOKAHEAD)
781da2e3ebdSchin 			n = LOOKAHEAD;
782da2e3ebdSchin 		ep->e_lookahead = n;
783da2e3ebdSchin 		while(n-- > 0)
784da2e3ebdSchin 			ep->e_lbuf[n] = *pp++;
785da2e3ebdSchin 		ep->e_default = 0;
786da2e3ebdSchin 	}
787da2e3ebdSchin }
788da2e3ebdSchin 
ed_putstring(register Edit_t * ep,const char * str)7897c2fbfb3SApril Chin static void ed_putstring(register Edit_t *ep, const char *str)
7907c2fbfb3SApril Chin {
7917c2fbfb3SApril Chin 	register int c;
7927c2fbfb3SApril Chin 	while(c = *str++)
7937c2fbfb3SApril Chin 		ed_putchar(ep,c);
7947c2fbfb3SApril Chin }
7957c2fbfb3SApril Chin 
ed_nputchar(register Edit_t * ep,int n,int c)7967c2fbfb3SApril Chin static void ed_nputchar(register Edit_t *ep, int n, int c)
7977c2fbfb3SApril Chin {
7987c2fbfb3SApril Chin 	while(n-->0)
7997c2fbfb3SApril Chin 		ed_putchar(ep,c);
8007c2fbfb3SApril Chin }
8017c2fbfb3SApril Chin 
802da2e3ebdSchin /*
803da2e3ebdSchin  * Do read, restart on interrupt unless SH_SIGSET or SH_SIGTRAP is set
804da2e3ebdSchin  * Use sfpkrd() to poll() or select() to wait for input if possible
805da2e3ebdSchin  * Unfortunately, systems that get interrupted from slow reads update
806da2e3ebdSchin  * this access time for for the terminal (in violation of POSIX).
807da2e3ebdSchin  * The fixtime() macro, resets the time to the time at entry in
808da2e3ebdSchin  * this case.  This is not necessary for systems that can handle
809da2e3ebdSchin  * sfpkrd() correctly (i,e., those that support poll() or select()
810da2e3ebdSchin  */
ed_read(void * context,int fd,char * buff,int size,int reedit)811da2e3ebdSchin int ed_read(void *context, int fd, char *buff, int size, int reedit)
812da2e3ebdSchin {
813da2e3ebdSchin 	register Edit_t *ep = (Edit_t*)context;
814da2e3ebdSchin 	register int rv= -1;
815*b30d1939SAndy Fiddaman 	register int delim = ((ep->e_raw&RAWMODE)?nttyparm.c_cc[VEOL]:'\n');
8167c2fbfb3SApril Chin 	Shell_t *shp = ep->sh;
817da2e3ebdSchin 	int mode = -1;
818*b30d1939SAndy Fiddaman 	int (*waitevent)(int,long,int) = shp->gd->waitevent;
819da2e3ebdSchin 	if(ep->e_raw==ALTMODE)
820da2e3ebdSchin 		mode = 1;
821da2e3ebdSchin 	if(size < 0)
822da2e3ebdSchin 	{
823da2e3ebdSchin 		mode = 1;
824da2e3ebdSchin 		size = -size;
825da2e3ebdSchin 	}
826da2e3ebdSchin 	sh_onstate(SH_TTYWAIT);
827da2e3ebdSchin 	errno = EINTR;
828*b30d1939SAndy Fiddaman 	shp->gd->waitevent = 0;
829da2e3ebdSchin 	while(rv<0 && errno==EINTR)
830da2e3ebdSchin 	{
8317c2fbfb3SApril Chin 		if(shp->trapnote&(SH_SIGSET|SH_SIGTRAP))
832da2e3ebdSchin 			goto done;
83334f9b3eeSRoland Mainz 		if(ep->sh->winch && sh_isstate(SH_INTERACTIVE) && (sh_isoption(SH_VI) || sh_isoption(SH_EMACS)))
8347c2fbfb3SApril Chin 		{
8357c2fbfb3SApril Chin 			Edpos_t	lastpos;
8367c2fbfb3SApril Chin 			int	n, rows, newsize;
8377c2fbfb3SApril Chin 			/* move cursor to start of first line */
8387c2fbfb3SApril Chin 			ed_putchar(ep,'\r');
8397c2fbfb3SApril Chin 			ed_flush(ep);
8407c2fbfb3SApril Chin 			astwinsize(2,&rows,&newsize);
8417c2fbfb3SApril Chin 			n = (ep->e_plen+ep->e_cur)/++ep->e_winsz;
8427c2fbfb3SApril Chin 			while(n--)
8437c2fbfb3SApril Chin 				ed_putstring(ep,CURSOR_UP);
8447c2fbfb3SApril Chin 			if(ep->e_multiline && newsize>ep->e_winsz && (lastpos.line=(ep->e_plen+ep->e_peol)/ep->e_winsz))
8457c2fbfb3SApril Chin 			{
8467c2fbfb3SApril Chin 				/* clear the current command line */
8477c2fbfb3SApril Chin 				n = lastpos.line;
8487c2fbfb3SApril Chin 				while(lastpos.line--)
8497c2fbfb3SApril Chin 				{
8507c2fbfb3SApril Chin 					ed_nputchar(ep,ep->e_winsz,' ');
8517c2fbfb3SApril Chin 					ed_putchar(ep,'\n');
8527c2fbfb3SApril Chin 				}
8537c2fbfb3SApril Chin 				ed_nputchar(ep,ep->e_winsz,' ');
8547c2fbfb3SApril Chin 				while(n--)
8557c2fbfb3SApril Chin 					ed_putstring(ep,CURSOR_UP);
8567c2fbfb3SApril Chin 			}
8577c2fbfb3SApril Chin 	                ep->sh->winch = 0;
8587c2fbfb3SApril Chin 			ed_flush(ep);
8597c2fbfb3SApril Chin 			sh_delay(.05);
8607c2fbfb3SApril Chin 			astwinsize(2,&rows,&newsize);
8617c2fbfb3SApril Chin 			ep->e_winsz = newsize-1;
862*b30d1939SAndy Fiddaman 			if(ep->e_winsz < MINWINDOW)
863*b30d1939SAndy Fiddaman 				ep->e_winsz = MINWINDOW;
8647c2fbfb3SApril Chin 			if(!ep->e_multiline && ep->e_wsize < MAXLINE)
8657c2fbfb3SApril Chin 				ep->e_wsize = ep->e_winsz-2;
8667c2fbfb3SApril Chin 			ep->e_nocrnl=1;
8677c2fbfb3SApril Chin 			if(*ep->e_vi_insert)
8687c2fbfb3SApril Chin 			{
8697c2fbfb3SApril Chin 				buff[0] = ESC;
8707c2fbfb3SApril Chin 				buff[1] = cntl('L');
8717c2fbfb3SApril Chin 				buff[2] = 'a';
8727c2fbfb3SApril Chin 				return(3);
8737c2fbfb3SApril Chin 			}
87434f9b3eeSRoland Mainz 			if(sh_isoption(SH_EMACS) || sh_isoption(SH_VI))
87534f9b3eeSRoland Mainz 				buff[0] = cntl('L');
8767c2fbfb3SApril Chin 			return(1);
8777c2fbfb3SApril Chin 		}
87834f9b3eeSRoland Mainz 		else
87934f9b3eeSRoland Mainz 			ep->sh->winch = 0;
880da2e3ebdSchin 		/* an interrupt that should be ignored */
881da2e3ebdSchin 		errno = 0;
882da2e3ebdSchin 		if(!waitevent || (rv=(*waitevent)(fd,-1L,0))>=0)
883da2e3ebdSchin 			rv = sfpkrd(fd,buff,size,delim,-1L,mode);
884da2e3ebdSchin 	}
885da2e3ebdSchin 	if(rv < 0)
886da2e3ebdSchin 	{
887da2e3ebdSchin #ifdef _hdr_utime
888da2e3ebdSchin #		define fixtime()	if(isdevtty)utime(ep->e_tty,&utimes)
889da2e3ebdSchin 		int	isdevtty=0;
890da2e3ebdSchin 		struct stat statb;
891da2e3ebdSchin 		struct utimbuf utimes;
892da2e3ebdSchin 	 	if(errno==0 && !ep->e_tty)
893da2e3ebdSchin 		{
894da2e3ebdSchin 			if((ep->e_tty=ttyname(fd)) && stat(ep->e_tty,&statb)>=0)
895da2e3ebdSchin 			{
896da2e3ebdSchin 				ep->e_tty_ino = statb.st_ino;
897da2e3ebdSchin 				ep->e_tty_dev = statb.st_dev;
898da2e3ebdSchin 			}
899da2e3ebdSchin 		}
900da2e3ebdSchin 		if(ep->e_tty_ino && fstat(fd,&statb)>=0 && statb.st_ino==ep->e_tty_ino && statb.st_dev==ep->e_tty_dev)
901da2e3ebdSchin 		{
902da2e3ebdSchin 			utimes.actime = statb.st_atime;
903da2e3ebdSchin 			utimes.modtime = statb.st_mtime;
904da2e3ebdSchin 			isdevtty=1;
905da2e3ebdSchin 		}
906da2e3ebdSchin #else
907da2e3ebdSchin #		define fixtime()
908da2e3ebdSchin #endif /* _hdr_utime */
909da2e3ebdSchin 		while(1)
910da2e3ebdSchin 		{
911da2e3ebdSchin 			rv = read(fd,buff,size);
912da2e3ebdSchin 			if(rv>=0 || errno!=EINTR)
913da2e3ebdSchin 				break;
9147c2fbfb3SApril Chin 			if(shp->trapnote&(SH_SIGSET|SH_SIGTRAP))
915da2e3ebdSchin 				goto done;
916da2e3ebdSchin 			/* an interrupt that should be ignored */
917da2e3ebdSchin 			fixtime();
918da2e3ebdSchin 		}
919da2e3ebdSchin 	}
920da2e3ebdSchin 	else if(rv>=0 && mode>0)
921da2e3ebdSchin 		rv = read(fd,buff,rv>0?rv:1);
922da2e3ebdSchin done:
923*b30d1939SAndy Fiddaman 	shp->gd->waitevent = waitevent;
924da2e3ebdSchin 	sh_offstate(SH_TTYWAIT);
925da2e3ebdSchin 	return(rv);
926da2e3ebdSchin }
927da2e3ebdSchin 
928da2e3ebdSchin 
929da2e3ebdSchin /*
930da2e3ebdSchin  * put <string> of length <nbyte> onto lookahead stack
931da2e3ebdSchin  * if <type> is non-zero,  the negation of the character is put
932da2e3ebdSchin  *    onto the stack so that it can be checked for KEYTRAP
933da2e3ebdSchin  * putstack() returns 1 except when in the middle of a multi-byte char
934da2e3ebdSchin  */
935da2e3ebdSchin static int putstack(Edit_t *ep,char string[], register int nbyte, int type)
936da2e3ebdSchin {
937da2e3ebdSchin 	register int c;
938da2e3ebdSchin #if SHOPT_MULTIBYTE
939da2e3ebdSchin 	char *endp, *p=string;
940da2e3ebdSchin 	int size, offset = ep->e_lookahead + nbyte;
941da2e3ebdSchin 	*(endp = &p[nbyte]) = 0;
942da2e3ebdSchin 	endp = &p[nbyte];
943da2e3ebdSchin 	do
944da2e3ebdSchin 	{
945da2e3ebdSchin 		c = (int)((*p) & STRIP);
946da2e3ebdSchin 		if(c< 0x80 && c!='<')
947da2e3ebdSchin 		{
948da2e3ebdSchin 			if (type)
949da2e3ebdSchin 				c = -c;
950da2e3ebdSchin #   ifndef CBREAK
951da2e3ebdSchin 			if(c == '\0')
952da2e3ebdSchin 			{
953da2e3ebdSchin 				/*** user break key ***/
954da2e3ebdSchin 				ep->e_lookahead = 0;
955da2e3ebdSchin #	if KSHELL
956da2e3ebdSchin 				sh_fault(SIGINT);
957da2e3ebdSchin 				siglongjmp(ep->e_env, UINTR);
958da2e3ebdSchin #	endif   /* KSHELL */
959da2e3ebdSchin 			}
960da2e3ebdSchin #   endif /* CBREAK */
961da2e3ebdSchin 
962da2e3ebdSchin 		}
963da2e3ebdSchin 		else
964da2e3ebdSchin 		{
965da2e3ebdSchin 		again:
966da2e3ebdSchin 			if((c=mbchar(p)) >=0)
967da2e3ebdSchin 			{
968da2e3ebdSchin 				p--;	/* incremented below */
969da2e3ebdSchin 				if(type)
970da2e3ebdSchin 					c = -c;
971da2e3ebdSchin 			}
972da2e3ebdSchin #ifdef EILSEQ
973da2e3ebdSchin 			else if(errno == EILSEQ)
974da2e3ebdSchin 				errno = 0;
975da2e3ebdSchin #endif
976da2e3ebdSchin 			else if((endp-p) < mbmax())
977da2e3ebdSchin 			{
978da2e3ebdSchin 				if ((c=ed_read(ep,ep->e_fd,endp, 1,0)) == 1)
979da2e3ebdSchin 				{
980da2e3ebdSchin 					*++endp = 0;
981da2e3ebdSchin 					goto again;
982da2e3ebdSchin 				}
983da2e3ebdSchin 				return(c);
984da2e3ebdSchin 			}
985da2e3ebdSchin 			else
986da2e3ebdSchin 			{
987da2e3ebdSchin 				ed_ringbell();
988da2e3ebdSchin 				c = -(int)((*p) & STRIP);
989da2e3ebdSchin 				offset += mbmax()-1;
990da2e3ebdSchin 			}
991da2e3ebdSchin 		}
992da2e3ebdSchin 		ep->e_lbuf[--offset] = c;
993da2e3ebdSchin 		p++;
994da2e3ebdSchin 	}
995da2e3ebdSchin 	while (p < endp);
996da2e3ebdSchin 	/* shift lookahead buffer if necessary */
997da2e3ebdSchin 	if(offset -= ep->e_lookahead)
998da2e3ebdSchin 	{
999da2e3ebdSchin 		for(size=offset;size < nbyte;size++)
1000da2e3ebdSchin 			ep->e_lbuf[ep->e_lookahead+size-offset] = ep->e_lbuf[ep->e_lookahead+size];
1001da2e3ebdSchin 	}
1002da2e3ebdSchin 	ep->e_lookahead += nbyte-offset;
1003da2e3ebdSchin #else
1004da2e3ebdSchin 	while (nbyte > 0)
1005da2e3ebdSchin 	{
1006da2e3ebdSchin 		c = string[--nbyte] & STRIP;
1007da2e3ebdSchin 		ep->e_lbuf[ep->e_lookahead++] = (type?-c:c);
1008da2e3ebdSchin #   ifndef CBREAK
1009da2e3ebdSchin 		if( c == '\0' )
1010da2e3ebdSchin 		{
1011da2e3ebdSchin 			/*** user break key ***/
1012da2e3ebdSchin 			ep->e_lookahead = 0;
1013da2e3ebdSchin #	if KSHELL
1014da2e3ebdSchin 			sh_fault(SIGINT);
1015da2e3ebdSchin 			siglongjmp(ep->e_env, UINTR);
1016da2e3ebdSchin #	endif	/* KSHELL */
1017da2e3ebdSchin 		}
1018da2e3ebdSchin #   endif /* CBREAK */
1019da2e3ebdSchin 	}
1020da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
1021da2e3ebdSchin 	return(1);
1022da2e3ebdSchin }
1023da2e3ebdSchin 
1024da2e3ebdSchin /*
1025da2e3ebdSchin  * routine to perform read from terminal for vi and emacs mode
1026da2e3ebdSchin  * <mode> can be one of the following:
1027da2e3ebdSchin  *   -2		vi insert mode - key binding is in effect
1028da2e3ebdSchin  *   -1		vi control mode - key binding is in effect
1029da2e3ebdSchin  *   0		normal command mode - key binding is in effect
1030da2e3ebdSchin  *   1		edit keys not mapped
1031da2e3ebdSchin  *   2		Next key is literal
1032da2e3ebdSchin  */
1033da2e3ebdSchin int ed_getchar(register Edit_t *ep,int mode)
1034da2e3ebdSchin {
1035da2e3ebdSchin 	register int n, c;
1036da2e3ebdSchin 	char readin[LOOKAHEAD+1];
1037da2e3ebdSchin 	if(!ep->e_lookahead)
1038da2e3ebdSchin 	{
1039da2e3ebdSchin 		ed_flush(ep);
1040da2e3ebdSchin 		ep->e_inmacro = 0;
1041da2e3ebdSchin 		/* The while is necessary for reads of partial multbyte chars */
10427c2fbfb3SApril Chin 		*ep->e_vi_insert = (mode==-2);
1043da2e3ebdSchin 		if((n=ed_read(ep,ep->e_fd,readin,-LOOKAHEAD,0)) > 0)
1044da2e3ebdSchin 			n = putstack(ep,readin,n,1);
10457c2fbfb3SApril Chin 		*ep->e_vi_insert = 0;
1046da2e3ebdSchin 	}
1047da2e3ebdSchin 	if(ep->e_lookahead)
1048da2e3ebdSchin 	{
1049da2e3ebdSchin 		/* check for possible key mapping */
1050da2e3ebdSchin 		if((c = ep->e_lbuf[--ep->e_lookahead]) < 0)
1051da2e3ebdSchin 		{
1052*b30d1939SAndy Fiddaman 			if(mode<=0 && -c == ep->e_intr)
1053*b30d1939SAndy Fiddaman 			{
1054*b30d1939SAndy Fiddaman 				sh_fault(SIGINT);
1055*b30d1939SAndy Fiddaman 				siglongjmp(ep->e_env, UINTR);
1056*b30d1939SAndy Fiddaman 			}
10577c2fbfb3SApril Chin 			if(mode<=0 && ep->sh->st.trap[SH_KEYTRAP])
1058da2e3ebdSchin 			{
1059*b30d1939SAndy Fiddaman 				ep->e_keytrap = 1;
1060da2e3ebdSchin 				n=1;
1061da2e3ebdSchin 				if((readin[0]= -c) == ESC)
1062da2e3ebdSchin 				{
1063da2e3ebdSchin 					while(1)
1064da2e3ebdSchin 					{
1065da2e3ebdSchin 						if(!ep->e_lookahead)
1066da2e3ebdSchin 						{
1067da2e3ebdSchin 							if((c=sfpkrd(ep->e_fd,readin+n,1,'\r',(mode?400L:-1L),0))>0)
1068da2e3ebdSchin 								putstack(ep,readin+n,c,1);
1069da2e3ebdSchin 						}
1070da2e3ebdSchin 						if(!ep->e_lookahead)
1071da2e3ebdSchin 							break;
1072da2e3ebdSchin 						if((c=ep->e_lbuf[--ep->e_lookahead])>=0)
1073da2e3ebdSchin 						{
1074da2e3ebdSchin 							ep->e_lookahead++;
1075da2e3ebdSchin 							break;
1076da2e3ebdSchin 						}
1077da2e3ebdSchin 						c = -c;
1078da2e3ebdSchin 						readin[n++] = c;
1079da2e3ebdSchin 						if(c>='0' && c<='9' && n>2)
1080da2e3ebdSchin 							continue;
1081da2e3ebdSchin 						if(n>2 || (c!= '['  &&  c!= 'O'))
1082da2e3ebdSchin 							break;
1083da2e3ebdSchin 					}
1084da2e3ebdSchin 				}
1085da2e3ebdSchin 				if(n=keytrap(ep,readin,n,LOOKAHEAD-n,mode))
1086da2e3ebdSchin 				{
1087da2e3ebdSchin 					putstack(ep,readin,n,0);
1088da2e3ebdSchin 					c = ep->e_lbuf[--ep->e_lookahead];
1089da2e3ebdSchin 				}
1090da2e3ebdSchin 				else
1091da2e3ebdSchin 					c = ed_getchar(ep,mode);
1092*b30d1939SAndy Fiddaman 				ep->e_keytrap = 0;
1093da2e3ebdSchin 			}
1094da2e3ebdSchin 			else
1095da2e3ebdSchin 				c = -c;
1096da2e3ebdSchin 		}
1097da2e3ebdSchin 		/*** map '\r' to '\n' ***/
1098da2e3ebdSchin 		if(c == '\r' && mode!=2)
1099da2e3ebdSchin 			c = '\n';
1100da2e3ebdSchin 		if(ep->e_tabcount && !(c=='\t'||c==ESC || c=='\\' || c=='=' || c==cntl('L') || isdigit(c)))
1101da2e3ebdSchin 			ep->e_tabcount = 0;
1102da2e3ebdSchin 	}
1103da2e3ebdSchin 	else
1104da2e3ebdSchin 		siglongjmp(ep->e_env,(n==0?UEOF:UINTR));
1105da2e3ebdSchin 	return(c);
1106da2e3ebdSchin }
1107da2e3ebdSchin 
1108da2e3ebdSchin void ed_ungetchar(Edit_t *ep,register int c)
1109da2e3ebdSchin {
1110da2e3ebdSchin 	if (ep->e_lookahead < LOOKAHEAD)
1111da2e3ebdSchin 		ep->e_lbuf[ep->e_lookahead++] = c;
1112da2e3ebdSchin 	return;
1113da2e3ebdSchin }
1114da2e3ebdSchin 
1115da2e3ebdSchin /*
1116da2e3ebdSchin  * put a character into the output buffer
1117da2e3ebdSchin  */
1118da2e3ebdSchin 
1119da2e3ebdSchin void	ed_putchar(register Edit_t *ep,register int c)
1120da2e3ebdSchin {
1121da2e3ebdSchin 	char buf[8];
1122da2e3ebdSchin 	register char *dp = ep->e_outptr;
1123da2e3ebdSchin 	register int i,size=1;
11247c2fbfb3SApril Chin 	if(!dp)
11257c2fbfb3SApril Chin 		return;
1126da2e3ebdSchin 	buf[0] = c;
1127da2e3ebdSchin #if SHOPT_MULTIBYTE
1128da2e3ebdSchin 	/* check for place holder */
1129da2e3ebdSchin 	if(c == MARKER)
1130da2e3ebdSchin 		return;
1131da2e3ebdSchin 	if((size = mbconv(buf, (wchar_t)c)) > 1)
1132da2e3ebdSchin 	{
1133da2e3ebdSchin 		for (i = 0; i < (size-1); i++)
1134da2e3ebdSchin 			*dp++ = buf[i];
1135da2e3ebdSchin 		c = buf[i];
1136da2e3ebdSchin 	}
1137da2e3ebdSchin 	else
1138da2e3ebdSchin 	{
1139da2e3ebdSchin 		buf[0] = c;
1140da2e3ebdSchin 		size = 1;
1141da2e3ebdSchin 	}
1142da2e3ebdSchin #endif	/* SHOPT_MULTIBYTE */
1143da2e3ebdSchin 	if (buf[0] == '_' && size==1)
1144da2e3ebdSchin 	{
1145da2e3ebdSchin 		*dp++ = ' ';
1146da2e3ebdSchin 		*dp++ = '\b';
1147da2e3ebdSchin 	}
1148da2e3ebdSchin 	*dp++ = c;
1149da2e3ebdSchin 	*dp = '\0';
1150da2e3ebdSchin 	if(dp >= ep->e_outlast)
1151da2e3ebdSchin 		ed_flush(ep);
1152da2e3ebdSchin 	else
1153da2e3ebdSchin 		ep->e_outptr = dp;
1154da2e3ebdSchin }
1155da2e3ebdSchin 
1156da2e3ebdSchin /*
1157da2e3ebdSchin  * returns the line and column corresponding to offset <off> in the physical buffer
1158da2e3ebdSchin  * if <cur> is non-zero and <= <off>, then correspodning <curpos> will start the search
1159da2e3ebdSchin  */
1160da2e3ebdSchin Edpos_t ed_curpos(Edit_t *ep,genchar *phys, int off, int cur, Edpos_t curpos)
1161da2e3ebdSchin {
1162da2e3ebdSchin 	register genchar *sp=phys;
1163da2e3ebdSchin 	register int c=1, col=ep->e_plen;
1164da2e3ebdSchin 	Edpos_t pos;
1165da2e3ebdSchin #if SHOPT_MULTIBYTE
1166da2e3ebdSchin 	char p[16];
1167da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
1168da2e3ebdSchin 	if(cur && off>=cur)
1169da2e3ebdSchin 	{
1170da2e3ebdSchin 		sp += cur;
1171da2e3ebdSchin 		off -= cur;
1172da2e3ebdSchin 		pos = curpos;
1173da2e3ebdSchin 		col = pos.col;
1174da2e3ebdSchin 	}
1175da2e3ebdSchin 	else
11767c2fbfb3SApril Chin 	{
1177da2e3ebdSchin 		pos.line = 0;
11787c2fbfb3SApril Chin 		while(col > ep->e_winsz)
11797c2fbfb3SApril Chin 		{
11807c2fbfb3SApril Chin 			pos.line++;
11817c2fbfb3SApril Chin 			col -= (ep->e_winsz+1);
11827c2fbfb3SApril Chin 		}
11837c2fbfb3SApril Chin 	}
1184da2e3ebdSchin 	while(off-->0)
1185da2e3ebdSchin 	{
1186da2e3ebdSchin 		if(c)
1187da2e3ebdSchin 			c = *sp++;
1188da2e3ebdSchin #if SHOPT_MULTIBYTE
1189da2e3ebdSchin 		if(c && (mbconv(p, (wchar_t)c))==1 && p[0]=='\n')
1190da2e3ebdSchin #else
1191da2e3ebdSchin 		if(c=='\n')
1192da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
1193da2e3ebdSchin 			col = 0;
1194da2e3ebdSchin 		else
1195da2e3ebdSchin 			col++;
1196da2e3ebdSchin 		if(col >  ep->e_winsz)
1197da2e3ebdSchin 			col = 0;
1198da2e3ebdSchin 		if(col==0)
1199da2e3ebdSchin 			pos.line++;
1200da2e3ebdSchin 	}
1201da2e3ebdSchin 	pos.col = col;
1202da2e3ebdSchin 	return(pos);
1203da2e3ebdSchin }
1204da2e3ebdSchin 
1205da2e3ebdSchin int ed_setcursor(register Edit_t *ep,genchar *physical,register int old,register int new,int first)
1206da2e3ebdSchin {
1207da2e3ebdSchin 	static int oldline;
1208da2e3ebdSchin 	register int delta;
12097c2fbfb3SApril Chin 	int clear = 0;
1210da2e3ebdSchin 	Edpos_t newpos;
1211da2e3ebdSchin 
1212da2e3ebdSchin 	delta = new - old;
12137c2fbfb3SApril Chin 	if(first < 0)
12147c2fbfb3SApril Chin 	{
12157c2fbfb3SApril Chin 		first = 0;
12167c2fbfb3SApril Chin 		clear = 1;
12177c2fbfb3SApril Chin 	}
12187c2fbfb3SApril Chin 	if( delta == 0  &&  !clear)
1219da2e3ebdSchin 		return(new);
1220da2e3ebdSchin 	if(ep->e_multiline)
1221da2e3ebdSchin 	{
1222da2e3ebdSchin 		ep->e_curpos = ed_curpos(ep, physical, old,0,ep->e_curpos);
12237c2fbfb3SApril Chin 		if(clear && old>=ep->e_peol && (clear=ep->e_winsz-ep->e_curpos.col)>0)
12247c2fbfb3SApril Chin 		{
12257c2fbfb3SApril Chin 			ed_nputchar(ep,clear,' ');
12267c2fbfb3SApril Chin 			ed_nputchar(ep,clear,'\b');
12277c2fbfb3SApril Chin 			return(new);
12287c2fbfb3SApril Chin 		}
1229da2e3ebdSchin 		newpos =     ed_curpos(ep, physical, new,old,ep->e_curpos);
1230da2e3ebdSchin 		if(ep->e_curpos.col==0 && ep->e_curpos.line>0 && oldline<ep->e_curpos.line && delta<0)
1231da2e3ebdSchin 			ed_putstring(ep,"\r\n");
1232da2e3ebdSchin 		oldline = newpos.line;
1233da2e3ebdSchin 		if(ep->e_curpos.line > newpos.line)
1234da2e3ebdSchin 		{
12357c2fbfb3SApril Chin 			int n,pline,plen=ep->e_plen;
1236da2e3ebdSchin 			for(;ep->e_curpos.line > newpos.line; ep->e_curpos.line--)
1237da2e3ebdSchin 				ed_putstring(ep,CURSOR_UP);
12387c2fbfb3SApril Chin 			pline = plen/(ep->e_winsz+1);
12397c2fbfb3SApril Chin 			if(newpos.line <= pline)
12407c2fbfb3SApril Chin 				plen -= pline*(ep->e_winsz+1);
12417c2fbfb3SApril Chin 			else
12427c2fbfb3SApril Chin 				plen = 0;
12437c2fbfb3SApril Chin 			if((n=plen- ep->e_curpos.col)>0)
1244da2e3ebdSchin 			{
1245da2e3ebdSchin 				ep->e_curpos.col += n;
1246da2e3ebdSchin 				ed_putchar(ep,'\r');
12477c2fbfb3SApril Chin 				if(!ep->e_crlf && pline==0)
1248da2e3ebdSchin 					ed_putstring(ep,ep->e_prompt);
1249da2e3ebdSchin 				else
1250da2e3ebdSchin 				{
12517c2fbfb3SApril Chin 					int m = ep->e_winsz+1-plen;
1252da2e3ebdSchin 					ed_putchar(ep,'\n');
12537c2fbfb3SApril Chin 					n = plen;
1254da2e3ebdSchin 					if(m < ed_genlen(physical))
1255da2e3ebdSchin 					{
1256da2e3ebdSchin 						while(physical[m] && n-->0)
1257da2e3ebdSchin 							ed_putchar(ep,physical[m++]);
1258da2e3ebdSchin 					}
12597c2fbfb3SApril Chin 					ed_nputchar(ep,n,' ');
1260da2e3ebdSchin 					ed_putstring(ep,CURSOR_UP);
1261da2e3ebdSchin 				}
1262da2e3ebdSchin 			}
1263da2e3ebdSchin 		}
1264da2e3ebdSchin 		else if(ep->e_curpos.line < newpos.line)
1265da2e3ebdSchin 		{
12667c2fbfb3SApril Chin 			ed_nputchar(ep, newpos.line-ep->e_curpos.line,'\n');
12677c2fbfb3SApril Chin 			ep->e_curpos.line = newpos.line;
1268da2e3ebdSchin 			ed_putchar(ep,'\r');
1269da2e3ebdSchin 			ep->e_curpos.col = 0;
1270da2e3ebdSchin 		}
1271da2e3ebdSchin 		delta = newpos.col - ep->e_curpos.col;
1272da2e3ebdSchin 		old   =  new - delta;
1273da2e3ebdSchin 	}
1274da2e3ebdSchin 	else
1275da2e3ebdSchin 		newpos.line=0;
1276da2e3ebdSchin 	if(delta<0)
1277da2e3ebdSchin 	{
12787c2fbfb3SApril Chin 		int bs= newpos.line && ep->e_plen>ep->e_winsz;
1279da2e3ebdSchin 		/*** move to left ***/
1280da2e3ebdSchin 		delta = -delta;
1281da2e3ebdSchin 		/*** attempt to optimize cursor movement ***/
12827c2fbfb3SApril Chin 		if(!ep->e_crlf || bs || (2*delta <= ((old-first)+(newpos.line?0:ep->e_plen))) )
1283da2e3ebdSchin 		{
12847c2fbfb3SApril Chin 			ed_nputchar(ep,delta,'\b');
12857c2fbfb3SApril Chin 			delta = 0;
1286da2e3ebdSchin 		}
1287da2e3ebdSchin 		else
1288da2e3ebdSchin 		{
1289da2e3ebdSchin 			if(newpos.line==0)
1290da2e3ebdSchin 				ed_putstring(ep,ep->e_prompt);
12917c2fbfb3SApril Chin 			else
12927c2fbfb3SApril Chin 			{
12937c2fbfb3SApril Chin 				first = 1+(newpos.line*ep->e_winsz - ep->e_plen);
12947c2fbfb3SApril Chin 				ed_putchar(ep,'\r');
12957c2fbfb3SApril Chin 			}
1296da2e3ebdSchin 			old = first;
1297da2e3ebdSchin 			delta = new-first;
1298da2e3ebdSchin 		}
1299da2e3ebdSchin 	}
1300da2e3ebdSchin 	while(delta-->0)
1301da2e3ebdSchin 		ed_putchar(ep,physical[old++]);
1302da2e3ebdSchin 	return(new);
1303da2e3ebdSchin }
1304da2e3ebdSchin 
1305da2e3ebdSchin /*
1306da2e3ebdSchin  * copy virtual to physical and return the index for cursor in physical buffer
1307da2e3ebdSchin  */
1308da2e3ebdSchin int ed_virt_to_phys(Edit_t *ep,genchar *virt,genchar *phys,int cur,int voff,int poff)
1309da2e3ebdSchin {
1310da2e3ebdSchin 	register genchar *sp = virt;
1311da2e3ebdSchin 	register genchar *dp = phys;
1312da2e3ebdSchin 	register int c;
1313da2e3ebdSchin 	genchar *curp = sp + cur;
1314da2e3ebdSchin 	genchar *dpmax = phys+MAXLINE;
1315da2e3ebdSchin 	int d, r;
1316da2e3ebdSchin 	sp += voff;
1317da2e3ebdSchin 	dp += poff;
1318da2e3ebdSchin 	for(r=poff;c= *sp;sp++)
1319da2e3ebdSchin 	{
1320da2e3ebdSchin 		if(curp == sp)
1321da2e3ebdSchin 			r = dp - phys;
1322da2e3ebdSchin #if SHOPT_MULTIBYTE
1323da2e3ebdSchin 		d = mbwidth((wchar_t)c);
1324da2e3ebdSchin 		if(d==1 && is_cntrl(c))
1325da2e3ebdSchin 			d = -1;
1326da2e3ebdSchin 		if(d>1)
1327da2e3ebdSchin 		{
1328da2e3ebdSchin 			/* multiple width character put in place holders */
1329da2e3ebdSchin 			*dp++ = c;
1330da2e3ebdSchin 			while(--d >0)
1331da2e3ebdSchin 				*dp++ = MARKER;
1332da2e3ebdSchin 			/* in vi mode the cursor is at the last character */
1333da2e3ebdSchin 			if(dp>=dpmax)
1334da2e3ebdSchin 				break;
1335da2e3ebdSchin 			continue;
1336da2e3ebdSchin 		}
1337da2e3ebdSchin 		else
1338da2e3ebdSchin #else
1339da2e3ebdSchin 		d = (is_cntrl(c)?-1:1);
1340da2e3ebdSchin #endif	/* SHOPT_MULTIBYTE */
1341da2e3ebdSchin 		if(d<0)
1342da2e3ebdSchin 		{
1343da2e3ebdSchin 			if(c=='\t')
1344da2e3ebdSchin 			{
1345da2e3ebdSchin 				c = dp-phys;
1346da2e3ebdSchin 				if(sh_isoption(SH_VI))
1347da2e3ebdSchin 					c += ep->e_plen;
1348da2e3ebdSchin 				c = TABSIZE - c%TABSIZE;
1349da2e3ebdSchin 				while(--c>0)
1350da2e3ebdSchin 					*dp++ = ' ';
1351da2e3ebdSchin 				c = ' ';
1352da2e3ebdSchin 			}
1353da2e3ebdSchin 			else
1354da2e3ebdSchin 			{
1355da2e3ebdSchin 				*dp++ = '^';
1356da2e3ebdSchin 				c = printchar(c);
1357da2e3ebdSchin 			}
1358da2e3ebdSchin 			/* in vi mode the cursor is at the last character */
1359da2e3ebdSchin 			if(curp == sp && sh_isoption(SH_VI))
1360da2e3ebdSchin 				r = dp - phys;
1361da2e3ebdSchin 		}
1362da2e3ebdSchin 		*dp++ = c;
1363da2e3ebdSchin 		if(dp>=dpmax)
1364da2e3ebdSchin 			break;
1365da2e3ebdSchin 	}
1366da2e3ebdSchin 	*dp = 0;
13677c2fbfb3SApril Chin 	ep->e_peol = dp-phys;
1368da2e3ebdSchin 	return(r);
1369da2e3ebdSchin }
1370da2e3ebdSchin 
1371da2e3ebdSchin #if SHOPT_MULTIBYTE
1372da2e3ebdSchin /*
1373da2e3ebdSchin  * convert external representation <src> to an array of genchars <dest>
1374da2e3ebdSchin  * <src> and <dest> can be the same
1375da2e3ebdSchin  * returns number of chars in dest
1376da2e3ebdSchin  */
1377da2e3ebdSchin 
1378da2e3ebdSchin int	ed_internal(const char *src, genchar *dest)
1379da2e3ebdSchin {
1380da2e3ebdSchin 	register const unsigned char *cp = (unsigned char *)src;
1381da2e3ebdSchin 	register int c;
1382da2e3ebdSchin 	register wchar_t *dp = (wchar_t*)dest;
1383da2e3ebdSchin 	if(dest == (genchar*)roundof(cp-(unsigned char*)0,sizeof(genchar)))
1384da2e3ebdSchin 	{
1385da2e3ebdSchin 		genchar buffer[MAXLINE];
1386da2e3ebdSchin 		c = ed_internal(src,buffer);
1387da2e3ebdSchin 		ed_gencpy((genchar*)dp,buffer);
1388da2e3ebdSchin 		return(c);
1389da2e3ebdSchin 	}
1390da2e3ebdSchin 	while(*cp)
1391da2e3ebdSchin 		*dp++ = mbchar(cp);
1392da2e3ebdSchin 	*dp = 0;
1393da2e3ebdSchin 	return(dp-(wchar_t*)dest);
1394da2e3ebdSchin }
1395da2e3ebdSchin 
1396da2e3ebdSchin /*
1397da2e3ebdSchin  * convert internal representation <src> into character array <dest>.
1398da2e3ebdSchin  * The <src> and <dest> may be the same.
1399da2e3ebdSchin  * returns number of chars in dest.
1400da2e3ebdSchin  */
1401da2e3ebdSchin 
1402da2e3ebdSchin int	ed_external(const genchar *src, char *dest)
1403da2e3ebdSchin {
1404da2e3ebdSchin 	register genchar wc;
1405da2e3ebdSchin 	register int c,size;
1406da2e3ebdSchin 	register char *dp = dest;
1407da2e3ebdSchin 	char *dpmax = dp+sizeof(genchar)*MAXLINE-2;
1408da2e3ebdSchin 	if((char*)src == dp)
1409da2e3ebdSchin 	{
1410da2e3ebdSchin 		char buffer[MAXLINE*sizeof(genchar)];
1411da2e3ebdSchin 		c = ed_external(src,buffer);
1412da2e3ebdSchin 
1413da2e3ebdSchin #ifdef _lib_wcscpy
1414da2e3ebdSchin 		wcscpy((wchar_t *)dest,(const wchar_t *)buffer);
1415da2e3ebdSchin #else
1416da2e3ebdSchin 		strcpy(dest,buffer);
1417da2e3ebdSchin #endif
1418da2e3ebdSchin 		return(c);
1419da2e3ebdSchin 	}
1420da2e3ebdSchin 	while((wc = *src++) && dp<dpmax)
1421da2e3ebdSchin 	{
1422da2e3ebdSchin 		if((size = mbconv(dp, wc)) < 0)
1423da2e3ebdSchin 		{
1424da2e3ebdSchin 			/* copy the character as is */
1425da2e3ebdSchin 			size = 1;
1426da2e3ebdSchin 			*dp = wc;
1427da2e3ebdSchin 		}
1428da2e3ebdSchin 		dp += size;
1429da2e3ebdSchin 	}
1430da2e3ebdSchin 	*dp = 0;
1431da2e3ebdSchin 	return(dp-dest);
1432da2e3ebdSchin }
1433da2e3ebdSchin 
1434da2e3ebdSchin /*
1435da2e3ebdSchin  * copy <sp> to <dp>
1436da2e3ebdSchin  */
1437da2e3ebdSchin 
1438da2e3ebdSchin void	ed_gencpy(genchar *dp,const genchar *sp)
1439da2e3ebdSchin {
1440da2e3ebdSchin 	dp = (genchar*)roundof((char*)dp-(char*)0,sizeof(genchar));
1441da2e3ebdSchin 	sp = (const genchar*)roundof((char*)sp-(char*)0,sizeof(genchar));
1442da2e3ebdSchin 	while(*dp++ = *sp++);
1443da2e3ebdSchin }
1444da2e3ebdSchin 
1445da2e3ebdSchin /*
1446da2e3ebdSchin  * copy at most <n> items from <sp> to <dp>
1447da2e3ebdSchin  */
1448da2e3ebdSchin 
1449da2e3ebdSchin void	ed_genncpy(register genchar *dp,register const genchar *sp, int n)
1450da2e3ebdSchin {
1451da2e3ebdSchin 	dp = (genchar*)roundof((char*)dp-(char*)0,sizeof(genchar));
1452