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