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