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