14887Schin /*********************************************************************** 24887Schin * * 34887Schin * This software is part of the ast package * 4*8462SApril.Chin@Sun.COM * Copyright (c) 1982-2008 AT&T Intellectual Property * 54887Schin * and is licensed under the * 64887Schin * Common Public License, Version 1.0 * 7*8462SApril.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 <ctype.h> 344887Schin #include "FEATURE/options" 354887Schin #include "FEATURE/time" 364887Schin #include "FEATURE/cmds" 374887Schin #ifdef _hdr_utime 384887Schin # include <utime.h> 394887Schin # include <ls.h> 404887Schin #endif 414887Schin 424887Schin #if KSHELL 434887Schin # include "defs.h" 444887Schin # include "variables.h" 454887Schin #else 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 56*8462SApril.Chin@Sun.COM 57*8462SApril.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 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 */ 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 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 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 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 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 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 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 */ 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 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 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 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 5864887Schin void ed_setup(register Edit_t *ep, int fd, int reedit) 5874887Schin { 588*8462SApril.Chin@Sun.COM Shell_t *shp = ep->sh; 5894887Schin register char *pp; 590*8462SApril.Chin@Sun.COM register char *last, *prev; 5914887Schin char *ppmax; 5924887Schin int myquote = 0, n; 593*8462SApril.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 598*8462SApril.Chin@Sun.COM if(!(shp->sigflag[SIGWINCH]&SH_SIGFAULT)) 5994887Schin { 6004887Schin signal(SIGWINCH,sh_fault); 601*8462SApril.Chin@Sun.COM shp->sigflag[SIGWINCH] |= SH_SIGFAULT; 6024887Schin } 603*8462SApril.Chin@Sun.COM pp = shp->st.trapcom[SIGWINCH]; 604*8462SApril.Chin@Sun.COM shp->st.trapcom[SIGWINCH] = 0; 6054887Schin sh_fault(SIGWINCH); 606*8462SApril.Chin@Sun.COM shp->st.trapcom[SIGWINCH] = pp; 607*8462SApril.Chin@Sun.COM ep->sh->winch = 0; 6084887Schin #endif 6094887Schin #if KSHELL 6104887Schin ep->e_stkptr = stakptr(0); 6114887Schin ep->e_stkoff = staktell(); 612*8462SApril.Chin@Sun.COM if(!(last = shp->prompt)) 6134887Schin last = ""; 614*8462SApril.Chin@Sun.COM shp->prompt = 0; 6154887Schin #else 6164887Schin last = ep->e_prbuff; 6174887Schin #endif /* KSHELL */ 618*8462SApril.Chin@Sun.COM if(shp->hist_ptr) 6194887Schin { 620*8462SApril.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; 641*8462SApril.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; 652*8462SApril.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 } 661*8462SApril.Chin@Sun.COM if(c==0 || c==ESC || c=='\r') 662*8462SApril.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 { 705*8462SApril.Chin@Sun.COM if(inquote) 706*8462SApril.Chin@Sun.COM qlen++; 707*8462SApril.Chin@Sun.COM else if(!is_print(c)) 7084887Schin ep->e_crlf = 0; 709*8462SApril.Chin@Sun.COM if((qwid = last - prev) > 1) 710*8462SApril.Chin@Sun.COM qlen += qwid - mbwidth(c); 711*8462SApril.Chin@Sun.COM while(prev < last && pp < ppmax) 712*8462SApril.Chin@Sun.COM *pp++ = *prev++; 7134887Schin } 714*8462SApril.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; 720*8462SApril.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) 753*8462SApril.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 763*8462SApril.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 777*8462SApril.Chin@Sun.COM static void ed_putstring(register Edit_t *ep, const char *str) 778*8462SApril.Chin@Sun.COM { 779*8462SApril.Chin@Sun.COM register int c; 780*8462SApril.Chin@Sun.COM while(c = *str++) 781*8462SApril.Chin@Sun.COM ed_putchar(ep,c); 782*8462SApril.Chin@Sun.COM } 783*8462SApril.Chin@Sun.COM 784*8462SApril.Chin@Sun.COM static void ed_nputchar(register Edit_t *ep, int n, int c) 785*8462SApril.Chin@Sun.COM { 786*8462SApril.Chin@Sun.COM while(n-->0) 787*8462SApril.Chin@Sun.COM ed_putchar(ep,c); 788*8462SApril.Chin@Sun.COM } 789*8462SApril.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 */ 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'); 804*8462SApril.Chin@Sun.COM Shell_t *shp = ep->sh; 8054887Schin int mode = -1; 806*8462SApril.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; 816*8462SApril.Chin@Sun.COM shp->waitevent = 0; 8174887Schin while(rv<0 && errno==EINTR) 8184887Schin { 819*8462SApril.Chin@Sun.COM if(shp->trapnote&(SH_SIGSET|SH_SIGTRAP)) 8204887Schin goto done; 821*8462SApril.Chin@Sun.COM if(ep->sh->winch) 822*8462SApril.Chin@Sun.COM { 823*8462SApril.Chin@Sun.COM Edpos_t lastpos; 824*8462SApril.Chin@Sun.COM int n, rows, newsize; 825*8462SApril.Chin@Sun.COM /* move cursor to start of first line */ 826*8462SApril.Chin@Sun.COM ed_putchar(ep,'\r'); 827*8462SApril.Chin@Sun.COM ed_flush(ep); 828*8462SApril.Chin@Sun.COM astwinsize(2,&rows,&newsize); 829*8462SApril.Chin@Sun.COM n = (ep->e_plen+ep->e_cur)/++ep->e_winsz; 830*8462SApril.Chin@Sun.COM while(n--) 831*8462SApril.Chin@Sun.COM ed_putstring(ep,CURSOR_UP); 832*8462SApril.Chin@Sun.COM if(ep->e_multiline && newsize>ep->e_winsz && (lastpos.line=(ep->e_plen+ep->e_peol)/ep->e_winsz)) 833*8462SApril.Chin@Sun.COM { 834*8462SApril.Chin@Sun.COM /* clear the current command line */ 835*8462SApril.Chin@Sun.COM n = lastpos.line; 836*8462SApril.Chin@Sun.COM while(lastpos.line--) 837*8462SApril.Chin@Sun.COM { 838*8462SApril.Chin@Sun.COM ed_nputchar(ep,ep->e_winsz,' '); 839*8462SApril.Chin@Sun.COM ed_putchar(ep,'\n'); 840*8462SApril.Chin@Sun.COM } 841*8462SApril.Chin@Sun.COM ed_nputchar(ep,ep->e_winsz,' '); 842*8462SApril.Chin@Sun.COM while(n--) 843*8462SApril.Chin@Sun.COM ed_putstring(ep,CURSOR_UP); 844*8462SApril.Chin@Sun.COM } 845*8462SApril.Chin@Sun.COM ep->sh->winch = 0; 846*8462SApril.Chin@Sun.COM ed_flush(ep); 847*8462SApril.Chin@Sun.COM sh_delay(.05); 848*8462SApril.Chin@Sun.COM astwinsize(2,&rows,&newsize); 849*8462SApril.Chin@Sun.COM ep->e_winsz = newsize-1; 850*8462SApril.Chin@Sun.COM if(!ep->e_multiline && ep->e_wsize < MAXLINE) 851*8462SApril.Chin@Sun.COM ep->e_wsize = ep->e_winsz-2; 852*8462SApril.Chin@Sun.COM ep->e_nocrnl=1; 853*8462SApril.Chin@Sun.COM if(*ep->e_vi_insert) 854*8462SApril.Chin@Sun.COM { 855*8462SApril.Chin@Sun.COM buff[0] = ESC; 856*8462SApril.Chin@Sun.COM buff[1] = cntl('L'); 857*8462SApril.Chin@Sun.COM buff[2] = 'a'; 858*8462SApril.Chin@Sun.COM return(3); 859*8462SApril.Chin@Sun.COM } 860*8462SApril.Chin@Sun.COM buff[0] = cntl('L'); 861*8462SApril.Chin@Sun.COM return(1); 862*8462SApril.Chin@Sun.COM } 8634887Schin /* an interrupt that should be ignored */ 8644887Schin errno = 0; 8654887Schin if(!waitevent || (rv=(*waitevent)(fd,-1L,0))>=0) 8664887Schin rv = sfpkrd(fd,buff,size,delim,-1L,mode); 8674887Schin } 8684887Schin if(rv < 0) 8694887Schin { 8704887Schin #ifdef _hdr_utime 8714887Schin # define fixtime() if(isdevtty)utime(ep->e_tty,&utimes) 8724887Schin int isdevtty=0; 8734887Schin struct stat statb; 8744887Schin struct utimbuf utimes; 8754887Schin if(errno==0 && !ep->e_tty) 8764887Schin { 8774887Schin if((ep->e_tty=ttyname(fd)) && stat(ep->e_tty,&statb)>=0) 8784887Schin { 8794887Schin ep->e_tty_ino = statb.st_ino; 8804887Schin ep->e_tty_dev = statb.st_dev; 8814887Schin } 8824887Schin } 8834887Schin if(ep->e_tty_ino && fstat(fd,&statb)>=0 && statb.st_ino==ep->e_tty_ino && statb.st_dev==ep->e_tty_dev) 8844887Schin { 8854887Schin utimes.actime = statb.st_atime; 8864887Schin utimes.modtime = statb.st_mtime; 8874887Schin isdevtty=1; 8884887Schin } 8894887Schin #else 8904887Schin # define fixtime() 8914887Schin #endif /* _hdr_utime */ 8924887Schin while(1) 8934887Schin { 8944887Schin rv = read(fd,buff,size); 8954887Schin if(rv>=0 || errno!=EINTR) 8964887Schin break; 897*8462SApril.Chin@Sun.COM if(shp->trapnote&(SH_SIGSET|SH_SIGTRAP)) 8984887Schin goto done; 8994887Schin /* an interrupt that should be ignored */ 9004887Schin fixtime(); 9014887Schin } 9024887Schin } 9034887Schin else if(rv>=0 && mode>0) 9044887Schin rv = read(fd,buff,rv>0?rv:1); 9054887Schin done: 906*8462SApril.Chin@Sun.COM shp->waitevent = waitevent; 9074887Schin sh_offstate(SH_TTYWAIT); 9084887Schin return(rv); 9094887Schin } 9104887Schin 9114887Schin 9124887Schin /* 9134887Schin * put <string> of length <nbyte> onto lookahead stack 9144887Schin * if <type> is non-zero, the negation of the character is put 9154887Schin * onto the stack so that it can be checked for KEYTRAP 9164887Schin * putstack() returns 1 except when in the middle of a multi-byte char 9174887Schin */ 9184887Schin static int putstack(Edit_t *ep,char string[], register int nbyte, int type) 9194887Schin { 9204887Schin register int c; 9214887Schin #if SHOPT_MULTIBYTE 9224887Schin char *endp, *p=string; 9234887Schin int size, offset = ep->e_lookahead + nbyte; 9244887Schin *(endp = &p[nbyte]) = 0; 9254887Schin endp = &p[nbyte]; 9264887Schin do 9274887Schin { 9284887Schin c = (int)((*p) & STRIP); 9294887Schin if(c< 0x80 && c!='<') 9304887Schin { 9314887Schin if (type) 9324887Schin c = -c; 9334887Schin # ifndef CBREAK 9344887Schin if(c == '\0') 9354887Schin { 9364887Schin /*** user break key ***/ 9374887Schin ep->e_lookahead = 0; 9384887Schin # if KSHELL 9394887Schin sh_fault(SIGINT); 9404887Schin siglongjmp(ep->e_env, UINTR); 9414887Schin # endif /* KSHELL */ 9424887Schin } 9434887Schin # endif /* CBREAK */ 9444887Schin 9454887Schin } 9464887Schin else 9474887Schin { 9484887Schin again: 9494887Schin if((c=mbchar(p)) >=0) 9504887Schin { 9514887Schin p--; /* incremented below */ 9524887Schin if(type) 9534887Schin c = -c; 9544887Schin } 9554887Schin #ifdef EILSEQ 9564887Schin else if(errno == EILSEQ) 9574887Schin errno = 0; 9584887Schin #endif 9594887Schin else if((endp-p) < mbmax()) 9604887Schin { 9614887Schin if ((c=ed_read(ep,ep->e_fd,endp, 1,0)) == 1) 9624887Schin { 9634887Schin *++endp = 0; 9644887Schin goto again; 9654887Schin } 9664887Schin return(c); 9674887Schin } 9684887Schin else 9694887Schin { 9704887Schin ed_ringbell(); 9714887Schin c = -(int)((*p) & STRIP); 9724887Schin offset += mbmax()-1; 9734887Schin } 9744887Schin } 9754887Schin ep->e_lbuf[--offset] = c; 9764887Schin p++; 9774887Schin } 9784887Schin while (p < endp); 9794887Schin /* shift lookahead buffer if necessary */ 9804887Schin if(offset -= ep->e_lookahead) 9814887Schin { 9824887Schin for(size=offset;size < nbyte;size++) 9834887Schin ep->e_lbuf[ep->e_lookahead+size-offset] = ep->e_lbuf[ep->e_lookahead+size]; 9844887Schin } 9854887Schin ep->e_lookahead += nbyte-offset; 9864887Schin #else 9874887Schin while (nbyte > 0) 9884887Schin { 9894887Schin c = string[--nbyte] & STRIP; 9904887Schin ep->e_lbuf[ep->e_lookahead++] = (type?-c:c); 9914887Schin # ifndef CBREAK 9924887Schin if( c == '\0' ) 9934887Schin { 9944887Schin /*** user break key ***/ 9954887Schin ep->e_lookahead = 0; 9964887Schin # if KSHELL 9974887Schin sh_fault(SIGINT); 9984887Schin siglongjmp(ep->e_env, UINTR); 9994887Schin # endif /* KSHELL */ 10004887Schin } 10014887Schin # endif /* CBREAK */ 10024887Schin } 10034887Schin #endif /* SHOPT_MULTIBYTE */ 10044887Schin return(1); 10054887Schin } 10064887Schin 10074887Schin /* 10084887Schin * routine to perform read from terminal for vi and emacs mode 10094887Schin * <mode> can be one of the following: 10104887Schin * -2 vi insert mode - key binding is in effect 10114887Schin * -1 vi control mode - key binding is in effect 10124887Schin * 0 normal command mode - key binding is in effect 10134887Schin * 1 edit keys not mapped 10144887Schin * 2 Next key is literal 10154887Schin */ 10164887Schin int ed_getchar(register Edit_t *ep,int mode) 10174887Schin { 10184887Schin register int n, c; 10194887Schin char readin[LOOKAHEAD+1]; 10204887Schin if(!ep->e_lookahead) 10214887Schin { 10224887Schin ed_flush(ep); 10234887Schin ep->e_inmacro = 0; 10244887Schin /* The while is necessary for reads of partial multbyte chars */ 1025*8462SApril.Chin@Sun.COM *ep->e_vi_insert = (mode==-2); 10264887Schin if((n=ed_read(ep,ep->e_fd,readin,-LOOKAHEAD,0)) > 0) 10274887Schin n = putstack(ep,readin,n,1); 1028*8462SApril.Chin@Sun.COM *ep->e_vi_insert = 0; 10294887Schin } 10304887Schin if(ep->e_lookahead) 10314887Schin { 10324887Schin /* check for possible key mapping */ 10334887Schin if((c = ep->e_lbuf[--ep->e_lookahead]) < 0) 10344887Schin { 1035*8462SApril.Chin@Sun.COM if(mode<=0 && ep->sh->st.trap[SH_KEYTRAP]) 10364887Schin { 10374887Schin n=1; 10384887Schin if((readin[0]= -c) == ESC) 10394887Schin { 10404887Schin while(1) 10414887Schin { 10424887Schin if(!ep->e_lookahead) 10434887Schin { 10444887Schin if((c=sfpkrd(ep->e_fd,readin+n,1,'\r',(mode?400L:-1L),0))>0) 10454887Schin putstack(ep,readin+n,c,1); 10464887Schin } 10474887Schin if(!ep->e_lookahead) 10484887Schin break; 10494887Schin if((c=ep->e_lbuf[--ep->e_lookahead])>=0) 10504887Schin { 10514887Schin ep->e_lookahead++; 10524887Schin break; 10534887Schin } 10544887Schin c = -c; 10554887Schin readin[n++] = c; 10564887Schin if(c>='0' && c<='9' && n>2) 10574887Schin continue; 10584887Schin if(n>2 || (c!= '[' && c!= 'O')) 10594887Schin break; 10604887Schin } 10614887Schin } 10624887Schin if(n=keytrap(ep,readin,n,LOOKAHEAD-n,mode)) 10634887Schin { 10644887Schin putstack(ep,readin,n,0); 10654887Schin c = ep->e_lbuf[--ep->e_lookahead]; 10664887Schin } 10674887Schin else 10684887Schin c = ed_getchar(ep,mode); 10694887Schin } 10704887Schin else 10714887Schin c = -c; 10724887Schin } 10734887Schin /*** map '\r' to '\n' ***/ 10744887Schin if(c == '\r' && mode!=2) 10754887Schin c = '\n'; 10764887Schin if(ep->e_tabcount && !(c=='\t'||c==ESC || c=='\\' || c=='=' || c==cntl('L') || isdigit(c))) 10774887Schin ep->e_tabcount = 0; 10784887Schin } 10794887Schin else 10804887Schin siglongjmp(ep->e_env,(n==0?UEOF:UINTR)); 10814887Schin return(c); 10824887Schin } 10834887Schin 10844887Schin void ed_ungetchar(Edit_t *ep,register int c) 10854887Schin { 10864887Schin if (ep->e_lookahead < LOOKAHEAD) 10874887Schin ep->e_lbuf[ep->e_lookahead++] = c; 10884887Schin return; 10894887Schin } 10904887Schin 10914887Schin /* 10924887Schin * put a character into the output buffer 10934887Schin */ 10944887Schin 10954887Schin void ed_putchar(register Edit_t *ep,register int c) 10964887Schin { 10974887Schin char buf[8]; 10984887Schin register char *dp = ep->e_outptr; 10994887Schin register int i,size=1; 1100*8462SApril.Chin@Sun.COM if(!dp) 1101*8462SApril.Chin@Sun.COM return; 11024887Schin buf[0] = c; 11034887Schin #if SHOPT_MULTIBYTE 11044887Schin /* check for place holder */ 11054887Schin if(c == MARKER) 11064887Schin return; 11074887Schin if((size = mbconv(buf, (wchar_t)c)) > 1) 11084887Schin { 11094887Schin for (i = 0; i < (size-1); i++) 11104887Schin *dp++ = buf[i]; 11114887Schin c = buf[i]; 11124887Schin } 11134887Schin else 11144887Schin { 11154887Schin buf[0] = c; 11164887Schin size = 1; 11174887Schin } 11184887Schin #endif /* SHOPT_MULTIBYTE */ 11194887Schin if (buf[0] == '_' && size==1) 11204887Schin { 11214887Schin *dp++ = ' '; 11224887Schin *dp++ = '\b'; 11234887Schin } 11244887Schin *dp++ = c; 11254887Schin *dp = '\0'; 11264887Schin if(dp >= ep->e_outlast) 11274887Schin ed_flush(ep); 11284887Schin else 11294887Schin ep->e_outptr = dp; 11304887Schin } 11314887Schin 11324887Schin /* 11334887Schin * returns the line and column corresponding to offset <off> in the physical buffer 11344887Schin * if <cur> is non-zero and <= <off>, then correspodning <curpos> will start the search 11354887Schin */ 11364887Schin Edpos_t ed_curpos(Edit_t *ep,genchar *phys, int off, int cur, Edpos_t curpos) 11374887Schin { 11384887Schin register genchar *sp=phys; 11394887Schin register int c=1, col=ep->e_plen; 11404887Schin Edpos_t pos; 11414887Schin #if SHOPT_MULTIBYTE 11424887Schin char p[16]; 11434887Schin #endif /* SHOPT_MULTIBYTE */ 11444887Schin if(cur && off>=cur) 11454887Schin { 11464887Schin sp += cur; 11474887Schin off -= cur; 11484887Schin pos = curpos; 11494887Schin col = pos.col; 11504887Schin } 11514887Schin else 1152*8462SApril.Chin@Sun.COM { 11534887Schin pos.line = 0; 1154*8462SApril.Chin@Sun.COM while(col > ep->e_winsz) 1155*8462SApril.Chin@Sun.COM { 1156*8462SApril.Chin@Sun.COM pos.line++; 1157*8462SApril.Chin@Sun.COM col -= (ep->e_winsz+1); 1158*8462SApril.Chin@Sun.COM } 1159*8462SApril.Chin@Sun.COM } 11604887Schin while(off-->0) 11614887Schin { 11624887Schin if(c) 11634887Schin c = *sp++; 11644887Schin #if SHOPT_MULTIBYTE 11654887Schin if(c && (mbconv(p, (wchar_t)c))==1 && p[0]=='\n') 11664887Schin #else 11674887Schin if(c=='\n') 11684887Schin #endif /* SHOPT_MULTIBYTE */ 11694887Schin col = 0; 11704887Schin else 11714887Schin col++; 11724887Schin if(col > ep->e_winsz) 11734887Schin col = 0; 11744887Schin if(col==0) 11754887Schin pos.line++; 11764887Schin } 11774887Schin pos.col = col; 11784887Schin return(pos); 11794887Schin } 11804887Schin 11814887Schin int ed_setcursor(register Edit_t *ep,genchar *physical,register int old,register int new,int first) 11824887Schin { 11834887Schin static int oldline; 11844887Schin register int delta; 1185*8462SApril.Chin@Sun.COM int clear = 0; 11864887Schin Edpos_t newpos; 11874887Schin 11884887Schin delta = new - old; 1189*8462SApril.Chin@Sun.COM if(first < 0) 1190*8462SApril.Chin@Sun.COM { 1191*8462SApril.Chin@Sun.COM first = 0; 1192*8462SApril.Chin@Sun.COM clear = 1; 1193*8462SApril.Chin@Sun.COM } 1194*8462SApril.Chin@Sun.COM if( delta == 0 && !clear) 11954887Schin return(new); 11964887Schin if(ep->e_multiline) 11974887Schin { 11984887Schin ep->e_curpos = ed_curpos(ep, physical, old,0,ep->e_curpos); 1199*8462SApril.Chin@Sun.COM if(clear && old>=ep->e_peol && (clear=ep->e_winsz-ep->e_curpos.col)>0) 1200*8462SApril.Chin@Sun.COM { 1201*8462SApril.Chin@Sun.COM ed_nputchar(ep,clear,' '); 1202*8462SApril.Chin@Sun.COM ed_nputchar(ep,clear,'\b'); 1203*8462SApril.Chin@Sun.COM return(new); 1204*8462SApril.Chin@Sun.COM } 12054887Schin newpos = ed_curpos(ep, physical, new,old,ep->e_curpos); 12064887Schin if(ep->e_curpos.col==0 && ep->e_curpos.line>0 && oldline<ep->e_curpos.line && delta<0) 12074887Schin ed_putstring(ep,"\r\n"); 12084887Schin oldline = newpos.line; 12094887Schin if(ep->e_curpos.line > newpos.line) 12104887Schin { 1211*8462SApril.Chin@Sun.COM int n,pline,plen=ep->e_plen; 12124887Schin for(;ep->e_curpos.line > newpos.line; ep->e_curpos.line--) 12134887Schin ed_putstring(ep,CURSOR_UP); 1214*8462SApril.Chin@Sun.COM pline = plen/(ep->e_winsz+1); 1215*8462SApril.Chin@Sun.COM if(newpos.line <= pline) 1216*8462SApril.Chin@Sun.COM plen -= pline*(ep->e_winsz+1); 1217*8462SApril.Chin@Sun.COM else 1218*8462SApril.Chin@Sun.COM plen = 0; 1219*8462SApril.Chin@Sun.COM if((n=plen- ep->e_curpos.col)>0) 12204887Schin { 12214887Schin ep->e_curpos.col += n; 12224887Schin ed_putchar(ep,'\r'); 1223*8462SApril.Chin@Sun.COM if(!ep->e_crlf && pline==0) 12244887Schin ed_putstring(ep,ep->e_prompt); 12254887Schin else 12264887Schin { 1227*8462SApril.Chin@Sun.COM int m = ep->e_winsz+1-plen; 12284887Schin ed_putchar(ep,'\n'); 1229*8462SApril.Chin@Sun.COM n = plen; 12304887Schin if(m < ed_genlen(physical)) 12314887Schin { 12324887Schin while(physical[m] && n-->0) 12334887Schin ed_putchar(ep,physical[m++]); 12344887Schin } 1235*8462SApril.Chin@Sun.COM ed_nputchar(ep,n,' '); 12364887Schin ed_putstring(ep,CURSOR_UP); 12374887Schin } 12384887Schin } 12394887Schin } 12404887Schin else if(ep->e_curpos.line < newpos.line) 12414887Schin { 1242*8462SApril.Chin@Sun.COM ed_nputchar(ep, newpos.line-ep->e_curpos.line,'\n'); 1243*8462SApril.Chin@Sun.COM ep->e_curpos.line = newpos.line; 12444887Schin ed_putchar(ep,'\r'); 12454887Schin ep->e_curpos.col = 0; 12464887Schin } 12474887Schin delta = newpos.col - ep->e_curpos.col; 12484887Schin old = new - delta; 12494887Schin } 12504887Schin else 12514887Schin newpos.line=0; 12524887Schin if(delta<0) 12534887Schin { 1254*8462SApril.Chin@Sun.COM int bs= newpos.line && ep->e_plen>ep->e_winsz; 12554887Schin /*** move to left ***/ 12564887Schin delta = -delta; 12574887Schin /*** attempt to optimize cursor movement ***/ 1258*8462SApril.Chin@Sun.COM if(!ep->e_crlf || bs || (2*delta <= ((old-first)+(newpos.line?0:ep->e_plen))) ) 12594887Schin { 1260*8462SApril.Chin@Sun.COM ed_nputchar(ep,delta,'\b'); 1261*8462SApril.Chin@Sun.COM delta = 0; 12624887Schin } 12634887Schin else 12644887Schin { 12654887Schin if(newpos.line==0) 12664887Schin ed_putstring(ep,ep->e_prompt); 1267*8462SApril.Chin@Sun.COM else 1268*8462SApril.Chin@Sun.COM { 1269*8462SApril.Chin@Sun.COM first = 1+(newpos.line*ep->e_winsz - ep->e_plen); 1270*8462SApril.Chin@Sun.COM ed_putchar(ep,'\r'); 1271*8462SApril.Chin@Sun.COM } 12724887Schin old = first; 12734887Schin delta = new-first; 12744887Schin } 12754887Schin } 12764887Schin while(delta-->0) 12774887Schin ed_putchar(ep,physical[old++]); 12784887Schin return(new); 12794887Schin } 12804887Schin 12814887Schin /* 12824887Schin * copy virtual to physical and return the index for cursor in physical buffer 12834887Schin */ 12844887Schin int ed_virt_to_phys(Edit_t *ep,genchar *virt,genchar *phys,int cur,int voff,int poff) 12854887Schin { 12864887Schin register genchar *sp = virt; 12874887Schin register genchar *dp = phys; 12884887Schin register int c; 12894887Schin genchar *curp = sp + cur; 12904887Schin genchar *dpmax = phys+MAXLINE; 12914887Schin int d, r; 12924887Schin sp += voff; 12934887Schin dp += poff; 12944887Schin for(r=poff;c= *sp;sp++) 12954887Schin { 12964887Schin if(curp == sp) 12974887Schin r = dp - phys; 12984887Schin #if SHOPT_MULTIBYTE 12994887Schin d = mbwidth((wchar_t)c); 13004887Schin if(d==1 && is_cntrl(c)) 13014887Schin d = -1; 13024887Schin if(d>1) 13034887Schin { 13044887Schin /* multiple width character put in place holders */ 13054887Schin *dp++ = c; 13064887Schin while(--d >0) 13074887Schin *dp++ = MARKER; 13084887Schin /* in vi mode the cursor is at the last character */ 13094887Schin if(dp>=dpmax) 13104887Schin break; 13114887Schin continue; 13124887Schin } 13134887Schin else 13144887Schin #else 13154887Schin d = (is_cntrl(c)?-1:1); 13164887Schin #endif /* SHOPT_MULTIBYTE */ 13174887Schin if(d<0) 13184887Schin { 13194887Schin if(c=='\t') 13204887Schin { 13214887Schin c = dp-phys; 13224887Schin if(sh_isoption(SH_VI)) 13234887Schin c += ep->e_plen; 13244887Schin c = TABSIZE - c%TABSIZE; 13254887Schin while(--c>0) 13264887Schin *dp++ = ' '; 13274887Schin c = ' '; 13284887Schin } 13294887Schin else 13304887Schin { 13314887Schin *dp++ = '^'; 13324887Schin c = printchar(c); 13334887Schin } 13344887Schin /* in vi mode the cursor is at the last character */ 13354887Schin if(curp == sp && sh_isoption(SH_VI)) 13364887Schin r = dp - phys; 13374887Schin } 13384887Schin *dp++ = c; 13394887Schin if(dp>=dpmax) 13404887Schin break; 13414887Schin } 13424887Schin *dp = 0; 1343*8462SApril.Chin@Sun.COM ep->e_peol = dp-phys; 13444887Schin return(r); 13454887Schin } 13464887Schin 13474887Schin #if SHOPT_MULTIBYTE 13484887Schin /* 13494887Schin * convert external representation <src> to an array of genchars <dest> 13504887Schin * <src> and <dest> can be the same 13514887Schin * returns number of chars in dest 13524887Schin */ 13534887Schin 13544887Schin int ed_internal(const char *src, genchar *dest) 13554887Schin { 13564887Schin register const unsigned char *cp = (unsigned char *)src; 13574887Schin register int c; 13584887Schin register wchar_t *dp = (wchar_t*)dest; 13594887Schin if(dest == (genchar*)roundof(cp-(unsigned char*)0,sizeof(genchar))) 13604887Schin { 13614887Schin genchar buffer[MAXLINE]; 13624887Schin c = ed_internal(src,buffer); 13634887Schin ed_gencpy((genchar*)dp,buffer); 13644887Schin return(c); 13654887Schin } 13664887Schin while(*cp) 13674887Schin *dp++ = mbchar(cp); 13684887Schin *dp = 0; 13694887Schin return(dp-(wchar_t*)dest); 13704887Schin } 13714887Schin 13724887Schin /* 13734887Schin * convert internal representation <src> into character array <dest>. 13744887Schin * The <src> and <dest> may be the same. 13754887Schin * returns number of chars in dest. 13764887Schin */ 13774887Schin 13784887Schin int ed_external(const genchar *src, char *dest) 13794887Schin { 13804887Schin register genchar wc; 13814887Schin register int c,size; 13824887Schin register char *dp = dest; 13834887Schin char *dpmax = dp+sizeof(genchar)*MAXLINE-2; 13844887Schin if((char*)src == dp) 13854887Schin { 13864887Schin char buffer[MAXLINE*sizeof(genchar)]; 13874887Schin c = ed_external(src,buffer); 13884887Schin 13894887Schin #ifdef _lib_wcscpy 13904887Schin wcscpy((wchar_t *)dest,(const wchar_t *)buffer); 13914887Schin #else 13924887Schin strcpy(dest,buffer); 13934887Schin #endif 13944887Schin return(c); 13954887Schin } 13964887Schin while((wc = *src++) && dp<dpmax) 13974887Schin { 13984887Schin if((size = mbconv(dp, wc)) < 0) 13994887Schin { 14004887Schin /* copy the character as is */ 14014887Schin size = 1; 14024887Schin *dp = wc; 14034887Schin } 14044887Schin dp += size; 14054887Schin } 14064887Schin *dp = 0; 14074887Schin return(dp-dest); 14084887Schin } 14094887Schin 14104887Schin /* 14114887Schin * copy <sp> to <dp> 14124887Schin */ 14134887Schin 14144887Schin void ed_gencpy(genchar *dp,const genchar *sp) 14154887Schin { 14164887Schin dp = (genchar*)roundof((char*)dp-(char*)0,sizeof(genchar)); 14174887Schin sp = (const genchar*)roundof((char*)sp-(char*)0,sizeof(genchar)); 14184887Schin while(*dp++ = *sp++); 14194887Schin } 14204887Schin 14214887Schin /* 14224887Schin * copy at most <n> items from <sp> to <dp> 14234887Schin */ 14244887Schin 14254887Schin void ed_genncpy(register genchar *dp,register const genchar *sp, int n) 14264887Schin { 14274887Schin dp = (genchar*)roundof((char*)dp-(char*)0,sizeof(genchar)); 14284887Schin sp = (const genchar*)roundof((char*)sp-(char*)0,sizeof(genchar)); 14294887Schin while(n-->0 && (*dp++ = *sp++)); 14304887Schin } 14314887Schin 14324887Schin /* 14334887Schin * find the string length of <str> 14344887Schin */ 14354887Schin 14364887Schin int ed_genlen(register const genchar *str) 14374887Schin { 14384887Schin register const genchar *sp = str; 14394887Schin sp = (const genchar*)roundof((char*)sp-(char*)0,sizeof(genchar)); 14404887Schin while(*sp++); 14414887Schin return(sp-str-1); 14424887Schin } 14434887Schin #endif /* SHOPT_MULTIBYTE */ 14444887Schin #endif /* SHOPT_ESH || SHOPT_VSH */ 14454887Schin 14464887Schin #ifdef future 14474887Schin /* 14484887Schin * returns 1 when <n> bytes starting at <a> and <b> are equal 14494887Schin */ 14504887Schin static int compare(register const char *a,register const char *b,register int n) 14514887Schin { 14524887Schin while(n-->0) 14534887Schin { 14544887Schin if(*a++ != *b++) 14554887Schin return(0); 14564887Schin } 14574887Schin return(1); 14584887Schin } 14594887Schin #endif 14604887Schin 14614887Schin #if SHOPT_OLDTERMIO 14624887Schin 14634887Schin # include <sys/termio.h> 14644887Schin 14654887Schin #ifndef ECHOCTL 14664887Schin # define ECHOCTL 0 14674887Schin #endif /* !ECHOCTL */ 14684887Schin #define ott ep->e_ott 14694887Schin 14704887Schin /* 14714887Schin * For backward compatibility only 14724887Schin * This version will use termios when possible, otherwise termio 14734887Schin */ 14744887Schin 1475*8462SApril.Chin@Sun.COM int tcgetattr(int fd, struct termios *tt) 14764887Schin { 14774887Schin register Edit_t *ep = (Edit_t*)(sh_getinterp()->ed_context); 14784887Schin register int r,i; 14794887Schin ep->e_tcgeta = 0; 14804887Schin ep->e_echoctl = (ECHOCTL!=0); 14814887Schin if((r=ioctl(fd,TCGETS,tt))>=0 || errno!=EINVAL) 14824887Schin return(r); 14834887Schin if((r=ioctl(fd,TCGETA,&ott)) >= 0) 14844887Schin { 14854887Schin tt->c_lflag = ott.c_lflag; 14864887Schin tt->c_oflag = ott.c_oflag; 14874887Schin tt->c_iflag = ott.c_iflag; 14884887Schin tt->c_cflag = ott.c_cflag; 14894887Schin for(i=0; i<NCC; i++) 14904887Schin tt->c_cc[i] = ott.c_cc[i]; 14914887Schin ep->e_tcgeta++; 14924887Schin ep->e_echoctl = 0; 14934887Schin } 14944887Schin return(r); 14954887Schin } 14964887Schin 1497*8462SApril.Chin@Sun.COM int tcsetattr(int fd,int mode,struct termios *tt) 14984887Schin { 14994887Schin register Edit_t *ep = (Edit_t*)(sh_getinterp()->ed_context); 15004887Schin register int r; 15014887Schin if(ep->e_tcgeta) 15024887Schin { 15034887Schin register int i; 15044887Schin ott.c_lflag = tt->c_lflag; 15054887Schin ott.c_oflag = tt->c_oflag; 15064887Schin ott.c_iflag = tt->c_iflag; 15074887Schin ott.c_cflag = tt->c_cflag; 15084887Schin for(i=0; i<NCC; i++) 15094887Schin ott.c_cc[i] = tt->c_cc[i]; 15104887Schin if(tt->c_lflag&ECHOCTL) 15114887Schin { 15124887Schin ott.c_lflag &= ~(ECHOCTL|IEXTEN); 15134887Schin ott.c_iflag &= ~(IGNCR|ICRNL); 15144887Schin ott.c_iflag |= INLCR; 15154887Schin ott.c_cc[VEOF]= ESC; /* ESC -> eof char */ 15164887Schin ott.c_cc[VEOL] = '\r'; /* CR -> eol char */ 15174887Schin ott.c_cc[VEOL2] = tt->c_cc[VEOF]; /* EOF -> eol char */ 15184887Schin } 15194887Schin switch(mode) 15204887Schin { 15214887Schin case TCSANOW: 15224887Schin mode = TCSETA; 15234887Schin break; 15244887Schin case TCSADRAIN: 15254887Schin mode = TCSETAW; 15264887Schin break; 15274887Schin case TCSAFLUSH: 15284887Schin mode = TCSETAF; 15294887Schin } 15304887Schin return(ioctl(fd,mode,&ott)); 15314887Schin } 15324887Schin return(ioctl(fd,mode,tt)); 15334887Schin } 15344887Schin #endif /* SHOPT_OLDTERMIO */ 15354887Schin 15364887Schin #if KSHELL 15374887Schin /* 15384887Schin * Execute keyboard trap on given buffer <inbuff> of given size <isize> 15394887Schin * <mode> < 0 for vi insert mode 15404887Schin */ 15414887Schin static int keytrap(Edit_t *ep,char *inbuff,register int insize, int bufsize, int mode) 15424887Schin { 15434887Schin register char *cp; 15444887Schin int savexit; 1545*8462SApril.Chin@Sun.COM Shell_t *shp = ep->sh; 15464887Schin #if SHOPT_MULTIBYTE 15474887Schin char buff[MAXLINE]; 15484887Schin ed_external(ep->e_inbuf,cp=buff); 15494887Schin #else 15504887Schin cp = ep->e_inbuf; 15514887Schin #endif /* SHOPT_MULTIBYTE */ 15524887Schin inbuff[insize] = 0; 15534887Schin ep->e_col = ep->e_cur; 15544887Schin if(mode== -2) 15554887Schin { 15564887Schin ep->e_col++; 15574887Schin *ep->e_vi_insert = ESC; 15584887Schin } 15594887Schin else 15604887Schin *ep->e_vi_insert = 0; 15614887Schin nv_putval(ED_CHRNOD,inbuff,NV_NOFREE); 15624887Schin nv_putval(ED_COLNOD,(char*)&ep->e_col,NV_NOFREE|NV_INTEGER); 15634887Schin nv_putval(ED_TXTNOD,(char*)cp,NV_NOFREE); 15644887Schin nv_putval(ED_MODENOD,ep->e_vi_insert,NV_NOFREE); 1565*8462SApril.Chin@Sun.COM savexit = shp->savexit; 1566*8462SApril.Chin@Sun.COM sh_trap(shp->st.trap[SH_KEYTRAP],0); 1567*8462SApril.Chin@Sun.COM shp->savexit = savexit; 15684887Schin if((cp = nv_getval(ED_CHRNOD)) == inbuff) 15694887Schin nv_unset(ED_CHRNOD); 1570*8462SApril.Chin@Sun.COM else if(bufsize>0) 15714887Schin { 15724887Schin strncpy(inbuff,cp,bufsize); 1573*8462SApril.Chin@Sun.COM inbuff[bufsize-1]='\0'; 15744887Schin insize = strlen(inbuff); 15754887Schin } 1576*8462SApril.Chin@Sun.COM else 1577*8462SApril.Chin@Sun.COM insize = 0; 15784887Schin nv_unset(ED_TXTNOD); 15794887Schin return(insize); 15804887Schin } 15814887Schin #endif /* KSHELL */ 15824887Schin 15834887Schin void *ed_open(Shell_t *shp) 15844887Schin { 15854887Schin Edit_t *ed = newof(0,Edit_t,1,0); 15864887Schin ed->sh = shp; 15874887Schin strcpy(ed->e_macro,"_??"); 15884887Schin return((void*)ed); 15894887Schin } 1590