read.c revision 84260
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 *	$NetBSD: read.c,v 1.18 2000/11/11 22:18:58 christos Exp $
37 */
38
39#if !defined(lint) && !defined(SCCSID)
40static char sccsid[] = "@(#)read.c	8.1 (Berkeley) 6/4/93";
41#endif /* not lint && not SCCSID */
42#include <sys/cdefs.h>
43__FBSDID("$FreeBSD: head/lib/libedit/read.c 84260 2001-10-01 08:41:27Z obrien $");
44
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(int, int);
59private int	read_preread(EditLine *);
60private int	read_getcmd(EditLine *, el_action_t *, char *);
61private int	read_char(EditLine *, char *);
62
63#ifdef DEBUG_EDIT
64private void
65read_debug(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
82/* read__fixio():
83 *	Try to recover from a read error
84 */
85/* ARGSUSED */
86private int
87read__fixio(int fd, int e)
88{
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		{
123			int zero = 0;
124
125			if (ioctl(fd, FIONBIO, (ioctl_t) & zero) == -1)
126				return (-1);
127			else
128				e = 1;
129		}
130#endif /* FIONBIO */
131
132#endif /* TRY_AGAIN */
133		return (e ? 0 : -1);
134
135	case EINTR:
136		return (0);
137
138	default:
139		return (-1);
140	}
141}
142
143
144/* read_preread():
145 *	Try to read the stuff in the input queue;
146 */
147private int
148read_preread(EditLine *el)
149{
150	int chrs = 0;
151
152	if (el->el_chared.c_macro.nline) {
153		el_free((ptr_t) el->el_chared.c_macro.nline);
154		el->el_chared.c_macro.nline = NULL;
155	}
156	if (el->el_tty.t_mode == ED_IO)
157		return (0);
158
159#ifdef FIONREAD
160	(void) ioctl(el->el_infd, FIONREAD, (ioctl_t) & chrs);
161	if (chrs > 0) {
162		char buf[EL_BUFSIZ];
163
164		chrs = read(el->el_infd, buf,
165		    (size_t) MIN(chrs, EL_BUFSIZ - 1));
166		if (chrs > 0) {
167			buf[chrs] = '\0';
168			el->el_chared.c_macro.nline = strdup(buf);
169			el_push(el, el->el_chared.c_macro.nline);
170		}
171	}
172#endif /* FIONREAD */
173
174	return (chrs > 0);
175}
176
177
178/* el_push():
179 *	Push a macro
180 */
181public void
182el_push(EditLine *el, const char *str)
183{
184	c_macro_t *ma = &el->el_chared.c_macro;
185
186	if (str != NULL && ma->level + 1 < EL_MAXMACRO) {
187		ma->level++;
188		/* LINTED const cast */
189		ma->macro[ma->level] = (char *) str;
190	} else {
191		term_beep(el);
192		term__flush();
193	}
194}
195
196
197/* read_getcmd():
198 *	Return next command from the input stream.
199 */
200private int
201read_getcmd(EditLine *el, el_action_t *cmdnum, 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		} 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				EL_ABORT((el->el_errfile, "Bad XK_ type \n"));
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/* read_char():
252 *	Read a character from the tty.
253 */
254private int
255read_char(EditLine *el, char *cp)
256{
257	int num_read;
258	int tried = 0;
259
260	while ((num_read = read(el->el_infd, cp, 1)) == -1)
261		if (!tried && read__fixio(el->el_infd, errno) == 0)
262			tried = 1;
263		else {
264			*cp = '\0';
265			return (-1);
266		}
267
268	return (num_read);
269}
270
271
272/* el_getc():
273 *	Read a character
274 */
275public int
276el_getc(EditLine *el, char *cp)
277{
278	int num_read;
279	c_macro_t *ma = &el->el_chared.c_macro;
280
281	term__flush();
282	for (;;) {
283		if (ma->level < 0) {
284			if (!read_preread(el))
285				break;
286		}
287		if (ma->level < 0)
288			break;
289
290		if (*ma->macro[ma->level] == 0) {
291			ma->level--;
292			continue;
293		}
294		*cp = *ma->macro[ma->level]++ & 0377;
295		if (*ma->macro[ma->level] == 0) {	/* Needed for QuoteMode
296							 * On */
297			ma->level--;
298		}
299		return (1);
300	}
301
302#ifdef DEBUG_READ
303	(void) fprintf(el->el_errfile, "Turning raw mode on\n");
304#endif /* DEBUG_READ */
305	if (tty_rawmode(el) < 0)/* make sure the tty is set up correctly */
306		return (0);
307
308#ifdef DEBUG_READ
309	(void) fprintf(el->el_errfile, "Reading a character\n");
310#endif /* DEBUG_READ */
311	num_read = read_char(el, cp);
312#ifdef DEBUG_READ
313	(void) fprintf(el->el_errfile, "Got it %c\n", *cp);
314#endif /* DEBUG_READ */
315	return (num_read);
316}
317
318
319public const char *
320el_gets(EditLine *el, int *nread)
321{
322	int retval;
323	el_action_t cmdnum = 0;
324	int num;		/* how many chars we have read at NL */
325	char ch;
326#ifdef FIONREAD
327	c_macro_t *ma = &el->el_chared.c_macro;
328#endif /* FIONREAD */
329
330	if (el->el_flags & HANDLE_SIGNALS)
331		sig_set(el);
332
333	if (el->el_flags & NO_TTY) {
334		char *cp = el->el_line.buffer;
335		size_t idx;
336
337		while (read_char(el, cp) == 1) {
338			/* make sure there is space for next character */
339			if (cp + 1 >= el->el_line.limit) {
340				idx = (cp - el->el_line.buffer);
341				if (!ch_enlargebufs(el, 2))
342					break;
343				cp = &el->el_line.buffer[idx];
344			}
345			cp++;
346			if (cp[-1] == '\r' || cp[-1] == '\n')
347				break;
348		}
349
350		el->el_line.cursor = el->el_line.lastchar = cp;
351		*cp = '\0';
352		if (nread)
353			*nread = el->el_line.cursor - el->el_line.buffer;
354		return (el->el_line.buffer);
355	}
356	re_clear_display(el);	/* reset the display stuff */
357	ch_reset(el);
358
359#ifdef FIONREAD
360	if (el->el_tty.t_mode == EX_IO && ma->level < 0) {
361		long chrs = 0;
362
363		(void) ioctl(el->el_infd, FIONREAD, (ioctl_t) & chrs);
364		if (chrs == 0) {
365			if (tty_rawmode(el) < 0) {
366				if (nread)
367					*nread = 0;
368				return (NULL);
369			}
370		}
371	}
372#endif /* FIONREAD */
373
374	re_refresh(el);		/* print the prompt */
375
376	if (el->el_flags & EDIT_DISABLED) {
377		char *cp = el->el_line.buffer;
378		size_t idx;
379
380		term__flush();
381
382		while (read_char(el, cp) == 1) {
383			/* make sure there is space next character */
384			if (cp + 1 >= el->el_line.limit) {
385				idx = (cp - el->el_line.buffer);
386				if (!ch_enlargebufs(el, 2))
387					break;
388				cp = &el->el_line.buffer[idx];
389			}
390			cp++;
391			if (cp[-1] == '\r' || cp[-1] == '\n')
392				break;
393		}
394
395		el->el_line.cursor = el->el_line.lastchar = cp;
396		*cp = '\0';
397		if (nread)
398			*nread = el->el_line.cursor - el->el_line.buffer;
399		return (el->el_line.buffer);
400	}
401	for (num = OKCMD; num == OKCMD;) {	/* while still editing this
402						 * line */
403#ifdef DEBUG_EDIT
404		read_debug(el);
405#endif /* DEBUG_EDIT */
406		/* if EOF or error */
407		if ((num = read_getcmd(el, &cmdnum, &ch)) != OKCMD) {
408#ifdef DEBUG_READ
409			(void) fprintf(el->el_errfile,
410			    "Returning from el_gets %d\n", num);
411#endif /* DEBUG_READ */
412			break;
413		}
414		if ((int) cmdnum >= el->el_map.nfunc) {	/* BUG CHECK command */
415#ifdef DEBUG_EDIT
416			(void) fprintf(el->el_errfile,
417			    "ERROR: illegal command from key 0%o\r\n", ch);
418#endif /* DEBUG_EDIT */
419			continue;	/* try again */
420		}
421		/* now do the real command */
422#ifdef DEBUG_READ
423		{
424			el_bindings_t *b;
425			for (b = el->el_map.help; b->name; b++)
426				if (b->func == cmdnum)
427					break;
428			if (b->name)
429				(void) fprintf(el->el_errfile,
430				    "Executing %s\n", b->name);
431			else
432				(void) fprintf(el->el_errfile,
433				    "Error command = %d\n", cmdnum);
434		}
435#endif /* DEBUG_READ */
436		retval = (*el->el_map.func[cmdnum]) (el, ch);
437
438		/* save the last command here */
439		el->el_state.lastcmd = cmdnum;
440
441		/* use any return value */
442		switch (retval) {
443		case CC_CURSOR:
444			el->el_state.argument = 1;
445			el->el_state.doingarg = 0;
446			re_refresh_cursor(el);
447			break;
448
449		case CC_REDISPLAY:
450			re_clear_lines(el);
451			re_clear_display(el);
452			/* FALLTHROUGH */
453
454		case CC_REFRESH:
455			el->el_state.argument = 1;
456			el->el_state.doingarg = 0;
457			re_refresh(el);
458			break;
459
460		case CC_REFRESH_BEEP:
461			el->el_state.argument = 1;
462			el->el_state.doingarg = 0;
463			re_refresh(el);
464			term_beep(el);
465			break;
466
467		case CC_NORM:	/* normal char */
468			el->el_state.argument = 1;
469			el->el_state.doingarg = 0;
470			break;
471
472		case CC_ARGHACK:	/* Suggested by Rich Salz */
473			/* <rsalz@pineapple.bbn.com> */
474			break;	/* keep going... */
475
476		case CC_EOF:	/* end of file typed */
477			num = 0;
478			break;
479
480		case CC_NEWLINE:	/* normal end of line */
481			num = el->el_line.lastchar - el->el_line.buffer;
482			break;
483
484		case CC_FATAL:	/* fatal error, reset to known state */
485#ifdef DEBUG_READ
486			(void) fprintf(el->el_errfile,
487			    "*** editor fatal ERROR ***\r\n\n");
488#endif /* DEBUG_READ */
489			/* put (real) cursor in a known place */
490			re_clear_display(el);	/* reset the display stuff */
491			ch_reset(el);	/* reset the input pointers */
492			re_refresh(el);	/* print the prompt again */
493			el->el_state.argument = 1;
494			el->el_state.doingarg = 0;
495			break;
496
497		case CC_ERROR:
498		default:	/* functions we don't know about */
499#ifdef DEBUG_READ
500			(void) fprintf(el->el_errfile,
501			    "*** editor ERROR ***\r\n\n");
502#endif /* DEBUG_READ */
503			el->el_state.argument = 1;
504			el->el_state.doingarg = 0;
505			term_beep(el);
506			term__flush();
507			break;
508		}
509	}
510
511	term__flush();		/* flush any buffered output */
512				/* make sure the tty is set up correctly */
513	(void) tty_cookedmode(el);
514	if (el->el_flags & HANDLE_SIGNALS)
515		sig_clr(el);
516	if (nread)
517		*nread = num;
518	return (num ? el->el_line.buffer : NULL);
519}
520