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