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 				*pp++ = c;
656 				for(n=1; c = *last++; n++)
657 				{
658 					if(pp < ppmax)
659 						*pp++ = c;
660 					if(c=='\a' || c==ESC || c=='\r')
661 						break;
662 					if(skip || (c>='0' && c<='9'))
663 					{
664 						skip = 0;
665 						continue;
666 					}
667 					if(n>1 && c==';')
668 						skip = 1;
669 					else if(n>2 || (c!= '[' &&  c!= ']'))
670 						break;
671 				}
672 				if(c==0 || c==ESC || c=='\r')
673 					last--;
674 				qlen += (n+1);
675 				break;
676 			}
677 			case '\b':
678 				if(pp>ep->e_prompt+1)
679 					pp--;
680 				break;
681 			case '\r':
682 				if(pp == (ep->e_prompt+2)) /* quote char */
683 					myquote = *(pp-1);
684 				/*FALLTHROUGH*/
685 
686 			case '\n':
687 				/* start again */
688 				ep->e_crlf = 1;
689 				qlen = 1;
690 				inquote = 0;
691 				pp = ep->e_prompt+1;
692 				break;
693 
694 			case '\t':
695 				/* expand tabs */
696 				while((pp-ep->e_prompt)%TABSIZE)
697 				{
698 					if(pp >= ppmax)
699 						break;
700 					*pp++ = ' ';
701 				}
702 				break;
703 
704 			case '\a':
705 				/* cut out bells */
706 				break;
707 
708 			default:
709 				if(c==myquote)
710 				{
711 					qlen += inquote;
712 					inquote ^= 1;
713 				}
714 				if(pp < ppmax)
715 				{
716 					if(inquote)
717 						qlen++;
718 					else if(!is_print(c))
719 						ep->e_crlf = 0;
720 					if((qwid = last - prev) > 1)
721 						qlen += qwid - mbwidth(c);
722 					while(prev < last && pp < ppmax)
723 						*pp++ = *prev++;
724 				}
725 				break;
726 		}
727 	}
728 	if(pp-ep->e_prompt > qlen)
729 		ep->e_plen = pp - ep->e_prompt - qlen;
730 	*pp = 0;
731 	if(!ep->e_multiline && (ep->e_wsize -= ep->e_plen) < 7)
732 	{
733 		register int shift = 7-ep->e_wsize;
734 		ep->e_wsize = 7;
735 		pp = ep->e_prompt+1;
736 		strcpy(pp,pp+shift);
737 		ep->e_plen -= shift;
738 		last[-ep->e_plen-2] = '\r';
739 	}
740 	sfsync(sfstderr);
741 	if(fd == sffileno(sfstderr))
742 	{
743 		/* can't use output buffer when reading from stderr */
744 		static char *buff;
745 		if(!buff)
746 			buff = (char*)malloc(MAXLINE);
747 		ep->e_outbase = ep->e_outptr = buff;
748 		ep->e_outlast = ep->e_outptr + MAXLINE;
749 		return;
750 	}
751 	qlen = sfset(sfstderr,SF_READ,0);
752 	/* make sure SF_READ not on */
753 	ep->e_outbase = ep->e_outptr = (char*)sfreserve(sfstderr,SF_UNBOUND,SF_LOCKR);
754 	ep->e_outlast = ep->e_outptr + sfvalue(sfstderr);
755 	if(qlen)
756 		sfset(sfstderr,SF_READ,1);
757 	sfwrite(sfstderr,ep->e_outptr,0);
758 	ep->e_eol = reedit;
759 	if(ep->e_multiline)
760 	{
761 #ifdef _cmd_tput
762 		char *term;
763 		if(!ep->e_term)
764 			ep->e_term = nv_search("TERM",shp->var_tree,0);
765 		if(ep->e_term && (term=nv_getval(ep->e_term)) && strlen(term)<sizeof(ep->e_termname) && strcmp(term,ep->e_termname))
766 		{
767 			sh_trap(".sh.subscript=$(tput cuu1 2>/dev/null)",0);
768 			if(pp=nv_getval(SH_SUBSCRNOD))
769 				strncpy(CURSOR_UP,pp,sizeof(CURSOR_UP)-1);
770 			nv_unset(SH_SUBSCRNOD);
771 			strcpy(ep->e_termname,term);
772 		}
773 #endif
774 		ep->e_wsize = MAXLINE - (ep->e_plen+1);
775 	}
776 	if(ep->e_default && (pp = nv_getval(ep->e_default)))
777 	{
778 		n = strlen(pp);
779 		if(n > LOOKAHEAD)
780 			n = LOOKAHEAD;
781 		ep->e_lookahead = n;
782 		while(n-- > 0)
783 			ep->e_lbuf[n] = *pp++;
784 		ep->e_default = 0;
785 	}
786 }
787 
ed_putstring(register Edit_t * ep,const char * str)788 static void ed_putstring(register Edit_t *ep, const char *str)
789 {
790 	register int c;
791 	while(c = *str++)
792 		ed_putchar(ep,c);
793 }
794 
ed_nputchar(register Edit_t * ep,int n,int c)795 static void ed_nputchar(register Edit_t *ep, int n, int c)
796 {
797 	while(n-->0)
798 		ed_putchar(ep,c);
799 }
800 
801 /*
802  * Do read, restart on interrupt unless SH_SIGSET or SH_SIGTRAP is set
803  * Use sfpkrd() to poll() or select() to wait for input if possible
804  * Unfortunately, systems that get interrupted from slow reads update
805  * this access time for for the terminal (in violation of POSIX).
806  * The fixtime() macro, resets the time to the time at entry in
807  * this case.  This is not necessary for systems that can handle
808  * sfpkrd() correctly (i,e., those that support poll() or select()
809  */
ed_read(void * context,int fd,char * buff,int size,int reedit)810 int ed_read(void *context, int fd, char *buff, int size, int reedit)
811 {
812 	register Edit_t *ep = (Edit_t*)context;
813 	register int rv= -1;
814 	register int delim = ((ep->e_raw&RAWMODE)?nttyparm.c_cc[VEOL]:'\n');
815 	Shell_t *shp = ep->sh;
816 	int mode = -1;
817 	int (*waitevent)(int,long,int) = shp->gd->waitevent;
818 	if(ep->e_raw==ALTMODE)
819 		mode = 1;
820 	if(size < 0)
821 	{
822 		mode = 1;
823 		size = -size;
824 	}
825 	sh_onstate(SH_TTYWAIT);
826 	errno = EINTR;
827 	shp->gd->waitevent = 0;
828 	while(rv<0 && errno==EINTR)
829 	{
830 		if(shp->trapnote&(SH_SIGSET|SH_SIGTRAP))
831 			goto done;
832 		if(ep->sh->winch && sh_isstate(SH_INTERACTIVE) && (sh_isoption(SH_VI) || sh_isoption(SH_EMACS)))
833 		{
834 			Edpos_t	lastpos;
835 			int	n, rows, newsize;
836 			/* move cursor to start of first line */
837 			ed_putchar(ep,'\r');
838 			ed_flush(ep);
839 			astwinsize(2,&rows,&newsize);
840 			n = (ep->e_plen+ep->e_cur)/++ep->e_winsz;
841 			while(n--)
842 				ed_putstring(ep,CURSOR_UP);
843 			if(ep->e_multiline && newsize>ep->e_winsz && (lastpos.line=(ep->e_plen+ep->e_peol)/ep->e_winsz))
844 			{
845 				/* clear the current command line */
846 				n = lastpos.line;
847 				while(lastpos.line--)
848 				{
849 					ed_nputchar(ep,ep->e_winsz,' ');
850 					ed_putchar(ep,'\n');
851 				}
852 				ed_nputchar(ep,ep->e_winsz,' ');
853 				while(n--)
854 					ed_putstring(ep,CURSOR_UP);
855 			}
856 	                ep->sh->winch = 0;
857 			ed_flush(ep);
858 			sh_delay(.05);
859 			astwinsize(2,&rows,&newsize);
860 			ep->e_winsz = newsize-1;
861 			if(ep->e_winsz < MINWINDOW)
862 				ep->e_winsz = MINWINDOW;
863 			if(!ep->e_multiline && ep->e_wsize < MAXLINE)
864 				ep->e_wsize = ep->e_winsz-2;
865 			ep->e_nocrnl=1;
866 			if(*ep->e_vi_insert)
867 			{
868 				buff[0] = ESC;
869 				buff[1] = cntl('L');
870 				buff[2] = 'a';
871 				return(3);
872 			}
873 			if(sh_isoption(SH_EMACS) || sh_isoption(SH_VI))
874 				buff[0] = cntl('L');
875 			return(1);
876 		}
877 		else
878 			ep->sh->winch = 0;
879 		/* an interrupt that should be ignored */
880 		errno = 0;
881 		if(!waitevent || (rv=(*waitevent)(fd,-1L,0))>=0)
882 			rv = sfpkrd(fd,buff,size,delim,-1L,mode);
883 	}
884 	if(rv < 0)
885 	{
886 #ifdef _hdr_utime
887 #		define fixtime()	if(isdevtty)utime(ep->e_tty,&utimes)
888 		int	isdevtty=0;
889 		struct stat statb;
890 		struct utimbuf utimes;
891 	 	if(errno==0 && !ep->e_tty)
892 		{
893 			if((ep->e_tty=ttyname(fd)) && stat(ep->e_tty,&statb)>=0)
894 			{
895 				ep->e_tty_ino = statb.st_ino;
896 				ep->e_tty_dev = statb.st_dev;
897 			}
898 		}
899 		if(ep->e_tty_ino && fstat(fd,&statb)>=0 && statb.st_ino==ep->e_tty_ino && statb.st_dev==ep->e_tty_dev)
900 		{
901 			utimes.actime = statb.st_atime;
902 			utimes.modtime = statb.st_mtime;
903 			isdevtty=1;
904 		}
905 #else
906 #		define fixtime()
907 #endif /* _hdr_utime */
908 		while(1)
909 		{
910 			rv = read(fd,buff,size);
911 			if(rv>=0 || errno!=EINTR)
912 				break;
913 			if(shp->trapnote&(SH_SIGSET|SH_SIGTRAP))
914 				goto done;
915 			/* an interrupt that should be ignored */
916 			fixtime();
917 		}
918 	}
919 	else if(rv>=0 && mode>0)
920 		rv = read(fd,buff,rv>0?rv:1);
921 done:
922 	shp->gd->waitevent = waitevent;
923 	sh_offstate(SH_TTYWAIT);
924 	return(rv);
925 }
926 
927 
928 /*
929  * put <string> of length <nbyte> onto lookahead stack
930  * if <type> is non-zero,  the negation of the character is put
931  *    onto the stack so that it can be checked for KEYTRAP
932  * putstack() returns 1 except when in the middle of a multi-byte char
933  */
934 static int putstack(Edit_t *ep,char string[], register int nbyte, int type)
935 {
936 	register int c;
937 #if SHOPT_MULTIBYTE
938 	char *endp, *p=string;
939 	int size, offset = ep->e_lookahead + nbyte;
940 	*(endp = &p[nbyte]) = 0;
941 	endp = &p[nbyte];
942 	do
943 	{
944 		c = (int)((*p) & STRIP);
945 		if(c< 0x80 && c!='<')
946 		{
947 			if (type)
948 				c = -c;
949 #   ifndef CBREAK
950 			if(c == '\0')
951 			{
952 				/*** user break key ***/
953 				ep->e_lookahead = 0;
954 #	if KSHELL
955 				sh_fault(SIGINT);
956 				siglongjmp(ep->e_env, UINTR);
957 #	endif   /* KSHELL */
958 			}
959 #   endif /* CBREAK */
960 
961 		}
962 		else
963 		{
964 		again:
965 			if((c=mbchar(p)) >=0)
966 			{
967 				p--;	/* incremented below */
968 				if(type)
969 					c = -c;
970 			}
971 #ifdef EILSEQ
972 			else if(errno == EILSEQ)
973 				errno = 0;
974 #endif
975 			else if((endp-p) < mbmax())
976 			{
977 				if ((c=ed_read(ep,ep->e_fd,endp, 1,0)) == 1)
978 				{
979 					*++endp = 0;
980 					goto again;
981 				}
982 				return(c);
983 			}
984 			else
985 			{
986 				ed_ringbell();
987 				c = -(int)((*p) & STRIP);
988 				offset += mbmax()-1;
989 			}
990 		}
991 		ep->e_lbuf[--offset] = c;
992 		p++;
993 	}
994 	while (p < endp);
995 	/* shift lookahead buffer if necessary */
996 	if(offset -= ep->e_lookahead)
997 	{
998 		for(size=offset;size < nbyte;size++)
999 			ep->e_lbuf[ep->e_lookahead+size-offset] = ep->e_lbuf[ep->e_lookahead+size];
1000 	}
1001 	ep->e_lookahead += nbyte-offset;
1002 #else
1003 	while (nbyte > 0)
1004 	{
1005 		c = string[--nbyte] & STRIP;
1006 		ep->e_lbuf[ep->e_lookahead++] = (type?-c:c);
1007 #   ifndef CBREAK
1008 		if( c == '\0' )
1009 		{
1010 			/*** user break key ***/
1011 			ep->e_lookahead = 0;
1012 #	if KSHELL
1013 			sh_fault(SIGINT);
1014 			siglongjmp(ep->e_env, UINTR);
1015 #	endif	/* KSHELL */
1016 		}
1017 #   endif /* CBREAK */
1018 	}
1019 #endif /* SHOPT_MULTIBYTE */
1020 	return(1);
1021 }
1022 
1023 /*
1024  * routine to perform read from terminal for vi and emacs mode
1025  * <mode> can be one of the following:
1026  *   -2		vi insert mode - key binding is in effect
1027  *   -1		vi control mode - key binding is in effect
1028  *   0		normal command mode - key binding is in effect
1029  *   1		edit keys not mapped
1030  *   2		Next key is literal
1031  */
1032 int ed_getchar(register Edit_t *ep,int mode)
1033 {
1034 	register int n, c;
1035 	char readin[LOOKAHEAD+1];
1036 	if(!ep->e_lookahead)
1037 	{
1038 		ed_flush(ep);
1039 		ep->e_inmacro = 0;
1040 		/* The while is necessary for reads of partial multbyte chars */
1041 		*ep->e_vi_insert = (mode==-2);
1042 		if((n=ed_read(ep,ep->e_fd,readin,-LOOKAHEAD,0)) > 0)
1043 			n = putstack(ep,readin,n,1);
1044 		*ep->e_vi_insert = 0;
1045 	}
1046 	if(ep->e_lookahead)
1047 	{
1048 		/* check for possible key mapping */
1049 		if((c = ep->e_lbuf[--ep->e_lookahead]) < 0)
1050 		{
1051 			if(mode<=0 && -c == ep->e_intr)
1052 			{
1053 				sh_fault(SIGINT);
1054 				siglongjmp(ep->e_env, UINTR);
1055 			}
1056 			if(mode<=0 && ep->sh->st.trap[SH_KEYTRAP])
1057 			{
1058 				ep->e_keytrap = 1;
1059 				n=1;
1060 				if((readin[0]= -c) == ESC)
1061 				{
1062 					while(1)
1063 					{
1064 						if(!ep->e_lookahead)
1065 						{
1066 							if((c=sfpkrd(ep->e_fd,readin+n,1,'\r',(mode?400L:-1L),0))>0)
1067 								putstack(ep,readin+n,c,1);
1068 						}
1069 						if(!ep->e_lookahead)
1070 							break;
1071 						if((c=ep->e_lbuf[--ep->e_lookahead])>=0)
1072 						{
1073 							ep->e_lookahead++;
1074 							break;
1075 						}
1076 						c = -c;
1077 						readin[n++] = c;
1078 						if(c>='0' && c<='9' && n>2)
1079 							continue;
1080 						if(n>2 || (c!= '['  &&  c!= 'O'))
1081 							break;
1082 					}
1083 				}
1084 				if(n=keytrap(ep,readin,n,LOOKAHEAD-n,mode))
1085 				{
1086 					putstack(ep,readin,n,0);
1087 					c = ep->e_lbuf[--ep->e_lookahead];
1088 				}
1089 				else
1090 					c = ed_getchar(ep,mode);
1091 				ep->e_keytrap = 0;
1092 			}
1093 			else
1094 				c = -c;
1095 		}
1096 		/*** map '\r' to '\n' ***/
1097 		if(c == '\r' && mode!=2)
1098 			c = '\n';
1099 		if(ep->e_tabcount && !(c=='\t'||c==ESC || c=='\\' || c=='=' || c==cntl('L') || isdigit(c)))
1100 			ep->e_tabcount = 0;
1101 	}
1102 	else
1103 		siglongjmp(ep->e_env,(n==0?UEOF:UINTR));
1104 	return(c);
1105 }
1106 
1107 void ed_ungetchar(Edit_t *ep,register int c)
1108 {
1109 	if (ep->e_lookahead < LOOKAHEAD)
1110 		ep->e_lbuf[ep->e_lookahead++] = c;
1111 	return;
1112 }
1113 
1114 /*
1115  * put a character into the output buffer
1116  */
1117 
1118 void	ed_putchar(register Edit_t *ep,register int c)
1119 {
1120 	char buf[8];
1121 	register char *dp = ep->e_outptr;
1122 	register int i,size=1;
1123 	if(!dp)
1124 		return;
1125 	buf[0] = c;
1126 #if SHOPT_MULTIBYTE
1127 	/* check for place holder */
1128 	if(c == MARKER)
1129 		return;
1130 	if((size = mbconv(buf, (wchar_t)c)) > 1)
1131 	{
1132 		for (i = 0; i < (size-1); i++)
1133 			*dp++ = buf[i];
1134 		c = buf[i];
1135 	}
1136 	else
1137 	{
1138 		buf[0] = c;
1139 		size = 1;
1140 	}
1141 #endif	/* SHOPT_MULTIBYTE */
1142 	if (buf[0] == '_' && size==1)
1143 	{
1144 		*dp++ = ' ';
1145 		*dp++ = '\b';
1146 	}
1147 	*dp++ = c;
1148 	*dp = '\0';
1149 	if(dp >= ep->e_outlast)
1150 		ed_flush(ep);
1151 	else
1152 		ep->e_outptr = dp;
1153 }
1154 
1155 /*
1156  * returns the line and column corresponding to offset <off> in the physical buffer
1157  * if <cur> is non-zero and <= <off>, then correspodning <curpos> will start the search
1158  */
1159 Edpos_t ed_curpos(Edit_t *ep,genchar *phys, int off, int cur, Edpos_t curpos)
1160 {
1161 	register genchar *sp=phys;
1162 	register int c=1, col=ep->e_plen;
1163 	Edpos_t pos;
1164 #if SHOPT_MULTIBYTE
1165 	char p[16];
1166 #endif /* SHOPT_MULTIBYTE */
1167 	if(cur && off>=cur)
1168 	{
1169 		sp += cur;
1170 		off -= cur;
1171 		pos = curpos;
1172 		col = pos.col;
1173 	}
1174 	else
1175 	{
1176 		pos.line = 0;
1177 		while(col > ep->e_winsz)
1178 		{
1179 			pos.line++;
1180 			col -= (ep->e_winsz+1);
1181 		}
1182 	}
1183 	while(off-->0)
1184 	{
1185 		if(c)
1186 			c = *sp++;
1187 #if SHOPT_MULTIBYTE
1188 		if(c && (mbconv(p, (wchar_t)c))==1 && p[0]=='\n')
1189 #else
1190 		if(c=='\n')
1191 #endif /* SHOPT_MULTIBYTE */
1192 			col = 0;
1193 		else
1194 			col++;
1195 		if(col >  ep->e_winsz)
1196 			col = 0;
1197 		if(col==0)
1198 			pos.line++;
1199 	}
1200 	pos.col = col;
1201 	return(pos);
1202 }
1203 
1204 int ed_setcursor(register Edit_t *ep,genchar *physical,register int old,register int new,int first)
1205 {
1206 	static int oldline;
1207 	register int delta;
1208 	int clear = 0;
1209 	Edpos_t newpos;
1210 
1211 	delta = new - old;
1212 	if(first < 0)
1213 	{
1214 		first = 0;
1215 		clear = 1;
1216 	}
1217 	if( delta == 0  &&  !clear)
1218 		return(new);
1219 	if(ep->e_multiline)
1220 	{
1221 		ep->e_curpos = ed_curpos(ep, physical, old,0,ep->e_curpos);
1222 		if(clear && old>=ep->e_peol && (clear=ep->e_winsz-ep->e_curpos.col)>0)
1223 		{
1224 			ed_nputchar(ep,clear,' ');
1225 			ed_nputchar(ep,clear,'\b');
1226 			return(new);
1227 		}
1228 		newpos =     ed_curpos(ep, physical, new,old,ep->e_curpos);
1229 		if(ep->e_curpos.col==0 && ep->e_curpos.line>0 && oldline<ep->e_curpos.line && delta<0)
1230 			ed_putstring(ep,"\r\n");
1231 		oldline = newpos.line;
1232 		if(ep->e_curpos.line > newpos.line)
1233 		{
1234 			int n,pline,plen=ep->e_plen;
1235 			for(;ep->e_curpos.line > newpos.line; ep->e_curpos.line--)
1236 				ed_putstring(ep,CURSOR_UP);
1237 			pline = plen/(ep->e_winsz+1);
1238 			if(newpos.line <= pline)
1239 				plen -= pline*(ep->e_winsz+1);
1240 			else
1241 				plen = 0;
1242 			if((n=plen- ep->e_curpos.col)>0)
1243 			{
1244 				ep->e_curpos.col += n;
1245 				ed_putchar(ep,'\r');
1246 				if(!ep->e_crlf && pline==0)
1247 					ed_putstring(ep,ep->e_prompt);
1248 				else
1249 				{
1250 					int m = ep->e_winsz+1-plen;
1251 					ed_putchar(ep,'\n');
1252 					n = plen;
1253 					if(m < ed_genlen(physical))
1254 					{
1255 						while(physical[m] && n-->0)
1256 							ed_putchar(ep,physical[m++]);
1257 					}
1258 					ed_nputchar(ep,n,' ');
1259 					ed_putstring(ep,CURSOR_UP);
1260 				}
1261 			}
1262 		}
1263 		else if(ep->e_curpos.line < newpos.line)
1264 		{
1265 			ed_nputchar(ep, newpos.line-ep->e_curpos.line,'\n');
1266 			ep->e_curpos.line = newpos.line;
1267 			ed_putchar(ep,'\r');
1268 			ep->e_curpos.col = 0;
1269 		}
1270 		delta = newpos.col - ep->e_curpos.col;
1271 		old   =  new - delta;
1272 	}
1273 	else
1274 		newpos.line=0;
1275 	if(delta<0)
1276 	{
1277 		int bs= newpos.line && ep->e_plen>ep->e_winsz;
1278 		/*** move to left ***/
1279 		delta = -delta;
1280 		/*** attempt to optimize cursor movement ***/
1281 		if(!ep->e_crlf || bs || (2*delta <= ((old-first)+(newpos.line?0:ep->e_plen))) )
1282 		{
1283 			ed_nputchar(ep,delta,'\b');
1284 			delta = 0;
1285 		}
1286 		else
1287 		{
1288 			if(newpos.line==0)
1289 				ed_putstring(ep,ep->e_prompt);
1290 			else
1291 			{
1292 				first = 1+(newpos.line*ep->e_winsz - ep->e_plen);
1293 				ed_putchar(ep,'\r');
1294 			}
1295 			old = first;
1296 			delta = new-first;
1297 		}
1298 	}
1299 	while(delta-->0)
1300 		ed_putchar(ep,physical[old++]);
1301 	return(new);
1302 }
1303 
1304 /*
1305  * copy virtual to physical and return the index for cursor in physical buffer
1306  */
1307 int ed_virt_to_phys(Edit_t *ep,genchar *virt,genchar *phys,int cur,int voff,int poff)
1308 {
1309 	register genchar *sp = virt;
1310 	register genchar *dp = phys;
1311 	register int c;
1312 	genchar *curp = sp + cur;
1313 	genchar *dpmax = phys+MAXLINE;
1314 	int d, r;
1315 	sp += voff;
1316 	dp += poff;
1317 	for(r=poff;c= *sp;sp++)
1318 	{
1319 		if(curp == sp)
1320 			r = dp - phys;
1321 #if SHOPT_MULTIBYTE
1322 		d = mbwidth((wchar_t)c);
1323 		if(d==1 && is_cntrl(c))
1324 			d = -1;
1325 		if(d>1)
1326 		{
1327 			/* multiple width character put in place holders */
1328 			*dp++ = c;
1329 			while(--d >0)
1330 				*dp++ = MARKER;
1331 			/* in vi mode the cursor is at the last character */
1332 			if(dp>=dpmax)
1333 				break;
1334 			continue;
1335 		}
1336 		else
1337 #else
1338 		d = (is_cntrl(c)?-1:1);
1339 #endif	/* SHOPT_MULTIBYTE */
1340 		if(d<0)
1341 		{
1342 			if(c=='\t')
1343 			{
1344 				c = dp-phys;
1345 				if(sh_isoption(SH_VI))
1346 					c += ep->e_plen;
1347 				c = TABSIZE - c%TABSIZE;
1348 				while(--c>0)
1349 					*dp++ = ' ';
1350 				c = ' ';
1351 			}
1352 			else
1353 			{
1354 				*dp++ = '^';
1355 				c = printchar(c);
1356 			}
1357 			/* in vi mode the cursor is at the last character */
1358 			if(curp == sp && sh_isoption(SH_VI))
1359 				r = dp - phys;
1360 		}
1361 		*dp++ = c;
1362 		if(dp>=dpmax)
1363 			break;
1364 	}
1365 	*dp = 0;
1366 	ep->e_peol = dp-phys;
1367 	return(r);
1368 }
1369 
1370 #if SHOPT_MULTIBYTE
1371 /*
1372  * convert external representation <src> to an array of genchars <dest>
1373  * <src> and <dest> can be the same
1374  * returns number of chars in dest
1375  */
1376 
1377 int	ed_internal(const char *src, genchar *dest)
1378 {
1379 	register const unsigned char *cp = (unsigned char *)src;
1380 	register int c;
1381 	register wchar_t *dp = (wchar_t*)dest;
1382 	if(dest == (genchar*)roundof(cp-(unsigned char*)0,sizeof(genchar)))
1383 	{
1384 		genchar buffer[MAXLINE];
1385 		c = ed_internal(src,buffer);
1386 		ed_gencpy((genchar*)dp,buffer);
1387 		return(c);
1388 	}
1389 	while(*cp)
1390 		*dp++ = mbchar(cp);
1391 	*dp = 0;
1392 	return(dp-(wchar_t*)dest);
1393 }
1394 
1395 /*
1396  * convert internal representation <src> into character array <dest>.
1397  * The <src> and <dest> may be the same.
1398  * returns number of chars in dest.
1399  */
1400 
1401 int	ed_external(const genchar *src, char *dest)
1402 {
1403 	register genchar wc;
1404 	register int c,size;
1405 	register char *dp = dest;
1406 	char *dpmax = dp+sizeof(genchar)*MAXLINE-2;
1407 	if((char*)src == dp)
1408 	{
1409 		char buffer[MAXLINE*sizeof(genchar)];
1410 		c = ed_external(src,buffer);
1411 
1412 #ifdef _lib_wcscpy
1413 		wcscpy((wchar_t *)dest,(const wchar_t *)buffer);
1414 #else
1415 		strcpy(dest,buffer);
1416 #endif
1417 		return(c);
1418 	}
1419 	while((wc = *src++) && dp<dpmax)
1420 	{
1421 		if((size = mbconv(dp, wc)) < 0)
1422 		{
1423 			/* copy the character as is */
1424 			size = 1;
1425 			*dp = wc;
1426 		}
1427 		dp += size;
1428 	}
1429 	*dp = 0;
1430 	return(dp-dest);
1431 }
1432 
1433 /*
1434  * copy <sp> to <dp>
1435  */
1436 
1437 void	ed_gencpy(genchar *dp,const genchar *sp)
1438 {
1439 	dp = (genchar*)roundof((char*)dp-(char*)0,sizeof(genchar));
1440 	sp = (const genchar*)roundof((char*)sp-(char*)0,sizeof(genchar));
1441 	while(*dp++ = *sp++);
1442 }
1443 
1444 /*
1445  * copy at most <n> items from <sp> to <dp>
1446  */
1447 
1448 void	ed_genncpy(register genchar *dp,register const genchar *sp, int n)
1449 {
1450 	dp = (genchar*)roundof((char*)dp-(char*)0,sizeof(genchar));
1451 	sp = (const genchar*)roundof((char*)sp-(char*)0,sizeof(genchar));
1452 	while(n-->0 && (*dp++ = *sp++));
1453 }
1454 
1455 #endif /* SHOPT_MULTIBYTE */
1456 /*
1457  * find the string length of <str>
1458  */
1459 
1460 int	ed_genlen(register const genchar *str)
1461 {
1462 	register const genchar *sp = str;
1463 	sp = (const genchar*)roundof((char*)sp-(char*)0,sizeof(genchar));
1464 	while(*sp++);
1465 	return(sp-str-1);
1466 }
1467 #endif /* SHOPT_ESH || SHOPT_VSH */
1468 
1469 #ifdef future
1470 /*
1471  * returns 1 when <n> bytes starting at <a> and <b> are equal
1472  */
1473 static int compare(register const char *a,register const char *b,register int n)
1474 {
1475 	while(n-->0)
1476 	{
1477 		if(*a++ != *b++)
1478 			return(0);
1479 	}
1480 	return(1);
1481 }
1482 #endif
1483 
1484 #if SHOPT_OLDTERMIO
1485 
1486 #   include	<sys/termio.h>
1487 
1488 #ifndef ECHOCTL
1489 #   define ECHOCTL	0
1490 #endif /* !ECHOCTL */
1491 #define ott	ep->e_ott
1492 
1493 /*
1494  * For backward compatibility only
1495  * This version will use termios when possible, otherwise termio
1496  */
1497 
1498 int tcgetattr(int fd, struct termios *tt)
1499 {
1500 	register Edit_t *ep = (Edit_t*)(shgd->ed_context);
1501 	register int r,i;
1502 	ep->e_tcgeta = 0;
1503 	ep->e_echoctl = (ECHOCTL!=0);
1504 	if((r=ioctl(fd,TCGETS,tt))>=0 ||  errno!=EINVAL)
1505 		return(r);
1506 	if((r=ioctl(fd,TCGETA,&ott)) >= 0)
1507 	{
1508 		tt->c_lflag = ott.c_lflag;
1509 		tt->c_oflag = ott.c_oflag;
1510 		tt->c_iflag = ott.c_iflag;
1511 		tt->c_cflag = ott.c_cflag;
1512 		for(i=0; i<NCC; i++)
1513 			tt->c_cc[i] = ott.c_cc[i];
1514 		ep->e_tcgeta++;
1515 		ep->e_echoctl = 0;
1516 	}
1517 	return(r);
1518 }
1519 
1520 int tcsetattr(int fd,int mode,struct termios *tt)
1521 {
1522 	register Edit_t *ep = (Edit_t*)(shgd->ed_context);
1523 	register int r;
1524 	if(ep->e_tcgeta)
1525 	{
1526 		register int i;
1527 		ott.c_lflag = tt->c_lflag;
1528 		ott.c_oflag = tt->c_oflag;
1529 		ott.c_iflag = tt->c_iflag;
1530 		ott.c_cflag = tt->c_cflag;
1531 		for(i=0; i<NCC; i++)
1532 			ott.c_cc[i] = tt->c_cc[i];
1533 		if(tt->c_lflag&ECHOCTL)
1534 		{
1535 			ott.c_lflag &= ~(ECHOCTL|IEXTEN);
1536 			ott.c_iflag &= ~(IGNCR|ICRNL);
1537 			ott.c_iflag |= INLCR;
1538 			ott.c_cc[VEOF]= ESC;  /* ESC -> eof char */
1539 			ott.c_cc[VEOL] = '\r'; /* CR -> eol char */
1540 			ott.c_cc[VEOL2] = tt->c_cc[VEOF]; /* EOF -> eol char */
1541 		}
1542 		switch(mode)
1543 		{
1544 			case TCSANOW:
1545 				mode = TCSETA;
1546 				break;
1547 			case TCSADRAIN:
1548 				mode = TCSETAW;
1549 				break;
1550 			case TCSAFLUSH:
1551 				mode = TCSETAF;
1552 		}
1553 		return(ioctl(fd,mode,&ott));
1554 	}
1555 	return(ioctl(fd,mode,tt));
1556 }
1557 #endif /* SHOPT_OLDTERMIO */
1558 
1559 #if KSHELL
1560 /*
1561  * Execute keyboard trap on given buffer <inbuff> of given size <isize>
1562  * <mode> < 0 for vi insert mode
1563  */
1564 static int keytrap(Edit_t *ep,char *inbuff,register int insize, int bufsize, int mode)
1565 {
1566 	register char *cp;
1567 	int savexit;
1568 	Shell_t *shp = ep->sh;
1569 #if SHOPT_MULTIBYTE
1570 	char buff[MAXLINE];
1571 	ed_external(ep->e_inbuf,cp=buff);
1572 #else
1573 	cp = ep->e_inbuf;
1574 #endif /* SHOPT_MULTIBYTE */
1575 	inbuff[insize] = 0;
1576 	ep->e_col = ep->e_cur;
1577 	if(mode== -2)
1578 	{
1579 		ep->e_col++;
1580 		*ep->e_vi_insert = ESC;
1581 	}
1582 	else
1583 		*ep->e_vi_insert = 0;
1584 	nv_putval(ED_CHRNOD,inbuff,NV_NOFREE);
1585 	nv_putval(ED_COLNOD,(char*)&ep->e_col,NV_NOFREE|NV_INTEGER);
1586 	nv_putval(ED_TXTNOD,(char*)cp,NV_NOFREE);
1587 	nv_putval(ED_MODENOD,ep->e_vi_insert,NV_NOFREE);
1588 	savexit = shp->savexit;
1589 	sh_trap(shp->st.trap[SH_KEYTRAP],0);
1590 	shp->savexit = savexit;
1591 	if((cp = nv_getval(ED_CHRNOD)) == inbuff)
1592 		nv_unset(ED_CHRNOD);
1593 	else if(bufsize>0)
1594 	{
1595 		strncpy(inbuff,cp,bufsize);
1596 		inbuff[bufsize-1]='\0';
1597 		insize = strlen(inbuff);
1598 	}
1599 	else
1600 		insize = 0;
1601 	nv_unset(ED_TXTNOD);
1602 	return(insize);
1603 }
1604 #endif /* KSHELL */
1605 
1606 #if SHOPT_EDPREDICT
1607 static int ed_sortdata(const char *s1, const char *s2)
1608 {
1609 	Histmatch_t *m1 = (Histmatch_t*)s1;
1610 	Histmatch_t *m2 = (Histmatch_t*)s2;
1611 	return(strcmp(m1->data,m2->data));
1612 }
1613 
1614 static int ed_sortindex(const char *s1, const char *s2)
1615 {
1616 	Histmatch_t *m1 = (Histmatch_t*)s1;
1617 	Histmatch_t *m2 = (Histmatch_t*)s2;
1618 	return(m2->index-m1->index);
1619 }
1620 
1621 static int ed_histlencopy(const char *cp, char *dp)
1622 {
1623 	int c,n=1,col=1;
1624 	const char *oldcp=cp;
1625 	for(n=0;c = mbchar(cp);oldcp=cp,col++)
1626 	{
1627 		if(c=='\n' && *cp)
1628 		{
1629 			n += 2;
1630 			if(dp)
1631 			{
1632 				*dp++ = '^';
1633 				*dp++ = 'J';
1634 				col +=2;
1635 			}
1636 		}
1637 		else if(c=='\t')
1638 		{
1639 			n++;
1640 			if(dp)
1641 				*dp++ = ' ';
1642 		}
1643 		else
1644 		{
1645 			n  += cp-oldcp;
1646 			if(dp)
1647 			{
1648 				while(oldcp < cp)
1649 					*dp++ = *oldcp++;
1650 			}
1651 		}
1652 
1653 	}
1654 	return(n);
1655 }
1656 
1657 int ed_histgen(Edit_t *ep,const char *pattern)
1658 {
1659 	Histmatch_t	*mp,*mplast=0;
1660 	History_t	*hp;
1661 	off_t		offset;
1662 	int 		ac=0,l,n,index1,index2;
1663 	size_t		m;
1664 	char		*cp, **argv=0, **av, **ar;
1665 	static		int maxmatch;
1666 	if(!(hp=ep->sh->gd->hist_ptr) && (!nv_getval(HISTFILE) || !sh_histinit(ep->sh)))
1667 		return(0);
1668 	if(ep->e_cur <=2)
1669 		maxmatch = 0;
1670 	else if(maxmatch && ep->e_cur > maxmatch)
1671 	{
1672 		ep->hlist = 0;
1673 		ep->hfirst = 0;
1674 		return(0);
1675 	}
1676 	hp = ep->sh->gd->hist_ptr;
1677 	if(*pattern=='#' && *++pattern=='#')
1678 		return(0);
1679 	cp = stakalloc(m=strlen(pattern)+6);
1680 	sfsprintf(cp,m,"@(%s)*%c",pattern,0);
1681 	if(ep->hlist)
1682 	{
1683 		m = strlen(ep->hpat)-4;
1684 		if(memcmp(pattern,ep->hpat+2,m)==0)
1685 		{
1686 			n = strcmp(cp,ep->hpat)==0;
1687 			for(argv=av=(char**)ep->hlist,mp=ep->hfirst; mp;mp= mp->next)
1688 			{
1689 				if(n || strmatch(mp->data,cp))
1690 					*av++ = (char*)mp;
1691 			}
1692 			*av = 0;
1693 			ep->hmax = av-argv;
1694 			if(ep->hmax==0)
1695 				maxmatch = ep->e_cur;
1696 			return(ep->hmax=av-argv);
1697 		}
1698 		stakset(ep->e_stkptr,ep->e_stkoff);
1699 	}
1700 	if((m=strlen(cp)) >= sizeof(ep->hpat))
1701 		m = sizeof(ep->hpat)-1;
1702 	memcpy(ep->hpat,cp,m);
1703 	ep->hpat[m] = 0;
1704 	pattern = cp;
1705 	index1 = (int)hp->histind;
1706 	for(index2=index1-hp->histsize; index1>index2; index1--)
1707 	{
1708 		offset = hist_tell(hp,index1);
1709 		sfseek(hp->histfp,offset,SEEK_SET);
1710 		if(!(cp = sfgetr(hp->histfp,0,0)))
1711 			continue;
1712 		if(*cp=='#')
1713 			continue;
1714 		if(strmatch(cp,pattern))
1715 		{
1716 			l = ed_histlencopy(cp,(char*)0);
1717 			mp = (Histmatch_t*)stakalloc(sizeof(Histmatch_t)+l);
1718 			mp->next = mplast;
1719 			mplast = mp;
1720 			mp->len = l;
1721 			ed_histlencopy(cp,mp->data);
1722 			mp->count = 1;
1723 			mp->data[l] = 0;
1724 			mp->index = index1;
1725 			ac++;
1726 		}
1727 	}
1728 	if(ac>0)
1729 	{
1730 		l = ac;
1731 		argv = av  = (char**)stakalloc((ac+1)*sizeof(char*));
1732 		for(mplast=0; l>=0 && (*av= (char*)mp); mplast=mp,mp=mp->next,av++)
1733 		{
1734 			l--;
1735 		}
1736 		*av = 0;
1737 		strsort(argv,ac,ed_sortdata);
1738 		mplast = (Histmatch_t*)argv[0];
1739 		for(ar= av= &argv[1]; mp=(Histmatch_t*)*av; av++)
1740 		{
1741 			if(strcmp(mp->data,mplast->data)==0)
1742 			{
1743 				mplast->count++;
1744 				if(mp->index> mplast->index)
1745 					mplast->index = mp->index;
1746 				continue;
1747 			}
1748 			*ar++ = (char*)(mplast=mp);
1749 		}
1750 		*ar = 0;
1751 		mplast->next = 0;
1752 		ac = ar-argv;
1753 		strsort(argv,ac,ed_sortindex);
1754 		mplast = (Histmatch_t*)argv[0];
1755 		for(av= &argv[1]; mp=(Histmatch_t*)*av; av++, mplast=mp)
1756 			mplast->next = mp;
1757 		mplast->next = 0;
1758 	}
1759 	ep->hlist = (Histmatch_t**)argv;
1760 	ep->hfirst = ep->hlist?ep->hlist[0]:0;
1761 	return(ep->hmax=ac);
1762 }
1763 
1764 void	ed_histlist(Edit_t *ep,int n)
1765 {
1766 	Histmatch_t	*mp,**mpp = ep->hlist+ep->hoff;
1767 	int		i,last=0,save[2];
1768 	if(n)
1769 	{
1770 		/* don't bother updating the screen if there is typeahead */
1771 		if(!ep->e_lookahead && sfpkrd(ep->e_fd,save,1,'\r',200L,-1)>0)
1772 			ed_ungetchar(ep,save[0]);
1773 		if(ep->e_lookahead)
1774 			return;
1775 		ed_putchar(ep,'\n');
1776 		ed_putchar(ep,'\r');
1777 	}
1778 	else
1779 	{
1780 		stakset(ep->e_stkptr,ep->e_stkoff);
1781 		ep->hlist = 0;
1782 		ep->nhlist = 0;
1783 	}
1784 	ed_putstring(ep,KILL_LINE);
1785 	if(n)
1786 	{
1787 		for(i=1; (mp= *mpp) && i <= 16 ; i++,mpp++)
1788 		{
1789 			last = 0;
1790 			if(mp->len >= ep->e_winsz-4)
1791 			{
1792 				last = ep->e_winsz-4;
1793 				save[0] = mp->data[last-1];
1794 				save[1] = mp->data[last];
1795 				mp->data[last-1] = '\n';
1796 				mp->data[last] = 0;
1797 			}
1798 			ed_putchar(ep,i<10?' ':'1');
1799 			ed_putchar(ep,i<10?'0'+i:'0'+i-10);
1800 			ed_putchar(ep,')');
1801 			ed_putchar(ep,' ');
1802 			ed_putstring(ep,mp->data);
1803 			if(last)
1804 			{
1805 				mp->data[last-1] = save[0];
1806 				mp->data[last] = save[1];
1807 			}
1808 			ep->nhlist = i;
1809 		}
1810 		last = i-1;
1811 		while(i-->0)
1812 			ed_putstring(ep,CURSOR_UP);
1813 	}
1814 	ed_flush(ep);
1815 }
1816 #endif /* SHOPT_EDPREDICT */
1817 
1818 void	*ed_open(Shell_t *shp)
1819 {
1820 	Edit_t *ed = newof(0,Edit_t,1,0);
1821 	ed->sh = shp;
1822 	strcpy(ed->e_macro,"_??");
1823 	return((void*)ed);
1824 }
1825 
1826 #undef ioctl
1827 int	sh_ioctl(int fd, int cmd, void* val, int sz)
1828 {
1829 	int r,err=errno;
1830 	if(sz == sizeof(void*))
1831 	{
1832 		while((r=ioctl(fd,cmd,val)) < 0 && errno==EINTR)
1833 			errno = err;
1834 	}
1835 	else
1836 	{
1837 		Sflong_t l = (Sflong_t)val;
1838 		if(sizeof(val)==sizeof(long))
1839 		{
1840 			while((r=ioctl(fd,cmd,(unsigned long)l)) < 0 && errno==EINTR)
1841 				errno = err;
1842 		}
1843 		else if(sizeof(int)!=sizeof(long))
1844 		{
1845 			while((r=ioctl(fd,cmd,(unsigned int)l)) < 0 && errno==EINTR)
1846 				errno = err;
1847 		}
1848 	}
1849 	return(r);
1850 }
1851 
1852 #ifdef _lib_tcgetattr
1853 #   undef tcgetattr
1854     sh_tcgetattr(int fd, struct termios *tty)
1855     {
1856 	int r,err = errno;
1857 	while((r=tcgetattr(fd,tty)) < 0 && errno==EINTR)
1858 		errno = err;
1859 	return(r);
1860     }
1861 
1862 #   undef tcsetattr
1863     sh_tcsetattr(int fd, int cmd, struct termios *tty)
1864     {
1865 	int r,err = errno;
1866 	while((r=tcsetattr(fd,cmd,tty)) < 0 && errno==EINTR)
1867 		errno = err;
1868 	return(r);
1869     }
1870 #endif
1871