1 /* @(#)edit.c 1.1 */ 2 3 /* 4 * edit.c - common routines for vi and emacs one line editors in shell 5 * 6 * David Korn P.D. Sullivan 7 * AT&T Bell Laboratories AT&T Bell Laboratories 8 * Room 5D-112 Room 1E253 9 * Murray Hill, N. J. 07974 Columbus, OH 43213 10 * Tel. x7975 Tel. x 2655 11 * 12 * Coded April 1983. 13 */ 14 15 #include <errno.h> 16 17 #ifdef KSHELL 18 #include "shtype.h" 19 #include "flags.h" 20 #include "defs.h" 21 #include "io.h" 22 #include "name.h" 23 #include "sym.h" 24 #include "stak.h" 25 #include "mode.h" 26 #include "builtins.h" 27 #include "brkincr.h" 28 29 #else 30 #include <stdio.h> 31 #include <signal.h> 32 #include <setjmp.h> 33 #include <ctype.h> 34 #endif /* KSHELL */ 35 36 #include "history.h" 37 #include "edit.h" 38 39 #define BAD -1 40 #define GOOD 0 41 #define TRUE (-1) 42 #define FALSE 0 43 #define SYSERR -1 44 45 #ifdef VENIX 46 #define RT 1 47 #endif /* VENIX */ 48 49 void e_crlf(); 50 void e_flush(); 51 int e_getchar(); 52 void e_putchar(); 53 void e_ringbell(); 54 void e_setup(); 55 int e_virt_to_phys(); 56 int e_window(); 57 void setcooked(); 58 void ungetchar(); 59 60 #if BSD || RT 61 #include <sgtty.h> 62 # ifdef BSD_4_2 63 # include <sys/time.h> 64 # endif /* BSD_4_2 */ 65 static struct sgttyb ttyparm; /* initial tty parameters */ 66 static struct sgttyb nttyparm; /* raw tty parameters */ 67 # ifdef BSD 68 extern int tty_speeds[]; 69 static int delay; 70 static int l_mask; 71 static struct tchars l_ttychars; 72 static struct ltchars l_chars; 73 static char l_changed; /* set if mode bits changed */ 74 #define L_CHARS 4 75 #define T_CHARS 2 76 #define L_MASK 1 77 # endif /* BSD */ 78 #else 79 # ifdef XENIX /* avoid symbol table overflows */ 80 # define NCC 8 81 struct termio { 82 unsigned short c_iflag; /* input modes */ 83 unsigned short c_oflag; /* output modes */ 84 unsigned short c_cflag; /* control modes */ 85 unsigned short c_lflag; /* line discipline modes */ 86 char c_line; /* line discipline */ 87 unsigned char c_cc[NCC]; /* control chars */ 88 char c_res; /* padding, AFTER the array */ 89 }; 90 #define TIOC ('T'<<8) 91 #define BRKINT 0000002 92 #define CBAUD 0000017 93 #define ECHO 0000010 94 #define ECHOE 0000020 95 #define ECHOK 0000040 96 #define ECHONL 0000100 97 #define ICANON 0000002 98 #define ICRNL 0000400 99 #define IGNCR 0000200 100 #define IGNPAR 0000004 101 #define INLCR 0000100 102 #define PARMRK 0000010 103 #define TCGETA (TIOC|1) 104 #define TCSETAW (TIOC|3) 105 #define TCXONC (TIOC|6) 106 #define VEOF 4 107 #define VERASE 2 108 #define VKILL 3 109 #define VMIN 4 110 #define VTIME 5 111 #define TM_CECHO 0010 112 # else 113 # include <termio.h> 114 # endif /* XENIX */ 115 116 static struct termio ttyparm; /* initial tty parameters */ 117 static struct termio nttyparm; /* raw tty parameters */ 118 #endif /* RT */ 119 120 #define lookahead editb.e_index 121 #define env editb.e_env 122 #define previous editb.e_lbuf 123 #define fildes editb.e_fd 124 125 #ifdef KSHELL 126 extern struct Amemory *alias; 127 extern char **arg_build(); 128 extern void failed(); 129 extern void fault(); 130 extern struct Namnod *findnod(); 131 extern int f_complete(); 132 extern void gsort(); 133 extern char *movstr(); 134 extern void p_flush(); 135 extern void p_setout(); 136 extern char *simple(); 137 extern char *tilde(); 138 extern char *valup(); 139 static char macro[] = "_?"; 140 141 #else 142 static char badcooked[] = "cannot reset tty to cooked mode"; 143 struct edit editb; 144 char trapnote; 145 extern char trapnote; 146 extern int errno; 147 #define p_flush() fflush(stderr) 148 #define p_setout(s) fflush(stdout) 149 #define error(s) failed(s,NULL) 150 #define SIGSLOW 1 151 #define output stderr 152 #endif /* KSHELL */ 153 154 extern char *strrchr(); 155 extern char *strcpy(); 156 157 static char bellchr[] = "\7"; /* bell char */ 158 159 static int control(); 160 /*{ SETCOOKED( fd ) 161 * 162 * This routine will set the tty in cooked mode. 163 * It is also called by error.done(). 164 * 165 }*/ 166 167 void setcooked(fd) 168 register int fd; 169 { 170 /*** don't do ioctl unless ttyparm has valid data ***/ 171 /* or in raw mode */ 172 173 if(editb.e_ttyspeed==0 || editb.e_raw==0) 174 return; 175 176 #ifdef BSD 177 if(editb.e_raw==RAWMODE && ioctl(fd, TIOCSETN, &ttyparm) == SYSERR ) 178 { 179 if(errno!=EBADF && errno!=ENOTTY) 180 error(badcooked); 181 return; 182 } 183 /* restore flags */ 184 if(l_changed&L_MASK) 185 ioctl(fd,TIOCLSET,&l_mask); 186 if(l_changed&T_CHARS) 187 /* restore alternate break character */ 188 ioctl(fd,TIOCSETC,&l_ttychars); 189 if(l_changed&L_CHARS) 190 /* restore alternate break character */ 191 ioctl(fd,TIOCSLTC,&l_chars); 192 l_changed = 0; 193 #else 194 # ifdef RT 195 if (stty(fd,&ttyparm) == SYSERR) 196 # else 197 if( editb.e_raw && control(fd, TCSETAW, &ttyparm) == SYSERR ) 198 # endif /* RT */ 199 { 200 if(errno!=EBADF && errno!=ENOTTY) 201 error(badcooked); 202 return; 203 } 204 #endif /* BSD */ 205 editb.e_raw = 0; 206 return; 207 } 208 209 /*{ SETRAW( fd ) 210 * 211 * This routine will set the tty in raw mode. 212 * 213 }*/ 214 215 setraw(fd) 216 register int fd; 217 { 218 #ifdef BSD 219 struct ltchars lchars; 220 #endif /* BSD */ 221 if(editb.e_raw==RAWMODE) 222 return(GOOD); 223 /* characters are echoed on standard error */ 224 p_setout(stderr); 225 #if BSD || RT 226 # ifdef BSD 227 if((ioctl(fd,TIOCGETP,&ttyparm) == SYSERR) 228 # else 229 if ((gtty(fd,&ttyparm) == SYSERR) 230 # endif /* BSD */ 231 || !(ttyparm.sg_flags & ECHO ) 232 || (ttyparm.sg_flags & LCASE )) 233 { 234 return(BAD); 235 } 236 nttyparm = ttyparm; 237 nttyparm.sg_flags &= ~(ECHO | TBDELAY); 238 # ifdef BSD 239 nttyparm.sg_flags |= CBREAK; 240 # else 241 nttyparm.sg_flags |= RAW; 242 # endif /* BSD */ 243 editb.e_erase = ttyparm.sg_erase; 244 editb.e_kill = ttyparm.sg_kill; 245 editb.e_eof = cntl(D); 246 # ifdef BSD 247 if( ioctl(fd, TIOCSETN, &nttyparm) == SYSERR ) 248 # else 249 if( stty(fd, &nttyparm) == SYSERR ) 250 # endif /* BSD */ 251 { 252 return(BAD); 253 } 254 editb.e_ttyspeed = (ttyparm.sg_ospeed>=B1200?FAST:SLOW); 255 #ifdef BSD 256 delay = tty_speeds[ttyparm.sg_ospeed]; 257 /* try to remove effect of ^V and ^Y */ 258 if(ioctl(fd,TIOCGLTC,&l_chars) != SYSERR) 259 { 260 lchars = l_chars; 261 lchars.t_lnextc = -1; 262 lchars.t_dsuspc = -1; /* no delayed stop process signal */ 263 if(ioctl(fd,TIOCSLTC,&lchars) != SYSERR) 264 l_changed |= L_CHARS; 265 } 266 #endif /* BSD */ 267 #else 268 269 # ifndef RAWONLY 270 if(editb.e_raw != ALTMODE) 271 # endif /* RAWONLY */ 272 if( (ioctl(fd, TCGETA, &ttyparm) == SYSERR) 273 || (!(ttyparm.c_lflag & ECHO ))) 274 { 275 return(BAD); 276 } 277 278 nttyparm = ttyparm; 279 #ifndef u370 280 nttyparm.c_iflag &= ~(IGNPAR|PARMRK|INLCR|IGNCR|ICRNL); 281 nttyparm.c_iflag |= BRKINT; 282 nttyparm.c_lflag &= ~(ICANON|ECHO); 283 #else 284 nttyparm.c_iflag &= 285 ~(IGNBRK|PARMRK|INLCR|IGNCR|ICRNL|INPCK); 286 nttyparm.c_iflag |= (BRKINT|IGNPAR); 287 nttyparm.c_lflag &= ~(ICANON|ECHO); 288 #endif /* u370 */ 289 nttyparm.c_cc[VTIME] = 0; 290 nttyparm.c_cc[VMIN] = 1; 291 editb.e_eof = ttyparm.c_cc[VEOF]; 292 editb.e_erase = ttyparm.c_cc[VERASE]; 293 editb.e_kill = ttyparm.c_cc[VKILL]; 294 #ifndef u370 295 if( control(fd, TCSETAW, &nttyparm) == SYSERR ) 296 #else 297 /* delays are too long, don't wait for output to drain */ 298 if( control(fd, TCSETA, &nttyparm) == SYSERR ) 299 #endif /* u370 */ 300 { 301 return(BAD); 302 } 303 control(fd,TCXONC,1); 304 editb.e_ttyspeed = ttyparm.c_cflag & CBAUD; 305 #endif 306 editb.e_raw = RAWMODE; 307 return(GOOD); 308 } 309 310 #ifndef BSD 311 /* 312 * give two tries for ioctl 313 * interrupts are ignored 314 */ 315 316 static int control(fd,request,arg) 317 { 318 register int i; 319 register int k = 2; 320 errno = 0; 321 while(k--) 322 { 323 if((i = ioctl(fd,request,arg)) != SYSERR) 324 return(i); 325 if(errno == EINTR) 326 { 327 errno = 0; 328 k++; 329 } 330 } 331 return(SYSERR); 332 } 333 #endif /* BSD */ 334 #ifndef RAWONLY 335 336 /* SET_TTY( fd ) 337 * 338 * Get tty parameters and make ESC and '\r' wakeup characters. 339 * 340 */ 341 342 #ifdef BSD 343 setalt(fd) 344 register int fd; 345 { 346 int mask; 347 struct tchars ttychars; 348 if(editb.e_raw==ALTMODE) 349 return(GOOD); 350 if(editb.e_raw==RAWMODE) 351 setcooked(fd); 352 l_changed = 0; 353 if( editb.e_ttyspeed == 0) 354 { 355 if((ioctl(fd,TIOCGETP,&ttyparm) != SYSERR)) 356 editb.e_ttyspeed = (ttyparm.sg_ospeed>=B1200?FAST:SLOW); 357 } 358 if(ioctl(fd,TIOCGETC,&l_ttychars) == SYSERR) 359 return(BAD); 360 if(ioctl(fd,TIOCLGET,&l_mask)==SYSERR) 361 return(BAD); 362 ttychars = l_ttychars; 363 mask = LCRTBS|LCRTERA|LCTLECH|LPENDIN|LCRTKIL; 364 if((l_mask|mask) != l_mask) 365 l_changed = L_MASK; 366 if(ioctl(fd,TIOCLBIS,&mask)==SYSERR) 367 return(BAD); 368 ttychars.t_brkc = ESC; 369 l_changed |= T_CHARS; 370 if(ioctl(fd,TIOCSETC,&ttychars) == SYSERR) 371 return(BAD); 372 editb.e_raw = ALTMODE; 373 return(GOOD); 374 } 375 #else 376 setalt(fd) 377 register int fd; 378 { 379 if(editb.e_raw==ALTMODE) 380 return(GOOD); 381 if(editb.e_raw==RAWMODE) 382 setcooked(fd); 383 if( (control(fd, TCGETA, &ttyparm) == SYSERR) 384 || (!(ttyparm.c_lflag & ECHO ))) 385 { 386 return(BAD); 387 } 388 nttyparm = ttyparm; 389 nttyparm.c_iflag &= ~(IGNCR|ICRNL); 390 nttyparm.c_iflag |= INLCR; 391 nttyparm.c_lflag |= (ECHOE|ECHOK); 392 nttyparm.c_cc[VEOF] = ESC; /* make ESC the eof char */ 393 nttyparm.c_cc[VEOL] = '\r'; /* make CR an eol char */ 394 editb.e_eof = ttyparm.c_cc[VEOF]; 395 nttyparm.c_cc[VEOL2] = editb.e_eof; /* make EOF an eol char */ 396 editb.e_erase = ttyparm.c_cc[VERASE]; 397 editb.e_kill = ttyparm.c_cc[VKILL]; 398 if( control(fd, TCSETAW, &nttyparm) == SYSERR ) 399 { 400 return(BAD); 401 } 402 editb.e_ttyspeed = ((ttyparm.c_cflag&CBAUD)>=B1200?FAST:SLOW); 403 editb.e_raw = ALTMODE; 404 return(GOOD); 405 } 406 407 #endif /* BSD */ 408 #endif /* RAWONLY */ 409 410 /* 411 * E_WINDOW() 412 * 413 * return the window size 414 */ 415 416 int e_window() 417 { 418 register int n = DFLTWINDOW-1; 419 register char *cp = valup(COLUMNS); 420 if(cp) 421 { 422 n = atoi(cp)-1; 423 if(n < MINWINDOW) 424 n = MINWINDOW; 425 if(n > MAXWINDOW) 426 n = MAXWINDOW; 427 } 428 return(n); 429 } 430 431 /* E_FLUSH() 432 * 433 * Flush the output buffer. 434 * 435 */ 436 437 void e_flush() 438 { 439 register unsigned char *buf = (unsigned char*)output->_base; 440 register int n = editb.e_outptr-buf; 441 register int fd = fileno(output); 442 if(n<=0) 443 return; 444 write(fd,(char*)buf,n); 445 editb.e_outptr = buf; 446 #ifdef BSD 447 # ifdef BSD_4_2 448 if(delay && n > delay/100) 449 { 450 /* delay until output drains */ 451 struct timeval timeloc; 452 n *= 10; 453 timeloc.tv_sec = n/delay; 454 timeloc.tv_usec = (1000000*(n%delay))/delay; 455 select(0,0,0,0,&timeloc); 456 } 457 # endif /* BSD_4_2 */ 458 #else 459 # ifndef RT 460 if(editb.e_raw==RAWMODE && n > 16) 461 ioctl(fd, TCSETAW, &nttyparm); 462 # endif /* RT */ 463 #endif /* BSD */ 464 } 465 466 /* 467 * send the bell character ^G to the terminal 468 */ 469 470 void e_ringbell() 471 { 472 write(fileno(output),bellchr,1); 473 } 474 475 /* 476 * send a carriage return line feed to the terminal 477 */ 478 479 void e_crlf() 480 { 481 #ifdef u370 482 e_putchar('\r'); 483 #endif /* u370 */ 484 #ifdef VENIX 485 e_putchar('\r'); 486 #endif /* VENIX */ 487 e_putchar('\n'); 488 e_flush(); 489 } 490 491 /* E_SETUP( max_prompt_size ) 492 * 493 * This routine sets up the prompt string 494 */ 495 496 void e_setup(fd,PRSIZE) 497 { 498 register char *last; 499 register char *pp = (char*)(output->_base); 500 char *ppmax; 501 editb.e_fd = fd; 502 if(fc_fix) 503 { 504 register struct fixcmd *fp = fc_fix; 505 editb.e_hismax = fp->fixind; 506 editb.e_hloff = fp->fixline; 507 editb.e_hismin = fp->fixind-fp->fixmax; 508 if(editb.e_hismin<0) 509 editb.e_hismin = 0; 510 } 511 else 512 { 513 editb.e_hismax = editb.e_hismin = editb.e_hloff = 0; 514 } 515 editb.e_hline = editb.e_hismax; 516 editb.e_wsize = e_window()-2; 517 editb.e_outptr = (unsigned char*)pp; 518 editb.e_crlf = YES; 519 *(output->_ptr) = 0; 520 if((last=strrchr(pp,'\n'))==NULL) 521 { 522 if(*(last=pp)==0) 523 editb.e_crlf = NO; 524 } 525 else 526 last++; 527 pp = editb.e_prompt; 528 ppmax = pp+PRSIZE-1; 529 *pp++ = '\r'; 530 { 531 register int c; 532 while(c = *last++) 533 { 534 /* cut out bells */ 535 if(c!=BELL) 536 { 537 if(pp < ppmax) 538 *pp++ = c; 539 if(!isprint(c)) 540 editb.e_crlf = NO; 541 } 542 } 543 } 544 editb.e_plen = pp - editb.e_prompt - 1; 545 *pp = 0; 546 #ifdef u370 547 if (editb.e_raw == RAWMODE) 548 u370fflush(output); 549 else 550 #endif /* u370 */ 551 p_flush(); 552 } 553 554 #ifdef u370 555 /* The u370 does not \r before \n in raw mode (known bug). 556 To get around this we will insert a \r before each \n 557 in the output buffer. 558 */ 559 560 u370fflush(file) 561 FILE *file; 562 { 563 unsigned char *base,*ptr,buffer[BUFSIZ*2]; 564 int icnt,ocnt; 565 ptr = buffer; 566 icnt = file->_ptr - file->_base; 567 ocnt = icnt; 568 base = file->_base ; 569 if (icnt <= 0) return; 570 while (base < file->_ptr) 571 { 572 if (*base == '\n' ) 573 { 574 *ptr++ = '\r'; 575 ocnt++; 576 } 577 *ptr++ = *base++; 578 } 579 base = file->_base; 580 ptr = buffer; 581 while (ocnt>0) 582 { 583 for(icnt=0;icnt<BUFSIZ;icnt++) 584 { 585 *base++ = *ptr++; 586 if (--ocnt <= 0) break; 587 } 588 file->_ptr = base; 589 p_flush(); 590 base = file->_base; 591 } 592 } 593 #endif /* u370 */ 594 595 #ifdef KSHELL 596 /* 597 * look for edit macro named _i 598 * if found, puts the macro definition into lookahead buffer and returns 1 599 */ 600 601 e_macro(i) 602 register int i; 603 { 604 register char *out; 605 struct Namnod *np; 606 genchar buff[LOOKAHEAD+1]; 607 if(i != '@') 608 macro[1] = i; 609 if (isalnum(i)&&(np=findnod(macro,alias,0))&&(out=valup(np))) 610 { 611 #ifdef MULTIBYTE 612 /* copy to buff in internal representation */ 613 int c = out[LOOKAHEAD]; 614 out[LOOKAHEAD] = 0; 615 i = e_internal(out,buff); 616 out[LOOKAHEAD] = c; 617 #else 618 strncpy((char*)buff,out,LOOKAHEAD); 619 i = strlen((char*)buff); 620 #endif /* MULTIBYTE */ 621 while(i-- > 0) 622 ungetchar(buff[i]); 623 return(1); 624 } 625 return(0); 626 } 627 /* 628 * file name generation for edit modes 629 * non-zero exit for error, <0 ring bell 630 * don't search back past <start> character of the buffer 631 * mode is '*' for inline expansion, otherwise files are listed in select format 632 */ 633 634 q_expand(outbuff,cur,eol,start,mode) 635 char outbuff[]; 636 int *cur; 637 int *eol; 638 int start; 639 int mode; 640 { 641 STKPTR staksav = stakbot; 642 COMPTR comptr = (COMPTR)getstak(COMTYPE); 643 ARGPTR ap = (ARGPTR)locstak(); 644 register char *out; 645 char *outmin = outbuff + start; 646 char *begin; 647 char *last; 648 int rval = 0; 649 int strip; 650 optflag savflags = flags; 651 #ifdef MULTIBYTE 652 { 653 register int c = *cur; 654 register genchar *cp; 655 /* adjust cur */ 656 cp = (genchar *)outbuff + *cur; 657 c = *cp; 658 *cp = 0; 659 *cur = e_external((genchar*)outbuff,(char*)stakbot); 660 *cp = c; 661 *eol = e_external((genchar*)outbuff,outbuff); 662 } 663 #endif /* MULTIBYTE */ 664 out = outbuff + *cur; 665 comptr->comtyp = COMSCAN; 666 comptr->comarg = ap; 667 ap->argflag = (A_MAC|A_EXP); 668 ap->argnxt = 0; 669 { 670 register int c; 671 register char *ptr = ap->argval; 672 int chktilde = 0; 673 int flag; 674 char *cp; 675 if(out>outmin) 676 { 677 /* go to beginning of word */ 678 do 679 { 680 out--; 681 c = *(unsigned char*)out; 682 } 683 while(out>outmin && !isqmeta(c)); 684 /* copy word into arg */ 685 if(isqmeta(c)) 686 out++; 687 } 688 else 689 out = outmin; 690 begin = out; 691 flag = '*'; 692 strip = TRUE; 693 /* copy word to arg and do ~ expansion */ 694 do 695 { 696 c = *(unsigned char*)out++; 697 if(isexp(c)) 698 flag = 0; 699 if ((c == '/') && (flag == 0)) 700 strip = FALSE; 701 *ptr++ = c; 702 if(chktilde==0 && (c==0 || c == '/')) 703 { 704 chktilde++; 705 if(cp=tilde(begin)) 706 { 707 ptr = movstr(cp,ap->argval); 708 *ptr++ = c; 709 } 710 } 711 712 } while (c && !isqmeta(c)); 713 714 out--; 715 *(ptr-1) = flag; 716 endstak(ptr); 717 last = ptr-1; 718 } 719 if(mode!='*') 720 on_option(MARKDIR); 721 { 722 register char **com; 723 int narg; 724 register int size; 725 while(1) 726 { 727 com = arg_build(&narg,comptr); 728 /* match? */ 729 if (narg > 1 || !eq(ap->argval,*com)) 730 break; 731 if (*last == 0) 732 *last = '*'; 733 else 734 { 735 rval = -1; 736 goto done; 737 } 738 } 739 if(mode!='*') 740 { 741 if (strip) 742 { 743 register char **ptrcom; 744 for(ptrcom=com;*ptrcom;ptrcom++) 745 /* trim directory prefix */ 746 *ptrcom = simple (*ptrcom); 747 } 748 p_setout(stderr); 749 newline(); 750 p_list(narg,com); 751 p_flush(); 752 goto done; 753 } 754 /* see if there is enough room */ 755 size = *eol - (out-begin); 756 size += narg; 757 { 758 char **savcom = com; 759 while (*com) 760 size += strlen(*com++); 761 com = savcom; 762 } 763 /* see if room for expansion */ 764 if(outbuff+size >= &outbuff[MAXLINE]) 765 { 766 com[0] = ap->argval; 767 com[1] = NULL; 768 } 769 /* save remainder of the buffer */ 770 strcpy(stakbot,out); 771 out = begin; 772 while (*com) 773 { 774 out = movstr(*com,out); 775 if (*++com) 776 *out++ = ' '; 777 } 778 *cur = (out-outbuff); 779 /* restore rest of buffer */ 780 out = movstr(stakbot,out); 781 *eol = (out-outbuff); 782 } 783 done: 784 tdystak(staksav); 785 flags = savflags; 786 #ifdef MULTIBYTE 787 { 788 register int c; 789 /* first re-adjust cur */ 790 out = outbuff + *cur; 791 c = *out; 792 *out = 0; 793 *cur = e_internal(outbuff,(genchar*)stakbot); 794 *out = c; 795 outbuff[*eol+1] = 0; 796 *eol = e_internal(outbuff,(genchar*)outbuff); 797 } 798 #endif /* MULTIBYTE */ 799 return(rval); 800 } 801 #endif /* KSHELL */ 802 803 804 /* 805 * routine to perform read from terminal for vi and emacs mode 806 */ 807 808 809 int 810 e_getchar() 811 { 812 register int i; 813 register int c; 814 register int maxtry = 100; 815 int nchar; /* number of characters to read at a time */ 816 #ifdef MULTIBYTE 817 static int curchar; 818 static int cursize; 819 #endif /* MULTIBYTE */ 820 char readin[LOOKAHEAD] ; 821 if (lookahead) 822 { 823 c = previous[--lookahead]; 824 /*** map '\r' to '\n' ***/ 825 if(c == '\r') 826 c = '\n'; 827 return(c); 828 } 829 830 e_flush() ; 831 /* you can't chance read ahead at the end of line */ 832 nchar = (editb.e_cur>=editb.e_eol?1:READAHEAD); 833 /* Set 'i' to indicate read failed, in case intr set */ 834 retry: 835 i = -1; 836 errno = 0; 837 editb.e_inmacro = 0; 838 while((trapnote&SIGSLOW)==0 && maxtry--) 839 { 840 errno=0; 841 if ((i = read(fildes,readin, nchar)) != -1) 842 break; 843 } 844 #ifdef MULTIBYTE 845 lookahead = maxtry = i; 846 i = 0; 847 while (i < maxtry) 848 { 849 c = readin[i++] & STRIP; 850 next: 851 if(cursize-- > 0) 852 { 853 curchar = (curchar<<7) | (c&~HIGHBIT); 854 if(cursize==0) 855 { 856 c = curchar; 857 goto gotit; 858 } 859 else if(i>=maxtry) 860 goto retry; 861 continue; 862 } 863 else if(curchar = echarset(c)) 864 { 865 cursize = in_csize(curchar); 866 if(curchar != 1) 867 c = 0; 868 curchar <<= 7*(ESS_MAXCHAR-cursize); 869 if(c) 870 goto next; 871 else if(i>=maxtry) 872 goto retry; 873 continue; 874 } 875 gotit: 876 previous[--lookahead] = c; 877 #else 878 while (i > 0) 879 { 880 c = readin[--i] & STRIP; 881 previous[lookahead++] = c; 882 #endif /* MULTIBYTE */ 883 #ifndef BSD 884 if( c == '\0' ) 885 { 886 /*** user break key ***/ 887 lookahead = 0; 888 # ifdef KSHELL 889 fault(SIGINT); 890 longjmp(env, UINTR); 891 # endif /* KSHELL */ 892 } 893 #endif /* !BSD */ 894 } 895 #ifdef MULTIBYTE 896 /* shift lookahead buffer if necessary */ 897 if(lookahead) 898 { 899 for(i=lookahead;i < maxtry;i++) 900 previous[i-lookahead] = previous[i]; 901 } 902 lookahead = maxtry-lookahead; 903 #endif /* MULTIBYTE */ 904 if (lookahead > 0) 905 return(e_getchar(1)); 906 longjmp(env,(i==0?UEOF:UINTR)); /* What a mess! Give up */ 907 /* NOTREACHED */ 908 } 909 910 void ungetchar(c) 911 register int c; 912 { 913 if (lookahead < LOOKAHEAD) 914 previous[lookahead++] = c; 915 return; 916 } 917 918 /* 919 * put a character into the output buffer 920 */ 921 922 void e_putchar(c) 923 register int c; 924 { 925 register unsigned char *dp = editb.e_outptr; 926 #ifdef MULTIBYTE 927 register int d; 928 /* check for place holder */ 929 if(c == MARKER) 930 return; 931 if(d = icharset(c)) 932 { 933 if(d == 2) 934 *dp++ = ESS2; 935 else if(d == 3) 936 *dp++ = ESS3; 937 d = in_csize(d); 938 while(--d>0) 939 *dp++ = HIGHBIT|(c>>(7*d)); 940 c |= HIGHBIT; 941 } 942 #endif /* MULTIBYTE */ 943 if (c == '_') 944 { 945 *dp++ = ' '; 946 *dp++ = '\b'; 947 } 948 *dp++ = c; 949 *dp = '\0'; 950 if ((dp - (unsigned char*)(output->_base))>=(BUFSIZ-3)) 951 e_flush(); 952 else 953 editb.e_outptr = dp; 954 } 955 956 /* 957 * copy virtual to physical and return the index for cursor in physical buffer 958 */ 959 e_virt_to_phys(virt,phys,cur,voff,poff) 960 genchar *virt; 961 genchar *phys; 962 int cur; 963 { 964 register genchar *sp = virt; 965 register genchar *dp = phys; 966 register int c; 967 genchar *curp = sp + cur; 968 genchar *dpmax = phys+MAXLINE; 969 int r = 0; 970 #ifdef MULTIBYTE 971 int d; 972 #endif /* MULTIBYTE */ 973 sp += voff; 974 dp += poff; 975 for(r=poff;c= *sp;sp++) 976 { 977 if(curp == sp) 978 r = dp - phys; 979 #ifdef MULTIBYTE 980 d = out_csize(icharset(c)); 981 if(d>1) 982 { 983 /* multiple width character put in place holders */ 984 *dp++ = c; 985 while(--d >0) 986 *dp++ = MARKER; 987 /* in vi mode the cursor is at the last character */ 988 if(dp>=dpmax) 989 break; 990 continue; 991 } 992 else 993 #endif /* MULTIBYTE */ 994 if(!isprint(c)) 995 { 996 if(c=='\t') 997 { 998 c = dp-phys; 999 c = ((c+8)&~07) - c; 1000 while(--c>0) 1001 *dp++ = ' '; 1002 c = ' '; 1003 } 1004 else 1005 { 1006 *dp++ = '^'; 1007 c ^= TO_PRINT; 1008 } 1009 /* in vi mode the cursor is at the last character */ 1010 if(curp == sp && is_option(EDITVI)) 1011 r = dp - phys; 1012 } 1013 *dp++ = c; 1014 if(dp>=dpmax) 1015 break; 1016 } 1017 *dp = 0; 1018 return(r); 1019 } 1020 1021 #ifdef MULTIBYTE 1022 /* 1023 * convert external representation <src> to an array of genchars <dest> 1024 * <src> and <dest> can be the same 1025 * returns number of chars in dest 1026 */ 1027 1028 int e_internal(src,dest) 1029 register unsigned char *src; 1030 genchar *dest; 1031 { 1032 register int c; 1033 register genchar *dp = dest; 1034 register int d; 1035 register int size; 1036 if((unsigned char*)dest == src) 1037 { 1038 genchar buffer[MAXLINE]; 1039 c = e_internal(src,buffer); 1040 e_gencpy(dp,buffer); 1041 return(c); 1042 } 1043 while(c = *src++) 1044 { 1045 if(size = echarset(c)) 1046 { 1047 d = (size==1?c:0); 1048 c = size; 1049 size = in_csize(c); 1050 c <<= 7*(ESS_MAXCHAR-size); 1051 if(d) 1052 { 1053 size--; 1054 c = (c<<7) | (d&~HIGHBIT); 1055 } 1056 while(size-- >0) 1057 c = (c<<7) | ((*src++)&~HIGHBIT); 1058 } 1059 *dp++ = c; 1060 } 1061 *dp = 0; 1062 return(dp-dest); 1063 } 1064 1065 /* 1066 * convert internal representation <src> into character array <dest>. 1067 * The <src> and <dest> may be the same. 1068 * returns number of chars in dest. 1069 */ 1070 1071 int e_external(src,dest) 1072 genchar *src; 1073 char *dest; 1074 { 1075 register int c; 1076 register char *dp = dest; 1077 register int d; 1078 char *dpmax = dp+sizeof(genchar)*MAXLINE-2; 1079 if((char*)src == dp) 1080 { 1081 char buffer[MAXLINE*sizeof(genchar)]; 1082 c = e_external(src,buffer); 1083 strcpy(dest,buffer); 1084 return(c); 1085 } 1086 while((c = *src++) && dp<dpmax) 1087 { 1088 if(d = icharset(c)) 1089 { 1090 if(d == 2) 1091 *dp++ = ESS2; 1092 else if(d == 3) 1093 *dp++ = ESS3; 1094 d = in_csize(d); 1095 while(--d>0) 1096 *dp++ = HIGHBIT|(c>>(7*d)); 1097 c |= HIGHBIT; 1098 } 1099 *dp++ = c; 1100 } 1101 *dp = 0; 1102 return(dp-dest); 1103 } 1104 1105 /* 1106 * copy <sp> to <dp> 1107 */ 1108 1109 int e_gencpy(dp,sp) 1110 register genchar *dp; 1111 register genchar *sp; 1112 { 1113 while(*dp++ = *sp++); 1114 } 1115 1116 /* 1117 * copy at most <n> items from <sp> to <dp> 1118 */ 1119 1120 int e_genncpy(dp,sp, n) 1121 register genchar *dp; 1122 register genchar *sp; 1123 register int n; 1124 { 1125 while(n-->0 && (*dp++ = *sp++)); 1126 } 1127 1128 /* 1129 * find the string length of <str> 1130 */ 1131 1132 int e_genlen(str) 1133 register genchar *str; 1134 { 1135 register genchar *sp = str; 1136 while(*sp++); 1137 return(sp-str-1); 1138 } 1139 #endif /* MULTIBYTE */ 1140