1 /* $NetBSD: read.c,v 1.107 2021/08/15 10:08:41 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.107 2021/08/15 10:08:41 christos Exp $"); 41 #endif 42 #endif /* not lint && not SCCSID */ 43 44 /* 45 * read.c: Terminal read functions 46 */ 47 #include <ctype.h> 48 #include <errno.h> 49 #include <fcntl.h> 50 #include <limits.h> 51 #include <stdlib.h> 52 #include <string.h> 53 #include <unistd.h> 54 55 #include "el.h" 56 #include "fcns.h" 57 #include "read.h" 58 59 #define EL_MAXMACRO 10 60 61 struct macros { 62 wchar_t **macro; 63 int level; 64 int offset; 65 }; 66 67 struct el_read_t { 68 struct macros macros; 69 el_rfunc_t read_char; /* Function to read a character. */ 70 int read_errno; 71 }; 72 73 static int read__fixio(int, int); 74 static int read_char(EditLine *, wchar_t *); 75 static int read_getcmd(EditLine *, el_action_t *, wchar_t *); 76 static void read_clearmacros(struct macros *); 77 static void read_pop(struct macros *); 78 static const wchar_t *noedit_wgets(EditLine *, int *); 79 80 /* read_init(): 81 * Initialize the read stuff 82 */ 83 libedit_private int 84 read_init(EditLine *el) 85 { 86 struct macros *ma; 87 88 if ((el->el_read = el_malloc(sizeof(*el->el_read))) == NULL) 89 return -1; 90 91 ma = &el->el_read->macros; 92 if ((ma->macro = el_calloc(EL_MAXMACRO, sizeof(*ma->macro))) == NULL) { 93 free(el->el_read); 94 return -1; 95 } 96 ma->level = -1; 97 ma->offset = 0; 98 99 /* builtin read_char */ 100 el->el_read->read_char = read_char; 101 return 0; 102 } 103 104 /* el_read_end(): 105 * Free the data structures used by the read stuff. 106 */ 107 libedit_private void 108 read_end(struct el_read_t *el_read) 109 { 110 read_clearmacros(&el_read->macros); 111 el_free(el_read->macros.macro); 112 el_read->macros.macro = NULL; 113 el_free(el_read); 114 } 115 116 /* el_read_setfn(): 117 * Set the read char function to the one provided. 118 * If it is set to EL_BUILTIN_GETCFN, then reset to the builtin one. 119 */ 120 libedit_private int 121 el_read_setfn(struct el_read_t *el_read, el_rfunc_t rc) 122 { 123 el_read->read_char = (rc == EL_BUILTIN_GETCFN) ? read_char : rc; 124 return 0; 125 } 126 127 128 /* el_read_getfn(): 129 * return the current read char function, or EL_BUILTIN_GETCFN 130 * if it is the default one 131 */ 132 libedit_private el_rfunc_t 133 el_read_getfn(struct el_read_t *el_read) 134 { 135 return el_read->read_char == read_char ? 136 EL_BUILTIN_GETCFN : el_read->read_char; 137 } 138 139 140 /* read__fixio(): 141 * Try to recover from a read error 142 */ 143 /* ARGSUSED */ 144 static int 145 read__fixio(int fd __attribute__((__unused__)), int e) 146 { 147 148 switch (e) { 149 case -1: /* Make sure that the code is reachable */ 150 151 #ifdef EWOULDBLOCK 152 case EWOULDBLOCK: 153 #ifndef TRY_AGAIN 154 #define TRY_AGAIN 155 #endif 156 #endif /* EWOULDBLOCK */ 157 158 #if defined(POSIX) && defined(EAGAIN) 159 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN 160 case EAGAIN: 161 #ifndef TRY_AGAIN 162 #define TRY_AGAIN 163 #endif 164 #endif /* EWOULDBLOCK && EWOULDBLOCK != EAGAIN */ 165 #endif /* POSIX && EAGAIN */ 166 167 e = 0; 168 #ifdef TRY_AGAIN 169 #if defined(F_SETFL) && defined(O_NDELAY) 170 if ((e = fcntl(fd, F_GETFL, 0)) == -1) 171 return -1; 172 173 if (fcntl(fd, F_SETFL, e & ~O_NDELAY) == -1) 174 return -1; 175 else 176 e = 1; 177 #endif /* F_SETFL && O_NDELAY */ 178 179 #ifdef FIONBIO 180 { 181 int zero = 0; 182 183 if (ioctl(fd, FIONBIO, &zero) == -1) 184 return -1; 185 else 186 e = 1; 187 } 188 #endif /* FIONBIO */ 189 190 #endif /* TRY_AGAIN */ 191 return e ? 0 : -1; 192 193 case EINTR: 194 return 0; 195 196 default: 197 return -1; 198 } 199 } 200 201 202 /* el_push(): 203 * Push a macro 204 */ 205 void 206 el_wpush(EditLine *el, const wchar_t *str) 207 { 208 struct macros *ma = &el->el_read->macros; 209 210 if (str != NULL && ma->level + 1 < EL_MAXMACRO) { 211 ma->level++; 212 if ((ma->macro[ma->level] = wcsdup(str)) != NULL) 213 return; 214 ma->level--; 215 } 216 terminal_beep(el); 217 terminal__flush(el); 218 } 219 220 221 /* read_getcmd(): 222 * Get next command from the input stream, 223 * return 0 on success or -1 on EOF or error. 224 * Character values > 255 are not looked up in the map, but inserted. 225 */ 226 static int 227 read_getcmd(EditLine *el, el_action_t *cmdnum, wchar_t *ch) 228 { 229 static const wchar_t meta = (wchar_t)0x80; 230 el_action_t cmd; 231 232 do { 233 if (el_wgetc(el, ch) != 1) 234 return -1; 235 236 #ifdef KANJI 237 if ((*ch & meta)) { 238 el->el_state.metanext = 0; 239 cmd = CcViMap[' ']; 240 break; 241 } else 242 #endif /* KANJI */ 243 244 if (el->el_state.metanext) { 245 el->el_state.metanext = 0; 246 *ch |= meta; 247 } 248 if (*ch >= N_KEYS) 249 cmd = ED_INSERT; 250 else 251 cmd = el->el_map.current[(unsigned char) *ch]; 252 if (cmd == ED_SEQUENCE_LEAD_IN) { 253 keymacro_value_t val; 254 switch (keymacro_get(el, ch, &val)) { 255 case XK_CMD: 256 cmd = val.cmd; 257 break; 258 case XK_STR: 259 el_wpush(el, val.str); 260 break; 261 case XK_NOD: 262 return -1; 263 default: 264 EL_ABORT((el->el_errfile, "Bad XK_ type \n")); 265 break; 266 } 267 } 268 } while (cmd == ED_SEQUENCE_LEAD_IN); 269 *cmdnum = cmd; 270 return 0; 271 } 272 273 /* read_char(): 274 * Read a character from the tty. 275 */ 276 static int 277 read_char(EditLine *el, wchar_t *cp) 278 { 279 ssize_t num_read; 280 int tried = (el->el_flags & FIXIO) == 0; 281 char cbuf[MB_LEN_MAX]; 282 size_t cbp = 0; 283 int save_errno = errno; 284 285 again: 286 el->el_signal->sig_no = 0; 287 while ((num_read = read(el->el_infd, cbuf + cbp, (size_t)1)) == -1) { 288 int e = errno; 289 switch (el->el_signal->sig_no) { 290 case SIGCONT: 291 el_wset(el, EL_REFRESH); 292 /*FALLTHROUGH*/ 293 case SIGWINCH: 294 sig_set(el); 295 goto again; 296 default: 297 break; 298 } 299 if (!tried && read__fixio(el->el_infd, e) == 0) { 300 errno = save_errno; 301 tried = 1; 302 } else { 303 errno = e; 304 *cp = L'\0'; 305 return -1; 306 } 307 } 308 309 /* Test for EOF */ 310 if (num_read == 0) { 311 *cp = L'\0'; 312 return 0; 313 } 314 315 for (;;) { 316 mbstate_t mbs; 317 318 ++cbp; 319 /* This only works because UTF8 is stateless. */ 320 memset(&mbs, 0, sizeof(mbs)); 321 switch (mbrtowc(cp, cbuf, cbp, &mbs)) { 322 case (size_t)-1: 323 if (cbp > 1) { 324 /* 325 * Invalid sequence, discard all bytes 326 * except the last one. 327 */ 328 cbuf[0] = cbuf[cbp - 1]; 329 cbp = 0; 330 break; 331 } else { 332 /* Invalid byte, discard it. */ 333 cbp = 0; 334 goto again; 335 } 336 case (size_t)-2: 337 if (cbp >= MB_LEN_MAX) { 338 errno = EILSEQ; 339 *cp = L'\0'; 340 return -1; 341 } 342 /* Incomplete sequence, read another byte. */ 343 goto again; 344 default: 345 /* Valid character, process it. */ 346 return 1; 347 } 348 } 349 } 350 351 /* read_pop(): 352 * Pop a macro from the stack 353 */ 354 static void 355 read_pop(struct macros *ma) 356 { 357 int i; 358 359 el_free(ma->macro[0]); 360 for (i = 0; i < ma->level; i++) 361 ma->macro[i] = ma->macro[i + 1]; 362 ma->level--; 363 ma->offset = 0; 364 } 365 366 static void 367 read_clearmacros(struct macros *ma) 368 { 369 while (ma->level >= 0) 370 el_free(ma->macro[ma->level--]); 371 ma->offset = 0; 372 } 373 374 /* el_wgetc(): 375 * Read a wide character 376 */ 377 int 378 el_wgetc(EditLine *el, wchar_t *cp) 379 { 380 struct macros *ma = &el->el_read->macros; 381 int num_read; 382 383 terminal__flush(el); 384 for (;;) { 385 if (ma->level < 0) 386 break; 387 388 if (ma->macro[0][ma->offset] == '\0') { 389 read_pop(ma); 390 continue; 391 } 392 393 *cp = ma->macro[0][ma->offset++]; 394 395 if (ma->macro[0][ma->offset] == '\0') { 396 /* Needed for QuoteMode On */ 397 read_pop(ma); 398 } 399 400 return 1; 401 } 402 403 if (tty_rawmode(el) < 0)/* make sure the tty is set up correctly */ 404 return 0; 405 406 num_read = (*el->el_read->read_char)(el, cp); 407 408 /* 409 * Remember the original reason of a read failure 410 * such that el_wgets() can restore it after doing 411 * various cleanup operation that might change errno. 412 */ 413 if (num_read < 0) 414 el->el_read->read_errno = errno; 415 416 return num_read; 417 } 418 419 libedit_private void 420 read_prepare(EditLine *el) 421 { 422 if (el->el_flags & HANDLE_SIGNALS) 423 sig_set(el); 424 if (el->el_flags & NO_TTY) 425 return; 426 if ((el->el_flags & (UNBUFFERED|EDIT_DISABLED)) == UNBUFFERED) 427 tty_rawmode(el); 428 429 /* This is relatively cheap, and things go terribly wrong if 430 we have the wrong size. */ 431 el_resize(el); 432 re_clear_display(el); /* reset the display stuff */ 433 ch_reset(el); 434 re_refresh(el); /* print the prompt */ 435 436 if (el->el_flags & UNBUFFERED) 437 terminal__flush(el); 438 } 439 440 libedit_private void 441 read_finish(EditLine *el) 442 { 443 if ((el->el_flags & UNBUFFERED) == 0) 444 (void) tty_cookedmode(el); 445 if (el->el_flags & HANDLE_SIGNALS) 446 sig_clr(el); 447 } 448 449 static const wchar_t * 450 noedit_wgets(EditLine *el, int *nread) 451 { 452 el_line_t *lp = &el->el_line; 453 int num; 454 455 while ((num = (*el->el_read->read_char)(el, lp->lastchar)) == 1) { 456 if (lp->lastchar + 1 >= lp->limit && 457 !ch_enlargebufs(el, (size_t)2)) 458 break; 459 lp->lastchar++; 460 if (el->el_flags & UNBUFFERED || 461 lp->lastchar[-1] == '\r' || 462 lp->lastchar[-1] == '\n') 463 break; 464 } 465 if (num == -1 && errno == EINTR) 466 lp->lastchar = lp->buffer; 467 lp->cursor = lp->lastchar; 468 *lp->lastchar = '\0'; 469 *nread = (int)(lp->lastchar - lp->buffer); 470 return *nread ? lp->buffer : NULL; 471 } 472 473 const wchar_t * 474 el_wgets(EditLine *el, int *nread) 475 { 476 int retval; 477 el_action_t cmdnum = 0; 478 int num; /* how many chars we have read at NL */ 479 wchar_t ch; 480 int nrb; 481 482 if (nread == NULL) 483 nread = &nrb; 484 *nread = 0; 485 el->el_read->read_errno = 0; 486 487 if (el->el_flags & NO_TTY) { 488 el->el_line.lastchar = el->el_line.buffer; 489 return noedit_wgets(el, nread); 490 } 491 492 #ifdef FIONREAD 493 if (el->el_tty.t_mode == EX_IO && el->el_read->macros.level < 0) { 494 int chrs = 0; 495 496 (void) ioctl(el->el_infd, FIONREAD, &chrs); 497 if (chrs == 0) { 498 if (tty_rawmode(el) < 0) { 499 errno = 0; 500 *nread = 0; 501 return NULL; 502 } 503 } 504 } 505 #endif /* FIONREAD */ 506 507 if ((el->el_flags & UNBUFFERED) == 0) 508 read_prepare(el); 509 510 if (el->el_flags & EDIT_DISABLED) { 511 if ((el->el_flags & UNBUFFERED) == 0) 512 el->el_line.lastchar = el->el_line.buffer; 513 terminal__flush(el); 514 return noedit_wgets(el, nread); 515 } 516 517 for (num = -1; num == -1;) { /* while still editing this line */ 518 /* if EOF or error */ 519 if (read_getcmd(el, &cmdnum, &ch) == -1) 520 break; 521 if ((size_t)cmdnum >= el->el_map.nfunc) /* BUG CHECK command */ 522 continue; /* try again */ 523 /* now do the real command */ 524 /* vi redo needs these way down the levels... */ 525 el->el_state.thiscmd = cmdnum; 526 el->el_state.thisch = ch; 527 if (el->el_map.type == MAP_VI && 528 el->el_map.current == el->el_map.key && 529 el->el_chared.c_redo.pos < el->el_chared.c_redo.lim) { 530 if (cmdnum == VI_DELETE_PREV_CHAR && 531 el->el_chared.c_redo.pos != el->el_chared.c_redo.buf 532 && iswprint(el->el_chared.c_redo.pos[-1])) 533 el->el_chared.c_redo.pos--; 534 else 535 *el->el_chared.c_redo.pos++ = ch; 536 } 537 retval = (*el->el_map.func[cmdnum]) (el, ch); 538 539 /* save the last command here */ 540 el->el_state.lastcmd = cmdnum; 541 542 /* use any return value */ 543 switch (retval) { 544 case CC_CURSOR: 545 re_refresh_cursor(el); 546 break; 547 548 case CC_REDISPLAY: 549 re_clear_lines(el); 550 re_clear_display(el); 551 /* FALLTHROUGH */ 552 553 case CC_REFRESH: 554 re_refresh(el); 555 break; 556 557 case CC_REFRESH_BEEP: 558 re_refresh(el); 559 terminal_beep(el); 560 break; 561 562 case CC_NORM: /* normal char */ 563 break; 564 565 case CC_ARGHACK: /* Suggested by Rich Salz */ 566 /* <rsalz@pineapple.bbn.com> */ 567 continue; /* keep going... */ 568 569 case CC_EOF: /* end of file typed */ 570 if ((el->el_flags & UNBUFFERED) == 0) 571 num = 0; 572 else if (num == -1) { 573 *el->el_line.lastchar++ = CONTROL('d'); 574 el->el_line.cursor = el->el_line.lastchar; 575 num = 1; 576 } 577 break; 578 579 case CC_NEWLINE: /* normal end of line */ 580 num = (int)(el->el_line.lastchar - el->el_line.buffer); 581 break; 582 583 case CC_FATAL: /* fatal error, reset to known state */ 584 /* put (real) cursor in a known place */ 585 re_clear_display(el); /* reset the display stuff */ 586 ch_reset(el); /* reset the input pointers */ 587 read_clearmacros(&el->el_read->macros); 588 re_refresh(el); /* print the prompt again */ 589 break; 590 591 case CC_ERROR: 592 default: /* functions we don't know about */ 593 terminal_beep(el); 594 terminal__flush(el); 595 break; 596 } 597 el->el_state.argument = 1; 598 el->el_state.doingarg = 0; 599 el->el_chared.c_vcmd.action = NOP; 600 if (el->el_flags & UNBUFFERED) 601 break; 602 } 603 604 terminal__flush(el); /* flush any buffered output */ 605 /* make sure the tty is set up correctly */ 606 if ((el->el_flags & UNBUFFERED) == 0) { 607 read_finish(el); 608 *nread = num != -1 ? num : 0; 609 } else 610 *nread = (int)(el->el_line.lastchar - el->el_line.buffer); 611 612 if (*nread == 0) { 613 if (num == -1) { 614 *nread = -1; 615 if (el->el_read->read_errno) 616 errno = el->el_read->read_errno; 617 } 618 return NULL; 619 } else 620 return el->el_line.buffer; 621 } 622