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