xref: /openbsd/lib/libedit/read.c (revision 771fbea0)
1 /*	$OpenBSD: read.c,v 1.44 2016/05/25 09:36:21 schwarze Exp $	*/
2 /*	$NetBSD: read.c,v 1.100 2016/05/24 19:31:27 christos Exp $	*/
3 
4 /*-
5  * Copyright (c) 1992, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * This code is derived from software contributed to Berkeley by
9  * Christos Zoulas of Cornell University.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 #include "config.h"
37 
38 /*
39  * read.c: Clean this junk up! This is horrible code.
40  *	   Terminal read functions
41  */
42 #include <ctype.h>
43 #include <errno.h>
44 #include <fcntl.h>
45 #include <limits.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <unistd.h>
49 
50 #include "el.h"
51 #include "fcns.h"
52 #include "read.h"
53 
54 #define	EL_MAXMACRO	10
55 
56 struct macros {
57 	wchar_t	**macro;
58 	int	  level;
59 	int	  offset;
60 };
61 
62 struct el_read_t {
63 	struct macros	 macros;
64 	el_rfunc_t	 read_char;	/* Function to read a character. */
65 	int		 read_errno;
66 };
67 
68 static int	read__fixio(int, int);
69 static int	read_char(EditLine *, wchar_t *);
70 static int	read_getcmd(EditLine *, el_action_t *, wchar_t *);
71 static void	read_clearmacros(struct macros *);
72 static void	read_pop(struct macros *);
73 
74 /* read_init():
75  *	Initialize the read stuff
76  */
77 protected int
78 read_init(EditLine *el)
79 {
80 	struct macros *ma;
81 
82 	if ((el->el_read = malloc(sizeof(*el->el_read))) == NULL)
83 		return -1;
84 
85 	ma = &el->el_read->macros;
86 	if ((ma->macro = reallocarray(NULL, EL_MAXMACRO,
87 	    sizeof(*ma->macro))) == NULL) {
88 		free(el->el_read);
89 		return -1;
90 	}
91 	ma->level = -1;
92 	ma->offset = 0;
93 
94 	/* builtin read_char */
95 	el->el_read->read_char = read_char;
96 	return 0;
97 }
98 
99 /* el_read_end():
100  *	Free the data structures used by the read stuff.
101  */
102 protected void
103 read_end(struct el_read_t *el_read)
104 {
105 	read_clearmacros(&el_read->macros);
106 	free(el_read->macros.macro);
107 	el_read->macros.macro = NULL;
108 }
109 
110 /* el_read_setfn():
111  *	Set the read char function to the one provided.
112  *	If it is set to EL_BUILTIN_GETCFN, then reset to the builtin one.
113  */
114 protected int
115 el_read_setfn(struct el_read_t *el_read, el_rfunc_t rc)
116 {
117 	el_read->read_char = (rc == EL_BUILTIN_GETCFN) ? read_char : rc;
118 	return 0;
119 }
120 
121 
122 /* el_read_getfn():
123  *	return the current read char function, or EL_BUILTIN_GETCFN
124  *	if it is the default one
125  */
126 protected el_rfunc_t
127 el_read_getfn(struct el_read_t *el_read)
128 {
129 	return el_read->read_char == read_char ?
130 	    EL_BUILTIN_GETCFN : el_read->read_char;
131 }
132 
133 
134 /* read__fixio():
135  *	Try to recover from a read error
136  */
137 /* ARGSUSED */
138 static int
139 read__fixio(int fd __attribute__((__unused__)), int e)
140 {
141 
142 	switch (e) {
143 	case -1:		/* Make sure that the code is reachable */
144 
145 #ifdef EWOULDBLOCK
146 	case EWOULDBLOCK:
147 #ifndef TRY_AGAIN
148 #define TRY_AGAIN
149 #endif
150 #endif /* EWOULDBLOCK */
151 
152 #if defined(POSIX) && defined(EAGAIN)
153 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
154 	case EAGAIN:
155 #ifndef TRY_AGAIN
156 #define TRY_AGAIN
157 #endif
158 #endif /* EWOULDBLOCK && EWOULDBLOCK != EAGAIN */
159 #endif /* POSIX && EAGAIN */
160 
161 		e = 0;
162 #ifdef TRY_AGAIN
163 #if defined(F_SETFL) && defined(O_NDELAY)
164 		if ((e = fcntl(fd, F_GETFL)) == -1)
165 			return -1;
166 
167 		if (fcntl(fd, F_SETFL, e & ~O_NDELAY) == -1)
168 			return -1;
169 		else
170 			e = 1;
171 #endif /* F_SETFL && O_NDELAY */
172 
173 #ifdef FIONBIO
174 		{
175 			int zero = 0;
176 
177 			if (ioctl(fd, FIONBIO, &zero) == -1)
178 				return -1;
179 			else
180 				e = 1;
181 		}
182 #endif /* FIONBIO */
183 
184 #endif /* TRY_AGAIN */
185 		return e ? 0 : -1;
186 
187 	case EINTR:
188 		return 0;
189 
190 	default:
191 		return -1;
192 	}
193 }
194 
195 
196 /* el_push():
197  *	Push a macro
198  */
199 void
200 el_wpush(EditLine *el, const wchar_t *str)
201 {
202 	struct macros *ma = &el->el_read->macros;
203 
204 	if (str != NULL && ma->level + 1 < EL_MAXMACRO) {
205 		ma->level++;
206 		if ((ma->macro[ma->level] = wcsdup(str)) != NULL)
207 			return;
208 		ma->level--;
209 	}
210 	terminal_beep(el);
211 	terminal__flush(el);
212 }
213 
214 
215 /* read_getcmd():
216  *	Get next command from the input stream,
217  *	return 0 on success or -1 on EOF or error.
218  *	Character values > 255 are not looked up in the map, but inserted.
219  */
220 static int
221 read_getcmd(EditLine *el, el_action_t *cmdnum, wchar_t *ch)
222 {
223 	static const wchar_t meta = (wchar_t)0x80;
224 	el_action_t cmd;
225 	int num;
226 
227 	do {
228 		if ((num = el_wgetc(el, ch)) != 1)
229 			return -1;
230 
231 #ifdef	KANJI
232 		if ((*ch & meta)) {
233 			el->el_state.metanext = 0;
234 			cmd = CcViMap[' '];
235 			break;
236 		} else
237 #endif /* KANJI */
238 
239 		if (el->el_state.metanext) {
240 			el->el_state.metanext = 0;
241 			*ch |= meta;
242 		}
243 		if (*ch >= N_KEYS)
244 			cmd = ED_INSERT;
245 		else
246 			cmd = el->el_map.current[(unsigned char) *ch];
247 		if (cmd == ED_SEQUENCE_LEAD_IN) {
248 			keymacro_value_t val;
249 			switch (keymacro_get(el, ch, &val)) {
250 			case XK_CMD:
251 				cmd = val.cmd;
252 				break;
253 			case XK_STR:
254 				el_wpush(el, val.str);
255 				break;
256 			case XK_NOD:
257 				return -1;
258 			default:
259 				EL_ABORT((el->el_errfile, "Bad XK_ type \n"));
260 				break;
261 			}
262 		}
263 	} while (cmd == ED_SEQUENCE_LEAD_IN);
264 	*cmdnum = cmd;
265 	return 0;
266 }
267 
268 /* read_char():
269  *	Read a character from the tty.
270  */
271 static int
272 read_char(EditLine *el, wchar_t *cp)
273 {
274 	ssize_t num_read;
275 	int tried = 0;
276 	char cbuf[MB_LEN_MAX];
277 	int cbp = 0;
278 	int save_errno = errno;
279 
280  again:
281 	el->el_signal->sig_no = 0;
282 	while ((num_read = read(el->el_infd, cbuf + cbp, 1)) == -1) {
283 		int e = errno;
284 		switch (el->el_signal->sig_no) {
285 		case SIGCONT:
286 			el_set(el, EL_REFRESH);
287 			/*FALLTHROUGH*/
288 		case SIGWINCH:
289 			sig_set(el);
290 			goto again;
291 		default:
292 			break;
293 		}
294 		if (!tried && read__fixio(el->el_infd, e) == 0) {
295 			errno = save_errno;
296 			tried = 1;
297 		} else {
298 			errno = e;
299 			*cp = L'\0';
300 			return -1;
301 		}
302 	}
303 
304 	/* Test for EOF */
305 	if (num_read == 0) {
306 		*cp = L'\0';
307 		return 0;
308 	}
309 
310 	for (;;) {
311 		mbstate_t mbs;
312 
313 		++cbp;
314 		/* This only works because UTF8 is stateless. */
315 		memset(&mbs, 0, sizeof(mbs));
316 		switch (mbrtowc(cp, cbuf, cbp, &mbs)) {
317 		case (size_t)-1:
318 			if (cbp > 1) {
319 				/*
320 				 * Invalid sequence, discard all bytes
321 				 * except the last one.
322 				 */
323 				cbuf[0] = cbuf[cbp - 1];
324 				cbp = 0;
325 				break;
326 			} else {
327 				/* Invalid byte, discard it. */
328 				cbp = 0;
329 				goto again;
330 			}
331 		case (size_t)-2:
332 			/*
333 			 * We don't support other multibyte charsets.
334 			 * The second condition shouldn't happen
335 			 * and is here merely for additional safety.
336 			 */
337 			if ((el->el_flags & CHARSET_IS_UTF8) == 0 ||
338 			    cbp >= MB_LEN_MAX) {
339 				errno = EILSEQ;
340 				*cp = L'\0';
341 				return -1;
342 			}
343 			/* Incomplete sequence, read another byte. */
344 			goto again;
345 		default:
346 			/* Valid character, process it. */
347 			return 1;
348 		}
349 	}
350 }
351 
352 /* read_pop():
353  *	Pop a macro from the stack
354  */
355 static void
356 read_pop(struct macros *ma)
357 {
358 	int i;
359 
360 	free(ma->macro[0]);
361 	for (i = 0; i < ma->level; i++)
362 		ma->macro[i] = ma->macro[i + 1];
363 	ma->level--;
364 	ma->offset = 0;
365 }
366 
367 static void
368 read_clearmacros(struct macros *ma)
369 {
370 	while (ma->level >= 0)
371 		free(ma->macro[ma->level--]);
372 	ma->offset = 0;
373 }
374 
375 /* el_wgetc():
376  *	Read a wide character
377  */
378 int
379 el_wgetc(EditLine *el, wchar_t *cp)
380 {
381 	struct macros *ma = &el->el_read->macros;
382 	int num_read;
383 
384 	terminal__flush(el);
385 	for (;;) {
386 		if (ma->level < 0)
387 			break;
388 
389 		if (ma->macro[0][ma->offset] == '\0') {
390 			read_pop(ma);
391 			continue;
392 		}
393 
394 		*cp = ma->macro[0][ma->offset++];
395 
396 		if (ma->macro[0][ma->offset] == '\0') {
397 			/* Needed for QuoteMode On */
398 			read_pop(ma);
399 		}
400 
401 		return 1;
402 	}
403 
404 	if (tty_rawmode(el) < 0)/* make sure the tty is set up correctly */
405 		return 0;
406 
407 	num_read = (*el->el_read->read_char)(el, cp);
408 
409 	/*
410 	 * Remember the original reason of a read failure
411 	 * such that el_wgets() can restore it after doing
412 	 * various cleanup operation that might change errno.
413 	 */
414 	if (num_read < 0)
415 		el->el_read->read_errno = errno;
416 
417 	return num_read;
418 }
419 
420 protected void
421 read_prepare(EditLine *el)
422 {
423 	if (el->el_flags & HANDLE_SIGNALS)
424 		sig_set(el);
425 	if (el->el_flags & NO_TTY)
426 		return;
427 	if ((el->el_flags & (UNBUFFERED|EDIT_DISABLED)) == UNBUFFERED)
428 		tty_rawmode(el);
429 
430 	/* This is relatively cheap, and things go terribly wrong if
431 	   we have the wrong size. */
432 	el_resize(el);
433 	re_clear_display(el);	/* reset the display stuff */
434 	ch_reset(el);
435 	re_refresh(el);		/* print the prompt */
436 
437 	if (el->el_flags & UNBUFFERED)
438 		terminal__flush(el);
439 }
440 
441 protected void
442 read_finish(EditLine *el)
443 {
444 	if ((el->el_flags & UNBUFFERED) == 0)
445 		(void) tty_cookedmode(el);
446 	if (el->el_flags & HANDLE_SIGNALS)
447 		sig_clr(el);
448 }
449 
450 const wchar_t *
451 el_wgets(EditLine *el, int *nread)
452 {
453 	int retval;
454 	el_action_t cmdnum = 0;
455 	int num;		/* how many chars we have read at NL */
456 	wchar_t wc;
457 	wchar_t ch, *cp;
458 	int crlf = 0;
459 	int nrb;
460 
461 	if (nread == NULL)
462 		nread = &nrb;
463 	*nread = 0;
464 	el->el_read->read_errno = 0;
465 
466 	if (el->el_flags & NO_TTY) {
467 		size_t idx;
468 
469 		cp = el->el_line.buffer;
470 		while ((num = (*el->el_read->read_char)(el, &wc)) == 1) {
471 			*cp = wc;
472 			/* make sure there is space for next character */
473 			if (cp + 1 >= el->el_line.limit) {
474 				idx = (cp - el->el_line.buffer);
475 				if (!ch_enlargebufs(el, 2))
476 					break;
477 				cp = &el->el_line.buffer[idx];
478 			}
479 			cp++;
480 			if (el->el_flags & UNBUFFERED)
481 				break;
482 			if (cp[-1] == '\r' || cp[-1] == '\n')
483 				break;
484 		}
485 		if (num == -1 && errno == EINTR)
486 			cp = el->el_line.buffer;
487 		goto noedit;
488 	}
489 
490 
491 #ifdef FIONREAD
492 	if (el->el_tty.t_mode == EX_IO && el->el_read->macros.level < 0) {
493 		int chrs = 0;
494 
495 		(void) ioctl(el->el_infd, FIONREAD, &chrs);
496 		if (chrs == 0) {
497 			if (tty_rawmode(el) < 0) {
498 				errno = 0;
499 				*nread = 0;
500 				return NULL;
501 			}
502 		}
503 	}
504 #endif /* FIONREAD */
505 
506 	if ((el->el_flags & UNBUFFERED) == 0)
507 		read_prepare(el);
508 
509 	if (el->el_flags & EDIT_DISABLED) {
510 		size_t idx;
511 
512 		if ((el->el_flags & UNBUFFERED) == 0)
513 			cp = el->el_line.buffer;
514 		else
515 			cp = el->el_line.lastchar;
516 
517 		terminal__flush(el);
518 
519 		while ((num = (*el->el_read->read_char)(el, &wc)) == 1) {
520 			*cp = wc;
521 			/* make sure there is space next character */
522 			if (cp + 1 >= el->el_line.limit) {
523 				idx = (cp - el->el_line.buffer);
524 				if (!ch_enlargebufs(el, 2))
525 					break;
526 				cp = &el->el_line.buffer[idx];
527 			}
528 			cp++;
529 			crlf = cp[-1] == '\r' || cp[-1] == '\n';
530 			if (el->el_flags & UNBUFFERED)
531 				break;
532 			if (crlf)
533 				break;
534 		}
535 		if (num == -1 && errno == EINTR)
536 			cp = el->el_line.buffer;
537 		goto noedit;
538 	}
539 
540 	for (num = -1; num == -1;) {  /* while still editing this line */
541 		/* if EOF or error */
542 		if (read_getcmd(el, &cmdnum, &ch) == -1)
543 			break;
544 		if ((int)cmdnum >= el->el_map.nfunc) /* BUG CHECK command */
545 			continue;	/* try again */
546 		/* now do the real command */
547 		/* vi redo needs these way down the levels... */
548 		el->el_state.thiscmd = cmdnum;
549 		el->el_state.thisch = ch;
550 		if (el->el_map.type == MAP_VI &&
551 		    el->el_map.current == el->el_map.key &&
552 		    el->el_chared.c_redo.pos < el->el_chared.c_redo.lim) {
553 			if (cmdnum == VI_DELETE_PREV_CHAR &&
554 			    el->el_chared.c_redo.pos != el->el_chared.c_redo.buf
555 			    && iswprint(el->el_chared.c_redo.pos[-1]))
556 				el->el_chared.c_redo.pos--;
557 			else
558 				*el->el_chared.c_redo.pos++ = ch;
559 		}
560 		retval = (*el->el_map.func[cmdnum]) (el, ch);
561 
562 		/* save the last command here */
563 		el->el_state.lastcmd = cmdnum;
564 
565 		/* use any return value */
566 		switch (retval) {
567 		case CC_CURSOR:
568 			re_refresh_cursor(el);
569 			break;
570 
571 		case CC_REDISPLAY:
572 			re_clear_lines(el);
573 			re_clear_display(el);
574 			/* FALLTHROUGH */
575 
576 		case CC_REFRESH:
577 			re_refresh(el);
578 			break;
579 
580 		case CC_REFRESH_BEEP:
581 			re_refresh(el);
582 			terminal_beep(el);
583 			break;
584 
585 		case CC_NORM:	/* normal char */
586 			break;
587 
588 		case CC_ARGHACK:	/* Suggested by Rich Salz */
589 			/* <rsalz@pineapple.bbn.com> */
590 			continue;	/* keep going... */
591 
592 		case CC_EOF:	/* end of file typed */
593 			if ((el->el_flags & UNBUFFERED) == 0)
594 				num = 0;
595 			else if (num == -1) {
596 				*el->el_line.lastchar++ = CONTROL('d');
597 				el->el_line.cursor = el->el_line.lastchar;
598 				num = 1;
599 			}
600 			break;
601 
602 		case CC_NEWLINE:	/* normal end of line */
603 			num = (int)(el->el_line.lastchar - el->el_line.buffer);
604 			break;
605 
606 		case CC_FATAL:	/* fatal error, reset to known state */
607 			/* put (real) cursor in a known place */
608 			re_clear_display(el);	/* reset the display stuff */
609 			ch_reset(el);	/* reset the input pointers */
610 			read_clearmacros(&el->el_read->macros);
611 			re_refresh(el); /* print the prompt again */
612 			break;
613 
614 		case CC_ERROR:
615 		default:	/* functions we don't know about */
616 			terminal_beep(el);
617 			terminal__flush(el);
618 			break;
619 		}
620 		el->el_state.argument = 1;
621 		el->el_state.doingarg = 0;
622 		el->el_chared.c_vcmd.action = NOP;
623 		if (el->el_flags & UNBUFFERED)
624 			break;
625 	}
626 
627 	terminal__flush(el);		/* flush any buffered output */
628 	/* make sure the tty is set up correctly */
629 	if ((el->el_flags & UNBUFFERED) == 0) {
630 		read_finish(el);
631 		*nread = num != -1 ? num : 0;
632 	} else {
633 		*nread = (int)(el->el_line.lastchar - el->el_line.buffer);
634 	}
635 	goto done;
636 noedit:
637 	el->el_line.cursor = el->el_line.lastchar = cp;
638 	*cp = '\0';
639 	*nread = (int)(el->el_line.cursor - el->el_line.buffer);
640 done:
641 	if (*nread == 0) {
642 		if (num == -1) {
643 			*nread = -1;
644 			if (el->el_read->read_errno)
645 				errno = el->el_read->read_errno;
646 		}
647 		return NULL;
648 	} else
649 		return el->el_line.buffer;
650 }
651