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