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