xref: /netbsd/lib/libedit/read.c (revision c4a72b64)
1 /*	$NetBSD: read.c,v 1.24 2002/11/20 16:50:08 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.24 2002/11/20 16:50:08 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;
240 	int num;
241 
242 	do {
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 	} while (cmd == ED_SEQUENCE_LEAD_IN);
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 
393 	/* This is relatively cheap, and things go terribly wrong if
394 	   we have the wrong size. */
395 	el_resize(el);
396 
397 	re_clear_display(el);	/* reset the display stuff */
398 	ch_reset(el);
399 
400 #ifdef FIONREAD
401 	if (el->el_tty.t_mode == EX_IO && ma->level < 0) {
402 		long chrs = 0;
403 
404 		(void) ioctl(el->el_infd, FIONREAD, (ioctl_t) & chrs);
405 		if (chrs == 0) {
406 			if (tty_rawmode(el) < 0) {
407 				if (nread)
408 					*nread = 0;
409 				return (NULL);
410 			}
411 		}
412 	}
413 #endif /* FIONREAD */
414 
415 	re_refresh(el);		/* print the prompt */
416 
417 	if (el->el_flags & EDIT_DISABLED) {
418 		char *cp = el->el_line.buffer;
419 		size_t idx;
420 
421 		term__flush();
422 
423 		while ((*el->el_read.read_char)(el, cp) == 1) {
424 			/* make sure there is space next character */
425 			if (cp + 1 >= el->el_line.limit) {
426 				idx = (cp - el->el_line.buffer);
427 				if (!ch_enlargebufs(el, 2))
428 					break;
429 				cp = &el->el_line.buffer[idx];
430 			}
431 			if (*cp == 4)	/* ought to be stty eof */
432 				break;
433 			cp++;
434 			if (cp[-1] == '\r' || cp[-1] == '\n')
435 				break;
436 		}
437 
438 		el->el_line.cursor = el->el_line.lastchar = cp;
439 		*cp = '\0';
440 		if (nread)
441 			*nread = el->el_line.cursor - el->el_line.buffer;
442 		return (el->el_line.buffer);
443 	}
444 
445 	for (num = OKCMD; num == OKCMD;) {	/* while still editing this
446 						 * line */
447 #ifdef DEBUG_EDIT
448 		read_debug(el);
449 #endif /* DEBUG_EDIT */
450 		/* if EOF or error */
451 		if ((num = read_getcmd(el, &cmdnum, &ch)) != OKCMD) {
452 #ifdef DEBUG_READ
453 			(void) fprintf(el->el_errfile,
454 			    "Returning from el_gets %d\n", num);
455 #endif /* DEBUG_READ */
456 			break;
457 		}
458 		if ((uint)cmdnum >= el->el_map.nfunc) {	/* BUG CHECK command */
459 #ifdef DEBUG_EDIT
460 			(void) fprintf(el->el_errfile,
461 			    "ERROR: illegal command from key 0%o\r\n", ch);
462 #endif /* DEBUG_EDIT */
463 			continue;	/* try again */
464 		}
465 		/* now do the real command */
466 #ifdef DEBUG_READ
467 		{
468 			el_bindings_t *b;
469 			for (b = el->el_map.help; b->name; b++)
470 				if (b->func == cmdnum)
471 					break;
472 			if (b->name)
473 				(void) fprintf(el->el_errfile,
474 				    "Executing %s\n", b->name);
475 			else
476 				(void) fprintf(el->el_errfile,
477 				    "Error command = %d\n", cmdnum);
478 		}
479 #endif /* DEBUG_READ */
480 		/* vi redo needs these way down the levels... */
481 		el->el_state.thiscmd = cmdnum;
482 		el->el_state.thisch = ch;
483 		if (el->el_map.type == MAP_VI &&
484 		    el->el_map.current == el->el_map.key &&
485 		    el->el_chared.c_redo.pos < el->el_chared.c_redo.lim) {
486 			if (cmdnum == VI_DELETE_PREV_CHAR &&
487 			    el->el_chared.c_redo.pos != el->el_chared.c_redo.buf
488 			    && isprint(el->el_chared.c_redo.pos[-1]))
489 				el->el_chared.c_redo.pos--;
490 			else
491 				*el->el_chared.c_redo.pos++ = ch;
492 		}
493 		retval = (*el->el_map.func[cmdnum]) (el, ch);
494 #ifdef DEBUG_READ
495 		(void) fprintf(el->el_errfile,
496 			"Returned state %d\n", retval );
497 #endif /* DEBUG_READ */
498 
499 		/* save the last command here */
500 		el->el_state.lastcmd = cmdnum;
501 
502 		/* use any return value */
503 		switch (retval) {
504 		case CC_CURSOR:
505 			re_refresh_cursor(el);
506 			break;
507 
508 		case CC_REDISPLAY:
509 			re_clear_lines(el);
510 			re_clear_display(el);
511 			/* FALLTHROUGH */
512 
513 		case CC_REFRESH:
514 			re_refresh(el);
515 			break;
516 
517 		case CC_REFRESH_BEEP:
518 			re_refresh(el);
519 			term_beep(el);
520 			break;
521 
522 		case CC_NORM:	/* normal char */
523 			break;
524 
525 		case CC_ARGHACK:	/* Suggested by Rich Salz */
526 			/* <rsalz@pineapple.bbn.com> */
527 			continue;	/* keep going... */
528 
529 		case CC_EOF:	/* end of file typed */
530 			num = 0;
531 			break;
532 
533 		case CC_NEWLINE:	/* normal end of line */
534 			num = el->el_line.lastchar - el->el_line.buffer;
535 			break;
536 
537 		case CC_FATAL:	/* fatal error, reset to known state */
538 #ifdef DEBUG_READ
539 			(void) fprintf(el->el_errfile,
540 			    "*** editor fatal ERROR ***\r\n\n");
541 #endif /* DEBUG_READ */
542 			/* put (real) cursor in a known place */
543 			re_clear_display(el);	/* reset the display stuff */
544 			ch_reset(el);	/* reset the input pointers */
545 			re_refresh(el);	/* print the prompt again */
546 			break;
547 
548 		case CC_ERROR:
549 		default:	/* functions we don't know about */
550 #ifdef DEBUG_READ
551 			(void) fprintf(el->el_errfile,
552 			    "*** editor ERROR ***\r\n\n");
553 #endif /* DEBUG_READ */
554 			term_beep(el);
555 			term__flush();
556 			break;
557 		}
558 		el->el_state.argument = 1;
559 		el->el_state.doingarg = 0;
560 		el->el_chared.c_vcmd.action = NOP;
561 	}
562 
563 	term__flush();		/* flush any buffered output */
564 	/* make sure the tty is set up correctly */
565 	(void) tty_cookedmode(el);
566 	if (el->el_flags & HANDLE_SIGNALS)
567 		sig_clr(el);
568 	if (nread)
569 		*nread = num;
570 	return (num ? el->el_line.buffer : NULL);
571 }
572