1 /* $NetBSD: read.c,v 1.16 2000/01/19 18:30:19 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. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 */ 38 39 #include <sys/cdefs.h> 40 #if !defined(lint) && !defined(SCCSID) 41 #if 0 42 static char sccsid[] = "@(#)read.c 8.1 (Berkeley) 6/4/93"; 43 #else 44 __RCSID("$NetBSD: read.c,v 1.16 2000/01/19 18:30:19 christos Exp $"); 45 #endif 46 #endif /* not lint && not SCCSID */ 47 48 /* 49 * read.c: Clean this junk up! This is horrible code. 50 * Terminal read functions 51 */ 52 #include "sys.h" 53 #include <errno.h> 54 #include <unistd.h> 55 #include <stdlib.h> 56 #include "el.h" 57 58 #define OKCMD -1 59 60 private int read__fixio __P((int, int)); 61 private int read_preread __P((EditLine *)); 62 private int read_getcmd __P((EditLine *, el_action_t *, char *)); 63 private int read_char __P((EditLine *, char *)); 64 65 #ifdef DEBUG_EDIT 66 private void 67 read_debug(el) 68 EditLine *el; 69 { 70 71 if (el->el_line.cursor > el->el_line.lastchar) 72 (void) fprintf(el->el_errfile, "cursor > lastchar\r\n"); 73 if (el->el_line.cursor < el->el_line.buffer) 74 (void) fprintf(el->el_errfile, "cursor < buffer\r\n"); 75 if (el->el_line.cursor > el->el_line.limit) 76 (void) fprintf(el->el_errfile, "cursor > limit\r\n"); 77 if (el->el_line.lastchar > el->el_line.limit) 78 (void) fprintf(el->el_errfile, "lastchar > limit\r\n"); 79 if (el->el_line.limit != &el->el_line.buffer[EL_BUFSIZ - 2]) 80 (void) fprintf(el->el_errfile, "limit != &buffer[EL_BUFSIZ-2]\r\n"); 81 } 82 #endif /* DEBUG_EDIT */ 83 84 /* read__fixio(): 85 * Try to recover from a read error 86 */ 87 /* ARGSUSED */ 88 private int 89 read__fixio(fd, e) 90 int fd, e; 91 { 92 switch (e) { 93 case -1: /* Make sure that the code is reachable */ 94 95 #ifdef EWOULDBLOCK 96 case EWOULDBLOCK: 97 # ifndef TRY_AGAIN 98 # define TRY_AGAIN 99 # endif 100 #endif /* EWOULDBLOCK */ 101 102 #if defined(POSIX) && defined(EAGAIN) 103 # if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN 104 case EAGAIN: 105 # ifndef TRY_AGAIN 106 # define TRY_AGAIN 107 # endif 108 # endif /* EWOULDBLOCK && EWOULDBLOCK != EAGAIN */ 109 #endif /* POSIX && EAGAIN */ 110 111 e = 0; 112 #ifdef TRY_AGAIN 113 # if defined(F_SETFL) && defined(O_NDELAY) 114 if ((e = fcntl(fd, F_GETFL, 0)) == -1) 115 return -1; 116 117 if (fcntl(fd, F_SETFL, e & ~O_NDELAY) == -1) 118 return -1; 119 else 120 e = 1; 121 # endif /* F_SETFL && O_NDELAY */ 122 123 # ifdef FIONBIO 124 { 125 int zero = 0; 126 127 if (ioctl(fd, FIONBIO, (ioctl_t) &zero) == -1) 128 return -1; 129 else 130 e = 1; 131 } 132 # endif /* FIONBIO */ 133 134 #endif /* TRY_AGAIN */ 135 return e ? 0 : -1; 136 137 case EINTR: 138 return 0; 139 140 default: 141 return -1; 142 } 143 } 144 145 146 /* read_preread(): 147 * Try to read the stuff in the input queue; 148 */ 149 private int 150 read_preread(el) 151 EditLine *el; 152 { 153 int chrs = 0; 154 155 if (el->el_chared.c_macro.nline) { 156 el_free((ptr_t) el->el_chared.c_macro.nline); 157 el->el_chared.c_macro.nline = NULL; 158 } 159 160 if (el->el_tty.t_mode == ED_IO) 161 return 0; 162 163 #ifdef FIONREAD 164 (void) ioctl(el->el_infd, FIONREAD, (ioctl_t) &chrs); 165 if (chrs > 0) { 166 char buf[EL_BUFSIZ]; 167 168 chrs = read(el->el_infd, buf, (size_t) MIN(chrs, EL_BUFSIZ - 1)); 169 if (chrs > 0) { 170 buf[chrs] = '\0'; 171 el->el_chared.c_macro.nline = strdup(buf); 172 el_push(el, el->el_chared.c_macro.nline); 173 } 174 } 175 #endif /* FIONREAD */ 176 177 return chrs > 0; 178 } 179 180 181 /* el_push(): 182 * Push a macro 183 */ 184 public void 185 el_push(el, str) 186 EditLine *el; 187 const char *str; 188 { 189 c_macro_t *ma = &el->el_chared.c_macro; 190 191 if (str != NULL && ma->level + 1 < EL_MAXMACRO) { 192 ma->level++; 193 /* LINTED const cast */ 194 ma->macro[ma->level] = (char *) str; 195 } 196 else { 197 term_beep(el); 198 term__flush(); 199 } 200 } 201 202 203 /* read_getcmd(): 204 * Return next command from the input stream. 205 */ 206 private int 207 read_getcmd(el, cmdnum, ch) 208 EditLine *el; 209 el_action_t *cmdnum; 210 char *ch; 211 { 212 el_action_t cmd = ED_UNASSIGNED; 213 int num; 214 215 while (cmd == ED_UNASSIGNED || cmd == ED_SEQUENCE_LEAD_IN) { 216 if ((num = el_getc(el, ch)) != 1) /* if EOF or error */ 217 return num; 218 219 #ifdef KANJI 220 if ((*ch & 0200)) { 221 el->el_state.metanext = 0; 222 cmd = CcViMap[' ']; 223 break; 224 } 225 else 226 #endif /* KANJI */ 227 228 if (el->el_state.metanext) { 229 el->el_state.metanext = 0; 230 *ch |= 0200; 231 } 232 cmd = el->el_map.current[(unsigned char) *ch]; 233 if (cmd == ED_SEQUENCE_LEAD_IN) { 234 key_value_t val; 235 switch (key_get(el, ch, &val)) { 236 case XK_CMD: 237 cmd = val.cmd; 238 break; 239 case XK_STR: 240 el_push(el, val.str); 241 break; 242 #ifdef notyet 243 case XK_EXE: 244 /* XXX: In the future to run a user function */ 245 RunCommand(val.str); 246 break; 247 #endif 248 default: 249 abort(); 250 break; 251 } 252 } 253 if (el->el_map.alt == NULL) 254 el->el_map.current = el->el_map.key; 255 } 256 *cmdnum = cmd; 257 return OKCMD; 258 } 259 260 /* read_char(): 261 * Read a character from the tty. 262 */ 263 private int 264 read_char(el, cp) 265 EditLine *el; 266 char *cp; 267 { 268 int num_read; 269 int tried = 0; 270 271 while ((num_read = read(el->el_infd, cp, 1)) == -1) 272 if (!tried && read__fixio(el->el_infd, errno) == 0) 273 tried = 1; 274 else { 275 *cp = '\0'; 276 return -1; 277 } 278 279 return num_read; 280 } 281 282 283 /* el_getc(): 284 * Read a character 285 */ 286 public int 287 el_getc(el, cp) 288 EditLine *el; 289 char *cp; 290 { 291 int num_read; 292 c_macro_t *ma = &el->el_chared.c_macro; 293 294 term__flush(); 295 for (;;) { 296 if (ma->level < 0) { 297 if (!read_preread(el)) 298 break; 299 } 300 if (ma->level < 0) 301 break; 302 303 if (*ma->macro[ma->level] == 0) { 304 ma->level--; 305 continue; 306 } 307 *cp = *ma->macro[ma->level]++ & 0377; 308 if (*ma->macro[ma->level] == 0) { /* Needed for QuoteMode On */ 309 ma->level--; 310 } 311 return 1; 312 } 313 314 #ifdef DEBUG_READ 315 (void) fprintf(el->el_errfile, "Turning raw mode on\n"); 316 #endif /* DEBUG_READ */ 317 if (tty_rawmode(el) < 0) /* make sure the tty is set up correctly */ 318 return 0; 319 320 #ifdef DEBUG_READ 321 (void) fprintf(el->el_errfile, "Reading a character\n"); 322 #endif /* DEBUG_READ */ 323 num_read = read_char(el, cp); 324 #ifdef DEBUG_READ 325 (void) fprintf(el->el_errfile, "Got it %c\n", *cp); 326 #endif /* DEBUG_READ */ 327 return num_read; 328 } 329 330 331 332 public const char * 333 el_gets(el, nread) 334 EditLine *el; 335 int *nread; 336 { 337 int retval; 338 el_action_t cmdnum = 0; 339 int num; /* how many chars we have read at NL */ 340 char ch; 341 #ifdef FIONREAD 342 c_macro_t *ma = &el->el_chared.c_macro; 343 #endif /* FIONREAD */ 344 345 if (el->el_flags & HANDLE_SIGNALS) 346 sig_set(el); 347 348 if (el->el_flags & NO_TTY) { 349 char *cp = el->el_line.buffer; 350 351 while (read_char(el, cp) == 1) { 352 cp++; 353 if (cp == el->el_line.limit) { 354 --cp; 355 break; 356 } 357 if (cp[-1] == '\r' || cp[-1] == '\n') 358 break; 359 } 360 el->el_line.cursor = el->el_line.lastchar = cp; 361 *cp = '\0'; 362 if (nread) 363 *nread = el->el_line.cursor - el->el_line.buffer; 364 return el->el_line.buffer; 365 } 366 367 re_clear_display(el); /* reset the display stuff */ 368 ch_reset(el); 369 370 #ifdef FIONREAD 371 if (el->el_tty.t_mode == EX_IO && ma->level < 0) { 372 long chrs = 0; 373 374 (void) ioctl(el->el_infd, FIONREAD, (ioctl_t) &chrs); 375 if (chrs == 0) { 376 if (tty_rawmode(el) < 0) { 377 if (nread) 378 *nread = 0; 379 return NULL; 380 } 381 } 382 } 383 #endif /* FIONREAD */ 384 385 re_refresh(el); /* print the prompt */ 386 387 if (el->el_flags & EDIT_DISABLED) { 388 char *cp = el->el_line.buffer; 389 390 term__flush(); 391 392 while (read_char(el, cp) == 1) { 393 cp++; 394 if (cp == el->el_line.limit) { 395 --cp; 396 break; 397 } 398 if (cp[-1] == '\r' || cp[-1] == '\n') 399 break; 400 401 } 402 el->el_line.cursor = el->el_line.lastchar = cp; 403 *cp = '\0'; 404 if (nread) 405 *nread = el->el_line.cursor - el->el_line.buffer; 406 return el->el_line.buffer; 407 } 408 409 410 for (num = OKCMD; num == OKCMD;) { /* while still editing this line */ 411 #ifdef DEBUG_EDIT 412 read_debug(el); 413 #endif /* DEBUG_EDIT */ 414 /* if EOF or error */ 415 if ((num = read_getcmd(el, &cmdnum, &ch)) != OKCMD) { 416 #ifdef DEBUG_READ 417 (void) fprintf(el->el_errfile, "Returning from el_gets %d\n", num); 418 #endif /* DEBUG_READ */ 419 break; 420 } 421 422 if ((int)cmdnum >= el->el_map.nfunc) { /* BUG CHECK command */ 423 #ifdef DEBUG_EDIT 424 (void) fprintf(el->el_errfile, 425 "ERROR: illegal command from key 0%o\r\n", ch); 426 #endif /* DEBUG_EDIT */ 427 continue; /* try again */ 428 } 429 430 /* now do the real command */ 431 #ifdef DEBUG_READ 432 { 433 el_bindings_t *b; 434 for (b = el->el_map.help; b->name; b++) 435 if (b->func == cmdnum) 436 break; 437 if (b->name) 438 (void) fprintf(el->el_errfile, "Executing %s\n", b->name); 439 else 440 (void) fprintf(el->el_errfile, "Error command = %d\n", cmdnum); 441 } 442 #endif /* DEBUG_READ */ 443 retval = (*el->el_map.func[cmdnum])(el, ch); 444 445 /* save the last command here */ 446 el->el_state.lastcmd = cmdnum; 447 448 /* use any return value */ 449 switch (retval) { 450 case CC_CURSOR: 451 el->el_state.argument = 1; 452 el->el_state.doingarg = 0; 453 re_refresh_cursor(el); 454 break; 455 456 case CC_REDISPLAY: 457 re_clear_lines(el); 458 re_clear_display(el); 459 /* FALLTHROUGH */ 460 461 case CC_REFRESH: 462 el->el_state.argument = 1; 463 el->el_state.doingarg = 0; 464 re_refresh(el); 465 break; 466 467 case CC_REFRESH_BEEP: 468 el->el_state.argument = 1; 469 el->el_state.doingarg = 0; 470 re_refresh(el); 471 term_beep(el); 472 break; 473 474 case CC_NORM: /* normal char */ 475 el->el_state.argument = 1; 476 el->el_state.doingarg = 0; 477 break; 478 479 case CC_ARGHACK: /* Suggested by Rich Salz */ 480 /* <rsalz@pineapple.bbn.com> */ 481 break; /* keep going... */ 482 483 case CC_EOF: /* end of file typed */ 484 num = 0; 485 break; 486 487 case CC_NEWLINE: /* normal end of line */ 488 num = el->el_line.lastchar - el->el_line.buffer; 489 break; 490 491 case CC_FATAL: /* fatal error, reset to known state */ 492 #ifdef DEBUG_READ 493 (void) fprintf(el->el_errfile, "*** editor fatal ERROR ***\r\n\n"); 494 #endif /* DEBUG_READ */ 495 /* put (real) cursor in a known place */ 496 re_clear_display(el); /* reset the display stuff */ 497 ch_reset(el); /* reset the input pointers */ 498 re_refresh(el); /* print the prompt again */ 499 el->el_state.argument = 1; 500 el->el_state.doingarg = 0; 501 break; 502 503 case CC_ERROR: 504 default: /* functions we don't know about */ 505 #ifdef DEBUG_READ 506 (void) fprintf(el->el_errfile, "*** editor ERROR ***\r\n\n"); 507 #endif /* DEBUG_READ */ 508 el->el_state.argument = 1; 509 el->el_state.doingarg = 0; 510 term_beep(el); 511 term__flush(); 512 break; 513 } 514 } 515 516 (void) tty_cookedmode(el); /* make sure the tty is set up correctly */ 517 term__flush(); /* flush any buffered output */ 518 if (el->el_flags & HANDLE_SIGNALS) 519 sig_clr(el); 520 if (nread) 521 *nread = num; 522 return num ? el->el_line.buffer : NULL; 523 } 524