xref: /original-bsd/local/toolchest/ksh/sh/edit.c (revision c816649e)
1 /* @(#)edit.c	1.1 */
2 
3 /*
4  *  edit.c - common routines for vi and emacs one line editors in shell
5  *
6  *   David Korn				P.D. Sullivan
7  *   AT&T Bell Laboratories		AT&T Bell Laboratories
8  *   Room 5D-112			Room 1E253
9  *   Murray Hill, N. J. 07974		Columbus, OH 43213
10  *   Tel. x7975				Tel. x 2655
11  *
12  *   Coded April 1983.
13  */
14 
15 #include	<errno.h>
16 
17 #ifdef KSHELL
18 #include	"shtype.h"
19 #include	"flags.h"
20 #include	"defs.h"
21 #include	"io.h"
22 #include	"name.h"
23 #include	"sym.h"
24 #include	"stak.h"
25 #include	"mode.h"
26 #include	"builtins.h"
27 #include	"brkincr.h"
28 
29 #else
30 #include	<stdio.h>
31 #include	<signal.h>
32 #include	<setjmp.h>
33 #include	<ctype.h>
34 #endif	/* KSHELL */
35 
36 #include	"history.h"
37 #include	"edit.h"
38 
39 #define BAD	-1
40 #define GOOD	0
41 #define	TRUE	(-1)
42 #define	FALSE	0
43 #define	SYSERR	-1
44 
45 #ifdef VENIX
46 #define RT 1
47 #endif	/* VENIX */
48 
49 void	e_crlf();
50 void	e_flush();
51 int	e_getchar();
52 void	e_putchar();
53 void	e_ringbell();
54 void	e_setup();
55 int	e_virt_to_phys();
56 int	e_window();
57 void	setcooked();
58 void	ungetchar();
59 
60 #if BSD || RT
61 #include	<sgtty.h>
62 # ifdef BSD_4_2
63 # include	<sys/time.h>
64 # endif /* BSD_4_2 */
65 static struct sgttyb ttyparm;		/* initial tty parameters */
66 static struct sgttyb nttyparm;		/* raw tty parameters */
67 # ifdef BSD
68 extern int tty_speeds[];
69 static int delay;
70 static int l_mask;
71 static struct tchars l_ttychars;
72 static struct ltchars l_chars;
73 static  char  l_changed;	/* set if mode bits changed */
74 #define L_CHARS	4
75 #define T_CHARS	2
76 #define L_MASK	1
77 # endif /* BSD */
78 #else
79 # ifdef XENIX	/* avoid symbol table overflows */
80 # define NCC 8
81 struct termio {
82 	unsigned short	c_iflag;	/* input modes */
83 	unsigned short	c_oflag;	/* output modes */
84 	unsigned short	c_cflag;	/* control modes */
85 	unsigned short	c_lflag;	/* line discipline modes */
86 	char		c_line;		/* line discipline */
87 	unsigned char	c_cc[NCC];	/* control chars */
88 	char		c_res;		/* padding, AFTER the array */
89 };
90 #define TIOC	('T'<<8)
91 #define	BRKINT	0000002
92 #define	CBAUD	0000017
93 #define	ECHO	0000010
94 #define	ECHOE	0000020
95 #define	ECHOK	0000040
96 #define	ECHONL	0000100
97 #define	ICANON	0000002
98 #define	ICRNL	0000400
99 #define	IGNCR	0000200
100 #define	IGNPAR	0000004
101 #define	INLCR	0000100
102 #define	PARMRK	0000010
103 #define	TCGETA	(TIOC|1)
104 #define	TCSETAW	(TIOC|3)
105 #define	TCXONC	(TIOC|6)
106 #define	VEOF	4
107 #define	VERASE	2
108 #define	VKILL	3
109 #define	VMIN	4
110 #define	VTIME	5
111 #define TM_CECHO	0010
112 # else
113 # include	<termio.h>
114 # endif /* XENIX */
115 
116 static struct termio ttyparm;		/* initial tty parameters */
117 static struct termio nttyparm;		/* raw tty parameters */
118 #endif	/* RT */
119 
120 #define lookahead	editb.e_index
121 #define env		editb.e_env
122 #define previous	editb.e_lbuf
123 #define fildes		editb.e_fd
124 
125 #ifdef KSHELL
126 extern struct Amemory	*alias;
127 extern char		**arg_build();
128 extern void		failed();
129 extern void		fault();
130 extern struct Namnod	*findnod();
131 extern int		f_complete();
132 extern void		gsort();
133 extern char		*movstr();
134 extern void		p_flush();
135 extern void		p_setout();
136 extern char		*simple();
137 extern char		*tilde();
138 extern char		*valup();
139 static char macro[]	= "_?";
140 
141 #else
142 static char badcooked[]	= "cannot reset tty to cooked mode";
143 struct edit editb;
144 char trapnote;
145 extern char trapnote;
146 extern int errno;
147 #define p_flush()	fflush(stderr)
148 #define p_setout(s)	fflush(stdout)
149 #define error(s)	failed(s,NULL)
150 #define SIGSLOW 1
151 #define output	stderr
152 #endif	/* KSHELL */
153 
154 extern char *strrchr();
155 extern char *strcpy();
156 
157 static char bellchr[] = "\7";		/* bell char */
158 
159 static int control();
160 /*{	SETCOOKED( fd )
161  *
162  *	This routine will set the tty in cooked mode.
163  * It is also called by error.done().
164  *
165 }*/
166 
setcooked(fd)167 void setcooked(fd)
168 register int fd;
169 {
170 	/*** don't do ioctl unless ttyparm has valid data ***/
171 	/* or in raw mode */
172 
173 	if(editb.e_ttyspeed==0 || editb.e_raw==0)
174 		return;
175 
176 #ifdef BSD
177 	if(editb.e_raw==RAWMODE && ioctl(fd, TIOCSETN, &ttyparm) == SYSERR )
178 	{
179 		if(errno!=EBADF && errno!=ENOTTY)
180 			error(badcooked);
181 		return;
182 	}
183 	/* restore flags */
184 	if(l_changed&L_MASK)
185 		ioctl(fd,TIOCLSET,&l_mask);
186 	if(l_changed&T_CHARS)
187 		/* restore alternate break character */
188 		ioctl(fd,TIOCSETC,&l_ttychars);
189 	if(l_changed&L_CHARS)
190 		/* restore alternate break character */
191 		ioctl(fd,TIOCSLTC,&l_chars);
192 	l_changed = 0;
193 #else
194 # ifdef RT
195 	if (stty(fd,&ttyparm) == SYSERR)
196 # else
197 	if( editb.e_raw && control(fd, TCSETAW, &ttyparm) == SYSERR )
198 # endif /* RT */
199 	{
200 		if(errno!=EBADF && errno!=ENOTTY)
201 			error(badcooked);
202 		return;
203 	}
204 #endif	/* BSD */
205 	editb.e_raw = 0;
206 	return;
207 }
208 
209 /*{	SETRAW( fd )
210  *
211  *	This routine will set the tty in raw mode.
212  *
213 }*/
214 
setraw(fd)215 setraw(fd)
216 register int fd;
217 {
218 #ifdef BSD
219 	struct ltchars lchars;
220 #endif	/* BSD */
221 	if(editb.e_raw==RAWMODE)
222 		return(GOOD);
223 	/* characters are echoed on standard error */
224 	p_setout(stderr);
225 #if BSD || RT
226 # ifdef BSD
227 	if((ioctl(fd,TIOCGETP,&ttyparm) == SYSERR)
228 # else
229 	if ((gtty(fd,&ttyparm) == SYSERR)
230 # endif /* BSD */
231 		|| !(ttyparm.sg_flags & ECHO )
232 		|| (ttyparm.sg_flags & LCASE ))
233 	{
234 		return(BAD);
235 	}
236 	nttyparm = ttyparm;
237 	nttyparm.sg_flags &= ~(ECHO | TBDELAY);
238 # ifdef BSD
239 	nttyparm.sg_flags |= CBREAK;
240 # else
241 	nttyparm.sg_flags |= RAW;
242 # endif /* BSD */
243 	editb.e_erase = ttyparm.sg_erase;
244 	editb.e_kill = ttyparm.sg_kill;
245 	editb.e_eof = cntl(D);
246 # ifdef BSD
247 	if( ioctl(fd, TIOCSETN, &nttyparm) == SYSERR )
248 # else
249 	if( stty(fd, &nttyparm) == SYSERR )
250 # endif /* BSD */
251 	{
252 		return(BAD);
253 	}
254 	editb.e_ttyspeed = (ttyparm.sg_ospeed>=B1200?FAST:SLOW);
255 #ifdef BSD
256 	delay = tty_speeds[ttyparm.sg_ospeed];
257 	/* try to remove effect of ^V  and ^Y */
258 	if(ioctl(fd,TIOCGLTC,&l_chars) != SYSERR)
259 	{
260 		lchars = l_chars;
261 		lchars.t_lnextc = -1;
262 		lchars.t_dsuspc = -1;	/* no delayed stop process signal */
263 		if(ioctl(fd,TIOCSLTC,&lchars) != SYSERR)
264 			l_changed |= L_CHARS;
265 	}
266 #endif	/* BSD */
267 #else
268 
269 # ifndef RAWONLY
270 	if(editb.e_raw != ALTMODE)
271 # endif /* RAWONLY */
272 		if( (ioctl(fd, TCGETA, &ttyparm) == SYSERR)
273 			|| (!(ttyparm.c_lflag & ECHO )))
274 		{
275 			return(BAD);
276 		}
277 
278 	nttyparm = ttyparm;
279 #ifndef u370
280 	nttyparm.c_iflag &= ~(IGNPAR|PARMRK|INLCR|IGNCR|ICRNL);
281 	nttyparm.c_iflag |= BRKINT;
282 	nttyparm.c_lflag &= ~(ICANON|ECHO);
283 #else
284 	nttyparm.c_iflag &=
285 			~(IGNBRK|PARMRK|INLCR|IGNCR|ICRNL|INPCK);
286 	nttyparm.c_iflag |= (BRKINT|IGNPAR);
287 	nttyparm.c_lflag &= ~(ICANON|ECHO);
288 #endif	/* u370 */
289 	nttyparm.c_cc[VTIME] = 0;
290 	nttyparm.c_cc[VMIN] = 1;
291 	editb.e_eof = ttyparm.c_cc[VEOF];
292 	editb.e_erase = ttyparm.c_cc[VERASE];
293 	editb.e_kill = ttyparm.c_cc[VKILL];
294 #ifndef u370
295 	if( control(fd, TCSETAW, &nttyparm) == SYSERR )
296 #else
297 	/* delays are too long, don't wait for output to drain */
298 	if( control(fd, TCSETA, &nttyparm) == SYSERR )
299 #endif	/* u370 */
300 	{
301 		return(BAD);
302 	}
303 	control(fd,TCXONC,1);
304 	editb.e_ttyspeed = ttyparm.c_cflag & CBAUD;
305 #endif
306 	editb.e_raw = RAWMODE;
307 	return(GOOD);
308 }
309 
310 #ifndef BSD
311 /*
312  * give two tries for ioctl
313  * interrupts are ignored
314  */
315 
control(fd,request,arg)316 static int control(fd,request,arg)
317 {
318 	register int i;
319 	register int k = 2;
320 	errno = 0;
321 	while(k--)
322 	{
323 		if((i = ioctl(fd,request,arg)) != SYSERR)
324 			return(i);
325 		if(errno == EINTR)
326 		{
327 			errno = 0;
328 			k++;
329 		}
330 	}
331 	return(SYSERR);
332 }
333 #endif	/* BSD */
334 #ifndef RAWONLY
335 
336 /*	SET_TTY( fd )
337  *
338  *	Get tty parameters and make ESC and '\r' wakeup characters.
339  *
340  */
341 
342 #ifdef BSD
setalt(fd)343 setalt(fd)
344 register int fd;
345 {
346 	int mask;
347 	struct tchars ttychars;
348 	if(editb.e_raw==ALTMODE)
349 		return(GOOD);
350 	if(editb.e_raw==RAWMODE)
351 		setcooked(fd);
352 	l_changed = 0;
353 	if( editb.e_ttyspeed == 0)
354 	{
355 		if((ioctl(fd,TIOCGETP,&ttyparm) != SYSERR))
356 			editb.e_ttyspeed = (ttyparm.sg_ospeed>=B1200?FAST:SLOW);
357 	}
358 	if(ioctl(fd,TIOCGETC,&l_ttychars) == SYSERR)
359 		return(BAD);
360 	if(ioctl(fd,TIOCLGET,&l_mask)==SYSERR)
361 		return(BAD);
362 	ttychars = l_ttychars;
363 	mask =  LCRTBS|LCRTERA|LCTLECH|LPENDIN|LCRTKIL;
364 	if((l_mask|mask) != l_mask)
365 		l_changed = L_MASK;
366 	if(ioctl(fd,TIOCLBIS,&mask)==SYSERR)
367 		return(BAD);
368 	ttychars.t_brkc = ESC;
369 	l_changed |= T_CHARS;
370 	if(ioctl(fd,TIOCSETC,&ttychars) == SYSERR)
371 		return(BAD);
372 	editb.e_raw = ALTMODE;
373 	return(GOOD);
374 }
375 #else
setalt(fd)376 setalt(fd)
377 register int fd;
378 {
379 	if(editb.e_raw==ALTMODE)
380 		return(GOOD);
381 	if(editb.e_raw==RAWMODE)
382 		setcooked(fd);
383 	if( (control(fd, TCGETA, &ttyparm) == SYSERR)
384 		|| (!(ttyparm.c_lflag & ECHO )))
385 	{
386 		return(BAD);
387 	}
388 	nttyparm = ttyparm;
389 	nttyparm.c_iflag &= ~(IGNCR|ICRNL);
390 	nttyparm.c_iflag |= INLCR;
391 	nttyparm.c_lflag |= (ECHOE|ECHOK);
392 	nttyparm.c_cc[VEOF] = ESC;	/* make ESC the eof char */
393 	nttyparm.c_cc[VEOL] = '\r';	/* make CR an eol char */
394 	editb.e_eof = ttyparm.c_cc[VEOF];
395 	nttyparm.c_cc[VEOL2] = editb.e_eof;	/* make EOF an eol char */
396 	editb.e_erase = ttyparm.c_cc[VERASE];
397 	editb.e_kill = ttyparm.c_cc[VKILL];
398 	if( control(fd, TCSETAW, &nttyparm) == SYSERR )
399 	{
400 		return(BAD);
401 	}
402 	editb.e_ttyspeed = ((ttyparm.c_cflag&CBAUD)>=B1200?FAST:SLOW);
403 	editb.e_raw = ALTMODE;
404 	return(GOOD);
405 }
406 
407 #endif	/* BSD */
408 #endif	/* RAWONLY */
409 
410 /*
411  *	E_WINDOW()
412  *
413  *	return the window size
414  */
415 
e_window()416 int e_window()
417 {
418 	register int n = DFLTWINDOW-1;
419 	register char *cp = valup(COLUMNS);
420 	if(cp)
421 	{
422 		n = atoi(cp)-1;
423 		if(n < MINWINDOW)
424 			n = MINWINDOW;
425 		if(n > MAXWINDOW)
426 			n = MAXWINDOW;
427 	}
428 	return(n);
429 }
430 
431 /*	E_FLUSH()
432  *
433  *	Flush the output buffer.
434  *
435  */
436 
e_flush()437 void e_flush()
438 {
439 	register unsigned char *buf = (unsigned char*)output->_base;
440 	register int n = editb.e_outptr-buf;
441 	register int fd = fileno(output);
442 	if(n<=0)
443 		return;
444 	write(fd,(char*)buf,n);
445 	editb.e_outptr = buf;
446 #ifdef BSD
447 # ifdef BSD_4_2
448 	if(delay && n > delay/100)
449 	{
450 		/* delay until output drains */
451 		struct timeval timeloc;
452 		n *= 10;
453 		timeloc.tv_sec = n/delay;
454 		timeloc.tv_usec = (1000000*(n%delay))/delay;
455 		select(0,0,0,0,&timeloc);
456 	}
457 # endif /* BSD_4_2 */
458 #else
459 # ifndef RT
460 	if(editb.e_raw==RAWMODE && n > 16)
461 		ioctl(fd, TCSETAW, &nttyparm);
462 # endif /* RT */
463 #endif /* BSD */
464 }
465 
466 /*
467  * send the bell character ^G to the terminal
468  */
469 
e_ringbell()470 void e_ringbell()
471 {
472 	write(fileno(output),bellchr,1);
473 }
474 
475 /*
476  * send a carriage return line feed to the terminal
477  */
478 
e_crlf()479 void e_crlf()
480 {
481 #ifdef u370
482 	e_putchar('\r');
483 #endif	/* u370 */
484 #ifdef VENIX
485 	e_putchar('\r');
486 #endif /* VENIX */
487 	e_putchar('\n');
488 	e_flush();
489 }
490 
491 /*	E_SETUP( max_prompt_size )
492  *
493  *	This routine sets up the prompt string
494  */
495 
e_setup(fd,PRSIZE)496 void	e_setup(fd,PRSIZE)
497 {
498 	register char *last;
499 	register char *pp = (char*)(output->_base);
500 	char *ppmax;
501 	editb.e_fd = fd;
502 	if(fc_fix)
503 	{
504 		register struct fixcmd *fp = fc_fix;
505 		editb.e_hismax = fp->fixind;
506 		editb.e_hloff = fp->fixline;
507 		editb.e_hismin = fp->fixind-fp->fixmax;
508 		if(editb.e_hismin<0)
509 			editb.e_hismin = 0;
510 	}
511 	else
512 	{
513 		editb.e_hismax = editb.e_hismin = editb.e_hloff = 0;
514 	}
515 	editb.e_hline = editb.e_hismax;
516 	editb.e_wsize = e_window()-2;
517 	editb.e_outptr = (unsigned char*)pp;
518 	editb.e_crlf = YES;
519 	*(output->_ptr) = 0;
520 	if((last=strrchr(pp,'\n'))==NULL)
521 	{
522 		if(*(last=pp)==0)
523 			editb.e_crlf = NO;
524 	}
525 	else
526 		last++;
527 	pp = editb.e_prompt;
528 	ppmax = pp+PRSIZE-1;
529 	*pp++ = '\r';
530 	{
531 		register int c;
532 		while(c = *last++)
533 		{
534 			/* cut out bells */
535 			if(c!=BELL)
536 			{
537 				if(pp < ppmax)
538 					*pp++ = c;
539 				if(!isprint(c))
540 					editb.e_crlf = NO;
541 			}
542 		}
543 	}
544 	editb.e_plen = pp - editb.e_prompt - 1;
545 	*pp = 0;
546 #ifdef u370
547 	if (editb.e_raw == RAWMODE)
548 		u370fflush(output);
549 	else
550 #endif	/* u370 */
551 	p_flush();
552 }
553 
554 #ifdef u370
555 /* The u370 does not \r before \n in raw mode (known bug).
556 	  To get around this we will insert a \r before each \n
557 	  in the output buffer.
558 */
559 
u370fflush(file)560 u370fflush(file)
561 FILE *file;
562 {
563 	unsigned char *base,*ptr,buffer[BUFSIZ*2];
564 	int icnt,ocnt;
565 	ptr = buffer;
566 	icnt = file->_ptr - file->_base;
567 	ocnt = icnt;
568 	base = file->_base ;
569 	if (icnt <= 0) return;
570 	while (base < file->_ptr)
571 	{
572 		if (*base == '\n' )
573 		{
574 			*ptr++ = '\r';
575 			ocnt++;
576 		}
577 		*ptr++ = *base++;
578 	}
579 	base = file->_base;
580 	ptr = buffer;
581 	while (ocnt>0)
582 	{
583 		for(icnt=0;icnt<BUFSIZ;icnt++)
584 		{
585 			*base++ = *ptr++;
586 			if (--ocnt <= 0) break;
587 		}
588 		file->_ptr = base;
589 		p_flush();
590 		base = file->_base;
591 	}
592 }
593 #endif	/* u370 */
594 
595 #ifdef KSHELL
596 /*
597  * look for edit macro named _i
598  * if found, puts the macro definition into lookahead buffer and returns 1
599  */
600 
e_macro(i)601 e_macro(i)
602 register int i;
603 {
604 	register char *out;
605 	struct Namnod *np;
606 	genchar buff[LOOKAHEAD+1];
607 	if(i != '@')
608 		macro[1] = i;
609 	if (isalnum(i)&&(np=findnod(macro,alias,0))&&(out=valup(np)))
610 	{
611 #ifdef MULTIBYTE
612 		/* copy to buff in internal representation */
613 		int c = out[LOOKAHEAD];
614 		out[LOOKAHEAD] = 0;
615 		i = e_internal(out,buff);
616 		out[LOOKAHEAD] = c;
617 #else
618 		strncpy((char*)buff,out,LOOKAHEAD);
619 		i = strlen((char*)buff);
620 #endif /* MULTIBYTE */
621 		while(i-- > 0)
622 			ungetchar(buff[i]);
623 		return(1);
624 	}
625 	return(0);
626 }
627 /*
628  * file name generation for edit modes
629  * non-zero exit for error, <0 ring bell
630  * don't search back past <start> character of the buffer
631  * mode is '*' for inline expansion, otherwise files are listed in select format
632  */
633 
q_expand(outbuff,cur,eol,start,mode)634 q_expand(outbuff,cur,eol,start,mode)
635 char outbuff[];
636 int *cur;
637 int *eol;
638 int start;
639 int mode;
640 {
641 	STKPTR staksav = stakbot;
642 	COMPTR  comptr = (COMPTR)getstak(COMTYPE);
643 	ARGPTR ap = (ARGPTR)locstak();
644 	register char *out;
645 	char *outmin = outbuff + start;
646 	char *begin;
647 	char *last;
648 	int rval = 0;
649 	int strip;
650 	optflag savflags = flags;
651 #ifdef MULTIBYTE
652 	{
653 		register int c = *cur;
654 		register genchar *cp;
655 		/* adjust cur */
656 		cp = (genchar *)outbuff + *cur;
657 		c = *cp;
658 		*cp = 0;
659 		*cur = e_external((genchar*)outbuff,(char*)stakbot);
660 		*cp = c;
661 		*eol = e_external((genchar*)outbuff,outbuff);
662 	}
663 #endif /* MULTIBYTE */
664 	out = outbuff + *cur;
665 	comptr->comtyp = COMSCAN;
666 	comptr->comarg = ap;
667 	ap->argflag = (A_MAC|A_EXP);
668 	ap->argnxt = 0;
669 	{
670 		register int c;
671 		register char *ptr = ap->argval;
672 		int chktilde = 0;
673 		int flag;
674 		char *cp;
675 		if(out>outmin)
676 		{
677 			/* go to beginning of word */
678 			do
679 			{
680 				out--;
681 				c = *(unsigned char*)out;
682 			}
683 			while(out>outmin && !isqmeta(c));
684 			/* copy word into arg */
685 			if(isqmeta(c))
686 				out++;
687 		}
688 		else
689 			out = outmin;
690 		begin = out;
691 		flag = '*';
692 		strip = TRUE;
693 		/* copy word to arg and do ~ expansion */
694 		do
695 		{
696 			c = *(unsigned char*)out++;
697 			if(isexp(c))
698 				flag = 0;
699 			if ((c == '/') && (flag == 0))
700 				strip = FALSE;
701 			*ptr++ = c;
702 			if(chktilde==0 && (c==0 || c == '/'))
703 			{
704 				chktilde++;
705 				if(cp=tilde(begin))
706 				{
707 					ptr = movstr(cp,ap->argval);
708 					*ptr++ = c;
709 				}
710 			}
711 
712 		} while (c && !isqmeta(c));
713 
714 		out--;
715 		*(ptr-1) = flag;
716 		endstak(ptr);
717 		last = ptr-1;
718 	}
719 	if(mode!='*')
720 		on_option(MARKDIR);
721 	{
722 		register char **com;
723 		int	 narg;
724 		register int size;
725 		while(1)
726 		{
727 			com = arg_build(&narg,comptr);
728 			/*  match? */
729 			if (narg > 1 || !eq(ap->argval,*com))
730 				break;
731 			if (*last == 0)
732 				*last = '*';
733 			else
734 			{
735 				rval = -1;
736 				goto done;
737 			}
738 		}
739 		if(mode!='*')
740 		{
741 			if (strip)
742 			{
743 				register char **ptrcom;
744 				for(ptrcom=com;*ptrcom;ptrcom++)
745 					/* trim directory prefix */
746 					*ptrcom = simple (*ptrcom);
747 			}
748 			p_setout(stderr);
749 			newline();
750 			p_list(narg,com);
751 			p_flush();
752 			goto done;
753 		}
754 		/* see if there is enough room */
755 		size = *eol - (out-begin);
756 		size += narg;
757 		{
758 			char **savcom = com;
759 			while (*com)
760 				size += strlen(*com++);
761 			com = savcom;
762 		}
763 		/* see if room for expansion */
764 		if(outbuff+size >= &outbuff[MAXLINE])
765 		{
766 			com[0] = ap->argval;
767 			com[1] = NULL;
768 		}
769 		/* save remainder of the buffer */
770 		strcpy(stakbot,out);
771 		out = begin;
772 		while (*com)
773 		{
774 			out = movstr(*com,out);
775 			if (*++com)
776 				*out++  = ' ';
777 		}
778 		*cur = (out-outbuff);
779 		/* restore rest of buffer */
780 		out = movstr(stakbot,out);
781 		*eol = (out-outbuff);
782 	}
783  done:
784 	tdystak(staksav);
785 	flags = savflags;
786 #ifdef MULTIBYTE
787 	{
788 		register int c;
789 		/* first re-adjust cur */
790 		out = outbuff + *cur;
791 		c = *out;
792 		*out = 0;
793 		*cur = e_internal(outbuff,(genchar*)stakbot);
794 		*out = c;
795 		outbuff[*eol+1] = 0;
796 		*eol = e_internal(outbuff,(genchar*)outbuff);
797 	}
798 #endif /* MULTIBYTE */
799 	return(rval);
800 }
801 #endif	/* KSHELL */
802 
803 
804 /*
805  * routine to perform read from terminal for vi and emacs mode
806  */
807 
808 
809 int
e_getchar()810 e_getchar()
811 {
812 	register int i;
813 	register int c;
814 	register int maxtry = 100;
815 	int nchar;	/* number of characters to read at a time */
816 #ifdef MULTIBYTE
817 	static int curchar;
818 	static int cursize;
819 #endif /* MULTIBYTE */
820 	char readin[LOOKAHEAD] ;
821 	if (lookahead)
822 	{
823 		c = previous[--lookahead];
824 		/*** map '\r' to '\n' ***/
825 		if(c == '\r')
826 			c = '\n';
827 		return(c);
828 	}
829 
830 	e_flush() ;
831 	/* you can't chance read ahead at the end of line */
832 	nchar = (editb.e_cur>=editb.e_eol?1:READAHEAD);
833 	/* Set 'i' to indicate read failed, in case intr set */
834 retry:
835 	i = -1;
836 	errno = 0;
837 	editb.e_inmacro = 0;
838 	while((trapnote&SIGSLOW)==0 && maxtry--)
839 	{
840 		errno=0;
841 		if ((i = read(fildes,readin, nchar)) != -1)
842 			break;
843 	}
844 #ifdef MULTIBYTE
845 	lookahead = maxtry = i;
846 	i = 0;
847 	while (i < maxtry)
848 	{
849 		c = readin[i++] & STRIP;
850 	next:
851 		if(cursize-- > 0)
852 		{
853 			curchar = (curchar<<7) | (c&~HIGHBIT);
854 			if(cursize==0)
855 			{
856 				c = curchar;
857 				goto gotit;
858 			}
859 			else if(i>=maxtry)
860 				goto retry;
861 			continue;
862 		}
863 		else if(curchar = echarset(c))
864 		{
865 			cursize = in_csize(curchar);
866 			if(curchar != 1)
867 				c = 0;
868 			curchar <<= 7*(ESS_MAXCHAR-cursize);
869 			if(c)
870 				goto next;
871 			else if(i>=maxtry)
872 				goto retry;
873 			continue;
874 		}
875 	gotit:
876 		previous[--lookahead] = c;
877 #else
878 	while (i > 0)
879 	{
880 		c = readin[--i] & STRIP;
881 		previous[lookahead++] = c;
882 #endif /* MULTIBYTE */
883 #ifndef BSD
884 		if( c == '\0' )
885 		{
886 			/*** user break key ***/
887 			lookahead = 0;
888 # ifdef KSHELL
889 			fault(SIGINT);
890 			longjmp(env, UINTR);
891 # endif	/* KSHELL */
892 		}
893 #endif	/* !BSD */
894 	}
895 #ifdef MULTIBYTE
896 	/* shift lookahead buffer if necessary */
897 	if(lookahead)
898 	{
899 		for(i=lookahead;i < maxtry;i++)
900 			previous[i-lookahead] = previous[i];
901 	}
902 	lookahead = maxtry-lookahead;
903 #endif /* MULTIBYTE */
904 	if (lookahead > 0)
905 		return(e_getchar(1));
906 	longjmp(env,(i==0?UEOF:UINTR)); /* What a mess! Give up */
907 	/* NOTREACHED */
908 }
909 
910 void ungetchar(c)
911 register int c;
912 {
913 	if (lookahead < LOOKAHEAD)
914 		previous[lookahead++] = c;
915 	return;
916 }
917 
918 /*
919  * put a character into the output buffer
920  */
921 
922 void	e_putchar(c)
923 register int c;
924 {
925 	register unsigned char *dp = editb.e_outptr;
926 #ifdef MULTIBYTE
927 	register int d;
928 	/* check for place holder */
929 	if(c == MARKER)
930 		return;
931 	if(d = icharset(c))
932 	{
933 		if(d == 2)
934 			*dp++ = ESS2;
935 		else if(d == 3)
936 			*dp++ = ESS3;
937 		d = in_csize(d);
938 		while(--d>0)
939 			*dp++ = HIGHBIT|(c>>(7*d));
940 		c |= HIGHBIT;
941 	}
942 #endif	/* MULTIBYTE */
943 	if (c == '_')
944 	{
945 		*dp++ = ' ';
946 		*dp++ = '\b';
947 	}
948 	*dp++ = c;
949 	*dp = '\0';
950 	if ((dp - (unsigned char*)(output->_base))>=(BUFSIZ-3))
951 		e_flush();
952 	else
953 		editb.e_outptr = dp;
954 }
955 
956 /*
957  * copy virtual to physical and return the index for cursor in physical buffer
958  */
959 e_virt_to_phys(virt,phys,cur,voff,poff)
960 genchar *virt;
961 genchar *phys;
962 int cur;
963 {
964 	register genchar *sp = virt;
965 	register genchar *dp = phys;
966 	register int c;
967 	genchar *curp = sp + cur;
968 	genchar *dpmax = phys+MAXLINE;
969 	int r = 0;
970 #ifdef MULTIBYTE
971 	int d;
972 #endif /* MULTIBYTE */
973 	sp += voff;
974 	dp += poff;
975 	for(r=poff;c= *sp;sp++)
976 	{
977 		if(curp == sp)
978 			r = dp - phys;
979 #ifdef MULTIBYTE
980 		d = out_csize(icharset(c));
981 		if(d>1)
982 		{
983 			/* multiple width character put in place holders */
984 			*dp++ = c;
985 			while(--d >0)
986 				*dp++ = MARKER;
987 			/* in vi mode the cursor is at the last character */
988 			if(dp>=dpmax)
989 				break;
990 			continue;
991 		}
992 		else
993 #endif	/* MULTIBYTE */
994 		if(!isprint(c))
995 		{
996 			if(c=='\t')
997 			{
998 				c = dp-phys;
999 				c = ((c+8)&~07) - c;
1000 				while(--c>0)
1001 					*dp++ = ' ';
1002 				c = ' ';
1003 			}
1004 			else
1005 			{
1006 				*dp++ = '^';
1007 				c ^= TO_PRINT;
1008 			}
1009 			/* in vi mode the cursor is at the last character */
1010 			if(curp == sp && is_option(EDITVI))
1011 				r = dp - phys;
1012 		}
1013 		*dp++ = c;
1014 		if(dp>=dpmax)
1015 			break;
1016 	}
1017 	*dp = 0;
1018 	return(r);
1019 }
1020 
1021 #ifdef MULTIBYTE
1022 /*
1023  * convert external representation <src> to an array of genchars <dest>
1024  * <src> and <dest> can be the same
1025  * returns number of chars in dest
1026  */
1027 
1028 int	e_internal(src,dest)
1029 register unsigned char *src;
1030 genchar *dest;
1031 {
1032 	register int c;
1033 	register genchar *dp = dest;
1034 	register int d;
1035 	register int size;
1036 	if((unsigned char*)dest == src)
1037 	{
1038 		genchar buffer[MAXLINE];
1039 		c = e_internal(src,buffer);
1040 		e_gencpy(dp,buffer);
1041 		return(c);
1042 	}
1043 	while(c = *src++)
1044 	{
1045 		if(size = echarset(c))
1046 		{
1047 			d = (size==1?c:0);
1048 			c = size;
1049 			size = in_csize(c);
1050 			c <<= 7*(ESS_MAXCHAR-size);
1051 			if(d)
1052 			{
1053 				size--;
1054 				c = (c<<7) | (d&~HIGHBIT);
1055 			}
1056 			while(size-- >0)
1057 				c = (c<<7) | ((*src++)&~HIGHBIT);
1058 		}
1059 		*dp++ = c;
1060 	}
1061 	*dp = 0;
1062 	return(dp-dest);
1063 }
1064 
1065 /*
1066  * convert internal representation <src> into character array <dest>.
1067  * The <src> and <dest> may be the same.
1068  * returns number of chars in dest.
1069  */
1070 
1071 int	e_external(src,dest)
1072 genchar *src;
1073 char *dest;
1074 {
1075 	register int c;
1076 	register char *dp = dest;
1077 	register int d;
1078 	char *dpmax = dp+sizeof(genchar)*MAXLINE-2;
1079 	if((char*)src == dp)
1080 	{
1081 		char buffer[MAXLINE*sizeof(genchar)];
1082 		c = e_external(src,buffer);
1083 		strcpy(dest,buffer);
1084 		return(c);
1085 	}
1086 	while((c = *src++) && dp<dpmax)
1087 	{
1088 		if(d = icharset(c))
1089 		{
1090 			if(d == 2)
1091 				*dp++ = ESS2;
1092 			else if(d == 3)
1093 				*dp++ = ESS3;
1094 			d = in_csize(d);
1095 			while(--d>0)
1096 				*dp++ = HIGHBIT|(c>>(7*d));
1097 			c |= HIGHBIT;
1098 		}
1099 		*dp++ = c;
1100 	}
1101 	*dp = 0;
1102 	return(dp-dest);
1103 }
1104 
1105 /*
1106  * copy <sp> to <dp>
1107  */
1108 
1109 int	e_gencpy(dp,sp)
1110 register genchar *dp;
1111 register genchar *sp;
1112 {
1113 	while(*dp++ = *sp++);
1114 }
1115 
1116 /*
1117  * copy at most <n> items from <sp> to <dp>
1118  */
1119 
1120 int	e_genncpy(dp,sp, n)
1121 register genchar *dp;
1122 register genchar *sp;
1123 register int n;
1124 {
1125 	while(n-->0 && (*dp++ = *sp++));
1126 }
1127 
1128 /*
1129  * find the string length of <str>
1130  */
1131 
1132 int	e_genlen(str)
1133 register genchar *str;
1134 {
1135 	register genchar *sp = str;
1136 	while(*sp++);
1137 	return(sp-str-1);
1138 }
1139 #endif /* MULTIBYTE */
1140