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