1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1982-2009 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 "FEATURE/options" 34 #include "FEATURE/time" 35 #include "FEATURE/cmds" 36 #ifdef _hdr_utime 37 # include <utime.h> 38 # include <ls.h> 39 #endif 40 41 #if KSHELL 42 # include "defs.h" 43 # include "variables.h" 44 #else 45 # include <ctype.h> 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 && sh_isstate(SH_INTERACTIVE) && (sh_isoption(SH_VI) || sh_isoption(SH_EMACS))) 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 if(sh_isoption(SH_EMACS) || sh_isoption(SH_VI)) 861 buff[0] = cntl('L'); 862 return(1); 863 } 864 else 865 ep->sh->winch = 0; 866 /* an interrupt that should be ignored */ 867 errno = 0; 868 if(!waitevent || (rv=(*waitevent)(fd,-1L,0))>=0) 869 rv = sfpkrd(fd,buff,size,delim,-1L,mode); 870 } 871 if(rv < 0) 872 { 873 #ifdef _hdr_utime 874 # define fixtime() if(isdevtty)utime(ep->e_tty,&utimes) 875 int isdevtty=0; 876 struct stat statb; 877 struct utimbuf utimes; 878 if(errno==0 && !ep->e_tty) 879 { 880 if((ep->e_tty=ttyname(fd)) && stat(ep->e_tty,&statb)>=0) 881 { 882 ep->e_tty_ino = statb.st_ino; 883 ep->e_tty_dev = statb.st_dev; 884 } 885 } 886 if(ep->e_tty_ino && fstat(fd,&statb)>=0 && statb.st_ino==ep->e_tty_ino && statb.st_dev==ep->e_tty_dev) 887 { 888 utimes.actime = statb.st_atime; 889 utimes.modtime = statb.st_mtime; 890 isdevtty=1; 891 } 892 #else 893 # define fixtime() 894 #endif /* _hdr_utime */ 895 while(1) 896 { 897 rv = read(fd,buff,size); 898 if(rv>=0 || errno!=EINTR) 899 break; 900 if(shp->trapnote&(SH_SIGSET|SH_SIGTRAP)) 901 goto done; 902 /* an interrupt that should be ignored */ 903 fixtime(); 904 } 905 } 906 else if(rv>=0 && mode>0) 907 rv = read(fd,buff,rv>0?rv:1); 908 done: 909 shp->waitevent = waitevent; 910 sh_offstate(SH_TTYWAIT); 911 return(rv); 912 } 913 914 915 /* 916 * put <string> of length <nbyte> onto lookahead stack 917 * if <type> is non-zero, the negation of the character is put 918 * onto the stack so that it can be checked for KEYTRAP 919 * putstack() returns 1 except when in the middle of a multi-byte char 920 */ 921 static int putstack(Edit_t *ep,char string[], register int nbyte, int type) 922 { 923 register int c; 924 #if SHOPT_MULTIBYTE 925 char *endp, *p=string; 926 int size, offset = ep->e_lookahead + nbyte; 927 *(endp = &p[nbyte]) = 0; 928 endp = &p[nbyte]; 929 do 930 { 931 c = (int)((*p) & STRIP); 932 if(c< 0x80 && c!='<') 933 { 934 if (type) 935 c = -c; 936 # ifndef CBREAK 937 if(c == '\0') 938 { 939 /*** user break key ***/ 940 ep->e_lookahead = 0; 941 # if KSHELL 942 sh_fault(SIGINT); 943 siglongjmp(ep->e_env, UINTR); 944 # endif /* KSHELL */ 945 } 946 # endif /* CBREAK */ 947 948 } 949 else 950 { 951 again: 952 if((c=mbchar(p)) >=0) 953 { 954 p--; /* incremented below */ 955 if(type) 956 c = -c; 957 } 958 #ifdef EILSEQ 959 else if(errno == EILSEQ) 960 errno = 0; 961 #endif 962 else if((endp-p) < mbmax()) 963 { 964 if ((c=ed_read(ep,ep->e_fd,endp, 1,0)) == 1) 965 { 966 *++endp = 0; 967 goto again; 968 } 969 return(c); 970 } 971 else 972 { 973 ed_ringbell(); 974 c = -(int)((*p) & STRIP); 975 offset += mbmax()-1; 976 } 977 } 978 ep->e_lbuf[--offset] = c; 979 p++; 980 } 981 while (p < endp); 982 /* shift lookahead buffer if necessary */ 983 if(offset -= ep->e_lookahead) 984 { 985 for(size=offset;size < nbyte;size++) 986 ep->e_lbuf[ep->e_lookahead+size-offset] = ep->e_lbuf[ep->e_lookahead+size]; 987 } 988 ep->e_lookahead += nbyte-offset; 989 #else 990 while (nbyte > 0) 991 { 992 c = string[--nbyte] & STRIP; 993 ep->e_lbuf[ep->e_lookahead++] = (type?-c:c); 994 # ifndef CBREAK 995 if( c == '\0' ) 996 { 997 /*** user break key ***/ 998 ep->e_lookahead = 0; 999 # if KSHELL 1000 sh_fault(SIGINT); 1001 siglongjmp(ep->e_env, UINTR); 1002 # endif /* KSHELL */ 1003 } 1004 # endif /* CBREAK */ 1005 } 1006 #endif /* SHOPT_MULTIBYTE */ 1007 return(1); 1008 } 1009 1010 /* 1011 * routine to perform read from terminal for vi and emacs mode 1012 * <mode> can be one of the following: 1013 * -2 vi insert mode - key binding is in effect 1014 * -1 vi control mode - key binding is in effect 1015 * 0 normal command mode - key binding is in effect 1016 * 1 edit keys not mapped 1017 * 2 Next key is literal 1018 */ 1019 int ed_getchar(register Edit_t *ep,int mode) 1020 { 1021 register int n, c; 1022 char readin[LOOKAHEAD+1]; 1023 if(!ep->e_lookahead) 1024 { 1025 ed_flush(ep); 1026 ep->e_inmacro = 0; 1027 /* The while is necessary for reads of partial multbyte chars */ 1028 *ep->e_vi_insert = (mode==-2); 1029 if((n=ed_read(ep,ep->e_fd,readin,-LOOKAHEAD,0)) > 0) 1030 n = putstack(ep,readin,n,1); 1031 *ep->e_vi_insert = 0; 1032 } 1033 if(ep->e_lookahead) 1034 { 1035 /* check for possible key mapping */ 1036 if((c = ep->e_lbuf[--ep->e_lookahead]) < 0) 1037 { 1038 if(mode<=0 && ep->sh->st.trap[SH_KEYTRAP]) 1039 { 1040 n=1; 1041 if((readin[0]= -c) == ESC) 1042 { 1043 while(1) 1044 { 1045 if(!ep->e_lookahead) 1046 { 1047 if((c=sfpkrd(ep->e_fd,readin+n,1,'\r',(mode?400L:-1L),0))>0) 1048 putstack(ep,readin+n,c,1); 1049 } 1050 if(!ep->e_lookahead) 1051 break; 1052 if((c=ep->e_lbuf[--ep->e_lookahead])>=0) 1053 { 1054 ep->e_lookahead++; 1055 break; 1056 } 1057 c = -c; 1058 readin[n++] = c; 1059 if(c>='0' && c<='9' && n>2) 1060 continue; 1061 if(n>2 || (c!= '[' && c!= 'O')) 1062 break; 1063 } 1064 } 1065 if(n=keytrap(ep,readin,n,LOOKAHEAD-n,mode)) 1066 { 1067 putstack(ep,readin,n,0); 1068 c = ep->e_lbuf[--ep->e_lookahead]; 1069 } 1070 else 1071 c = ed_getchar(ep,mode); 1072 } 1073 else 1074 c = -c; 1075 } 1076 /*** map '\r' to '\n' ***/ 1077 if(c == '\r' && mode!=2) 1078 c = '\n'; 1079 if(ep->e_tabcount && !(c=='\t'||c==ESC || c=='\\' || c=='=' || c==cntl('L') || isdigit(c))) 1080 ep->e_tabcount = 0; 1081 } 1082 else 1083 siglongjmp(ep->e_env,(n==0?UEOF:UINTR)); 1084 return(c); 1085 } 1086 1087 void ed_ungetchar(Edit_t *ep,register int c) 1088 { 1089 if (ep->e_lookahead < LOOKAHEAD) 1090 ep->e_lbuf[ep->e_lookahead++] = c; 1091 return; 1092 } 1093 1094 /* 1095 * put a character into the output buffer 1096 */ 1097 1098 void ed_putchar(register Edit_t *ep,register int c) 1099 { 1100 char buf[8]; 1101 register char *dp = ep->e_outptr; 1102 register int i,size=1; 1103 if(!dp) 1104 return; 1105 buf[0] = c; 1106 #if SHOPT_MULTIBYTE 1107 /* check for place holder */ 1108 if(c == MARKER) 1109 return; 1110 if((size = mbconv(buf, (wchar_t)c)) > 1) 1111 { 1112 for (i = 0; i < (size-1); i++) 1113 *dp++ = buf[i]; 1114 c = buf[i]; 1115 } 1116 else 1117 { 1118 buf[0] = c; 1119 size = 1; 1120 } 1121 #endif /* SHOPT_MULTIBYTE */ 1122 if (buf[0] == '_' && size==1) 1123 { 1124 *dp++ = ' '; 1125 *dp++ = '\b'; 1126 } 1127 *dp++ = c; 1128 *dp = '\0'; 1129 if(dp >= ep->e_outlast) 1130 ed_flush(ep); 1131 else 1132 ep->e_outptr = dp; 1133 } 1134 1135 /* 1136 * returns the line and column corresponding to offset <off> in the physical buffer 1137 * if <cur> is non-zero and <= <off>, then correspodning <curpos> will start the search 1138 */ 1139 Edpos_t ed_curpos(Edit_t *ep,genchar *phys, int off, int cur, Edpos_t curpos) 1140 { 1141 register genchar *sp=phys; 1142 register int c=1, col=ep->e_plen; 1143 Edpos_t pos; 1144 #if SHOPT_MULTIBYTE 1145 char p[16]; 1146 #endif /* SHOPT_MULTIBYTE */ 1147 if(cur && off>=cur) 1148 { 1149 sp += cur; 1150 off -= cur; 1151 pos = curpos; 1152 col = pos.col; 1153 } 1154 else 1155 { 1156 pos.line = 0; 1157 while(col > ep->e_winsz) 1158 { 1159 pos.line++; 1160 col -= (ep->e_winsz+1); 1161 } 1162 } 1163 while(off-->0) 1164 { 1165 if(c) 1166 c = *sp++; 1167 #if SHOPT_MULTIBYTE 1168 if(c && (mbconv(p, (wchar_t)c))==1 && p[0]=='\n') 1169 #else 1170 if(c=='\n') 1171 #endif /* SHOPT_MULTIBYTE */ 1172 col = 0; 1173 else 1174 col++; 1175 if(col > ep->e_winsz) 1176 col = 0; 1177 if(col==0) 1178 pos.line++; 1179 } 1180 pos.col = col; 1181 return(pos); 1182 } 1183 1184 int ed_setcursor(register Edit_t *ep,genchar *physical,register int old,register int new,int first) 1185 { 1186 static int oldline; 1187 register int delta; 1188 int clear = 0; 1189 Edpos_t newpos; 1190 1191 delta = new - old; 1192 if(first < 0) 1193 { 1194 first = 0; 1195 clear = 1; 1196 } 1197 if( delta == 0 && !clear) 1198 return(new); 1199 if(ep->e_multiline) 1200 { 1201 ep->e_curpos = ed_curpos(ep, physical, old,0,ep->e_curpos); 1202 if(clear && old>=ep->e_peol && (clear=ep->e_winsz-ep->e_curpos.col)>0) 1203 { 1204 ed_nputchar(ep,clear,' '); 1205 ed_nputchar(ep,clear,'\b'); 1206 return(new); 1207 } 1208 newpos = ed_curpos(ep, physical, new,old,ep->e_curpos); 1209 if(ep->e_curpos.col==0 && ep->e_curpos.line>0 && oldline<ep->e_curpos.line && delta<0) 1210 ed_putstring(ep,"\r\n"); 1211 oldline = newpos.line; 1212 if(ep->e_curpos.line > newpos.line) 1213 { 1214 int n,pline,plen=ep->e_plen; 1215 for(;ep->e_curpos.line > newpos.line; ep->e_curpos.line--) 1216 ed_putstring(ep,CURSOR_UP); 1217 pline = plen/(ep->e_winsz+1); 1218 if(newpos.line <= pline) 1219 plen -= pline*(ep->e_winsz+1); 1220 else 1221 plen = 0; 1222 if((n=plen- ep->e_curpos.col)>0) 1223 { 1224 ep->e_curpos.col += n; 1225 ed_putchar(ep,'\r'); 1226 if(!ep->e_crlf && pline==0) 1227 ed_putstring(ep,ep->e_prompt); 1228 else 1229 { 1230 int m = ep->e_winsz+1-plen; 1231 ed_putchar(ep,'\n'); 1232 n = plen; 1233 if(m < ed_genlen(physical)) 1234 { 1235 while(physical[m] && n-->0) 1236 ed_putchar(ep,physical[m++]); 1237 } 1238 ed_nputchar(ep,n,' '); 1239 ed_putstring(ep,CURSOR_UP); 1240 } 1241 } 1242 } 1243 else if(ep->e_curpos.line < newpos.line) 1244 { 1245 ed_nputchar(ep, newpos.line-ep->e_curpos.line,'\n'); 1246 ep->e_curpos.line = newpos.line; 1247 ed_putchar(ep,'\r'); 1248 ep->e_curpos.col = 0; 1249 } 1250 delta = newpos.col - ep->e_curpos.col; 1251 old = new - delta; 1252 } 1253 else 1254 newpos.line=0; 1255 if(delta<0) 1256 { 1257 int bs= newpos.line && ep->e_plen>ep->e_winsz; 1258 /*** move to left ***/ 1259 delta = -delta; 1260 /*** attempt to optimize cursor movement ***/ 1261 if(!ep->e_crlf || bs || (2*delta <= ((old-first)+(newpos.line?0:ep->e_plen))) ) 1262 { 1263 ed_nputchar(ep,delta,'\b'); 1264 delta = 0; 1265 } 1266 else 1267 { 1268 if(newpos.line==0) 1269 ed_putstring(ep,ep->e_prompt); 1270 else 1271 { 1272 first = 1+(newpos.line*ep->e_winsz - ep->e_plen); 1273 ed_putchar(ep,'\r'); 1274 } 1275 old = first; 1276 delta = new-first; 1277 } 1278 } 1279 while(delta-->0) 1280 ed_putchar(ep,physical[old++]); 1281 return(new); 1282 } 1283 1284 /* 1285 * copy virtual to physical and return the index for cursor in physical buffer 1286 */ 1287 int ed_virt_to_phys(Edit_t *ep,genchar *virt,genchar *phys,int cur,int voff,int poff) 1288 { 1289 register genchar *sp = virt; 1290 register genchar *dp = phys; 1291 register int c; 1292 genchar *curp = sp + cur; 1293 genchar *dpmax = phys+MAXLINE; 1294 int d, r; 1295 sp += voff; 1296 dp += poff; 1297 for(r=poff;c= *sp;sp++) 1298 { 1299 if(curp == sp) 1300 r = dp - phys; 1301 #if SHOPT_MULTIBYTE 1302 d = mbwidth((wchar_t)c); 1303 if(d==1 && is_cntrl(c)) 1304 d = -1; 1305 if(d>1) 1306 { 1307 /* multiple width character put in place holders */ 1308 *dp++ = c; 1309 while(--d >0) 1310 *dp++ = MARKER; 1311 /* in vi mode the cursor is at the last character */ 1312 if(dp>=dpmax) 1313 break; 1314 continue; 1315 } 1316 else 1317 #else 1318 d = (is_cntrl(c)?-1:1); 1319 #endif /* SHOPT_MULTIBYTE */ 1320 if(d<0) 1321 { 1322 if(c=='\t') 1323 { 1324 c = dp-phys; 1325 if(sh_isoption(SH_VI)) 1326 c += ep->e_plen; 1327 c = TABSIZE - c%TABSIZE; 1328 while(--c>0) 1329 *dp++ = ' '; 1330 c = ' '; 1331 } 1332 else 1333 { 1334 *dp++ = '^'; 1335 c = printchar(c); 1336 } 1337 /* in vi mode the cursor is at the last character */ 1338 if(curp == sp && sh_isoption(SH_VI)) 1339 r = dp - phys; 1340 } 1341 *dp++ = c; 1342 if(dp>=dpmax) 1343 break; 1344 } 1345 *dp = 0; 1346 ep->e_peol = dp-phys; 1347 return(r); 1348 } 1349 1350 #if SHOPT_MULTIBYTE 1351 /* 1352 * convert external representation <src> to an array of genchars <dest> 1353 * <src> and <dest> can be the same 1354 * returns number of chars in dest 1355 */ 1356 1357 int ed_internal(const char *src, genchar *dest) 1358 { 1359 register const unsigned char *cp = (unsigned char *)src; 1360 register int c; 1361 register wchar_t *dp = (wchar_t*)dest; 1362 if(dest == (genchar*)roundof(cp-(unsigned char*)0,sizeof(genchar))) 1363 { 1364 genchar buffer[MAXLINE]; 1365 c = ed_internal(src,buffer); 1366 ed_gencpy((genchar*)dp,buffer); 1367 return(c); 1368 } 1369 while(*cp) 1370 *dp++ = mbchar(cp); 1371 *dp = 0; 1372 return(dp-(wchar_t*)dest); 1373 } 1374 1375 /* 1376 * convert internal representation <src> into character array <dest>. 1377 * The <src> and <dest> may be the same. 1378 * returns number of chars in dest. 1379 */ 1380 1381 int ed_external(const genchar *src, char *dest) 1382 { 1383 register genchar wc; 1384 register int c,size; 1385 register char *dp = dest; 1386 char *dpmax = dp+sizeof(genchar)*MAXLINE-2; 1387 if((char*)src == dp) 1388 { 1389 char buffer[MAXLINE*sizeof(genchar)]; 1390 c = ed_external(src,buffer); 1391 1392 #ifdef _lib_wcscpy 1393 wcscpy((wchar_t *)dest,(const wchar_t *)buffer); 1394 #else 1395 strcpy(dest,buffer); 1396 #endif 1397 return(c); 1398 } 1399 while((wc = *src++) && dp<dpmax) 1400 { 1401 if((size = mbconv(dp, wc)) < 0) 1402 { 1403 /* copy the character as is */ 1404 size = 1; 1405 *dp = wc; 1406 } 1407 dp += size; 1408 } 1409 *dp = 0; 1410 return(dp-dest); 1411 } 1412 1413 /* 1414 * copy <sp> to <dp> 1415 */ 1416 1417 void ed_gencpy(genchar *dp,const genchar *sp) 1418 { 1419 dp = (genchar*)roundof((char*)dp-(char*)0,sizeof(genchar)); 1420 sp = (const genchar*)roundof((char*)sp-(char*)0,sizeof(genchar)); 1421 while(*dp++ = *sp++); 1422 } 1423 1424 /* 1425 * copy at most <n> items from <sp> to <dp> 1426 */ 1427 1428 void ed_genncpy(register genchar *dp,register const genchar *sp, int n) 1429 { 1430 dp = (genchar*)roundof((char*)dp-(char*)0,sizeof(genchar)); 1431 sp = (const genchar*)roundof((char*)sp-(char*)0,sizeof(genchar)); 1432 while(n-->0 && (*dp++ = *sp++)); 1433 } 1434 1435 /* 1436 * find the string length of <str> 1437 */ 1438 1439 int ed_genlen(register const genchar *str) 1440 { 1441 register const genchar *sp = str; 1442 sp = (const genchar*)roundof((char*)sp-(char*)0,sizeof(genchar)); 1443 while(*sp++); 1444 return(sp-str-1); 1445 } 1446 #endif /* SHOPT_MULTIBYTE */ 1447 #endif /* SHOPT_ESH || SHOPT_VSH */ 1448 1449 #ifdef future 1450 /* 1451 * returns 1 when <n> bytes starting at <a> and <b> are equal 1452 */ 1453 static int compare(register const char *a,register const char *b,register int n) 1454 { 1455 while(n-->0) 1456 { 1457 if(*a++ != *b++) 1458 return(0); 1459 } 1460 return(1); 1461 } 1462 #endif 1463 1464 #if SHOPT_OLDTERMIO 1465 1466 # include <sys/termio.h> 1467 1468 #ifndef ECHOCTL 1469 # define ECHOCTL 0 1470 #endif /* !ECHOCTL */ 1471 #define ott ep->e_ott 1472 1473 /* 1474 * For backward compatibility only 1475 * This version will use termios when possible, otherwise termio 1476 */ 1477 1478 int tcgetattr(int fd, struct termios *tt) 1479 { 1480 register Edit_t *ep = (Edit_t*)(sh_getinterp()->ed_context); 1481 register int r,i; 1482 ep->e_tcgeta = 0; 1483 ep->e_echoctl = (ECHOCTL!=0); 1484 if((r=ioctl(fd,TCGETS,tt))>=0 || errno!=EINVAL) 1485 return(r); 1486 if((r=ioctl(fd,TCGETA,&ott)) >= 0) 1487 { 1488 tt->c_lflag = ott.c_lflag; 1489 tt->c_oflag = ott.c_oflag; 1490 tt->c_iflag = ott.c_iflag; 1491 tt->c_cflag = ott.c_cflag; 1492 for(i=0; i<NCC; i++) 1493 tt->c_cc[i] = ott.c_cc[i]; 1494 ep->e_tcgeta++; 1495 ep->e_echoctl = 0; 1496 } 1497 return(r); 1498 } 1499 1500 int tcsetattr(int fd,int mode,struct termios *tt) 1501 { 1502 register Edit_t *ep = (Edit_t*)(sh_getinterp()->ed_context); 1503 register int r; 1504 if(ep->e_tcgeta) 1505 { 1506 register int i; 1507 ott.c_lflag = tt->c_lflag; 1508 ott.c_oflag = tt->c_oflag; 1509 ott.c_iflag = tt->c_iflag; 1510 ott.c_cflag = tt->c_cflag; 1511 for(i=0; i<NCC; i++) 1512 ott.c_cc[i] = tt->c_cc[i]; 1513 if(tt->c_lflag&ECHOCTL) 1514 { 1515 ott.c_lflag &= ~(ECHOCTL|IEXTEN); 1516 ott.c_iflag &= ~(IGNCR|ICRNL); 1517 ott.c_iflag |= INLCR; 1518 ott.c_cc[VEOF]= ESC; /* ESC -> eof char */ 1519 ott.c_cc[VEOL] = '\r'; /* CR -> eol char */ 1520 ott.c_cc[VEOL2] = tt->c_cc[VEOF]; /* EOF -> eol char */ 1521 } 1522 switch(mode) 1523 { 1524 case TCSANOW: 1525 mode = TCSETA; 1526 break; 1527 case TCSADRAIN: 1528 mode = TCSETAW; 1529 break; 1530 case TCSAFLUSH: 1531 mode = TCSETAF; 1532 } 1533 return(ioctl(fd,mode,&ott)); 1534 } 1535 return(ioctl(fd,mode,tt)); 1536 } 1537 #endif /* SHOPT_OLDTERMIO */ 1538 1539 #if KSHELL 1540 /* 1541 * Execute keyboard trap on given buffer <inbuff> of given size <isize> 1542 * <mode> < 0 for vi insert mode 1543 */ 1544 static int keytrap(Edit_t *ep,char *inbuff,register int insize, int bufsize, int mode) 1545 { 1546 register char *cp; 1547 int savexit; 1548 Shell_t *shp = ep->sh; 1549 #if SHOPT_MULTIBYTE 1550 char buff[MAXLINE]; 1551 ed_external(ep->e_inbuf,cp=buff); 1552 #else 1553 cp = ep->e_inbuf; 1554 #endif /* SHOPT_MULTIBYTE */ 1555 inbuff[insize] = 0; 1556 ep->e_col = ep->e_cur; 1557 if(mode== -2) 1558 { 1559 ep->e_col++; 1560 *ep->e_vi_insert = ESC; 1561 } 1562 else 1563 *ep->e_vi_insert = 0; 1564 nv_putval(ED_CHRNOD,inbuff,NV_NOFREE); 1565 nv_putval(ED_COLNOD,(char*)&ep->e_col,NV_NOFREE|NV_INTEGER); 1566 nv_putval(ED_TXTNOD,(char*)cp,NV_NOFREE); 1567 nv_putval(ED_MODENOD,ep->e_vi_insert,NV_NOFREE); 1568 savexit = shp->savexit; 1569 sh_trap(shp->st.trap[SH_KEYTRAP],0); 1570 shp->savexit = savexit; 1571 if((cp = nv_getval(ED_CHRNOD)) == inbuff) 1572 nv_unset(ED_CHRNOD); 1573 else if(bufsize>0) 1574 { 1575 strncpy(inbuff,cp,bufsize); 1576 inbuff[bufsize-1]='\0'; 1577 insize = strlen(inbuff); 1578 } 1579 else 1580 insize = 0; 1581 nv_unset(ED_TXTNOD); 1582 return(insize); 1583 } 1584 #endif /* KSHELL */ 1585 1586 void *ed_open(Shell_t *shp) 1587 { 1588 Edit_t *ed = newof(0,Edit_t,1,0); 1589 ed->sh = shp; 1590 strcpy(ed->e_macro,"_??"); 1591 return((void*)ed); 1592 } 1593