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