14887Schin /***********************************************************************
24887Schin * *
34887Schin * This software is part of the ast package *
4*12068SRoger.Faulkner@Oracle.COM * Copyright (c) 1982-2010 AT&T Intellectual Property *
54887Schin * and is licensed under the *
64887Schin * Common Public License, Version 1.0 *
78462SApril.Chin@Sun.COM * by AT&T Intellectual Property *
84887Schin * *
94887Schin * A copy of the License is available at *
104887Schin * http://www.opensource.org/licenses/cpl1.0.txt *
114887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
124887Schin * *
134887Schin * Information and Software Systems Research *
144887Schin * AT&T Research *
154887Schin * Florham Park NJ *
164887Schin * *
174887Schin * David Korn <dgk@research.att.com> *
184887Schin * *
194887Schin ***********************************************************************/
204887Schin #pragma prototyped
214887Schin /*
224887Schin * edit.c - common routines for vi and emacs one line editors in shell
234887Schin *
244887Schin * David Korn P.D. Sullivan
254887Schin * AT&T Labs
264887Schin *
274887Schin * Coded April 1983.
284887Schin */
294887Schin
304887Schin #include <ast.h>
314887Schin #include <errno.h>
324887Schin #include <ccode.h>
334887Schin #include "FEATURE/options"
344887Schin #include "FEATURE/time"
354887Schin #include "FEATURE/cmds"
364887Schin #ifdef _hdr_utime
374887Schin # include <utime.h>
384887Schin # include <ls.h>
394887Schin #endif
404887Schin
414887Schin #if KSHELL
424887Schin # include "defs.h"
434887Schin # include "variables.h"
444887Schin #else
4510898Sroland.mainz@nrubsig.org # include <ctype.h>
464887Schin extern char ed_errbuf[];
474887Schin char e_version[] = "\n@(#)$Id: Editlib version 1993-12-28 r $\0\n";
484887Schin #endif /* KSHELL */
494887Schin #include "io.h"
504887Schin #include "terminal.h"
514887Schin #include "history.h"
524887Schin #include "edit.h"
534887Schin
544887Schin static char CURSOR_UP[20] = { ESC, '[', 'A', 0 };
554887Schin
568462SApril.Chin@Sun.COM
578462SApril.Chin@Sun.COM
584887Schin #if SHOPT_MULTIBYTE
594887Schin # define is_cntrl(c) ((c<=STRIP) && iscntrl(c))
604887Schin # define is_print(c) ((c&~STRIP) || isprint(c))
614887Schin #else
624887Schin # define is_cntrl(c) iscntrl(c)
634887Schin # define is_print(c) isprint(c)
644887Schin #endif
654887Schin
664887Schin #if (CC_NATIVE == CC_ASCII)
674887Schin # define printchar(c) ((c) ^ ('A'-cntl('A')))
684887Schin #else
printchar(int c)694887Schin static int printchar(int c)
704887Schin {
714887Schin switch(c)
724887Schin {
734887Schin
744887Schin case cntl('A'): return('A');
754887Schin case cntl('B'): return('B');
764887Schin case cntl('C'): return('C');
774887Schin case cntl('D'): return('D');
784887Schin case cntl('E'): return('E');
794887Schin case cntl('F'): return('F');
804887Schin case cntl('G'): return('G');
814887Schin case cntl('H'): return('H');
824887Schin case cntl('I'): return('I');
834887Schin case cntl('J'): return('J');
844887Schin case cntl('K'): return('K');
854887Schin case cntl('L'): return('L');
864887Schin case cntl('M'): return('M');
874887Schin case cntl('N'): return('N');
884887Schin case cntl('O'): return('O');
894887Schin case cntl('P'): return('P');
904887Schin case cntl('Q'): return('Q');
914887Schin case cntl('R'): return('R');
924887Schin case cntl('S'): return('S');
934887Schin case cntl('T'): return('T');
944887Schin case cntl('U'): return('U');
954887Schin case cntl('V'): return('V');
964887Schin case cntl('W'): return('W');
974887Schin case cntl('X'): return('X');
984887Schin case cntl('Y'): return('Y');
994887Schin case cntl('Z'): return('Z');
1004887Schin case cntl(']'): return(']');
1014887Schin case cntl('['): return('[');
1024887Schin }
1034887Schin return('?');
1044887Schin }
1054887Schin #endif
1064887Schin #define MINWINDOW 15 /* minimum width window */
1074887Schin #define DFLTWINDOW 80 /* default window width */
1084887Schin #define RAWMODE 1
1094887Schin #define ALTMODE 2
1104887Schin #define ECHOMODE 3
1114887Schin #define SYSERR -1
1124887Schin
1134887Schin #if SHOPT_OLDTERMIO
1144887Schin # undef tcgetattr
1154887Schin # undef tcsetattr
1164887Schin #endif /* SHOPT_OLDTERMIO */
1174887Schin
1184887Schin #ifdef RT
1194887Schin # define VENIX 1
1204887Schin #endif /* RT */
1214887Schin
1224887Schin
1234887Schin #ifdef _hdr_sgtty
1244887Schin # ifdef TIOCGETP
1254887Schin static int l_mask;
1264887Schin static struct tchars l_ttychars;
1274887Schin static struct ltchars l_chars;
1284887Schin static char l_changed; /* set if mode bits changed */
1294887Schin # define L_CHARS 4
1304887Schin # define T_CHARS 2
1314887Schin # define L_MASK 1
1324887Schin # endif /* TIOCGETP */
1334887Schin #endif /* _hdr_sgtty */
1344887Schin
1354887Schin #if KSHELL
1364887Schin static int keytrap(Edit_t *,char*, int, int, int);
1374887Schin #else
1384887Schin Edit_t editb;
1394887Schin #endif /* KSHELL */
1404887Schin
1414887Schin
1424887Schin #ifndef _POSIX_DISABLE
1434887Schin # define _POSIX_DISABLE 0
1444887Schin #endif
1454887Schin
1464887Schin #ifdef future
1474887Schin static int compare(const char*, const char*, int);
1484887Schin #endif /* future */
1494887Schin #if SHOPT_VSH || SHOPT_ESH
1504887Schin # define ttyparm (ep->e_ttyparm)
1514887Schin # define nttyparm (ep->e_nttyparm)
1524887Schin static const char bellchr[] = "\a"; /* bell char */
1534887Schin #endif /* SHOPT_VSH || SHOPT_ESH */
1544887Schin
1554887Schin
1564887Schin /*
1574887Schin * This routine returns true if fd refers to a terminal
1584887Schin * This should be equivalent to isatty
1594887Schin */
tty_check(int fd)1604887Schin int tty_check(int fd)
1614887Schin {
1624887Schin register Edit_t *ep = (Edit_t*)(sh_getinterp()->ed_context);
1634887Schin struct termios tty;
1644887Schin ep->e_savefd = -1;
1654887Schin return(tty_get(fd,&tty)==0);
1664887Schin }
1674887Schin
1684887Schin /*
1694887Schin * Get the current terminal attributes
1704887Schin * This routine remembers the attributes and just returns them if it
1714887Schin * is called again without an intervening tty_set()
1724887Schin */
1734887Schin
tty_get(register int fd,register struct termios * tty)1744887Schin int tty_get(register int fd, register struct termios *tty)
1754887Schin {
1764887Schin register Edit_t *ep = (Edit_t*)(sh_getinterp()->ed_context);
1774887Schin if(fd == ep->e_savefd)
1784887Schin *tty = ep->e_savetty;
1794887Schin else
1804887Schin {
1814887Schin while(tcgetattr(fd,tty) == SYSERR)
1824887Schin {
1834887Schin if(errno !=EINTR)
1844887Schin return(SYSERR);
1854887Schin errno = 0;
1864887Schin }
1874887Schin /* save terminal settings if in cannonical state */
1884887Schin if(ep->e_raw==0)
1894887Schin {
1904887Schin ep->e_savetty = *tty;
1914887Schin ep->e_savefd = fd;
1924887Schin }
1934887Schin }
1944887Schin return(0);
1954887Schin }
1964887Schin
1974887Schin /*
1984887Schin * Set the terminal attributes
1994887Schin * If fd<0, then current attributes are invalidated
2004887Schin */
2014887Schin
tty_set(int fd,int action,struct termios * tty)2024887Schin int tty_set(int fd, int action, struct termios *tty)
2034887Schin {
2044887Schin register Edit_t *ep = (Edit_t*)(sh_getinterp()->ed_context);
2054887Schin if(fd >=0)
2064887Schin {
2074887Schin #ifdef future
2084887Schin if(ep->e_savefd>=0 && compare(&ep->e_savetty,tty,sizeof(struct termios)))
2094887Schin return(0);
2104887Schin #endif
2114887Schin while(tcsetattr(fd, action, tty) == SYSERR)
2124887Schin {
2134887Schin if(errno !=EINTR)
2144887Schin return(SYSERR);
2154887Schin errno = 0;
2164887Schin }
2174887Schin ep->e_savetty = *tty;
2184887Schin }
2194887Schin ep->e_savefd = fd;
2204887Schin return(0);
2214887Schin }
2224887Schin
2234887Schin #if SHOPT_ESH || SHOPT_VSH
2244887Schin /*{ TTY_COOKED( fd )
2254887Schin *
2264887Schin * This routine will set the tty in cooked mode.
2274887Schin * It is also called by error.done().
2284887Schin *
2294887Schin }*/
2304887Schin
tty_cooked(register int fd)2314887Schin void tty_cooked(register int fd)
2324887Schin {
2334887Schin register Edit_t *ep = (Edit_t*)(sh_getinterp()->ed_context);
2344887Schin if(ep->e_raw==0)
2354887Schin return;
2364887Schin if(fd < 0)
2374887Schin fd = ep->e_savefd;
2384887Schin #ifdef L_MASK
2394887Schin /* restore flags */
2404887Schin if(l_changed&L_MASK)
2414887Schin ioctl(fd,TIOCLSET,&l_mask);
2424887Schin if(l_changed&T_CHARS)
2434887Schin /* restore alternate break character */
2444887Schin ioctl(fd,TIOCSETC,&l_ttychars);
2454887Schin if(l_changed&L_CHARS)
2464887Schin /* restore alternate break character */
2474887Schin ioctl(fd,TIOCSLTC,&l_chars);
2484887Schin l_changed = 0;
2494887Schin #endif /* L_MASK */
2504887Schin /*** don't do tty_set unless ttyparm has valid data ***/
2514887Schin if(tty_set(fd, TCSANOW, &ttyparm) == SYSERR)
2524887Schin return;
2534887Schin ep->e_raw = 0;
2544887Schin return;
2554887Schin }
2564887Schin
2574887Schin /*{ TTY_RAW( fd )
2584887Schin *
2594887Schin * This routine will set the tty in raw mode.
2604887Schin *
2614887Schin }*/
2624887Schin
tty_raw(register int fd,int echomode)2634887Schin int tty_raw(register int fd, int echomode)
2644887Schin {
2654887Schin int echo = echomode;
2664887Schin #ifdef L_MASK
2674887Schin struct ltchars lchars;
2684887Schin #endif /* L_MASK */
2694887Schin register Edit_t *ep = (Edit_t*)(sh_getinterp()->ed_context);
2704887Schin if(ep->e_raw==RAWMODE)
2714887Schin return(echo?-1:0);
2724887Schin else if(ep->e_raw==ECHOMODE)
2734887Schin return(echo?0:-1);
2744887Schin #if !SHOPT_RAWONLY
2754887Schin if(ep->e_raw != ALTMODE)
2764887Schin #endif /* SHOPT_RAWONLY */
2774887Schin {
2784887Schin if(tty_get(fd,&ttyparm) == SYSERR)
2794887Schin return(-1);
2804887Schin }
2814887Schin #if L_MASK || VENIX
2824887Schin if(ttyparm.sg_flags&LCASE)
2834887Schin return(-1);
2844887Schin if(!(ttyparm.sg_flags&ECHO))
2854887Schin {
2864887Schin if(!echomode)
2874887Schin return(-1);
2884887Schin echo = 0;
2894887Schin }
2904887Schin nttyparm = ttyparm;
2914887Schin if(!echo)
2924887Schin nttyparm.sg_flags &= ~(ECHO | TBDELAY);
2934887Schin # ifdef CBREAK
2944887Schin nttyparm.sg_flags |= CBREAK;
2954887Schin # else
2964887Schin nttyparm.sg_flags |= RAW;
2974887Schin # endif /* CBREAK */
2984887Schin ep->e_erase = ttyparm.sg_erase;
2994887Schin ep->e_kill = ttyparm.sg_kill;
3004887Schin ep->e_eof = cntl('D');
3014887Schin ep->e_werase = cntl('W');
3024887Schin ep->e_lnext = cntl('V');
3034887Schin if( tty_set(fd, TCSADRAIN, &nttyparm) == SYSERR )
3044887Schin return(-1);
3054887Schin ep->e_ttyspeed = (ttyparm.sg_ospeed>=B1200?FAST:SLOW);
3064887Schin # ifdef TIOCGLTC
3074887Schin /* try to remove effect of ^V and ^Y and ^O */
3084887Schin if(ioctl(fd,TIOCGLTC,&l_chars) != SYSERR)
3094887Schin {
3104887Schin lchars = l_chars;
3114887Schin lchars.t_lnextc = -1;
3124887Schin lchars.t_flushc = -1;
3134887Schin lchars.t_dsuspc = -1; /* no delayed stop process signal */
3144887Schin if(ioctl(fd,TIOCSLTC,&lchars) != SYSERR)
3154887Schin l_changed |= L_CHARS;
3164887Schin }
3174887Schin # endif /* TIOCGLTC */
3184887Schin #else
3194887Schin if (!(ttyparm.c_lflag & ECHO ))
3204887Schin {
3214887Schin if(!echomode)
3224887Schin return(-1);
3234887Schin echo = 0;
3244887Schin }
3254887Schin # ifdef FLUSHO
3264887Schin ttyparm.c_lflag &= ~FLUSHO;
3274887Schin # endif /* FLUSHO */
3284887Schin nttyparm = ttyparm;
3294887Schin # ifndef u370
3304887Schin nttyparm.c_iflag &= ~(IGNPAR|PARMRK|INLCR|IGNCR|ICRNL);
3314887Schin nttyparm.c_iflag |= BRKINT;
3324887Schin # else
3334887Schin nttyparm.c_iflag &=
3344887Schin ~(IGNBRK|PARMRK|INLCR|IGNCR|ICRNL|INPCK);
3354887Schin nttyparm.c_iflag |= (BRKINT|IGNPAR);
3364887Schin # endif /* u370 */
3374887Schin if(echo)
3384887Schin nttyparm.c_lflag &= ~ICANON;
3394887Schin else
3404887Schin nttyparm.c_lflag &= ~(ICANON|ECHO|ECHOK);
3414887Schin nttyparm.c_cc[VTIME] = 0;
3424887Schin nttyparm.c_cc[VMIN] = 1;
3434887Schin # ifdef VREPRINT
3444887Schin nttyparm.c_cc[VREPRINT] = _POSIX_DISABLE;
3454887Schin # endif /* VREPRINT */
3464887Schin # ifdef VDISCARD
3474887Schin nttyparm.c_cc[VDISCARD] = _POSIX_DISABLE;
3484887Schin # endif /* VDISCARD */
3494887Schin # ifdef VDSUSP
3504887Schin nttyparm.c_cc[VDSUSP] = _POSIX_DISABLE;
3514887Schin # endif /* VDSUSP */
3524887Schin # ifdef VWERASE
3534887Schin if(ttyparm.c_cc[VWERASE] == _POSIX_DISABLE)
3544887Schin ep->e_werase = cntl('W');
3554887Schin else
3564887Schin ep->e_werase = nttyparm.c_cc[VWERASE];
3574887Schin nttyparm.c_cc[VWERASE] = _POSIX_DISABLE;
3584887Schin # else
3594887Schin ep->e_werase = cntl('W');
3604887Schin # endif /* VWERASE */
3614887Schin # ifdef VLNEXT
3624887Schin if(ttyparm.c_cc[VLNEXT] == _POSIX_DISABLE )
3634887Schin ep->e_lnext = cntl('V');
3644887Schin else
3654887Schin ep->e_lnext = nttyparm.c_cc[VLNEXT];
3664887Schin nttyparm.c_cc[VLNEXT] = _POSIX_DISABLE;
3674887Schin # else
3684887Schin ep->e_lnext = cntl('V');
3694887Schin # endif /* VLNEXT */
3704887Schin ep->e_eof = ttyparm.c_cc[VEOF];
3714887Schin ep->e_erase = ttyparm.c_cc[VERASE];
3724887Schin ep->e_kill = ttyparm.c_cc[VKILL];
3734887Schin if( tty_set(fd, TCSADRAIN, &nttyparm) == SYSERR )
3744887Schin return(-1);
3754887Schin ep->e_ttyspeed = (cfgetospeed(&ttyparm)>=B1200?FAST:SLOW);
3764887Schin #endif
3774887Schin ep->e_raw = (echomode?ECHOMODE:RAWMODE);
3784887Schin return(0);
3794887Schin }
3804887Schin
3814887Schin #if !SHOPT_RAWONLY
3824887Schin
3834887Schin /*
3844887Schin *
3854887Schin * Get tty parameters and make ESC and '\r' wakeup characters.
3864887Schin *
3874887Schin */
3884887Schin
3894887Schin # ifdef TIOCGETC
tty_alt(register int fd)3904887Schin int tty_alt(register int fd)
3914887Schin {
3924887Schin register Edit_t *ep = (Edit_t*)(sh_getinterp()->ed_context);
3934887Schin int mask;
3944887Schin struct tchars ttychars;
3954887Schin switch(ep->e_raw)
3964887Schin {
3974887Schin case ECHOMODE:
3984887Schin return(-1);
3994887Schin case ALTMODE:
4004887Schin return(0);
4014887Schin case RAWMODE:
4024887Schin tty_cooked(fd);
4034887Schin }
4044887Schin l_changed = 0;
4054887Schin if( ep->e_ttyspeed == 0)
4064887Schin {
4074887Schin if((tty_get(fd,&ttyparm) != SYSERR))
4084887Schin ep->e_ttyspeed = (ttyparm.sg_ospeed>=B1200?FAST:SLOW);
4094887Schin ep->e_raw = ALTMODE;
4104887Schin }
4114887Schin if(ioctl(fd,TIOCGETC,&l_ttychars) == SYSERR)
4124887Schin return(-1);
4134887Schin if(ioctl(fd,TIOCLGET,&l_mask)==SYSERR)
4144887Schin return(-1);
4154887Schin ttychars = l_ttychars;
4164887Schin mask = LCRTBS|LCRTERA|LCTLECH|LPENDIN|LCRTKIL;
4174887Schin if((l_mask|mask) != l_mask)
4184887Schin l_changed = L_MASK;
4194887Schin if(ioctl(fd,TIOCLBIS,&mask)==SYSERR)
4204887Schin return(-1);
4214887Schin if(ttychars.t_brkc!=ESC)
4224887Schin {
4234887Schin ttychars.t_brkc = ESC;
4244887Schin l_changed |= T_CHARS;
4254887Schin if(ioctl(fd,TIOCSETC,&ttychars) == SYSERR)
4264887Schin return(-1);
4274887Schin }
4284887Schin return(0);
4294887Schin }
4304887Schin # else
4314887Schin # ifndef PENDIN
4324887Schin # define PENDIN 0
4334887Schin # endif /* PENDIN */
4344887Schin # ifndef IEXTEN
4354887Schin # define IEXTEN 0
4364887Schin # endif /* IEXTEN */
4374887Schin
tty_alt(register int fd)4384887Schin int tty_alt(register int fd)
4394887Schin {
4404887Schin register Edit_t *ep = (Edit_t*)(sh_getinterp()->ed_context);
4414887Schin switch(ep->e_raw)
4424887Schin {
4434887Schin case ECHOMODE:
4444887Schin return(-1);
4454887Schin case ALTMODE:
4464887Schin return(0);
4474887Schin case RAWMODE:
4484887Schin tty_cooked(fd);
4494887Schin }
4504887Schin if((tty_get(fd, &ttyparm)==SYSERR) || (!(ttyparm.c_lflag&ECHO)))
4514887Schin return(-1);
4524887Schin # ifdef FLUSHO
4534887Schin ttyparm.c_lflag &= ~FLUSHO;
4544887Schin # endif /* FLUSHO */
4554887Schin nttyparm = ttyparm;
4564887Schin ep->e_eof = ttyparm.c_cc[VEOF];
4574887Schin # ifdef ECHOCTL
4584887Schin /* escape character echos as ^[ */
4594887Schin nttyparm.c_lflag |= (ECHOE|ECHOK|ECHOCTL|PENDIN|IEXTEN);
4604887Schin nttyparm.c_cc[VEOL] = ESC;
4614887Schin # else
4624887Schin /* switch VEOL2 and EOF, since EOF isn't echo'd by driver */
4634887Schin nttyparm.c_lflag |= (ECHOE|ECHOK);
4644887Schin nttyparm.c_cc[VEOF] = ESC; /* make ESC the eof char */
4654887Schin # ifdef VEOL2
4664887Schin nttyparm.c_iflag &= ~(IGNCR|ICRNL);
4674887Schin nttyparm.c_iflag |= INLCR;
4684887Schin nttyparm.c_cc[VEOL] = '\r'; /* make CR an eol char */
4694887Schin nttyparm.c_cc[VEOL2] = ep->e_eof; /* make EOF an eol char */
4704887Schin # else
4714887Schin nttyparm.c_cc[VEOL] = ep->e_eof; /* make EOF an eol char */
4724887Schin # endif /* VEOL2 */
4734887Schin # endif /* ECHOCTL */
4744887Schin # ifdef VREPRINT
4754887Schin nttyparm.c_cc[VREPRINT] = _POSIX_DISABLE;
4764887Schin # endif /* VREPRINT */
4774887Schin # ifdef VDISCARD
4784887Schin nttyparm.c_cc[VDISCARD] = _POSIX_DISABLE;
4794887Schin # endif /* VDISCARD */
4804887Schin # ifdef VWERASE
4814887Schin if(ttyparm.c_cc[VWERASE] == _POSIX_DISABLE)
4824887Schin nttyparm.c_cc[VWERASE] = cntl('W');
4834887Schin ep->e_werase = nttyparm.c_cc[VWERASE];
4844887Schin # else
4854887Schin ep->e_werase = cntl('W');
4864887Schin # endif /* VWERASE */
4874887Schin # ifdef VLNEXT
4884887Schin if(ttyparm.c_cc[VLNEXT] == _POSIX_DISABLE )
4894887Schin nttyparm.c_cc[VLNEXT] = cntl('V');
4904887Schin ep->e_lnext = nttyparm.c_cc[VLNEXT];
4914887Schin # else
4924887Schin ep->e_lnext = cntl('V');
4934887Schin # endif /* VLNEXT */
4944887Schin ep->e_erase = ttyparm.c_cc[VERASE];
4954887Schin ep->e_kill = ttyparm.c_cc[VKILL];
4964887Schin if( tty_set(fd, TCSADRAIN, &nttyparm) == SYSERR )
4974887Schin return(-1);
4984887Schin ep->e_ttyspeed = (cfgetospeed(&ttyparm)>=B1200?FAST:SLOW);
4994887Schin ep->e_raw = ALTMODE;
5004887Schin return(0);
5014887Schin }
5024887Schin
5034887Schin # endif /* TIOCGETC */
5044887Schin #endif /* SHOPT_RAWONLY */
5054887Schin
5064887Schin /*
5074887Schin * ED_WINDOW()
5084887Schin *
5094887Schin * return the window size
5104887Schin */
ed_window(void)5114887Schin int ed_window(void)
5124887Schin {
5134887Schin int rows,cols;
5144887Schin register char *cp = nv_getval(COLUMNS);
5154887Schin if(cp)
5164887Schin cols = (int)strtol(cp, (char**)0, 10)-1;
5174887Schin else
5184887Schin {
5194887Schin astwinsize(2,&rows,&cols);
5204887Schin if(--cols <0)
5214887Schin cols = DFLTWINDOW-1;
5224887Schin }
5234887Schin if(cols < MINWINDOW)
5244887Schin cols = MINWINDOW;
5254887Schin else if(cols > MAXWINDOW)
5264887Schin cols = MAXWINDOW;
5274887Schin return(cols);
5284887Schin }
5294887Schin
5304887Schin /* E_FLUSH()
5314887Schin *
5324887Schin * Flush the output buffer.
5334887Schin *
5344887Schin */
5354887Schin
ed_flush(Edit_t * ep)5364887Schin void ed_flush(Edit_t *ep)
5374887Schin {
5384887Schin register int n = ep->e_outptr-ep->e_outbase;
5394887Schin register int fd = ERRIO;
5404887Schin if(n<=0)
5414887Schin return;
5424887Schin write(fd,ep->e_outbase,(unsigned)n);
5434887Schin ep->e_outptr = ep->e_outbase;
5444887Schin }
5454887Schin
5464887Schin /*
5474887Schin * send the bell character ^G to the terminal
5484887Schin */
5494887Schin
ed_ringbell(void)5504887Schin void ed_ringbell(void)
5514887Schin {
5524887Schin write(ERRIO,bellchr,1);
5534887Schin }
5544887Schin
5554887Schin /*
5564887Schin * send a carriage return line feed to the terminal
5574887Schin */
5584887Schin
ed_crlf(register Edit_t * ep)5594887Schin void ed_crlf(register Edit_t *ep)
5604887Schin {
5614887Schin #ifdef cray
5624887Schin ed_putchar(ep,'\r');
5634887Schin #endif /* cray */
5644887Schin #ifdef u370
5654887Schin ed_putchar(ep,'\r');
5664887Schin #endif /* u370 */
5674887Schin #ifdef VENIX
5684887Schin ed_putchar(ep,'\r');
5694887Schin #endif /* VENIX */
5704887Schin ed_putchar(ep,'\n');
5714887Schin ed_flush(ep);
5724887Schin }
5734887Schin
5744887Schin /* ED_SETUP( max_prompt_size )
5754887Schin *
5764887Schin * This routine sets up the prompt string
5774887Schin * The following is an unadvertised feature.
5784887Schin * Escape sequences in the prompt can be excluded from the calculated
5794887Schin * prompt length. This is accomplished as follows:
5804887Schin * - if the prompt string starts with "%\r, or contains \r%\r", where %
5814887Schin * represents any char, then % is taken to be the quote character.
5824887Schin * - strings enclosed by this quote character, and the quote character,
5834887Schin * are not counted as part of the prompt length.
5844887Schin */
5854887Schin
ed_setup(register Edit_t * ep,int fd,int reedit)5864887Schin void ed_setup(register Edit_t *ep, int fd, int reedit)
5874887Schin {
5888462SApril.Chin@Sun.COM Shell_t *shp = ep->sh;
5894887Schin register char *pp;
5908462SApril.Chin@Sun.COM register char *last, *prev;
5914887Schin char *ppmax;
5924887Schin int myquote = 0, n;
5938462SApril.Chin@Sun.COM register int qlen = 1, qwid;
5944887Schin char inquote = 0;
5954887Schin ep->e_fd = fd;
5964887Schin ep->e_multiline = sh_isoption(SH_MULTILINE)!=0;
5974887Schin #ifdef SIGWINCH
5988462SApril.Chin@Sun.COM if(!(shp->sigflag[SIGWINCH]&SH_SIGFAULT))
5994887Schin {
6004887Schin signal(SIGWINCH,sh_fault);
6018462SApril.Chin@Sun.COM shp->sigflag[SIGWINCH] |= SH_SIGFAULT;
6024887Schin }
6038462SApril.Chin@Sun.COM pp = shp->st.trapcom[SIGWINCH];
6048462SApril.Chin@Sun.COM shp->st.trapcom[SIGWINCH] = 0;
6054887Schin sh_fault(SIGWINCH);
6068462SApril.Chin@Sun.COM shp->st.trapcom[SIGWINCH] = pp;
6078462SApril.Chin@Sun.COM ep->sh->winch = 0;
6084887Schin #endif
6094887Schin #if KSHELL
6104887Schin ep->e_stkptr = stakptr(0);
6114887Schin ep->e_stkoff = staktell();
6128462SApril.Chin@Sun.COM if(!(last = shp->prompt))
6134887Schin last = "";
6148462SApril.Chin@Sun.COM shp->prompt = 0;
6154887Schin #else
6164887Schin last = ep->e_prbuff;
6174887Schin #endif /* KSHELL */
6188462SApril.Chin@Sun.COM if(shp->hist_ptr)
6194887Schin {
6208462SApril.Chin@Sun.COM register History_t *hp = shp->hist_ptr;
6214887Schin ep->e_hismax = hist_max(hp);
6224887Schin ep->e_hismin = hist_min(hp);
6234887Schin }
6244887Schin else
6254887Schin {
6264887Schin ep->e_hismax = ep->e_hismin = ep->e_hloff = 0;
6274887Schin }
6284887Schin ep->e_hline = ep->e_hismax;
6294887Schin if(!sh_isoption(SH_VI) && !sh_isoption(SH_EMACS) && !sh_isoption(SH_GMACS))
6304887Schin ep->e_wsize = MAXLINE;
6314887Schin else
6324887Schin ep->e_wsize = ed_window()-2;
6334887Schin ep->e_winsz = ep->e_wsize+2;
6344887Schin ep->e_crlf = 1;
6354887Schin ep->e_plen = 0;
6364887Schin pp = ep->e_prompt;
6374887Schin ppmax = pp+PRSIZE-1;
6384887Schin *pp++ = '\r';
6394887Schin {
6404887Schin register int c;
6418462SApril.Chin@Sun.COM while(prev = last, c = mbchar(last)) switch(c)
6424887Schin {
6434887Schin case ESC:
6444887Schin {
6454887Schin int skip=0;
6464887Schin ep->e_crlf = 0;
6474887Schin *pp++ = c;
6484887Schin for(n=1; c = *last++; n++)
6494887Schin {
6504887Schin if(pp < ppmax)
6514887Schin *pp++ = c;
6528462SApril.Chin@Sun.COM if(c=='\a' || c==ESC || c=='\r')
6534887Schin break;
6544887Schin if(skip || (c>='0' && c<='9'))
6554887Schin continue;
6564887Schin if(n>1 && c==';')
6574887Schin skip = 1;
6584887Schin else if(n>2 || (c!= '[' && c!= ']'))
6594887Schin break;
6604887Schin }
6618462SApril.Chin@Sun.COM if(c==0 || c==ESC || c=='\r')
6628462SApril.Chin@Sun.COM last--;
6634887Schin qlen += (n+1);
6644887Schin break;
6654887Schin }
6664887Schin case '\b':
6674887Schin if(pp>ep->e_prompt+1)
6684887Schin pp--;
6694887Schin break;
6704887Schin case '\r':
6714887Schin if(pp == (ep->e_prompt+2)) /* quote char */
6724887Schin myquote = *(pp-1);
6734887Schin /*FALLTHROUGH*/
6744887Schin
6754887Schin case '\n':
6764887Schin /* start again */
6774887Schin ep->e_crlf = 1;
6784887Schin qlen = 1;
6794887Schin inquote = 0;
6804887Schin pp = ep->e_prompt+1;
6814887Schin break;
6824887Schin
6834887Schin case '\t':
6844887Schin /* expand tabs */
6854887Schin while((pp-ep->e_prompt)%TABSIZE)
6864887Schin {
6874887Schin if(pp >= ppmax)
6884887Schin break;
6894887Schin *pp++ = ' ';
6904887Schin }
6914887Schin break;
6924887Schin
6934887Schin case '\a':
6944887Schin /* cut out bells */
6954887Schin break;
6964887Schin
6974887Schin default:
6984887Schin if(c==myquote)
6994887Schin {
7004887Schin qlen += inquote;
7014887Schin inquote ^= 1;
7024887Schin }
7034887Schin if(pp < ppmax)
7044887Schin {
7058462SApril.Chin@Sun.COM if(inquote)
7068462SApril.Chin@Sun.COM qlen++;
7078462SApril.Chin@Sun.COM else if(!is_print(c))
7084887Schin ep->e_crlf = 0;
7098462SApril.Chin@Sun.COM if((qwid = last - prev) > 1)
7108462SApril.Chin@Sun.COM qlen += qwid - mbwidth(c);
7118462SApril.Chin@Sun.COM while(prev < last && pp < ppmax)
7128462SApril.Chin@Sun.COM *pp++ = *prev++;
7134887Schin }
7148462SApril.Chin@Sun.COM break;
7154887Schin }
7164887Schin }
7174887Schin if(pp-ep->e_prompt > qlen)
7184887Schin ep->e_plen = pp - ep->e_prompt - qlen;
7194887Schin *pp = 0;
7208462SApril.Chin@Sun.COM if(!ep->e_multiline && (ep->e_wsize -= ep->e_plen) < 7)
7214887Schin {
7224887Schin register int shift = 7-ep->e_wsize;
7234887Schin ep->e_wsize = 7;
7244887Schin pp = ep->e_prompt+1;
7254887Schin strcpy(pp,pp+shift);
7264887Schin ep->e_plen -= shift;
7274887Schin last[-ep->e_plen-2] = '\r';
7284887Schin }
7294887Schin sfsync(sfstderr);
7304887Schin if(fd == sffileno(sfstderr))
7314887Schin {
7324887Schin /* can't use output buffer when reading from stderr */
7334887Schin static char *buff;
7344887Schin if(!buff)
7354887Schin buff = (char*)malloc(MAXLINE);
7364887Schin ep->e_outbase = ep->e_outptr = buff;
7374887Schin ep->e_outlast = ep->e_outptr + MAXLINE;
7384887Schin return;
7394887Schin }
7404887Schin qlen = sfset(sfstderr,SF_READ,0);
7414887Schin /* make sure SF_READ not on */
7424887Schin ep->e_outbase = ep->e_outptr = (char*)sfreserve(sfstderr,SF_UNBOUND,SF_LOCKR);
7434887Schin ep->e_outlast = ep->e_outptr + sfvalue(sfstderr);
7444887Schin if(qlen)
7454887Schin sfset(sfstderr,SF_READ,1);
7464887Schin sfwrite(sfstderr,ep->e_outptr,0);
7474887Schin ep->e_eol = reedit;
7484887Schin if(ep->e_multiline)
7494887Schin {
7504887Schin #ifdef _cmd_tput
7514887Schin char *term;
7524887Schin if(!ep->e_term)
7538462SApril.Chin@Sun.COM ep->e_term = nv_search("TERM",shp->var_tree,0);
7544887Schin if(ep->e_term && (term=nv_getval(ep->e_term)) && strlen(term)<sizeof(ep->e_termname) && strcmp(term,ep->e_termname))
7554887Schin {
7564887Schin sh_trap(".sh.subscript=$(tput cuu1 2>/dev/null)",0);
7574887Schin if(pp=nv_getval(SH_SUBSCRNOD))
7584887Schin strncpy(CURSOR_UP,pp,sizeof(CURSOR_UP)-1);
7594887Schin nv_unset(SH_SUBSCRNOD);
7604887Schin strcpy(ep->e_termname,term);
7614887Schin }
7624887Schin #endif
7638462SApril.Chin@Sun.COM ep->e_wsize = MAXLINE - (ep->e_plen+1);
7644887Schin }
7654887Schin if(ep->e_default && (pp = nv_getval(ep->e_default)))
7664887Schin {
7674887Schin n = strlen(pp);
7684887Schin if(n > LOOKAHEAD)
7694887Schin n = LOOKAHEAD;
7704887Schin ep->e_lookahead = n;
7714887Schin while(n-- > 0)
7724887Schin ep->e_lbuf[n] = *pp++;
7734887Schin ep->e_default = 0;
7744887Schin }
7754887Schin }
7764887Schin
ed_putstring(register Edit_t * ep,const char * str)7778462SApril.Chin@Sun.COM static void ed_putstring(register Edit_t *ep, const char *str)
7788462SApril.Chin@Sun.COM {
7798462SApril.Chin@Sun.COM register int c;
7808462SApril.Chin@Sun.COM while(c = *str++)
7818462SApril.Chin@Sun.COM ed_putchar(ep,c);
7828462SApril.Chin@Sun.COM }
7838462SApril.Chin@Sun.COM
ed_nputchar(register Edit_t * ep,int n,int c)7848462SApril.Chin@Sun.COM static void ed_nputchar(register Edit_t *ep, int n, int c)
7858462SApril.Chin@Sun.COM {
7868462SApril.Chin@Sun.COM while(n-->0)
7878462SApril.Chin@Sun.COM ed_putchar(ep,c);
7888462SApril.Chin@Sun.COM }
7898462SApril.Chin@Sun.COM
7904887Schin /*
7914887Schin * Do read, restart on interrupt unless SH_SIGSET or SH_SIGTRAP is set
7924887Schin * Use sfpkrd() to poll() or select() to wait for input if possible
7934887Schin * Unfortunately, systems that get interrupted from slow reads update
7944887Schin * this access time for for the terminal (in violation of POSIX).
7954887Schin * The fixtime() macro, resets the time to the time at entry in
7964887Schin * this case. This is not necessary for systems that can handle
7974887Schin * sfpkrd() correctly (i,e., those that support poll() or select()
7984887Schin */
ed_read(void * context,int fd,char * buff,int size,int reedit)7994887Schin int ed_read(void *context, int fd, char *buff, int size, int reedit)
8004887Schin {
8014887Schin register Edit_t *ep = (Edit_t*)context;
8024887Schin register int rv= -1;
8034887Schin register int delim = (ep->e_raw==RAWMODE?'\r':'\n');
8048462SApril.Chin@Sun.COM Shell_t *shp = ep->sh;
8054887Schin int mode = -1;
8068462SApril.Chin@Sun.COM int (*waitevent)(int,long,int) = shp->waitevent;
8074887Schin if(ep->e_raw==ALTMODE)
8084887Schin mode = 1;
8094887Schin if(size < 0)
8104887Schin {
8114887Schin mode = 1;
8124887Schin size = -size;
8134887Schin }
8144887Schin sh_onstate(SH_TTYWAIT);
8154887Schin errno = EINTR;
8168462SApril.Chin@Sun.COM shp->waitevent = 0;
8174887Schin while(rv<0 && errno==EINTR)
8184887Schin {
8198462SApril.Chin@Sun.COM if(shp->trapnote&(SH_SIGSET|SH_SIGTRAP))
8204887Schin goto done;
82110898Sroland.mainz@nrubsig.org if(ep->sh->winch && sh_isstate(SH_INTERACTIVE) && (sh_isoption(SH_VI) || sh_isoption(SH_EMACS)))
8228462SApril.Chin@Sun.COM {
8238462SApril.Chin@Sun.COM Edpos_t lastpos;
8248462SApril.Chin@Sun.COM int n, rows, newsize;
8258462SApril.Chin@Sun.COM /* move cursor to start of first line */
8268462SApril.Chin@Sun.COM ed_putchar(ep,'\r');
8278462SApril.Chin@Sun.COM ed_flush(ep);
8288462SApril.Chin@Sun.COM astwinsize(2,&rows,&newsize);
8298462SApril.Chin@Sun.COM n = (ep->e_plen+ep->e_cur)/++ep->e_winsz;
8308462SApril.Chin@Sun.COM while(n--)
8318462SApril.Chin@Sun.COM ed_putstring(ep,CURSOR_UP);
8328462SApril.Chin@Sun.COM if(ep->e_multiline && newsize>ep->e_winsz && (lastpos.line=(ep->e_plen+ep->e_peol)/ep->e_winsz))
8338462SApril.Chin@Sun.COM {
8348462SApril.Chin@Sun.COM /* clear the current command line */
8358462SApril.Chin@Sun.COM n = lastpos.line;
8368462SApril.Chin@Sun.COM while(lastpos.line--)
8378462SApril.Chin@Sun.COM {
8388462SApril.Chin@Sun.COM ed_nputchar(ep,ep->e_winsz,' ');
8398462SApril.Chin@Sun.COM ed_putchar(ep,'\n');
8408462SApril.Chin@Sun.COM }
8418462SApril.Chin@Sun.COM ed_nputchar(ep,ep->e_winsz,' ');
8428462SApril.Chin@Sun.COM while(n--)
8438462SApril.Chin@Sun.COM ed_putstring(ep,CURSOR_UP);
8448462SApril.Chin@Sun.COM }
8458462SApril.Chin@Sun.COM ep->sh->winch = 0;
8468462SApril.Chin@Sun.COM ed_flush(ep);
8478462SApril.Chin@Sun.COM sh_delay(.05);
8488462SApril.Chin@Sun.COM astwinsize(2,&rows,&newsize);
8498462SApril.Chin@Sun.COM ep->e_winsz = newsize-1;
8508462SApril.Chin@Sun.COM if(!ep->e_multiline && ep->e_wsize < MAXLINE)
8518462SApril.Chin@Sun.COM ep->e_wsize = ep->e_winsz-2;
8528462SApril.Chin@Sun.COM ep->e_nocrnl=1;
8538462SApril.Chin@Sun.COM if(*ep->e_vi_insert)
8548462SApril.Chin@Sun.COM {
8558462SApril.Chin@Sun.COM buff[0] = ESC;
8568462SApril.Chin@Sun.COM buff[1] = cntl('L');
8578462SApril.Chin@Sun.COM buff[2] = 'a';
8588462SApril.Chin@Sun.COM return(3);
8598462SApril.Chin@Sun.COM }
86010898Sroland.mainz@nrubsig.org if(sh_isoption(SH_EMACS) || sh_isoption(SH_VI))
86110898Sroland.mainz@nrubsig.org buff[0] = cntl('L');
8628462SApril.Chin@Sun.COM return(1);
8638462SApril.Chin@Sun.COM }
86410898Sroland.mainz@nrubsig.org else
86510898Sroland.mainz@nrubsig.org ep->sh->winch = 0;
8664887Schin /* an interrupt that should be ignored */
8674887Schin errno = 0;
8684887Schin if(!waitevent || (rv=(*waitevent)(fd,-1L,0))>=0)
8694887Schin rv = sfpkrd(fd,buff,size,delim,-1L,mode);
8704887Schin }
8714887Schin if(rv < 0)
8724887Schin {
8734887Schin #ifdef _hdr_utime
8744887Schin # define fixtime() if(isdevtty)utime(ep->e_tty,&utimes)
8754887Schin int isdevtty=0;
8764887Schin struct stat statb;
8774887Schin struct utimbuf utimes;
8784887Schin if(errno==0 && !ep->e_tty)
8794887Schin {
8804887Schin if((ep->e_tty=ttyname(fd)) && stat(ep->e_tty,&statb)>=0)
8814887Schin {
8824887Schin ep->e_tty_ino = statb.st_ino;
8834887Schin ep->e_tty_dev = statb.st_dev;
8844887Schin }
8854887Schin }
8864887Schin if(ep->e_tty_ino && fstat(fd,&statb)>=0 && statb.st_ino==ep->e_tty_ino && statb.st_dev==ep->e_tty_dev)
8874887Schin {
8884887Schin utimes.actime = statb.st_atime;
8894887Schin utimes.modtime = statb.st_mtime;
8904887Schin isdevtty=1;
8914887Schin }
8924887Schin #else
8934887Schin # define fixtime()
8944887Schin #endif /* _hdr_utime */
8954887Schin while(1)
8964887Schin {
8974887Schin rv = read(fd,buff,size);
8984887Schin if(rv>=0 || errno!=EINTR)
8994887Schin break;
9008462SApril.Chin@Sun.COM if(shp->trapnote&(SH_SIGSET|SH_SIGTRAP))
9014887Schin goto done;
9024887Schin /* an interrupt that should be ignored */
9034887Schin fixtime();
9044887Schin }
9054887Schin }
9064887Schin else if(rv>=0 && mode>0)
9074887Schin rv = read(fd,buff,rv>0?rv:1);
9084887Schin done:
9098462SApril.Chin@Sun.COM shp->waitevent = waitevent;
9104887Schin sh_offstate(SH_TTYWAIT);
9114887Schin return(rv);
9124887Schin }
9134887Schin
9144887Schin
9154887Schin /*
9164887Schin * put <string> of length <nbyte> onto lookahead stack
9174887Schin * if <type> is non-zero, the negation of the character is put
9184887Schin * onto the stack so that it can be checked for KEYTRAP
9194887Schin * putstack() returns 1 except when in the middle of a multi-byte char
9204887Schin */
9214887Schin static int putstack(Edit_t *ep,char string[], register int nbyte, int type)
9224887Schin {
9234887Schin register int c;
9244887Schin #if SHOPT_MULTIBYTE
9254887Schin char *endp, *p=string;
9264887Schin int size, offset = ep->e_lookahead + nbyte;
9274887Schin *(endp = &p[nbyte]) = 0;
9284887Schin endp = &p[nbyte];
9294887Schin do
9304887Schin {
9314887Schin c = (int)((*p) & STRIP);
9324887Schin if(c< 0x80 && c!='<')
9334887Schin {
9344887Schin if (type)
9354887Schin c = -c;
9364887Schin # ifndef CBREAK
9374887Schin if(c == '\0')
9384887Schin {
9394887Schin /*** user break key ***/
9404887Schin ep->e_lookahead = 0;
9414887Schin # if KSHELL
9424887Schin sh_fault(SIGINT);
9434887Schin siglongjmp(ep->e_env, UINTR);
9444887Schin # endif /* KSHELL */
9454887Schin }
9464887Schin # endif /* CBREAK */
9474887Schin
9484887Schin }
9494887Schin else
9504887Schin {
9514887Schin again:
9524887Schin if((c=mbchar(p)) >=0)
9534887Schin {
9544887Schin p--; /* incremented below */
9554887Schin if(type)
9564887Schin c = -c;
9574887Schin }
9584887Schin #ifdef EILSEQ
9594887Schin else if(errno == EILSEQ)
9604887Schin errno = 0;
9614887Schin #endif
9624887Schin else if((endp-p) < mbmax())
9634887Schin {
9644887Schin if ((c=ed_read(ep,ep->e_fd,endp, 1,0)) == 1)
9654887Schin {
9664887Schin *++endp = 0;
9674887Schin goto again;
9684887Schin }
9694887Schin return(c);
9704887Schin }
9714887Schin else
9724887Schin {
9734887Schin ed_ringbell();
9744887Schin c = -(int)((*p) & STRIP);
9754887Schin offset += mbmax()-1;
9764887Schin }
9774887Schin }
9784887Schin ep->e_lbuf[--offset] = c;
9794887Schin p++;
9804887Schin }
9814887Schin while (p < endp);
9824887Schin /* shift lookahead buffer if necessary */
9834887Schin if(offset -= ep->e_lookahead)
9844887Schin {
9854887Schin for(size=offset;size < nbyte;size++)
9864887Schin ep->e_lbuf[ep->e_lookahead+size-offset] = ep->e_lbuf[ep->e_lookahead+size];
9874887Schin }
9884887Schin ep->e_lookahead += nbyte-offset;
9894887Schin #else
9904887Schin while (nbyte > 0)
9914887Schin {
9924887Schin c = string[--nbyte] & STRIP;
9934887Schin ep->e_lbuf[ep->e_lookahead++] = (type?-c:c);
9944887Schin # ifndef CBREAK
9954887Schin if( c == '\0' )
9964887Schin {
9974887Schin /*** user break key ***/
9984887Schin ep->e_lookahead = 0;
9994887Schin # if KSHELL
10004887Schin sh_fault(SIGINT);
10014887Schin siglongjmp(ep->e_env, UINTR);
10024887Schin # endif /* KSHELL */
10034887Schin }
10044887Schin # endif /* CBREAK */
10054887Schin }
10064887Schin #endif /* SHOPT_MULTIBYTE */
10074887Schin return(1);
10084887Schin }
10094887Schin
10104887Schin /*
10114887Schin * routine to perform read from terminal for vi and emacs mode
10124887Schin * <mode> can be one of the following:
10134887Schin * -2 vi insert mode - key binding is in effect
10144887Schin * -1 vi control mode - key binding is in effect
10154887Schin * 0 normal command mode - key binding is in effect
10164887Schin * 1 edit keys not mapped
10174887Schin * 2 Next key is literal
10184887Schin */
10194887Schin int ed_getchar(register Edit_t *ep,int mode)
10204887Schin {
10214887Schin register int n, c;
10224887Schin char readin[LOOKAHEAD+1];
10234887Schin if(!ep->e_lookahead)
10244887Schin {
10254887Schin ed_flush(ep);
10264887Schin ep->e_inmacro = 0;
10274887Schin /* The while is necessary for reads of partial multbyte chars */
10288462SApril.Chin@Sun.COM *ep->e_vi_insert = (mode==-2);
10294887Schin if((n=ed_read(ep,ep->e_fd,readin,-LOOKAHEAD,0)) > 0)
10304887Schin n = putstack(ep,readin,n,1);
10318462SApril.Chin@Sun.COM *ep->e_vi_insert = 0;
10324887Schin }
10334887Schin if(ep->e_lookahead)
10344887Schin {
10354887Schin /* check for possible key mapping */
10364887Schin if((c = ep->e_lbuf[--ep->e_lookahead]) < 0)
10374887Schin {
10388462SApril.Chin@Sun.COM if(mode<=0 && ep->sh->st.trap[SH_KEYTRAP])
10394887Schin {
10404887Schin n=1;
10414887Schin if((readin[0]= -c) == ESC)
10424887Schin {
10434887Schin while(1)
10444887Schin {
10454887Schin if(!ep->e_lookahead)
10464887Schin {
10474887Schin if((c=sfpkrd(ep->e_fd,readin+n,1,'\r',(mode?400L:-1L),0))>0)
10484887Schin putstack(ep,readin+n,c,1);
10494887Schin }
10504887Schin if(!ep->e_lookahead)
10514887Schin break;
10524887Schin if((c=ep->e_lbuf[--ep->e_lookahead])>=0)
10534887Schin {
10544887Schin ep->e_lookahead++;
10554887Schin break;
10564887Schin }
10574887Schin c = -c;
10584887Schin readin[n++] = c;
10594887Schin if(c>='0' && c<='9' && n>2)
10604887Schin continue;
10614887Schin if(n>2 || (c!= '[' && c!= 'O'))
10624887Schin break;
10634887Schin }
10644887Schin }
10654887Schin if(n=keytrap(ep,readin,n,LOOKAHEAD-n,mode))
10664887Schin {
10674887Schin putstack(ep,readin,n,0);
10684887Schin c = ep->e_lbuf[--ep->e_lookahead];
10694887Schin }
10704887Schin else
10714887Schin c = ed_getchar(ep,mode);
10724887Schin }
10734887Schin else
10744887Schin c = -c;
10754887Schin }
10764887Schin /*** map '\r' to '\n' ***/
10774887Schin if(c == '\r' && mode!=2)
10784887Schin c = '\n';
10794887Schin if(ep->e_tabcount && !(c=='\t'||c==ESC || c=='\\' || c=='=' || c==cntl('L') || isdigit(c)))
10804887Schin ep->e_tabcount = 0;
10814887Schin }
10824887Schin else
10834887Schin siglongjmp(ep->e_env,(n==0?UEOF:UINTR));
10844887Schin return(c);
10854887Schin }
10864887Schin
10874887Schin void ed_ungetchar(Edit_t *ep,register int c)
10884887Schin {
10894887Schin if (ep->e_lookahead < LOOKAHEAD)
10904887Schin ep->e_lbuf[ep->e_lookahead++] = c;
10914887Schin return;
10924887Schin }
10934887Schin
10944887Schin /*
10954887Schin * put a character into the output buffer
10964887Schin */
10974887Schin
10984887Schin void ed_putchar(register Edit_t *ep,register int c)
10994887Schin {
11004887Schin char buf[8];
11014887Schin register char *dp = ep->e_outptr;
11024887Schin register int i,size=1;
11038462SApril.Chin@Sun.COM if(!dp)
11048462SApril.Chin@Sun.COM return;
11054887Schin buf[0] = c;
11064887Schin #if SHOPT_MULTIBYTE
11074887Schin /* check for place holder */
11084887Schin if(c == MARKER)
11094887Schin return;
11104887Schin if((size = mbconv(buf, (wchar_t)c)) > 1)
11114887Schin {
11124887Schin for (i = 0; i < (size-1); i++)
11134887Schin *dp++ = buf[i];
11144887Schin c = buf[i];
11154887Schin }
11164887Schin else
11174887Schin {
11184887Schin buf[0] = c;
11194887Schin size = 1;
11204887Schin }
11214887Schin #endif /* SHOPT_MULTIBYTE */
11224887Schin if (buf[0] == '_' && size==1)
11234887Schin {
11244887Schin *dp++ = ' ';
11254887Schin *dp++ = '\b';
11264887Schin }
11274887Schin *dp++ = c;
11284887Schin *dp = '\0';
11294887Schin if(dp >= ep->e_outlast)
11304887Schin ed_flush(ep);
11314887Schin else
11324887Schin ep->e_outptr = dp;
11334887Schin }
11344887Schin
11354887Schin /*
11364887Schin * returns the line and column corresponding to offset <off> in the physical buffer
11374887Schin * if <cur> is non-zero and <= <off>, then correspodning <curpos> will start the search
11384887Schin */
11394887Schin Edpos_t ed_curpos(Edit_t *ep,genchar *phys, int off, int cur, Edpos_t curpos)
11404887Schin {
11414887Schin register genchar *sp=phys;
11424887Schin register int c=1, col=ep->e_plen;
11434887Schin Edpos_t pos;
11444887Schin #if SHOPT_MULTIBYTE
11454887Schin char p[16];
11464887Schin #endif /* SHOPT_MULTIBYTE */
11474887Schin if(cur && off>=cur)
11484887Schin {
11494887Schin sp += cur;
11504887Schin off -= cur;
11514887Schin pos = curpos;
11524887Schin col = pos.col;
11534887Schin }
11544887Schin else
11558462SApril.Chin@Sun.COM {
11564887Schin pos.line = 0;
11578462SApril.Chin@Sun.COM while(col > ep->e_winsz)
11588462SApril.Chin@Sun.COM {
11598462SApril.Chin@Sun.COM pos.line++;
11608462SApril.Chin@Sun.COM col -= (ep->e_winsz+1);
11618462SApril.Chin@Sun.COM }
11628462SApril.Chin@Sun.COM }
11634887Schin while(off-->0)
11644887Schin {
11654887Schin if(c)
11664887Schin c = *sp++;
11674887Schin #if SHOPT_MULTIBYTE
11684887Schin if(c && (mbconv(p, (wchar_t)c))==1 && p[0]=='\n')
11694887Schin #else
11704887Schin if(c=='\n')
11714887Schin #endif /* SHOPT_MULTIBYTE */
11724887Schin col = 0;
11734887Schin else
11744887Schin col++;
11754887Schin if(col > ep->e_winsz)
11764887Schin col = 0;
11774887Schin if(col==0)
11784887Schin pos.line++;
11794887Schin }
11804887Schin pos.col = col;
11814887Schin return(pos);
11824887Schin }
11834887Schin
11844887Schin int ed_setcursor(register Edit_t *ep,genchar *physical,register int old,register int new,int first)
11854887Schin {
11864887Schin static int oldline;
11874887Schin register int delta;
11888462SApril.Chin@Sun.COM int clear = 0;
11894887Schin Edpos_t newpos;
11904887Schin
11914887Schin delta = new - old;
11928462SApril.Chin@Sun.COM if(first < 0)
11938462SApril.Chin@Sun.COM {
11948462SApril.Chin@Sun.COM first = 0;
11958462SApril.Chin@Sun.COM clear = 1;
11968462SApril.Chin@Sun.COM }
11978462SApril.Chin@Sun.COM if( delta == 0 && !clear)
11984887Schin return(new);
11994887Schin if(ep->e_multiline)
12004887Schin {
12014887Schin ep->e_curpos = ed_curpos(ep, physical, old,0,ep->e_curpos);
12028462SApril.Chin@Sun.COM if(clear && old>=ep->e_peol && (clear=ep->e_winsz-ep->e_curpos.col)>0)
12038462SApril.Chin@Sun.COM {
12048462SApril.Chin@Sun.COM ed_nputchar(ep,clear,' ');
12058462SApril.Chin@Sun.COM ed_nputchar(ep,clear,'\b');
12068462SApril.Chin@Sun.COM return(new);
12078462SApril.Chin@Sun.COM }
12084887Schin newpos = ed_curpos(ep, physical, new,old,ep->e_curpos);
12094887Schin if(ep->e_curpos.col==0 && ep->e_curpos.line>0 && oldline<ep->e_curpos.line && delta<0)
12104887Schin ed_putstring(ep,"\r\n");
12114887Schin oldline = newpos.line;
12124887Schin if(ep->e_curpos.line > newpos.line)
12134887Schin {
12148462SApril.Chin@Sun.COM int n,pline,plen=ep->e_plen;
12154887Schin for(;ep->e_curpos.line > newpos.line; ep->e_curpos.line--)
12164887Schin ed_putstring(ep,CURSOR_UP);
12178462SApril.Chin@Sun.COM pline = plen/(ep->e_winsz+1);
12188462SApril.Chin@Sun.COM if(newpos.line <= pline)
12198462SApril.Chin@Sun.COM plen -= pline*(ep->e_winsz+1);
12208462SApril.Chin@Sun.COM else
12218462SApril.Chin@Sun.COM plen = 0;
12228462SApril.Chin@Sun.COM if((n=plen- ep->e_curpos.col)>0)
12234887Schin {
12244887Schin ep->e_curpos.col += n;
12254887Schin ed_putchar(ep,'\r');
12268462SApril.Chin@Sun.COM if(!ep->e_crlf && pline==0)
12274887Schin ed_putstring(ep,ep->e_prompt);
12284887Schin else
12294887Schin {
12308462SApril.Chin@Sun.COM int m = ep->e_winsz+1-plen;
12314887Schin ed_putchar(ep,'\n');
12328462SApril.Chin@Sun.COM n = plen;
12334887Schin if(m < ed_genlen(physical))
12344887Schin {
12354887Schin while(physical[m] && n-->0)
12364887Schin ed_putchar(ep,physical[m++]);
12374887Schin }
12388462SApril.Chin@Sun.COM ed_nputchar(ep,n,' ');
12394887Schin ed_putstring(ep,CURSOR_UP);
12404887Schin }
12414887Schin }
12424887Schin }
12434887Schin else if(ep->e_curpos.line < newpos.line)
12444887Schin {
12458462SApril.Chin@Sun.COM ed_nputchar(ep, newpos.line-ep->e_curpos.line,'\n');
12468462SApril.Chin@Sun.COM ep->e_curpos.line = newpos.line;
12474887Schin ed_putchar(ep,'\r');
12484887Schin ep->e_curpos.col = 0;
12494887Schin }
12504887Schin delta = newpos.col - ep->e_curpos.col;
12514887Schin old = new - delta;
12524887Schin }
12534887Schin else
12544887Schin newpos.line=0;
12554887Schin if(delta<0)
12564887Schin {
12578462SApril.Chin@Sun.COM int bs= newpos.line && ep->e_plen>ep->e_winsz;
12584887Schin /*** move to left ***/
12594887Schin delta = -delta;
12604887Schin /*** attempt to optimize cursor movement ***/
12618462SApril.Chin@Sun.COM if(!ep->e_crlf || bs || (2*delta <= ((old-first)+(newpos.line?0:ep->e_plen))) )
12624887Schin {
12638462SApril.Chin@Sun.COM ed_nputchar(ep,delta,'\b');
12648462SApril.Chin@Sun.COM delta = 0;
12654887Schin }
12664887Schin else
12674887Schin {
12684887Schin if(newpos.line==0)
12694887Schin ed_putstring(ep,ep->e_prompt);
12708462SApril.Chin@Sun.COM else
12718462SApril.Chin@Sun.COM {
12728462SApril.Chin@Sun.COM first = 1+(newpos.line*ep->e_winsz - ep->e_plen);
12738462SApril.Chin@Sun.COM ed_putchar(ep,'\r');
12748462SApril.Chin@Sun.COM }
12754887Schin old = first;
12764887Schin delta = new-first;
12774887Schin }
12784887Schin }
12794887Schin while(delta-->0)
12804887Schin ed_putchar(ep,physical[old++]);
12814887Schin return(new);
12824887Schin }
12834887Schin
12844887Schin /*
12854887Schin * copy virtual to physical and return the index for cursor in physical buffer
12864887Schin */
12874887Schin int ed_virt_to_phys(Edit_t *ep,genchar *virt,genchar *phys,int cur,int voff,int poff)
12884887Schin {
12894887Schin register genchar *sp = virt;
12904887Schin register genchar *dp = phys;
12914887Schin register int c;
12924887Schin genchar *curp = sp + cur;
12934887Schin genchar *dpmax = phys+MAXLINE;
12944887Schin int d, r;
12954887Schin sp += voff;
12964887Schin dp += poff;
12974887Schin for(r=poff;c= *sp;sp++)
12984887Schin {
12994887Schin if(curp == sp)
13004887Schin r = dp - phys;
13014887Schin #if SHOPT_MULTIBYTE
13024887Schin d = mbwidth((wchar_t)c);
13034887Schin if(d==1 && is_cntrl(c))
13044887Schin d = -1;
13054887Schin if(d>1)
13064887Schin {
13074887Schin /* multiple width character put in place holders */
13084887Schin *dp++ = c;
13094887Schin while(--d >0)
13104887Schin *dp++ = MARKER;
13114887Schin /* in vi mode the cursor is at the last character */
13124887Schin if(dp>=dpmax)
13134887Schin break;
13144887Schin continue;
13154887Schin }
13164887Schin else
13174887Schin #else
13184887Schin d = (is_cntrl(c)?-1:1);
13194887Schin #endif /* SHOPT_MULTIBYTE */
13204887Schin if(d<0)
13214887Schin {
13224887Schin if(c=='\t')
13234887Schin {
13244887Schin c = dp-phys;
13254887Schin if(sh_isoption(SH_VI))
13264887Schin c += ep->e_plen;
13274887Schin c = TABSIZE - c%TABSIZE;
13284887Schin while(--c>0)
13294887Schin *dp++ = ' ';
13304887Schin c = ' ';
13314887Schin }
13324887Schin else
13334887Schin {
13344887Schin *dp++ = '^';
13354887Schin c = printchar(c);
13364887Schin }
13374887Schin /* in vi mode the cursor is at the last character */
13384887Schin if(curp == sp && sh_isoption(SH_VI))
13394887Schin r = dp - phys;
13404887Schin }
13414887Schin *dp++ = c;
13424887Schin if(dp>=dpmax)
13434887Schin break;
13444887Schin }
13454887Schin *dp = 0;
13468462SApril.Chin@Sun.COM ep->e_peol = dp-phys;
13474887Schin return(r);
13484887Schin }
13494887Schin
13504887Schin #if SHOPT_MULTIBYTE
13514887Schin /*
13524887Schin * convert external representation <src> to an array of genchars <dest>
13534887Schin * <src> and <dest> can be the same
13544887Schin * returns number of chars in dest
13554887Schin */
13564887Schin
13574887Schin int ed_internal(const char *src, genchar *dest)
13584887Schin {
13594887Schin register const unsigned char *cp = (unsigned char *)src;
13604887Schin register int c;
13614887Schin register wchar_t *dp = (wchar_t*)dest;
13624887Schin if(dest == (genchar*)roundof(cp-(unsigned char*)0,sizeof(genchar)))
13634887Schin {
13644887Schin genchar buffer[MAXLINE];
13654887Schin c = ed_internal(src,buffer);
13664887Schin ed_gencpy((genchar*)dp,buffer);
13674887Schin return(c);
13684887Schin }
13694887Schin while(*cp)
13704887Schin *dp++ = mbchar(cp);
13714887Schin *dp = 0;
13724887Schin return(dp-(wchar_t*)dest);
13734887Schin }
13744887Schin
13754887Schin /*
13764887Schin * convert internal representation <src> into character array <dest>.
13774887Schin * The <src> and <dest> may be the same.
13784887Schin * returns number of chars in dest.
13794887Schin */
13804887Schin
13814887Schin int ed_external(const genchar *src, char *dest)
13824887Schin {
13834887Schin register genchar wc;
13844887Schin register int c,size;
13854887Schin register char *dp = dest;
13864887Schin char *dpmax = dp+sizeof(genchar)*MAXLINE-2;
13874887Schin if((char*)src == dp)
13884887Schin {
13894887Schin char buffer[MAXLINE*sizeof(genchar)];
13904887Schin c = ed_external(src,buffer);
13914887Schin
13924887Schin #ifdef _lib_wcscpy
13934887Schin wcscpy((wchar_t *)dest,(const wchar_t *)buffer);
13944887Schin #else
13954887Schin strcpy(dest,buffer);
13964887Schin #endif
13974887Schin return(c);
13984887Schin }
13994887Schin while((wc = *src++) && dp<dpmax)
14004887Schin {
14014887Schin if((size = mbconv(dp, wc)) < 0)
14024887Schin {
14034887Schin /* copy the character as is */
14044887Schin size = 1;
14054887Schin *dp = wc;
14064887Schin }
14074887Schin dp += size;
14084887Schin }
14094887Schin *dp = 0;
14104887Schin return(dp-dest);
14114887Schin }
14124887Schin
14134887Schin /*
14144887Schin * copy <sp> to <dp>
14154887Schin */
14164887Schin
14174887Schin void ed_gencpy(genchar *dp,const genchar *sp)
14184887Schin {
14194887Schin dp = (genchar*)roundof((char*)dp-(char*)0,sizeof(genchar));
14204887Schin sp = (const genchar*)roundof((char*)sp-(char*)0,sizeof(genchar));
14214887Schin while(*dp++ = *sp++);
14224887Schin }
14234887Schin
14244887Schin /*
14254887Schin * copy at most <n> items from <sp> to <dp>
14264887Schin */
14274887Schin
14284887Schin void ed_genncpy(register genchar *dp,register const genchar *sp, int n)
14294887Schin {
14304887Schin dp = (genchar*)roundof((char*)dp-(char*)0,sizeof(genchar));
14314887Schin sp = (const genchar*)roundof((char*)sp-(char*)0,sizeof(genchar));
14324887Schin while(n-->0 && (*dp++ = *sp++));
14334887Schin }
14344887Schin
14354887Schin /*
14364887Schin * find the string length of <str>
14374887Schin */
14384887Schin
14394887Schin int ed_genlen(register const genchar *str)
14404887Schin {
14414887Schin register const genchar *sp = str;
14424887Schin sp = (const genchar*)roundof((char*)sp-(char*)0,sizeof(genchar));
14434887Schin while(*sp++);
14444887Schin return(sp-str-1);
14454887Schin }
14464887Schin #endif /* SHOPT_MULTIBYTE */
14474887Schin #endif /* SHOPT_ESH || SHOPT_VSH */
14484887Schin
14494887Schin #ifdef future
14504887Schin /*
14514887Schin * returns 1 when <n> bytes starting at <a> and <b> are equal
14524887Schin */
14534887Schin static int compare(register const char *a,register const char *b,register int n)
14544887Schin {
14554887Schin while(n-->0)
14564887Schin {
14574887Schin if(*a++ != *b++)
14584887Schin return(0);
14594887Schin }
14604887Schin return(1);
14614887Schin }
14624887Schin #endif
14634887Schin
14644887Schin #if SHOPT_OLDTERMIO
14654887Schin
14664887Schin # include <sys/termio.h>
14674887Schin
14684887Schin #ifndef ECHOCTL
14694887Schin # define ECHOCTL 0
14704887Schin #endif /* !ECHOCTL */
14714887Schin #define ott ep->e_ott
14724887Schin
14734887Schin /*
14744887Schin * For backward compatibility only
14754887Schin * This version will use termios when possible, otherwise termio
14764887Schin */
14774887Schin
14788462SApril.Chin@Sun.COM int tcgetattr(int fd, struct termios *tt)
14794887Schin {
14804887Schin register Edit_t *ep = (Edit_t*)(sh_getinterp()->ed_context);
14814887Schin register int r,i;
14824887Schin ep->e_tcgeta = 0;
14834887Schin ep->e_echoctl = (ECHOCTL!=0);
14844887Schin if((r=ioctl(fd,TCGETS,tt))>=0 || errno!=EINVAL)
14854887Schin return(r);
14864887Schin if((r=ioctl(fd,TCGETA,&ott)) >= 0)
14874887Schin {
14884887Schin tt->c_lflag = ott.c_lflag;
14894887Schin tt->c_oflag = ott.c_oflag;
14904887Schin tt->c_iflag = ott.c_iflag;
14914887Schin tt->c_cflag = ott.c_cflag;
14924887Schin for(i=0; i<NCC; i++)
14934887Schin tt->c_cc[i] = ott.c_cc[i];
14944887Schin ep->e_tcgeta++;
14954887Schin ep->e_echoctl = 0;
14964887Schin }
14974887Schin return(r);
14984887Schin }
14994887Schin
15008462SApril.Chin@Sun.COM int tcsetattr(int fd,int mode,struct termios *tt)
15014887Schin {
15024887Schin register Edit_t *ep = (Edit_t*)(sh_getinterp()->ed_context);
15034887Schin register int r;
15044887Schin if(ep->e_tcgeta)
15054887Schin {
15064887Schin register int i;
15074887Schin ott.c_lflag = tt->c_lflag;
15084887Schin ott.c_oflag = tt->c_oflag;
15094887Schin ott.c_iflag = tt->c_iflag;
15104887Schin ott.c_cflag = tt->c_cflag;
15114887Schin for(i=0; i<NCC; i++)
15124887Schin ott.c_cc[i] = tt->c_cc[i];
15134887Schin if(tt->c_lflag&ECHOCTL)
15144887Schin {
15154887Schin ott.c_lflag &= ~(ECHOCTL|IEXTEN);
15164887Schin ott.c_iflag &= ~(IGNCR|ICRNL);
15174887Schin ott.c_iflag |= INLCR;
15184887Schin ott.c_cc[VEOF]= ESC; /* ESC -> eof char */
15194887Schin ott.c_cc[VEOL] = '\r'; /* CR -> eol char */
15204887Schin ott.c_cc[VEOL2] = tt->c_cc[VEOF]; /* EOF -> eol char */
15214887Schin }
15224887Schin switch(mode)
15234887Schin {
15244887Schin case TCSANOW:
15254887Schin mode = TCSETA;
15264887Schin break;
15274887Schin case TCSADRAIN:
15284887Schin mode = TCSETAW;
15294887Schin break;
15304887Schin case TCSAFLUSH:
15314887Schin mode = TCSETAF;
15324887Schin }
15334887Schin return(ioctl(fd,mode,&ott));
15344887Schin }
15354887Schin return(ioctl(fd,mode,tt));
15364887Schin }
15374887Schin #endif /* SHOPT_OLDTERMIO */
15384887Schin
15394887Schin #if KSHELL
15404887Schin /*
15414887Schin * Execute keyboard trap on given buffer <inbuff> of given size <isize>
15424887Schin * <mode> < 0 for vi insert mode
15434887Schin */
15444887Schin static int keytrap(Edit_t *ep,char *inbuff,register int insize, int bufsize, int mode)
15454887Schin {
15464887Schin register char *cp;
15474887Schin int savexit;
15488462SApril.Chin@Sun.COM Shell_t *shp = ep->sh;
15494887Schin #if SHOPT_MULTIBYTE
15504887Schin char buff[MAXLINE];
15514887Schin ed_external(ep->e_inbuf,cp=buff);
15524887Schin #else
15534887Schin cp = ep->e_inbuf;
15544887Schin #endif /* SHOPT_MULTIBYTE */
15554887Schin inbuff[insize] = 0;
15564887Schin ep->e_col = ep->e_cur;
15574887Schin if(mode== -2)
15584887Schin {
15594887Schin ep->e_col++;
15604887Schin *ep->e_vi_insert = ESC;
15614887Schin }
15624887Schin else
15634887Schin *ep->e_vi_insert = 0;
15644887Schin nv_putval(ED_CHRNOD,inbuff,NV_NOFREE);
15654887Schin nv_putval(ED_COLNOD,(char*)&ep->e_col,NV_NOFREE|NV_INTEGER);
15664887Schin nv_putval(ED_TXTNOD,(char*)cp,NV_NOFREE);
15674887Schin nv_putval(ED_MODENOD,ep->e_vi_insert,NV_NOFREE);
15688462SApril.Chin@Sun.COM savexit = shp->savexit;
15698462SApril.Chin@Sun.COM sh_trap(shp->st.trap[SH_KEYTRAP],0);
15708462SApril.Chin@Sun.COM shp->savexit = savexit;
15714887Schin if((cp = nv_getval(ED_CHRNOD)) == inbuff)
15724887Schin nv_unset(ED_CHRNOD);
15738462SApril.Chin@Sun.COM else if(bufsize>0)
15744887Schin {
15754887Schin strncpy(inbuff,cp,bufsize);
15768462SApril.Chin@Sun.COM inbuff[bufsize-1]='\0';
15774887Schin insize = strlen(inbuff);
15784887Schin }
15798462SApril.Chin@Sun.COM else
15808462SApril.Chin@Sun.COM insize = 0;
15814887Schin nv_unset(ED_TXTNOD);
15824887Schin return(insize);
15834887Schin }
15844887Schin #endif /* KSHELL */
15854887Schin
15864887Schin void *ed_open(Shell_t *shp)
15874887Schin {
15884887Schin Edit_t *ed = newof(0,Edit_t,1,0);
15894887Schin ed->sh = shp;
15904887Schin strcpy(ed->e_macro,"_??");
15914887Schin return((void*)ed);
15924887Schin }
1593