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