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