14887Schin /*********************************************************************** 24887Schin * * 34887Schin * This software is part of the ast package * 4*10898Sroland.mainz@nrubsig.org * Copyright (c) 1982-2009 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 45*10898Sroland.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 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 { 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 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 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 */ 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; 821*10898Sroland.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 } 860*10898Sroland.mainz@nrubsig.org if(sh_isoption(SH_EMACS) || sh_isoption(SH_VI)) 861*10898Sroland.mainz@nrubsig.org buff[0] = cntl('L'); 8628462SApril.Chin@Sun.COM return(1); 8638462SApril.Chin@Sun.COM } 864*10898Sroland.mainz@nrubsig.org else 865*10898Sroland.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