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