1 /* $NetBSD: read.c,v 1.71 2014/07/06 18:15:34 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 1992, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Christos Zoulas of Cornell University. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 #include "config.h" 36 #if !defined(lint) && !defined(SCCSID) 37 #if 0 38 static char sccsid[] = "@(#)read.c 8.1 (Berkeley) 6/4/93"; 39 #else 40 __RCSID("$NetBSD: read.c,v 1.71 2014/07/06 18:15:34 christos Exp $"); 41 #endif 42 #endif /* not lint && not SCCSID */ 43 #include <sys/cdefs.h> 44 __FBSDID("$FreeBSD$"); 45 46 /* 47 * read.c: Clean this junk up! This is horrible code. 48 * Terminal read functions 49 */ 50 #include <errno.h> 51 #include <fcntl.h> 52 #include <unistd.h> 53 #include <stdlib.h> 54 #include <limits.h> 55 #include "el.h" 56 57 #define OKCMD -1 /* must be -1! */ 58 59 private int read__fixio(int, int); 60 private int read_preread(EditLine *); 61 private int read_char(EditLine *, Char *); 62 private int read_getcmd(EditLine *, el_action_t *, Char *); 63 private void read_pop(c_macro_t *); 64 65 /* read_init(): 66 * Initialize the read stuff 67 */ 68 protected int 69 read_init(EditLine *el) 70 { 71 /* builtin read_char */ 72 el->el_read.read_char = read_char; 73 return 0; 74 } 75 76 77 /* el_read_setfn(): 78 * Set the read char function to the one provided. 79 * If it is set to EL_BUILTIN_GETCFN, then reset to the builtin one. 80 */ 81 protected int 82 el_read_setfn(EditLine *el, el_rfunc_t rc) 83 { 84 el->el_read.read_char = (rc == EL_BUILTIN_GETCFN) ? read_char : rc; 85 return 0; 86 } 87 88 89 /* el_read_getfn(): 90 * return the current read char function, or EL_BUILTIN_GETCFN 91 * if it is the default one 92 */ 93 protected el_rfunc_t 94 el_read_getfn(EditLine *el) 95 { 96 return el->el_read.read_char == read_char ? 97 EL_BUILTIN_GETCFN : el->el_read.read_char; 98 } 99 100 101 #ifndef MIN 102 #define MIN(A,B) ((A) < (B) ? (A) : (B)) 103 #endif 104 105 #ifdef DEBUG_EDIT 106 private void 107 read_debug(EditLine *el) 108 { 109 110 if (el->el_line.cursor > el->el_line.lastchar) 111 (void) fprintf(el->el_errfile, "cursor > lastchar\r\n"); 112 if (el->el_line.cursor < el->el_line.buffer) 113 (void) fprintf(el->el_errfile, "cursor < buffer\r\n"); 114 if (el->el_line.cursor > el->el_line.limit) 115 (void) fprintf(el->el_errfile, "cursor > limit\r\n"); 116 if (el->el_line.lastchar > el->el_line.limit) 117 (void) fprintf(el->el_errfile, "lastchar > limit\r\n"); 118 if (el->el_line.limit != &el->el_line.buffer[EL_BUFSIZ - 2]) 119 (void) fprintf(el->el_errfile, "limit != &buffer[EL_BUFSIZ-2]\r\n"); 120 } 121 #endif /* DEBUG_EDIT */ 122 123 124 /* read__fixio(): 125 * Try to recover from a read error 126 */ 127 /* ARGSUSED */ 128 private int 129 read__fixio(int fd __attribute__((__unused__)), int e) 130 { 131 132 switch (e) { 133 case -1: /* Make sure that the code is reachable */ 134 135 #ifdef EWOULDBLOCK 136 case EWOULDBLOCK: 137 #ifndef TRY_AGAIN 138 #define TRY_AGAIN 139 #endif 140 #endif /* EWOULDBLOCK */ 141 142 #if defined(POSIX) && defined(EAGAIN) 143 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN 144 case EAGAIN: 145 #ifndef TRY_AGAIN 146 #define TRY_AGAIN 147 #endif 148 #endif /* EWOULDBLOCK && EWOULDBLOCK != EAGAIN */ 149 #endif /* POSIX && EAGAIN */ 150 151 e = 0; 152 #ifdef TRY_AGAIN 153 #if defined(F_SETFL) && defined(O_NDELAY) 154 if ((e = fcntl(fd, F_GETFL, 0)) == -1) 155 return -1; 156 157 if (fcntl(fd, F_SETFL, e & ~O_NDELAY) == -1) 158 return -1; 159 else 160 e = 1; 161 #endif /* F_SETFL && O_NDELAY */ 162 163 #ifdef FIONBIO 164 { 165 int zero = 0; 166 167 if (ioctl(fd, FIONBIO, &zero) == -1) 168 return -1; 169 else 170 e = 1; 171 } 172 #endif /* FIONBIO */ 173 174 #endif /* TRY_AGAIN */ 175 return e ? 0 : -1; 176 177 case EINTR: 178 return 0; 179 180 default: 181 return -1; 182 } 183 } 184 185 186 /* read_preread(): 187 * Try to read the stuff in the input queue; 188 */ 189 private int 190 read_preread(EditLine *el) 191 { 192 int chrs = 0; 193 194 if (el->el_tty.t_mode == ED_IO) 195 return 0; 196 197 #ifndef WIDECHAR 198 /* FIONREAD attempts to buffer up multiple bytes, and to make that work 199 * properly with partial wide/UTF-8 characters would need some careful work. */ 200 #ifdef FIONREAD 201 (void) ioctl(el->el_infd, FIONREAD, &chrs); 202 if (chrs > 0) { 203 char buf[EL_BUFSIZ]; 204 205 chrs = read(el->el_infd, buf, 206 (size_t) MIN(chrs, EL_BUFSIZ - 1)); 207 if (chrs > 0) { 208 buf[chrs] = '\0'; 209 el_push(el, buf); 210 } 211 } 212 #endif /* FIONREAD */ 213 #endif 214 return chrs > 0; 215 } 216 217 218 /* el_push(): 219 * Push a macro 220 */ 221 public void 222 FUN(el,push)(EditLine *el, const Char *str) 223 { 224 c_macro_t *ma = &el->el_chared.c_macro; 225 226 if (str != NULL && ma->level + 1 < EL_MAXMACRO) { 227 ma->level++; 228 if ((ma->macro[ma->level] = Strdup(str)) != NULL) 229 return; 230 ma->level--; 231 } 232 terminal_beep(el); 233 terminal__flush(el); 234 } 235 236 237 /* read_getcmd(): 238 * Get next command from the input stream, return OKCMD on success. 239 * Character values > 255 are not looked up in the map, but inserted. 240 */ 241 private int 242 read_getcmd(EditLine *el, el_action_t *cmdnum, Char *ch) 243 { 244 el_action_t cmd; 245 int num; 246 247 el->el_errno = 0; 248 do { 249 if ((num = FUN(el,getc)(el, ch)) != 1) {/* if EOF or error */ 250 el->el_errno = num == 0 ? 0 : errno; 251 return 0; /* not OKCMD */ 252 } 253 254 #ifdef KANJI 255 if ((*ch & 0200)) { 256 el->el_state.metanext = 0; 257 cmd = CcViMap[' ']; 258 break; 259 } else 260 #endif /* KANJI */ 261 262 if (el->el_state.metanext) { 263 el->el_state.metanext = 0; 264 *ch |= 0200; 265 } 266 #ifdef WIDECHAR 267 if (*ch >= N_KEYS) 268 cmd = ED_INSERT; 269 else 270 #endif 271 cmd = el->el_map.current[(unsigned char) *ch]; 272 if (cmd == ED_SEQUENCE_LEAD_IN) { 273 keymacro_value_t val; 274 switch (keymacro_get(el, ch, &val)) { 275 case XK_CMD: 276 cmd = val.cmd; 277 break; 278 case XK_STR: 279 FUN(el,push)(el, val.str); 280 break; 281 #ifdef notyet 282 case XK_EXE: 283 /* XXX: In the future to run a user function */ 284 RunCommand(val.str); 285 break; 286 #endif 287 default: 288 EL_ABORT((el->el_errfile, "Bad XK_ type \n")); 289 break; 290 } 291 } 292 if (el->el_map.alt == NULL) 293 el->el_map.current = el->el_map.key; 294 } while (cmd == ED_SEQUENCE_LEAD_IN); 295 *cmdnum = cmd; 296 return OKCMD; 297 } 298 299 #ifdef WIDECHAR 300 /* utf8_islead(): 301 * Test whether a byte is a leading byte of a UTF-8 sequence. 302 */ 303 private int 304 utf8_islead(int c) 305 { 306 return c < 0x80 || /* single byte char */ 307 (c >= 0xc2 && c <= 0xf4); /* start of multibyte sequence */ 308 } 309 #endif 310 311 /* read_char(): 312 * Read a character from the tty. 313 */ 314 private int 315 read_char(EditLine *el, Char *cp) 316 { 317 ssize_t num_read; 318 int tried = 0; 319 char cbuf[MB_LEN_MAX]; 320 size_t cbp = 0; 321 int bytes = 0; 322 323 again: 324 el->el_signal->sig_no = 0; 325 while ((num_read = read(el->el_infd, cbuf + cbp, (size_t)1)) == -1) { 326 int e = errno; 327 switch (el->el_signal->sig_no) { 328 case SIGCONT: 329 FUN(el,set)(el, EL_REFRESH); 330 /*FALLTHROUGH*/ 331 case SIGWINCH: 332 sig_set(el); 333 goto again; 334 default: 335 break; 336 } 337 if (!tried && read__fixio(el->el_infd, e) == 0) 338 tried = 1; 339 else { 340 errno = e; 341 *cp = '\0'; 342 return -1; 343 } 344 } 345 346 /* Test for EOF */ 347 if (num_read == 0) { 348 errno = 0; 349 *cp = '\0'; 350 return 0; 351 } 352 353 #ifdef WIDECHAR 354 if (el->el_flags & CHARSET_IS_UTF8) { 355 if (!utf8_islead((unsigned char)cbuf[0])) 356 goto again; /* discard the byte we read and try again */ 357 ++cbp; 358 if ((bytes = ct_mbtowc(cp, cbuf, cbp)) == -1) { 359 ct_mbtowc_reset; 360 if (cbp >= MB_LEN_MAX) { /* "shouldn't happen" */ 361 errno = EILSEQ; 362 *cp = '\0'; 363 return -1; 364 } 365 goto again; 366 } 367 } else if (isascii((unsigned char)cbuf[0]) || 368 /* we don't support other multibyte charsets */ 369 ++cbp != 1 || 370 /* Try non-ASCII characters in a 8-bit character set */ 371 (bytes = ct_mbtowc(cp, cbuf, cbp)) != 1) 372 #endif 373 *cp = (unsigned char)cbuf[0]; 374 375 if ((el->el_flags & IGNORE_EXTCHARS) && bytes > 1) { 376 cbp = 0; /* skip this character */ 377 goto again; 378 } 379 380 return (int)num_read; 381 } 382 383 /* read_pop(): 384 * Pop a macro from the stack 385 */ 386 private void 387 read_pop(c_macro_t *ma) 388 { 389 int i; 390 391 el_free(ma->macro[0]); 392 for (i = 0; i < ma->level; i++) 393 ma->macro[i] = ma->macro[i + 1]; 394 ma->level--; 395 ma->offset = 0; 396 } 397 398 /* el_getc(): 399 * Read a character 400 */ 401 public int 402 FUN(el,getc)(EditLine *el, Char *cp) 403 { 404 int num_read; 405 c_macro_t *ma = &el->el_chared.c_macro; 406 407 terminal__flush(el); 408 for (;;) { 409 if (ma->level < 0) { 410 if (!read_preread(el)) 411 break; 412 } 413 414 if (ma->level < 0) 415 break; 416 417 if (ma->macro[0][ma->offset] == '\0') { 418 read_pop(ma); 419 continue; 420 } 421 422 *cp = ma->macro[0][ma->offset++]; 423 424 if (ma->macro[0][ma->offset] == '\0') { 425 /* Needed for QuoteMode On */ 426 read_pop(ma); 427 } 428 429 return 1; 430 } 431 432 #ifdef DEBUG_READ 433 (void) fprintf(el->el_errfile, "Turning raw mode on\n"); 434 #endif /* DEBUG_READ */ 435 if (tty_rawmode(el) < 0)/* make sure the tty is set up correctly */ 436 return 0; 437 438 #ifdef DEBUG_READ 439 (void) fprintf(el->el_errfile, "Reading a character\n"); 440 #endif /* DEBUG_READ */ 441 num_read = (*el->el_read.read_char)(el, cp); 442 if (num_read < 0) 443 el->el_errno = errno; 444 #ifdef WIDECHAR 445 if (el->el_flags & NARROW_READ) 446 *cp = *(char *)(void *)cp; 447 #endif 448 #ifdef DEBUG_READ 449 (void) fprintf(el->el_errfile, "Got it %c\n", *cp); 450 #endif /* DEBUG_READ */ 451 return num_read; 452 } 453 454 protected void 455 read_prepare(EditLine *el) 456 { 457 if (el->el_flags & HANDLE_SIGNALS) 458 sig_set(el); 459 if (el->el_flags & NO_TTY) 460 return; 461 if ((el->el_flags & (UNBUFFERED|EDIT_DISABLED)) == UNBUFFERED) 462 tty_rawmode(el); 463 464 /* This is relatively cheap, and things go terribly wrong if 465 we have the wrong size. */ 466 el_resize(el); 467 re_clear_display(el); /* reset the display stuff */ 468 ch_reset(el, 0); 469 re_refresh(el); /* print the prompt */ 470 471 if (el->el_flags & UNBUFFERED) 472 terminal__flush(el); 473 } 474 475 protected void 476 read_finish(EditLine *el) 477 { 478 if ((el->el_flags & UNBUFFERED) == 0) 479 (void) tty_cookedmode(el); 480 if (el->el_flags & HANDLE_SIGNALS) 481 sig_clr(el); 482 } 483 484 public const Char * 485 FUN(el,gets)(EditLine *el, int *nread) 486 { 487 int retval; 488 el_action_t cmdnum = 0; 489 int num; /* how many chars we have read at NL */ 490 Char ch, *cp; 491 int crlf = 0; 492 int nrb; 493 #ifdef FIONREAD 494 c_macro_t *ma = &el->el_chared.c_macro; 495 #endif /* FIONREAD */ 496 497 if (nread == NULL) 498 nread = &nrb; 499 *nread = 0; 500 501 if (el->el_flags & NO_TTY) { 502 size_t idx; 503 504 cp = el->el_line.buffer; 505 while ((num = (*el->el_read.read_char)(el, cp)) == 1) { 506 /* make sure there is space for next character */ 507 if (cp + 1 >= el->el_line.limit) { 508 idx = (size_t)(cp - el->el_line.buffer); 509 if (!ch_enlargebufs(el, (size_t)2)) 510 break; 511 cp = &el->el_line.buffer[idx]; 512 } 513 cp++; 514 if (el->el_flags & UNBUFFERED) 515 break; 516 if (cp[-1] == '\r' || cp[-1] == '\n') 517 break; 518 } 519 if (num == -1) { 520 if (errno == EINTR) 521 cp = el->el_line.buffer; 522 el->el_errno = errno; 523 } 524 525 goto noedit; 526 } 527 528 529 #ifdef FIONREAD 530 if (el->el_tty.t_mode == EX_IO && ma->level < 0) { 531 long chrs = 0; 532 533 (void) ioctl(el->el_infd, FIONREAD, &chrs); 534 if (chrs == 0) { 535 if (tty_rawmode(el) < 0) { 536 errno = 0; 537 *nread = 0; 538 return NULL; 539 } 540 } 541 } 542 #endif /* FIONREAD */ 543 544 if ((el->el_flags & UNBUFFERED) == 0) 545 read_prepare(el); 546 547 if (el->el_flags & EDIT_DISABLED) { 548 size_t idx; 549 550 if ((el->el_flags & UNBUFFERED) == 0) 551 cp = el->el_line.buffer; 552 else 553 cp = el->el_line.lastchar; 554 555 terminal__flush(el); 556 557 while ((num = (*el->el_read.read_char)(el, cp)) == 1) { 558 /* make sure there is space next character */ 559 if (cp + 1 >= el->el_line.limit) { 560 idx = (size_t)(cp - el->el_line.buffer); 561 if (!ch_enlargebufs(el, (size_t)2)) 562 break; 563 cp = &el->el_line.buffer[idx]; 564 } 565 cp++; 566 crlf = cp[-1] == '\r' || cp[-1] == '\n'; 567 if (el->el_flags & UNBUFFERED) 568 break; 569 if (crlf) 570 break; 571 } 572 573 if (num == -1) { 574 if (errno == EINTR) 575 cp = el->el_line.buffer; 576 el->el_errno = errno; 577 } 578 579 goto noedit; 580 } 581 582 for (num = OKCMD; num == OKCMD;) { /* while still editing this 583 * line */ 584 #ifdef DEBUG_EDIT 585 read_debug(el); 586 #endif /* DEBUG_EDIT */ 587 /* if EOF or error */ 588 if ((num = read_getcmd(el, &cmdnum, &ch)) != OKCMD) { 589 num = -1; 590 #ifdef DEBUG_READ 591 (void) fprintf(el->el_errfile, 592 "Returning from el_gets %d\n", num); 593 #endif /* DEBUG_READ */ 594 break; 595 } 596 if (el->el_errno == EINTR) { 597 el->el_line.buffer[0] = '\0'; 598 el->el_line.lastchar = 599 el->el_line.cursor = el->el_line.buffer; 600 break; 601 } 602 if ((size_t)cmdnum >= el->el_map.nfunc) { /* BUG CHECK command */ 603 #ifdef DEBUG_EDIT 604 (void) fprintf(el->el_errfile, 605 "ERROR: illegal command from key 0%o\r\n", ch); 606 #endif /* DEBUG_EDIT */ 607 continue; /* try again */ 608 } 609 /* now do the real command */ 610 #ifdef DEBUG_READ 611 { 612 el_bindings_t *b; 613 for (b = el->el_map.help; b->name; b++) 614 if (b->func == cmdnum) 615 break; 616 if (b->name) 617 (void) fprintf(el->el_errfile, 618 "Executing %s\n", b->name); 619 else 620 (void) fprintf(el->el_errfile, 621 "Error command = %d\n", cmdnum); 622 } 623 #endif /* DEBUG_READ */ 624 /* vi redo needs these way down the levels... */ 625 el->el_state.thiscmd = cmdnum; 626 el->el_state.thisch = ch; 627 if (el->el_map.type == MAP_VI && 628 el->el_map.current == el->el_map.key && 629 el->el_chared.c_redo.pos < el->el_chared.c_redo.lim) { 630 if (cmdnum == VI_DELETE_PREV_CHAR && 631 el->el_chared.c_redo.pos != el->el_chared.c_redo.buf 632 && Isprint(el->el_chared.c_redo.pos[-1])) 633 el->el_chared.c_redo.pos--; 634 else 635 *el->el_chared.c_redo.pos++ = ch; 636 } 637 retval = (*el->el_map.func[cmdnum]) (el, ch); 638 #ifdef DEBUG_READ 639 (void) fprintf(el->el_errfile, 640 "Returned state %d\n", retval ); 641 #endif /* DEBUG_READ */ 642 643 /* save the last command here */ 644 el->el_state.lastcmd = cmdnum; 645 646 /* use any return value */ 647 switch (retval) { 648 case CC_CURSOR: 649 re_refresh_cursor(el); 650 break; 651 652 case CC_REDISPLAY: 653 re_clear_lines(el); 654 re_clear_display(el); 655 /* FALLTHROUGH */ 656 657 case CC_REFRESH: 658 re_refresh(el); 659 break; 660 661 case CC_REFRESH_BEEP: 662 re_refresh(el); 663 terminal_beep(el); 664 break; 665 666 case CC_NORM: /* normal char */ 667 break; 668 669 case CC_ARGHACK: /* Suggested by Rich Salz */ 670 /* <[email protected]> */ 671 continue; /* keep going... */ 672 673 case CC_EOF: /* end of file typed */ 674 if ((el->el_flags & UNBUFFERED) == 0) 675 num = 0; 676 else if (num == -1) { 677 *el->el_line.lastchar++ = CONTROL('d'); 678 el->el_line.cursor = el->el_line.lastchar; 679 num = 1; 680 } 681 break; 682 683 case CC_NEWLINE: /* normal end of line */ 684 num = (int)(el->el_line.lastchar - el->el_line.buffer); 685 break; 686 687 case CC_FATAL: /* fatal error, reset to known state */ 688 #ifdef DEBUG_READ 689 (void) fprintf(el->el_errfile, 690 "*** editor fatal ERROR ***\r\n\n"); 691 #endif /* DEBUG_READ */ 692 /* put (real) cursor in a known place */ 693 re_clear_display(el); /* reset the display stuff */ 694 ch_reset(el, 1); /* reset the input pointers */ 695 re_refresh(el); /* print the prompt again */ 696 break; 697 698 case CC_ERROR: 699 default: /* functions we don't know about */ 700 #ifdef DEBUG_READ 701 (void) fprintf(el->el_errfile, 702 "*** editor ERROR ***\r\n\n"); 703 #endif /* DEBUG_READ */ 704 terminal_beep(el); 705 terminal__flush(el); 706 break; 707 } 708 el->el_state.argument = 1; 709 el->el_state.doingarg = 0; 710 el->el_chared.c_vcmd.action = NOP; 711 if (el->el_flags & UNBUFFERED) 712 break; 713 } 714 715 terminal__flush(el); /* flush any buffered output */ 716 /* make sure the tty is set up correctly */ 717 if ((el->el_flags & UNBUFFERED) == 0) { 718 read_finish(el); 719 *nread = num != -1 ? num : 0; 720 } else { 721 *nread = (int)(el->el_line.lastchar - el->el_line.buffer); 722 } 723 goto done; 724 noedit: 725 el->el_line.cursor = el->el_line.lastchar = cp; 726 *cp = '\0'; 727 *nread = (int)(el->el_line.cursor - el->el_line.buffer); 728 done: 729 if (*nread == 0) { 730 if (num == -1) { 731 *nread = -1; 732 errno = el->el_errno; 733 } 734 return NULL; 735 } else 736 return el->el_line.buffer; 737 } 738