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