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