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