1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1984-2011 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 *                             Pat Sullivan                             *
19 *                                                                      *
20 ***********************************************************************/
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 Bell Laboratories		AT&T Bell Laboratories
26  *   Room 3C-526B			Room 1B-286
27  *   Murray Hill, N. J. 07974		Columbus, OH 43213
28  *   Tel. x7975				Tel. x 2655
29  *
30  *   Coded April 1983.
31  */
32 
33 #ifdef KSHELL
34 #   include	"defs.h"
35 #   include	"terminal.h"
36 #   include	"builtins.h"
37 #   include	"sym.h"
38 #else
39 #   include	"io.h"
40 #   include	"terminal.h"
41 #   undef SIG_NORESTART
42 #   define SIG_NORESTART	1
43 #   define _sobuf	ed_errbuf
44     extern char ed_errbuf[];
45     const char e_version[] = "\n@(#)$Id: edit library (AT&T Research) 1988-11-16 i $\0\n";
46 #endif	/* KSHELL */
47 #include	"history.h"
48 #include	"edit.h"
49 
50 #include	<error.h>
51 
52 #define BAD	-1
53 #define GOOD	0
54 #define	SYSERR	-1
55 
56 #ifdef OLDTERMIO
57 #   undef tcgetattr
58 #   undef tcsetattr
59 #endif /* OLDTERMIO */
60 
61 #ifdef RT
62 #   define VENIX 1
63 #endif	/* RT */
64 
65 #define lookahead	editb.e_index
66 #define env		editb.e_env
67 #define previous	editb.e_lbuf
68 #define fildes		editb.e_fd
69 #define in_raw		editb.e_addnl
70 
71 
72 #ifdef _hdr_sgtty
73 #   ifdef TIOCGETP
74 	static int l_mask;
75 	static struct tchars l_ttychars;
76 	static struct ltchars l_chars;
77 	static  char  l_changed;	/* set if mode bits changed */
78 #	define L_CHARS	4
79 #	define T_CHARS	2
80 #	define L_MASK	1
81 #   endif /* TIOCGETP */
82 #endif /* _hdr_sgtty */
83 
84 #ifndef IODELAY
85 #   undef _SELECT5_
86 #endif /* IODELAY */
87 #ifdef _SELECT5_
88 #   ifndef included_sys_time
89 #       define included_sys_time	1
90 #	include	<sys/time.h>
91 #   endif /* included_sys_time */
92 	static int delay;
93 #   ifndef KSHELL
94     	    int tty_speeds[] = {0, 50, 75, 110, 134, 150, 200, 300,
95 		600,1200,1800,2400,9600,19200,0};
96 #   endif	/* KSHELL */
97 #endif /* _SELECT5_ */
98 
99 #ifdef KSHELL
100     extern char		*sh_tilde();
101     static char macro[]	= "_??";
102 #   define slowsig()	(sh.trapnote&SIGSLOW)
103 #else
104     struct edit editb = { 0 };
105 #   define slowsig()	(0)
106 #endif	/* KSHELL */
107 
108 
109 static struct termios savetty;
110 static int savefd = -1;
111 #ifdef future
112 static int compare();
113 #endif
114 #if VSH || ESH
115     static struct termios ttyparm;	/* initial tty parameters */
116     static struct termios nttyparm;	/* raw tty parameters */
117     static char bellchr[] = "\7";	/* bell char */
118 #   define tenex 1
119 #   ifdef tenex
120 	static char *overlay();
121 #   endif /* tenex */
122 #endif /* VSH || ESH */
123 
124 
125 /*
126  * This routine returns true if fd refers to a terminal
127  * This should be equivalent to isatty
128  */
129 
tty_check(fd)130 int tty_check(fd)
131 int fd;
132 {
133 	savefd = -1;
134 	return(tty_get(fd,(struct termios*)0)==0);
135 }
136 
137 /*
138  * Get the current terminal attributes
139  * This routine remembers the attributes and just returns them if it
140  *   is called again without an intervening tty_set()
141  */
142 
tty_get(fd,tty)143 int tty_get(fd, tty)
144 int fd;
145 struct termios *tty;
146 {
147 	if(fd != savefd)
148 	{
149 #ifndef SIG_NORESTART
150 		VOID (*savint)() = st.intfn;
151 		st.intfn = 0;
152 #endif	/* SIG_NORESTART */
153 		while(tcgetattr(fd,&savetty) == SYSERR)
154 		{
155 			if(errno !=EINTR)
156 			{
157 #ifndef SIG_NORESTART
158 				st.intfn = savint;
159 #endif	/* SIG_NORESTART */
160 				return(SYSERR);
161 			}
162 			errno = 0;
163 		}
164 #ifndef SIG_NORESTART
165 		st.intfn = savint;
166 #endif	/* SIG_NORESTART */
167 		savefd = fd;
168 	}
169 	if(tty)
170 		*tty = savetty;
171 	return(0);
172 }
173 
174 /*
175  * Set the terminal attributes
176  * If fd<0, then current attributes are invalidated
177  */
178 
179 /* VARARGS 2 */
tty_set(fd,action,tty)180 int tty_set(fd, action, tty)
181 int fd, action;
182 struct termios *tty;
183 {
184 	if(fd >=0)
185 	{
186 #ifndef SIG_NORESTART
187 		VOID (*savint)() = st.intfn;
188 #endif	/* SIG_NORESTART */
189 #ifdef future
190 		if(savefd>=0 && compare(&savetty,tty,sizeof(struct termios)))
191 			return(0);
192 #endif
193 #ifndef SIG_NORESTART
194 		st.intfn = 0;
195 #endif	/* SIG_NORESTART */
196 		while(tcsetattr(fd, action, tty) == SYSERR)
197 		{
198 			if(errno !=EINTR)
199 			{
200 #ifndef SIG_NORESTART
201 				st.intfn = savint;
202 #endif	/* SIG_NORESTART */
203 				return(SYSERR);
204 			}
205 			errno = 0;
206 		}
207 #ifndef SIG_NORESTART
208 		st.intfn = savint;
209 #endif	/* SIG_NORESTART */
210 		savetty = *tty;
211 	}
212 	savefd = fd;
213 	return(0);
214 }
215 
216 #if ESH || VSH
217 /*{	TTY_COOKED( fd )
218  *
219  *	This routine will set the tty in cooked mode.
220  *	It is also called by error.done().
221  *
222 }*/
223 
tty_cooked(fd)224 void tty_cooked(fd)
225 register int fd;
226 {
227 
228 	if(editb.e_raw==0)
229 		return;
230 	if(fd < 0)
231 		fd = savefd;
232 #ifdef L_MASK
233 	/* restore flags */
234 	if(l_changed&L_MASK)
235 		ioctl(fd,TIOCLSET,&l_mask);
236 	if(l_changed&T_CHARS)
237 		/* restore alternate break character */
238 		ioctl(fd,TIOCSETC,&l_ttychars);
239 	if(l_changed&L_CHARS)
240 		/* restore alternate break character */
241 		ioctl(fd,TIOCSLTC,&l_chars);
242 	l_changed = 0;
243 #endif	/* L_MASK */
244 	/*** don't do tty_set unless ttyparm has valid data ***/
245 	if(savefd<0 || tty_set(fd, TCSANOW, &ttyparm) == SYSERR)
246 		return;
247 	editb.e_raw = 0;
248 	return;
249 }
250 
251 /*{	TTY_RAW( fd )
252  *
253  *	This routine will set the tty in raw mode.
254  *
255 }*/
256 
tty_raw(fd)257 int tty_raw(fd)
258 register int fd;
259 {
260 #ifdef L_MASK
261 	struct ltchars lchars;
262 #endif	/* L_MASK */
263 	if(editb.e_raw==RAWMODE)
264 		return(GOOD);
265 #ifndef RAWONLY
266 	if(editb.e_raw != ALTMODE)
267 #endif /* RAWONLY */
268 	{
269 		if(tty_get(fd,&ttyparm) == SYSERR)
270 			return(BAD);
271 	}
272 #if  L_MASK || VENIX
273 	if(!(ttyparm.sg_flags&ECHO) || (ttyparm.sg_flags&LCASE))
274 		return(BAD);
275 	nttyparm = ttyparm;
276 	nttyparm.sg_flags &= ~(ECHO | TBDELAY);
277 #   ifdef CBREAK
278 	nttyparm.sg_flags |= CBREAK;
279 #   else
280 	nttyparm.sg_flags |= RAW;
281 #   endif /* CBREAK */
282 	editb.e_erase = ttyparm.sg_erase;
283 	editb.e_kill = ttyparm.sg_kill;
284 	editb.e_eof = cntl('D');
285 	if( tty_set(fd, TCSADRAIN, &nttyparm) == SYSERR )
286 		return(BAD);
287 	editb.e_ttyspeed = (ttyparm.sg_ospeed>=B1200?FAST:SLOW);
288 #   ifdef _SELECT5_
289 	    delay = tty_speeds[ttyparm.sg_ospeed];
290 #   endif /* _SELECT5_ */
291 #   ifdef TIOCGLTC
292 	/* try to remove effect of ^V  and ^Y and ^O */
293 	if(ioctl(fd,TIOCGLTC,&l_chars) != SYSERR)
294 	{
295 		lchars = l_chars;
296 		lchars.t_lnextc = -1;
297 		lchars.t_flushc = -1;
298 		lchars.t_dsuspc = -1;	/* no delayed stop process signal */
299 		if(ioctl(fd,TIOCSLTC,&lchars) != SYSERR)
300 			l_changed |= L_CHARS;
301 	}
302 #   endif	/* TIOCGLTC */
303 #else
304 
305 	if (!(ttyparm.c_lflag & ECHO ))
306 		return(BAD);
307 
308 #   ifdef FLUSHO
309 	ttyparm.c_lflag &= ~FLUSHO;
310 #   endif /* FLUSHO */
311 	nttyparm = ttyparm;
312 #  ifndef u370
313 	nttyparm.c_iflag &= ~(IGNPAR|PARMRK|INLCR|IGNCR|ICRNL);
314 	nttyparm.c_iflag |= BRKINT;
315 #   else
316 	nttyparm.c_iflag &=
317 			~(IGNBRK|PARMRK|INLCR|IGNCR|ICRNL|INPCK);
318 	nttyparm.c_iflag |= (BRKINT|IGNPAR);
319 #   endif	/* u370 */
320 	nttyparm.c_lflag &= ~(ICANON|ECHO|ECHOK);
321 	nttyparm.c_cc[VTIME] = 0;
322 	nttyparm.c_cc[VMIN] = 1;
323 #   ifdef VDISCARD
324 	nttyparm.c_cc[VDISCARD] = 0;
325 #   endif /* VDISCARD */
326 #   ifdef VWERASE
327 	nttyparm.c_cc[VWERASE] = 0;
328 #   endif /* VWERASE */
329 #   ifdef VLNEXT
330         nttyparm.c_cc[VLNEXT] = 0;
331 #   endif /* VLNEXT */
332 	editb.e_eof = ttyparm.c_cc[VEOF];
333 	editb.e_erase = ttyparm.c_cc[VERASE];
334 	editb.e_kill = ttyparm.c_cc[VKILL];
335 	if( tty_set(fd, TCSADRAIN, &nttyparm) == SYSERR )
336 		return(BAD);
337 	editb.e_ttyspeed = (cfgetospeed(&ttyparm)>=B1200?FAST:SLOW);
338 #endif
339 	editb.e_raw = RAWMODE;
340 	return(GOOD);
341 }
342 
343 #ifndef RAWONLY
344 
345 /*
346  *
347  *	Get tty parameters and make ESC and '\r' wakeup characters.
348  *
349  */
350 
351 #   ifdef TIOCGETC
tty_alt(fd)352 int tty_alt(fd)
353 register int fd;
354 {
355 	int mask;
356 	struct tchars ttychars;
357 	if(editb.e_raw==ALTMODE)
358 		return(GOOD);
359 	if(editb.e_raw==RAWMODE)
360 		tty_cooked(fd);
361 	l_changed = 0;
362 	if( editb.e_ttyspeed == 0)
363 	{
364 		if((tty_get(fd,&ttyparm) != SYSERR))
365 			editb.e_ttyspeed = (ttyparm.sg_ospeed>=B1200?FAST:SLOW);
366 		editb.e_raw = ALTMODE;
367 	}
368 	if(ioctl(fd,TIOCGETC,&l_ttychars) == SYSERR)
369 		return(BAD);
370 	if(ioctl(fd,TIOCLGET,&l_mask)==SYSERR)
371 		return(BAD);
372 	ttychars = l_ttychars;
373 	mask =  LCRTBS|LCRTERA|LCTLECH|LPENDIN|LCRTKIL;
374 	if((l_mask|mask) != l_mask)
375 		l_changed = L_MASK;
376 	if(ioctl(fd,TIOCLBIS,&mask)==SYSERR)
377 		return(BAD);
378 	if(ttychars.t_brkc!=ESC)
379 	{
380 		ttychars.t_brkc = ESC;
381 		l_changed |= T_CHARS;
382 		if(ioctl(fd,TIOCSETC,&ttychars) == SYSERR)
383 			return(BAD);
384 	}
385 	return(GOOD);
386 }
387 #   else
388 #	ifndef PENDIN
389 #	    define PENDIN	0
390 #	endif /* PENDIN */
391 #	ifndef IEXTEN
392 #	    define IEXTEN	0
393 #	endif /* IEXTEN */
tty_alt(fd)394 int tty_alt(fd)
395 register int fd;
396 {
397 	if(editb.e_raw==ALTMODE)
398 		return(GOOD);
399 	if(editb.e_raw==RAWMODE)
400 		tty_cooked(fd);
401 	if((tty_get(fd, &ttyparm)==SYSERR) || (!(ttyparm.c_lflag&ECHO)))
402 		return(BAD);
403 #	ifdef FLUSHO
404 	    ttyparm.c_lflag &= ~FLUSHO;
405 #	endif /* FLUSHO */
406 	nttyparm = ttyparm;
407 	editb.e_eof = ttyparm.c_cc[VEOF];
408 #	ifdef ECHOCTL
409 	    /* escape character echos as ^[ */
410 	    nttyparm.c_lflag |= (ECHOE|ECHOK|ECHOCTL|PENDIN|IEXTEN);
411 	    nttyparm.c_cc[VEOL2] = ESC;
412 #	else
413 	    /* switch VEOL2 and EOF, since EOF isn't echo'd by driver */
414 	    nttyparm.c_iflag &= ~(IGNCR|ICRNL);
415 	    nttyparm.c_iflag |= INLCR;
416 	    nttyparm.c_lflag |= (ECHOE|ECHOK);
417 	    nttyparm.c_cc[VEOF] = ESC;	/* make ESC the eof char */
418 	    nttyparm.c_cc[VEOL] = '\r';	/* make CR an eol char */
419 	    nttyparm.c_cc[VEOL2] = editb.e_eof;	/* make EOF an eol char */
420 #	endif /* ECHOCTL */
421 #	ifdef VWERASE
422 	    nttyparm.c_cc[VWERASE] = cntl('W');
423 #	endif /* VWERASE */
424 #	ifdef VLNEXT
425 	    nttyparm.c_cc[VLNEXT] = cntl('V');
426 #	endif /* VLNEXT */
427 	editb.e_erase = ttyparm.c_cc[VERASE];
428 	editb.e_kill = ttyparm.c_cc[VKILL];
429 	if( tty_set(fd, TCSADRAIN, &nttyparm) == SYSERR )
430 		return(BAD);
431 	editb.e_ttyspeed = (cfgetospeed(&ttyparm)>=B1200?FAST:SLOW);
432 	editb.e_raw = ALTMODE;
433 	return(GOOD);
434 }
435 
436 #   endif /* TIOCGETC */
437 #endif	/* RAWONLY */
438 
439 /*
440  *	ED_WINDOW()
441  *
442  *	return the window size
443  */
444 
445 #ifdef _sys_stream
446 #   include	<sys/stream.h>
447 #endif /* _sys_stream */
448 #ifdef _sys_ptem
449 #   include	<sys/ptem.h>
450 #endif /* _sys_ptem */
451 #ifdef _sys_jioctl
452 #   include	<sys/jioctl.h>
453 #   define winsize	jwinsize
454 #   define ws_col	bytesx
455 #   ifdef TIOCGWINSZ
456 #	undef TIOCGWINSZ
457 #   endif /* TIOCGWINSZ */
458 #   define TIOCGWINSZ	JWINSIZE
459 #endif /* _sys_jioctl */
460 
ed_window()461 int ed_window()
462 {
463 	register int n = DFLTWINDOW-1;
464 	register char *cp = nam_strval(COLUMNS);
465 	if(cp)
466 	{
467 		n = (int)strtol(cp, (char**)0, 10)-1;
468 		if(n > MAXWINDOW)
469 			n = MAXWINDOW;
470 	}
471 #ifdef TIOCGWINSZ
472 	else
473 	{
474 		/* for 5620's and 630's */
475 		struct winsize size;
476 		if (ioctl(ERRIO, TIOCGWINSZ, &size) != -1)
477 			if(size.ws_col > 0)
478 				n = size.ws_col - 1;
479 	}
480 #endif /*TIOCGWINSZ */
481 	if(n < MINWINDOW)
482 		n = MINWINDOW;
483 	return(n);
484 }
485 
486 /*	E_FLUSH()
487  *
488  *	Flush the output buffer.
489  *
490  */
491 
ed_flush()492 void ed_flush()
493 {
494 	register int n = editb.e_outptr-editb.e_outbase;
495 	register int fd = ERRIO;
496 	if(n<=0)
497 		return;
498 	write(fd,editb.e_outbase,(unsigned)n);
499 	editb.e_outptr = editb.e_outbase;
500 #ifdef _SELECT5_
501 	if(delay && n > delay/100)
502 	{
503 		/* delay until output drains */
504 		struct timeval timeloc;
505 		n *= 10;
506 		timeloc.tv_sec = n/delay;
507 		timeloc.tv_usec = (1000000*(n%delay))/delay;
508 		select(0,(fd_set*)0,(fd_set*)0,(fd_set*)0,&timeloc);
509 	}
510 #else
511 #   ifdef IODELAY
512 	if(editb.e_raw==RAWMODE && n > 16)
513 		tty_set(fd, TCSADRAIN, &nttyparm);
514 #   endif /* IODELAY */
515 #endif /* _SELECT5_ */
516 }
517 
518 /*
519  * send the bell character ^G to the terminal
520  */
521 
ed_ringbell()522 void ed_ringbell()
523 {
524 	write(ERRIO,bellchr,1);
525 }
526 
527 /*
528  * send a carriage return line feed to the terminal
529  */
530 
ed_crlf()531 void ed_crlf()
532 {
533 #ifdef cray
534 	ed_putchar('\r');
535 #endif /* cray */
536 #ifdef u370
537 	ed_putchar('\r');
538 #endif	/* u370 */
539 #ifdef VENIX
540 	ed_putchar('\r');
541 #endif /* VENIX */
542 	ed_putchar('\n');
543 	ed_flush();
544 }
545 
546 /*	E_SETUP( max_prompt_size )
547  *
548  *	This routine sets up the prompt string
549  *	The following is an unadvertised feature.
550  *	  Escape sequences in the prompt can be excluded from the calculated
551  *	  prompt length.  This is accomplished as follows:
552  *	  - if the prompt string starts with "%\r, or contains \r%\r", where %
553  *	    represents any char, then % is taken to be the quote character.
554  *	  - strings enclosed by this quote character, and the quote character,
555  *	    are not counted as part of the prompt length.
556  */
557 
ed_setup(fd)558 void	ed_setup(fd)
559 int fd;
560 {
561 	register char *pp;
562 	register char *last;
563 	char *ppmax;
564 	int myquote = 0;
565 	int qlen = 1;
566 	char inquote = 0;
567 	editb.e_fd = fd;
568 	p_setout(ERRIO);
569 #ifdef KSHELL
570 	last = _sobuf;
571 #else
572 	last = editb.e_prbuff;
573 #endif /* KSHELL */
574 	if(hist_ptr)
575 	{
576 		register struct history *fp = hist_ptr;
577 		editb.e_hismax = fp->fixind;
578 		editb.e_hloff = 0;
579 		editb.e_hismin = fp->fixind-fp->fixmax;
580 		if(editb.e_hismin<0)
581 			editb.e_hismin = 0;
582 	}
583 	else
584 	{
585 		editb.e_hismax = editb.e_hismin = editb.e_hloff = 0;
586 	}
587 	editb.e_hline = editb.e_hismax;
588 	editb.e_wsize = ed_window()-2;
589 	editb.e_crlf = (*last?YES:NO);
590 	pp = editb.e_prompt;
591 	ppmax = pp+PRSIZE-1;
592 	*pp++ = '\r';
593 	{
594 		register int c;
595 		while(c= *last++) switch(c)
596 		{
597 			case '\r':
598 				if(pp == (editb.e_prompt+2)) /* quote char */
599 					myquote = *(pp-1);
600 				/*FALLTHROUGH*/
601 
602 			case '\n':
603 				/* start again */
604 				editb.e_crlf = YES;
605 				qlen = 1;
606 				inquote = 0;
607 				pp = editb.e_prompt+1;
608 				break;
609 
610 			case '\t':
611 				/* expand tabs */
612 				while((pp-editb.e_prompt)%TABSIZE)
613 				{
614 					if(pp >= ppmax)
615 						break;
616 					*pp++ = ' ';
617 				}
618 				break;
619 
620 			case BELL:
621 				/* cut out bells */
622 				break;
623 
624 			default:
625 				if(c==myquote)
626 				{
627 					qlen += inquote;
628 					inquote ^= 1;
629 				}
630 				if(pp < ppmax)
631 				{
632 					qlen += inquote;
633 					*pp++ = c;
634 					if(!inquote && !isprint(c))
635 						editb.e_crlf = NO;
636 				}
637 		}
638 	}
639 	editb.e_plen = pp - editb.e_prompt - qlen;
640 	*pp = 0;
641 	if((editb.e_wsize -= editb.e_plen) < 7)
642 	{
643 		register int shift = 7-editb.e_wsize;
644 		editb.e_wsize = 7;
645 		pp = editb.e_prompt+1;
646 		strcpy(pp,pp+shift);
647 		editb.e_plen -= shift;
648 		last[-editb.e_plen-2] = '\r';
649 	}
650 	p_flush();
651 	editb.e_outptr = _sobuf;
652 	editb.e_outbase = editb.e_outptr;
653 	editb.e_outlast = editb.e_outptr + IOBSIZE-3;
654 }
655 
656 #ifdef KSHELL
657 /*
658  * look for edit macro named _i
659  * if found, puts the macro definition into lookahead buffer and returns 1
660  */
661 
ed_macro(i)662 ed_macro(i)
663 register int i;
664 {
665 	register char *out;
666 	struct namnod *np;
667 	genchar buff[LOOKAHEAD+1];
668 	if(i != '@')
669 		macro[1] = i;
670 	/* undocumented feature, macros of the form <ESC>[c evoke alias __c */
671 	if(i=='_')
672 		macro[2] = ed_getchar();
673 	else
674 		macro[2] = 0;
675 	if (isalnum(i)&&(np=nam_search(macro,sh.alias_tree,N_NOSCOPE))&&(out=nam_strval(np)))
676 	{
677 #ifdef MULTIBYTE
678 		/* copy to buff in internal representation */
679 		int c = out[LOOKAHEAD];
680 		out[LOOKAHEAD] = 0;
681 		i = ed_internal(out,buff);
682 		out[LOOKAHEAD] = c;
683 #else
684 		strncpy((char*)buff,out,LOOKAHEAD);
685 		i = strlen((char*)buff);
686 #endif /* MULTIBYTE */
687 		while(i-- > 0)
688 			ed_ungetchar(buff[i]);
689 		return(1);
690 	}
691 	return(0);
692 }
693 /*
694  * file name generation for edit modes
695  * non-zero exit for error, <0 ring bell
696  * don't search back past beginning of the buffer
697  * mode is '*' for inline expansion,
698  * mode is '\' for filename completion
699  * mode is '=' cause files to be listed in select format
700  */
701 
ed_expand(outbuff,cur,eol,mode)702 ed_expand(outbuff,cur,eol,mode)
703 char outbuff[];
704 int *cur;
705 int *eol;
706 int mode;
707 {
708 	int	offset = staktell();
709 	char	*staksav = stakptr(0);
710 	struct comnod  *comptr = (struct comnod*)stakalloc(sizeof(struct comnod));
711 	struct argnod *ap = (struct argnod*)stakseek(ARGVAL);
712 	register char *out;
713 	char *begin;
714 	int addstar;
715 	int istilde = 0;
716 	int rval = 0;
717 	int strip;
718 	optflag savflags = opt_flags;
719 #ifdef MULTIBYTE
720 	{
721 		register int c = *cur;
722 		register genchar *cp;
723 		/* adjust cur */
724 		cp = (genchar *)outbuff + *cur;
725 		c = *cp;
726 		*cp = 0;
727 		*cur = ed_external((genchar*)outbuff,(char*)stakptr(0));
728 		*cp = c;
729 		*eol = ed_external((genchar*)outbuff,outbuff);
730 	}
731 #endif /* MULTIBYTE */
732 	out = outbuff + *cur;
733 	comptr->comtyp = COMSCAN;
734 	comptr->comarg = ap;
735 	ap->argflag = (A_MAC|A_EXP);
736 	ap->argnxt.ap = 0;
737 	{
738 		register int c;
739 		int chktilde;
740 		char *cp;
741 		if(out>outbuff)
742 		{
743 			/* go to beginning of word */
744 			do
745 			{
746 				out--;
747 				c = *(unsigned char*)out;
748 			}
749 			while(out>outbuff && !isqmeta(c));
750 			/* copy word into arg */
751 			if(isqmeta(c))
752 				out++;
753 		}
754 		else
755 			out = outbuff;
756 		begin = out;
757 		chktilde = (*out=='~');
758 		/* addstar set to zero if * should not be added */
759 		addstar = '*';
760 		strip = 1;
761 		/* copy word to arg and do ~ expansion */
762 		do
763 		{
764 			c = *(unsigned char*)out;
765 			if(isexp(c))
766 				addstar = 0;
767 			if ((c == '/') && (addstar == 0))
768 				strip = 0;
769 			stakputc(c);
770 			if(chktilde && (c==0 || c == '/'))
771 			{
772 				chktilde=0;
773 				*out = 0;
774 				if(cp=sh_tilde(begin))
775 				{
776 					istilde++;
777 					stakseek(ARGVAL);
778 					stakputs(cp);
779 					stakputc(c);
780 					if(c==0)
781 					{
782 						addstar = 0;
783 						strip = 0;
784 					}
785 				}
786 				*out = c;
787 			}
788 			out++;
789 		} while (c && !isqmeta(c));
790 
791 		out--;
792 #ifdef tenex
793 		if(mode=='\\')
794 			addstar = '*';
795 #endif /* tenex */
796 		*stakptr(staktell()-1) = addstar;
797 		stakfreeze(1);
798 	}
799 	if(mode!='*')
800 		on_option(MARKDIR);
801 	{
802 		register char **com;
803 		int	 narg;
804 		register int size;
805 		VOID (*savfn)();
806 		savfn = st.intfn;
807 		com = arg_build(&narg,comptr);
808 		st.intfn = savfn;
809 		/*  match? */
810 		if (*com==0 || (!istilde && narg <= 1 && eq(ap->argval,*com)))
811 		{
812 			rval = -1;
813 			goto done;
814 		}
815 		if(mode=='=')
816 		{
817 			if (strip)
818 			{
819 				register char **ptrcom;
820 				for(ptrcom=com;*ptrcom;ptrcom++)
821 					/* trim directory prefix */
822 					*ptrcom = path_basename(*ptrcom);
823 			}
824 			p_setout(ERRIO);
825 			newline();
826 			p_list(narg,com);
827 			p_flush();
828 			goto done;
829 		}
830 		/* see if there is enough room */
831 		size = *eol - (out-begin);
832 #ifdef tenex
833 		if(mode=='\\')
834 		{
835 			/* just expand until name is unique */
836 			size += strlen(*com);
837 		}
838 		else
839 #endif
840 		{
841 			size += narg;
842 			{
843 				char **savcom = com;
844 				while (*com)
845 					size += strlen(*com++);
846 				com = savcom;
847 			}
848 		}
849 		/* see if room for expansion */
850 		if(outbuff+size >= &outbuff[MAXLINE])
851 		{
852 			com[0] = ap->argval;
853 			com[1] = 0;
854 		}
855 		/* save remainder of the buffer */
856 		strcpy(stakptr(0),out);
857 		out = sh_copy(*com++, begin);
858 #ifdef tenex
859 		if(mode=='\\')
860 		{
861 			if(*com==0 && out[-1]!='/')
862 				*out++ = ' ';
863 			while (*com && *begin)
864 				out = overlay(begin,*com++);
865 			if(*begin==0)
866 				ed_ringbell();
867 		}
868 		else
869 #endif
870 			while (*com)
871 			{
872 				*out++  = ' ';
873 				out = sh_copy(*com++,out);
874 			}
875 		*cur = (out-outbuff);
876 		/* restore rest of buffer */
877 		out = sh_copy(stakptr(0),out);
878 		*eol = (out-outbuff);
879 	}
880  done:
881 	stakset(staksav,offset);
882 	opt_flags = savflags;
883 #ifdef MULTIBYTE
884 	{
885 		register int c;
886 		/* first re-adjust cur */
887 		out = outbuff + *cur;
888 		c = *out;
889 		*out = 0;
890 		*cur = ed_internal(outbuff,(genchar*)stakptr(0));
891 		*out = c;
892 		outbuff[*eol+1] = 0;
893 		*eol = ed_internal(outbuff,(genchar*)outbuff);
894 	}
895 #endif /* MULTIBYTE */
896 	return(rval);
897 }
898 
899 #   ifdef tenex
overlay(str,newstr)900 static char *overlay(str,newstr)
901 register char *str,*newstr;
902 {
903 	while(*str && *str == *newstr++)
904 		str++;
905 	*str = 0;
906 	return(str);
907 }
908 #   endif
909 
910 /*
911  * Enter the fc command on the current history line
912  */
ed_fulledit()913 ed_fulledit()
914 {
915 	register char *cp;
916 	if(!hist_ptr || (st.states&BUILTIN))
917 		return(BAD);
918 	/* use EDITOR on current command */
919 	if(editb.e_hline == editb.e_hismax)
920 	{
921 		if(editb.e_eol<=0)
922 			return(BAD);
923 		editb.e_inbuf[editb.e_eol+1] = 0;
924 		p_setout(hist_ptr->fixfd);
925 		p_str((char*)editb.e_inbuf,0);
926 		st.states |= FIXFLG;
927 		hist_flush();
928 	}
929 	cp = sh_copy(e_runvi, (char*)editb.e_inbuf);
930 	cp = sh_copy(sh_itos(editb.e_hline), cp);
931 	editb.e_eol = (unsigned char*)cp - (unsigned char*)editb.e_inbuf;
932 	return(GOOD);
933 }
934 #endif	/* KSHELL */
935 
936 
937 /*
938  * routine to perform read from terminal for vi and emacs mode
939  */
940 
941 
942 int
ed_getchar()943 ed_getchar()
944 {
945 	register int i;
946 	register int c;
947 	register int maxtry = MAXTRY;
948 	unsigned nchar = READAHEAD; /* number of characters to read at a time */
949 #ifdef MULTIBYTE
950 	static int curchar;
951 	static int cursize;
952 #endif /* MULTIBYTE */
953 	char readin[LOOKAHEAD] ;
954 	if (lookahead)
955 	{
956 		c = previous[--lookahead];
957 		/*** map '\r' to '\n' ***/
958 		if(c == '\r' && !in_raw)
959 			c = '\n';
960 		return(c);
961 	}
962 
963 	ed_flush() ;
964 	/*
965 	 * you can't chance read ahead at the end of line
966 	 * or when the input is a pipe
967 	 */
968 #ifdef KSHELL
969 	if((editb.e_cur>=editb.e_eol) || fnobuff(io_ftable[fildes]))
970 #else
971 	if(editb.e_cur>=editb.e_eol)
972 #endif /* KSHELL */
973 		nchar = 1;
974 	/* Set 'i' to indicate read failed, in case intr set */
975 #ifdef MULTIBYTE
976 retry:
977 #endif /* MULTIBYTE */
978 	i = -1;
979 	errno = 0;
980 	editb.e_inmacro = 0;
981 	while(slowsig()==0 && maxtry--)
982 	{
983 		errno=0;
984 		if ((i = read(fildes,readin, nchar)) != -1)
985 			break;
986 	}
987 #ifdef MULTIBYTE
988 	lookahead = maxtry = i;
989 	i = 0;
990 	while (i < maxtry)
991 	{
992 		c = readin[i++] & STRIP;
993 	next:
994 		if(cursize-- > 0)
995 		{
996 			curchar = (curchar<<7) | (c&~HIGHBIT);
997 			if(cursize==0)
998 			{
999 				c = curchar;
1000 				goto gotit;
1001 			}
1002 			else if(i>=maxtry)
1003 				goto retry;
1004 			continue;
1005 		}
1006 		else if(curchar = echarset(c))
1007 		{
1008 			cursize = in_csize(curchar);
1009 			if(curchar != 1)
1010 				c = 0;
1011 			curchar <<= 7*(ESS_MAXCHAR-cursize);
1012 			if(c)
1013 				goto next;
1014 			else if(i>=maxtry)
1015 				goto retry;
1016 			continue;
1017 		}
1018 	gotit:
1019 		previous[--lookahead] = c;
1020 #else
1021 	while (i > 0)
1022 	{
1023 		c = readin[--i] & STRIP;
1024 		previous[lookahead++] = c;
1025 #endif /* MULTIBYTE */
1026 #ifndef CBREAK
1027 		if( c == '\0' )
1028 		{
1029 			/*** user break key ***/
1030 			lookahead = 0;
1031 # ifdef KSHELL
1032 			sh_fault(SIGINT);
1033 			LONGJMP(env, UINTR);
1034 # endif	/* KSHELL */
1035 		}
1036 #endif	/* !CBREAK */
1037 	}
1038 #ifdef MULTIBYTE
1039 	/* shift lookahead buffer if necessary */
1040 	if(lookahead)
1041 	{
1042 		for(i=lookahead;i < maxtry;i++)
1043 			previous[i-lookahead] = previous[i];
1044 	}
1045 	lookahead = maxtry-lookahead;
1046 #endif /* MULTIBYTE */
1047 	if (lookahead > 0)
1048 		return(ed_getchar());
1049 	LONGJMP(env,(i==0?UEOF:UINTR)); /* What a mess! Give up */
1050 	return(0);
1051 	/* NOTREACHED */
1052 }
1053 
1054 void ed_ungetchar(c)
1055 register int c;
1056 {
1057 	if (lookahead < LOOKAHEAD)
1058 		previous[lookahead++] = c;
1059 	return;
1060 }
1061 
1062 /*
1063  * put a character into the output buffer
1064  */
1065 
1066 void	ed_putchar(c)
1067 register int c;
1068 {
1069 	register char *dp = editb.e_outptr;
1070 #ifdef MULTIBYTE
1071 	register int d;
1072 	/* check for place holder */
1073 	if(c == MARKER)
1074 		return;
1075 	if(d = icharset(c))
1076 	{
1077 		if(d == 2)
1078 			*dp++ = ESS2;
1079 		else if(d == 3)
1080 			*dp++ = ESS3;
1081 		d = in_csize(d);
1082 		while(--d>0)
1083 			*dp++ = HIGHBIT|(c>>(7*d));
1084 		c |= HIGHBIT;
1085 	}
1086 #endif	/* MULTIBYTE */
1087 	if (c == '_')
1088 	{
1089 		*dp++ = ' ';
1090 		*dp++ = '\b';
1091 	}
1092 	*dp++ = c;
1093 	*dp = '\0';
1094 	if(dp >= editb.e_outlast)
1095 		ed_flush();
1096 	else
1097 		editb.e_outptr = dp;
1098 }
1099 
1100 /*
1101  * copy virtual to physical and return the index for cursor in physical buffer
1102  */
1103 int ed_virt_to_phys(virt,phys,cur,voff,poff)
1104 genchar *virt;
1105 genchar *phys;
1106 int cur, voff, poff;
1107 {
1108 	register genchar *sp = virt;
1109 	register genchar *dp = phys;
1110 	register int c;
1111 	genchar *curp = sp + cur;
1112 	genchar *dpmax = phys+MAXLINE;
1113 	int r;
1114 #ifdef MULTIBYTE
1115 	int d;
1116 #endif /* MULTIBYTE */
1117 	sp += voff;
1118 	dp += poff;
1119 	for(r=poff;c= *sp;sp++)
1120 	{
1121 		if(curp == sp)
1122 			r = dp - phys;
1123 #ifdef MULTIBYTE
1124 		d = out_csize(icharset(c));
1125 		if(d>1)
1126 		{
1127 			/* multiple width character put in place holders */
1128 			*dp++ = c;
1129 			while(--d >0)
1130 				*dp++ = MARKER;
1131 			/* in vi mode the cursor is at the last character */
1132 			if(dp>=dpmax)
1133 				break;
1134 			continue;
1135 		}
1136 		else
1137 #endif	/* MULTIBYTE */
1138 		if(!isprint(c))
1139 		{
1140 			if(c=='\t')
1141 			{
1142 				c = dp-phys;
1143 				if(is_option(EDITVI))
1144 					c += editb.e_plen;
1145 				c = TABSIZE - c%TABSIZE;
1146 				while(--c>0)
1147 					*dp++ = ' ';
1148 				c = ' ';
1149 			}
1150 			else
1151 			{
1152 				*dp++ = '^';
1153 				c ^= TO_PRINT;
1154 			}
1155 			/* in vi mode the cursor is at the last character */
1156 			if(curp == sp && is_option(EDITVI))
1157 				r = dp - phys;
1158 		}
1159 		*dp++ = c;
1160 		if(dp>=dpmax)
1161 			break;
1162 	}
1163 	*dp = 0;
1164 	return(r);
1165 }
1166 
1167 #ifdef MULTIBYTE
1168 /*
1169  * convert external representation <src> to an array of genchars <dest>
1170  * <src> and <dest> can be the same
1171  * returns number of chars in dest
1172  */
1173 
1174 int	ed_internal(src,dest)
1175 register unsigned char *src;
1176 genchar *dest;
1177 {
1178 	register int c;
1179 	register genchar *dp = dest;
1180 	register int d;
1181 	register int size;
1182 	if((unsigned char*)dest == src)
1183 	{
1184 		genchar buffer[MAXLINE];
1185 		c = ed_internal(src,buffer);
1186 		ed_gencpy(dp,buffer);
1187 		return(c);
1188 	}
1189 	while(c = *src++)
1190 	{
1191 		if(size = echarset(c))
1192 		{
1193 			d = (size==1?c:0);
1194 			c = size;
1195 			size = in_csize(c);
1196 			c <<= 7*(ESS_MAXCHAR-size);
1197 			if(d)
1198 			{
1199 				size--;
1200 				c = (c<<7) | (d&~HIGHBIT);
1201 			}
1202 			while(size-- >0)
1203 				c = (c<<7) | ((*src++)&~HIGHBIT);
1204 		}
1205 		*dp++ = c;
1206 	}
1207 	*dp = 0;
1208 	return(dp-dest);
1209 }
1210 
1211 /*
1212  * convert internal representation <src> into character array <dest>.
1213  * The <src> and <dest> may be the same.
1214  * returns number of chars in dest.
1215  */
1216 
1217 int	ed_external(src,dest)
1218 genchar *src;
1219 char *dest;
1220 {
1221 	register int c;
1222 	register char *dp = dest;
1223 	register int d;
1224 	char *dpmax = dp+sizeof(genchar)*MAXLINE-2;
1225 	if((char*)src == dp)
1226 	{
1227 		char buffer[MAXLINE*sizeof(genchar)];
1228 		c = ed_external(src,buffer);
1229 		strcpy(dest,buffer);
1230 		return(c);
1231 	}
1232 	while((c = *src++) && dp<dpmax)
1233 	{
1234 		if(d = icharset(c))
1235 		{
1236 			if(d == 2)
1237 				*dp++ = ESS2;
1238 			else if(d == 3)
1239 				*dp++ = ESS3;
1240 			d = in_csize(d);
1241 			while(--d>0)
1242 				*dp++ = HIGHBIT|(c>>(7*d));
1243 			c |= HIGHBIT;
1244 		}
1245 		*dp++ = c;
1246 	}
1247 	*dp = 0;
1248 	return(dp-dest);
1249 }
1250 
1251 /*
1252  * copy <sp> to <dp>
1253  */
1254 
1255 int	ed_gencpy(dp,sp)
1256 register genchar *dp;
1257 register genchar *sp;
1258 {
1259 	while(*dp++ = *sp++);
1260 }
1261 
1262 /*
1263  * copy at most <n> items from <sp> to <dp>
1264  */
1265 
1266 int	ed_genncpy(dp,sp, n)
1267 register genchar *dp;
1268 register genchar *sp;
1269 register int n;
1270 {
1271 	while(n-->0 && (*dp++ = *sp++));
1272 }
1273 
1274 /*
1275  * find the string length of <str>
1276  */
1277 
1278 int	ed_genlen(str)
1279 register genchar *str;
1280 {
1281 	register genchar *sp = str;
1282 	while(*sp++);
1283 	return(sp-str-1);
1284 }
1285 #endif /* MULTIBYTE */
1286 #endif /* ESH || VSH */
1287 
1288 #ifdef MULTIBYTE
1289 /*
1290  * set the multibyte widths
1291  * format of string is x1[:y1][,x2[:y2][,x3[:y3]]]
1292  * returns 1 if string in not in this format, 0 otherwise.
1293  */
1294 
1295 extern char int_charsize[];
1296 ed_setwidth(string)
1297 char *string;
1298 {
1299 	register int indx = 0;
1300 	register int state = 0;
1301 	register int c;
1302 	register int n = 0;
1303 	static char widths[6] = {1,1};
1304 	while(1) switch(c = *string++)
1305 	{
1306 		case ':':
1307 			if(state!=1)
1308 				return(1);
1309 			state++;
1310 			/* fall through */
1311 
1312 		case 0:
1313 		case ',':
1314 			if(state==0)
1315 				return(1);
1316 			widths[indx++] = n;
1317 			if(state==1)
1318 				widths[indx++] = n;
1319 			if(c==0)
1320 			{
1321 				for(n=1;n<= 3;n++)
1322 				{
1323 					int_charsize[n] = widths[c++];
1324 					int_charsize[n+4] = widths[c++];
1325 				}
1326 				return(0);
1327 			}
1328 			else if(c==',')
1329 				state = 0;
1330 			n = 0;
1331 			break;
1332 
1333 		case '0': case '1': case '2': case '3': case '4':
1334 			if(state&1)
1335 				return(1);
1336 			n = c - '0';
1337 			state++;
1338 			break;
1339 
1340 		default:
1341 			return(1);
1342 	}
1343 	/* NOTREACHED */
1344 }
1345 #endif /* MULTIBYTE */
1346 
1347 #ifdef future
1348 /*
1349  * returns 1 when <n> bytes starting at <a> and <b> are equal
1350  */
1351 static int compare(a,b,n)
1352 register char *a;
1353 register char *b;
1354 register int n;
1355 {
1356 	while(n-->0)
1357 	{
1358 		if(*a++ != *b++)
1359 			return(0);
1360 	}
1361 	return(1);
1362 }
1363 #endif
1364 
1365 #ifdef OLDTERMIO
1366 
1367 #   include	<sys/termio.h>
1368 
1369 #ifndef ECHOCTL
1370 #   define ECHOCTL	0
1371 #endif /* !ECHOCTL */
1372 char echoctl;
1373 static char tcgeta;
1374 static struct termio ott;
1375 
1376 /*
1377  * For backward compatibility only
1378  * This version will use termios when possible, otherwise termio
1379  */
1380 
1381 
1382 tcgetattr(fd,tt)
1383 struct termios *tt;
1384 {
1385 	register int r;
1386 	register int i;
1387 	tcgeta = 0;
1388 	echoctl = (ECHOCTL!=0);
1389 	if((r=ioctl(fd,TCGETS,tt))>=0 ||  errno!=EINVAL)
1390 		return(r);
1391 	if((r=ioctl(fd,TCGETA,&ott)) >= 0)
1392 	{
1393 		tt->c_lflag = ott.c_lflag;
1394 		tt->c_oflag = ott.c_oflag;
1395 		tt->c_iflag = ott.c_iflag;
1396 		tt->c_cflag = ott.c_cflag;
1397 		for(i=0; i<NCC; i++)
1398 			tt->c_cc[i] = ott.c_cc[i];
1399 		tcgeta++;
1400 		echoctl = 0;
1401 	}
1402 	return(r);
1403 }
1404 
1405 tcsetattr(fd,mode,tt)
1406 register int mode;
1407 struct termios *tt;
1408 {
1409 	register int r;
1410 	if(tcgeta)
1411 	{
1412 		register int i;
1413 		ott.c_lflag = tt->c_lflag;
1414 		ott.c_oflag = tt->c_oflag;
1415 		ott.c_iflag = tt->c_iflag;
1416 		ott.c_cflag = tt->c_cflag;
1417 		for(i=0; i<NCC; i++)
1418 			ott.c_cc[i] = tt->c_cc[i];
1419 		if(tt->c_lflag&ECHOCTL)
1420 		{
1421 			ott.c_lflag &= ~(ECHOCTL|IEXTEN);
1422 			ott.c_iflag &= ~(IGNCR|ICRNL);
1423 			ott.c_iflag |= INLCR;
1424 			ott.c_cc[VEOF]= ESC;  /* ESC -> eof char */
1425 			ott.c_cc[VEOL] = '\r'; /* CR -> eol char */
1426 			ott.c_cc[VEOL2] = tt->c_cc[VEOF]; /* EOF -> eol char */
1427 		}
1428 		switch(mode)
1429 		{
1430 			case TCSANOW:
1431 				mode = TCSETA;
1432 				break;
1433 			case TCSADRAIN:
1434 				mode = TCSETAW;
1435 				break;
1436 			case TCSAFLUSH:
1437 				mode = TCSETAF;
1438 		}
1439 		return(ioctl(fd,mode,&ott));
1440 	}
1441 	return(ioctl(fd,mode,tt));
1442 }
1443 #endif /* OLDTERMIO */
1444