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