1/*	$NetBSD: read.c,v 1.86 2016/03/02 19:24:20 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. Neither the name of the University nor the names of its contributors
19 *    may be used to endorse or promote products derived from this software
20 *    without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35#include "config.h"
36#if !defined(lint) && !defined(SCCSID)
37#if 0
38static char sccsid[] = "@(#)read.c	8.1 (Berkeley) 6/4/93";
39#else
40__RCSID("$NetBSD: read.c,v 1.86 2016/03/02 19:24:20 christos Exp $");
41#endif
42#endif /* not lint && not SCCSID */
43#include <sys/cdefs.h>
44__FBSDID("$FreeBSD: stable/11/lib/libedit/read.c 343091 2019-01-16 12:04:29Z bapt $");
45
46/*
47 * read.c: Clean this junk up! This is horrible code.
48 *	   Terminal read functions
49 */
50#include <ctype.h>
51#include <errno.h>
52#include <fcntl.h>
53#include <limits.h>
54#include <stdlib.h>
55#include <string.h>
56#include <unistd.h>
57
58#include "el.h"
59
60#define OKCMD	-1	/* must be -1! */
61
62private int	read__fixio(int, int);
63private int	read_preread(EditLine *);
64private int	read_char(EditLine *, wchar_t *);
65private int	read_getcmd(EditLine *, el_action_t *, Char *);
66private void	read_pop(c_macro_t *);
67
68/* read_init():
69 *	Initialize the read stuff
70 */
71protected int
72read_init(EditLine *el)
73{
74	/* builtin read_char */
75	el->el_read.read_char = read_char;
76	return 0;
77}
78
79
80/* el_read_setfn():
81 *	Set the read char function to the one provided.
82 *	If it is set to EL_BUILTIN_GETCFN, then reset to the builtin one.
83 */
84protected int
85el_read_setfn(EditLine *el, el_rfunc_t rc)
86{
87	el->el_read.read_char = (rc == EL_BUILTIN_GETCFN) ? read_char : rc;
88	return 0;
89}
90
91
92/* el_read_getfn():
93 *	return the current read char function, or EL_BUILTIN_GETCFN
94 *	if it is the default one
95 */
96protected el_rfunc_t
97el_read_getfn(EditLine *el)
98{
99       return el->el_read.read_char == read_char ?
100	    EL_BUILTIN_GETCFN : el->el_read.read_char;
101}
102
103
104#ifndef MIN
105#define MIN(A,B) ((A) < (B) ? (A) : (B))
106#endif
107
108#ifdef DEBUG_EDIT
109private void
110read_debug(EditLine *el)
111{
112
113	if (el->el_line.cursor > el->el_line.lastchar)
114		(void) fprintf(el->el_errfile, "cursor > lastchar\r\n");
115	if (el->el_line.cursor < el->el_line.buffer)
116		(void) fprintf(el->el_errfile, "cursor < buffer\r\n");
117	if (el->el_line.cursor > el->el_line.limit)
118		(void) fprintf(el->el_errfile, "cursor > limit\r\n");
119	if (el->el_line.lastchar > el->el_line.limit)
120		(void) fprintf(el->el_errfile, "lastchar > limit\r\n");
121	if (el->el_line.limit != &el->el_line.buffer[EL_BUFSIZ - 2])
122		(void) fprintf(el->el_errfile, "limit != &buffer[EL_BUFSIZ-2]\r\n");
123}
124#endif /* DEBUG_EDIT */
125
126
127/* read__fixio():
128 *	Try to recover from a read error
129 */
130/* ARGSUSED */
131private int
132read__fixio(int fd __attribute__((__unused__)), int e)
133{
134
135	switch (e) {
136	case -1:		/* Make sure that the code is reachable */
137
138#ifdef EWOULDBLOCK
139	case EWOULDBLOCK:
140#ifndef TRY_AGAIN
141#define TRY_AGAIN
142#endif
143#endif /* EWOULDBLOCK */
144
145#if defined(POSIX) && defined(EAGAIN)
146#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
147	case EAGAIN:
148#ifndef TRY_AGAIN
149#define TRY_AGAIN
150#endif
151#endif /* EWOULDBLOCK && EWOULDBLOCK != EAGAIN */
152#endif /* POSIX && EAGAIN */
153
154		e = 0;
155#ifdef TRY_AGAIN
156#if defined(F_SETFL) && defined(O_NDELAY)
157		if ((e = fcntl(fd, F_GETFL, 0)) == -1)
158			return -1;
159
160		if (fcntl(fd, F_SETFL, e & ~O_NDELAY) == -1)
161			return -1;
162		else
163			e = 1;
164#endif /* F_SETFL && O_NDELAY */
165
166#ifdef FIONBIO
167		{
168			int zero = 0;
169
170			if (ioctl(fd, FIONBIO, &zero) == -1)
171				return -1;
172			else
173				e = 1;
174		}
175#endif /* FIONBIO */
176
177#endif /* TRY_AGAIN */
178		return e ? 0 : -1;
179
180	case EINTR:
181		return 0;
182
183	default:
184		return -1;
185	}
186}
187
188
189/* read_preread():
190 *	Try to read the stuff in the input queue;
191 */
192private int
193read_preread(EditLine *el)
194{
195	int chrs = 0;
196
197	if (el->el_tty.t_mode == ED_IO)
198		return 0;
199
200#ifndef WIDECHAR
201/* FIONREAD attempts to buffer up multiple bytes, and to make that work
202 * properly with partial wide/UTF-8 characters would need some careful work. */
203#ifdef FIONREAD
204	(void) ioctl(el->el_infd, FIONREAD, &chrs);
205	if (chrs > 0) {
206		char buf[EL_BUFSIZ];
207
208		chrs = read(el->el_infd, buf,
209		    (size_t) MIN(chrs, EL_BUFSIZ - 1));
210		if (chrs > 0) {
211			buf[chrs] = '\0';
212			el_push(el, buf);
213		}
214	}
215#endif /* FIONREAD */
216#endif
217	return chrs > 0;
218}
219
220
221/* el_push():
222 *	Push a macro
223 */
224public void
225FUN(el,push)(EditLine *el, const Char *str)
226{
227	c_macro_t *ma = &el->el_chared.c_macro;
228
229	if (str != NULL && ma->level + 1 < EL_MAXMACRO) {
230		ma->level++;
231		if ((ma->macro[ma->level] = Strdup(str)) != NULL)
232			return;
233		ma->level--;
234	}
235	terminal_beep(el);
236	terminal__flush(el);
237}
238
239
240/* read_getcmd():
241 *	Get next command from the input stream, return OKCMD on success.
242 *	Character values > 255 are not looked up in the map, but inserted.
243 */
244private int
245read_getcmd(EditLine *el, el_action_t *cmdnum, Char *ch)
246{
247	static const Char meta = (Char)0x80;
248	el_action_t cmd;
249	wchar_t wc;
250	int num;
251
252	el->el_errno = 0;
253	do {
254		if ((num = el_wgetc(el, &wc)) != 1) {/* if EOF or error */
255			el->el_errno = num == 0 ? 0 : errno;
256			return 0;	/* not OKCMD */
257		}
258		*ch = (Char)wc;
259
260#ifdef	KANJI
261		if ((*ch & meta)) {
262			el->el_state.metanext = 0;
263			cmd = CcViMap[' '];
264			break;
265		} else
266#endif /* KANJI */
267
268		if (el->el_state.metanext) {
269			el->el_state.metanext = 0;
270			*ch |= meta;
271		}
272#ifdef WIDECHAR
273		if (*ch >= N_KEYS)
274			cmd = ED_INSERT;
275		else
276#endif
277			cmd = el->el_map.current[(unsigned char) *ch];
278		if (cmd == ED_SEQUENCE_LEAD_IN) {
279			keymacro_value_t val;
280			switch (keymacro_get(el, ch, &val)) {
281			case XK_CMD:
282				cmd = val.cmd;
283				break;
284			case XK_STR:
285				FUN(el,push)(el, val.str);
286				break;
287#ifdef notyet
288			case XK_EXE:
289				/* XXX: In the future to run a user function */
290				RunCommand(val.str);
291				break;
292#endif
293			default:
294				EL_ABORT((el->el_errfile, "Bad XK_ type \n"));
295				break;
296			}
297		}
298		if (el->el_map.alt == NULL)
299			el->el_map.current = el->el_map.key;
300	} while (cmd == ED_SEQUENCE_LEAD_IN);
301	*cmdnum = cmd;
302	return OKCMD;
303}
304
305/* read_char():
306 *	Read a character from the tty.
307 */
308private int
309read_char(EditLine *el, wchar_t *cp)
310{
311	ssize_t num_read;
312	int tried = 0;
313	char cbuf[MB_LEN_MAX];
314	size_t cbp = 0;
315	int save_errno = errno;
316
317 again:
318	el->el_signal->sig_no = 0;
319	while ((num_read = read(el->el_infd, cbuf + cbp, (size_t)1)) == -1) {
320		int e = errno;
321		switch (el->el_signal->sig_no) {
322		case SIGCONT:
323			FUN(el,set)(el, EL_REFRESH);
324			/*FALLTHROUGH*/
325		case SIGWINCH:
326			sig_set(el);
327			goto again;
328		default:
329			break;
330		}
331		if (!tried && read__fixio(el->el_infd, e) == 0) {
332			errno = save_errno;
333			tried = 1;
334		} else {
335			errno = e;
336			*cp = L'\0';
337			return -1;
338		}
339	}
340
341	/* Test for EOF */
342	if (num_read == 0) {
343		*cp = L'\0';
344		return 0;
345	}
346
347	for (;;) {
348
349		++cbp;
350		switch (ct_mbrtowc(cp, cbuf, cbp)) {
351		case (size_t)-1:
352			if (cbp > 1) {
353				/*
354				 * Invalid sequence, discard all bytes
355				 * except the last one.
356				 */
357				cbuf[0] = cbuf[cbp - 1];
358				cbp = 0;
359				break;
360			} else {
361				/* Invalid byte, discard it. */
362				cbp = 0;
363				goto again;
364			}
365		case (size_t)-2:
366			if (cbp >= MB_LEN_MAX) {
367				errno = EILSEQ;
368				*cp = L'\0';
369				return -1;
370			}
371			/* Incomplete sequence, read another byte. */
372			goto again;
373		default:
374			/* Valid character, process it. */
375			return 1;
376		}
377	}
378}
379
380/* read_pop():
381 *	Pop a macro from the stack
382 */
383private void
384read_pop(c_macro_t *ma)
385{
386	int i;
387
388	el_free(ma->macro[0]);
389	for (i = 0; i < ma->level; i++)
390		ma->macro[i] = ma->macro[i + 1];
391	ma->level--;
392	ma->offset = 0;
393}
394
395/* el_wgetc():
396 *	Read a wide character
397 */
398public int
399el_wgetc(EditLine *el, wchar_t *cp)
400{
401	int num_read;
402	c_macro_t *ma = &el->el_chared.c_macro;
403
404	terminal__flush(el);
405	for (;;) {
406		if (ma->level < 0) {
407			if (!read_preread(el))
408				break;
409		}
410
411		if (ma->level < 0)
412			break;
413
414		if (ma->macro[0][ma->offset] == '\0') {
415			read_pop(ma);
416			continue;
417		}
418
419		*cp = ma->macro[0][ma->offset++];
420
421		if (ma->macro[0][ma->offset] == '\0') {
422			/* Needed for QuoteMode On */
423			read_pop(ma);
424		}
425
426		return 1;
427	}
428
429#ifdef DEBUG_READ
430	(void) fprintf(el->el_errfile, "Turning raw mode on\n");
431#endif /* DEBUG_READ */
432	if (tty_rawmode(el) < 0)/* make sure the tty is set up correctly */
433		return 0;
434
435#ifdef DEBUG_READ
436	(void) fprintf(el->el_errfile, "Reading a character\n");
437#endif /* DEBUG_READ */
438	num_read = (*el->el_read.read_char)(el, cp);
439	if (num_read < 0)
440		el->el_errno = errno;
441#ifdef DEBUG_READ
442	(void) fprintf(el->el_errfile, "Got it %lc\n", *cp);
443#endif /* DEBUG_READ */
444	return num_read;
445}
446
447protected void
448read_prepare(EditLine *el)
449{
450	if (el->el_flags & HANDLE_SIGNALS)
451		sig_set(el);
452	if (el->el_flags & NO_TTY)
453		return;
454	if ((el->el_flags & (UNBUFFERED|EDIT_DISABLED)) == UNBUFFERED)
455		tty_rawmode(el);
456
457	/* This is relatively cheap, and things go terribly wrong if
458	   we have the wrong size. */
459	el_resize(el);
460	re_clear_display(el);	/* reset the display stuff */
461	ch_reset(el, 0);
462	re_refresh(el);		/* print the prompt */
463
464	if (el->el_flags & UNBUFFERED)
465		terminal__flush(el);
466}
467
468protected void
469read_finish(EditLine *el)
470{
471	if ((el->el_flags & UNBUFFERED) == 0)
472		(void) tty_cookedmode(el);
473	if (el->el_flags & HANDLE_SIGNALS)
474		sig_clr(el);
475}
476
477public const Char *
478FUN(el,gets)(EditLine *el, int *nread)
479{
480	int retval;
481	el_action_t cmdnum = 0;
482	int num;		/* how many chars we have read at NL */
483	wchar_t wc;
484	Char ch, *cp;
485	int crlf = 0;
486	int nrb;
487#ifdef FIONREAD
488	c_macro_t *ma = &el->el_chared.c_macro;
489#endif /* FIONREAD */
490
491	if (nread == NULL)
492		nread = &nrb;
493	*nread = 0;
494
495	if (el->el_flags & NO_TTY) {
496		size_t idx;
497
498		cp = el->el_line.buffer;
499		while ((num = (*el->el_read.read_char)(el, &wc)) == 1) {
500			*cp = (Char)wc;
501			/* make sure there is space for next character */
502			if (cp + 1 >= el->el_line.limit) {
503				idx = (size_t)(cp - el->el_line.buffer);
504				if (!ch_enlargebufs(el, (size_t)2))
505					break;
506				cp = &el->el_line.buffer[idx];
507			}
508			cp++;
509			if (el->el_flags & UNBUFFERED)
510				break;
511			if (cp[-1] == '\r' || cp[-1] == '\n')
512				break;
513		}
514		if (num == -1) {
515			if (errno == EINTR)
516				cp = el->el_line.buffer;
517			el->el_errno = errno;
518		}
519
520		goto noedit;
521	}
522
523
524#ifdef FIONREAD
525	if (el->el_tty.t_mode == EX_IO && ma->level < 0) {
526		long chrs = 0;
527
528		(void) ioctl(el->el_infd, FIONREAD, &chrs);
529		if (chrs == 0) {
530			if (tty_rawmode(el) < 0) {
531				errno = 0;
532				*nread = 0;
533				return NULL;
534			}
535		}
536	}
537#endif /* FIONREAD */
538
539	if ((el->el_flags & UNBUFFERED) == 0)
540		read_prepare(el);
541
542	if (el->el_flags & EDIT_DISABLED) {
543		size_t idx;
544
545		if ((el->el_flags & UNBUFFERED) == 0)
546			cp = el->el_line.buffer;
547		else
548			cp = el->el_line.lastchar;
549
550		terminal__flush(el);
551
552		while ((num = (*el->el_read.read_char)(el, &wc)) == 1) {
553			*cp = (Char)wc;
554			/* make sure there is space next character */
555			if (cp + 1 >= el->el_line.limit) {
556				idx = (size_t)(cp - el->el_line.buffer);
557				if (!ch_enlargebufs(el, (size_t)2))
558					break;
559				cp = &el->el_line.buffer[idx];
560			}
561			cp++;
562			crlf = cp[-1] == '\r' || cp[-1] == '\n';
563			if (el->el_flags & UNBUFFERED)
564				break;
565			if (crlf)
566				break;
567		}
568
569		if (num == -1) {
570			if (errno == EINTR)
571				cp = el->el_line.buffer;
572			el->el_errno = errno;
573		}
574
575		goto noedit;
576	}
577
578	for (num = OKCMD; num == OKCMD;) {	/* while still editing this
579						 * line */
580#ifdef DEBUG_EDIT
581		read_debug(el);
582#endif /* DEBUG_EDIT */
583		/* if EOF or error */
584		if ((num = read_getcmd(el, &cmdnum, &ch)) != OKCMD) {
585			num = -1;
586#ifdef DEBUG_READ
587			(void) fprintf(el->el_errfile,
588			    "Returning from el_gets %d\n", num);
589#endif /* DEBUG_READ */
590			break;
591		}
592		if (el->el_errno == EINTR) {
593			el->el_line.buffer[0] = '\0';
594			el->el_line.lastchar =
595			    el->el_line.cursor = el->el_line.buffer;
596			break;
597		}
598		if ((size_t)cmdnum >= el->el_map.nfunc) {	/* BUG CHECK command */
599#ifdef DEBUG_EDIT
600			(void) fprintf(el->el_errfile,
601			    "ERROR: illegal command from key 0%o\r\n", ch);
602#endif /* DEBUG_EDIT */
603			continue;	/* try again */
604		}
605		/* now do the real command */
606#ifdef DEBUG_READ
607		{
608			el_bindings_t *b;
609			for (b = el->el_map.help; b->name; b++)
610				if (b->func == cmdnum)
611					break;
612			if (b->name)
613				(void) fprintf(el->el_errfile,
614				    "Executing " FSTR "\n", b->name);
615			else
616				(void) fprintf(el->el_errfile,
617				    "Error command = %d\n", cmdnum);
618		}
619#endif /* DEBUG_READ */
620		/* vi redo needs these way down the levels... */
621		el->el_state.thiscmd = cmdnum;
622		el->el_state.thisch = ch;
623		if (el->el_map.type == MAP_VI &&
624		    el->el_map.current == el->el_map.key &&
625		    el->el_chared.c_redo.pos < el->el_chared.c_redo.lim) {
626			if (cmdnum == VI_DELETE_PREV_CHAR &&
627			    el->el_chared.c_redo.pos != el->el_chared.c_redo.buf
628			    && Isprint(el->el_chared.c_redo.pos[-1]))
629				el->el_chared.c_redo.pos--;
630			else
631				*el->el_chared.c_redo.pos++ = ch;
632		}
633		retval = (*el->el_map.func[cmdnum]) (el, ch);
634#ifdef DEBUG_READ
635		(void) fprintf(el->el_errfile,
636			"Returned state %d\n", retval );
637#endif /* DEBUG_READ */
638
639		/* save the last command here */
640		el->el_state.lastcmd = cmdnum;
641
642		/* use any return value */
643		switch (retval) {
644		case CC_CURSOR:
645			re_refresh_cursor(el);
646			break;
647
648		case CC_REDISPLAY:
649			re_clear_lines(el);
650			re_clear_display(el);
651			/* FALLTHROUGH */
652
653		case CC_REFRESH:
654			re_refresh(el);
655			break;
656
657		case CC_REFRESH_BEEP:
658			re_refresh(el);
659			terminal_beep(el);
660			break;
661
662		case CC_NORM:	/* normal char */
663			break;
664
665		case CC_ARGHACK:	/* Suggested by Rich Salz */
666			/* <rsalz@pineapple.bbn.com> */
667			continue;	/* keep going... */
668
669		case CC_EOF:	/* end of file typed */
670			if ((el->el_flags & UNBUFFERED) == 0)
671				num = 0;
672			else if (num == -1) {
673				*el->el_line.lastchar++ = CONTROL('d');
674				el->el_line.cursor = el->el_line.lastchar;
675				num = 1;
676			}
677			break;
678
679		case CC_NEWLINE:	/* normal end of line */
680			num = (int)(el->el_line.lastchar - el->el_line.buffer);
681			break;
682
683		case CC_FATAL:	/* fatal error, reset to known state */
684#ifdef DEBUG_READ
685			(void) fprintf(el->el_errfile,
686			    "*** editor fatal ERROR ***\r\n\n");
687#endif /* DEBUG_READ */
688			/* put (real) cursor in a known place */
689			re_clear_display(el);	/* reset the display stuff */
690			ch_reset(el, 1);	/* reset the input pointers */
691			re_refresh(el); /* print the prompt again */
692			break;
693
694		case CC_ERROR:
695		default:	/* functions we don't know about */
696#ifdef DEBUG_READ
697			(void) fprintf(el->el_errfile,
698			    "*** editor ERROR ***\r\n\n");
699#endif /* DEBUG_READ */
700			terminal_beep(el);
701			terminal__flush(el);
702			break;
703		}
704		el->el_state.argument = 1;
705		el->el_state.doingarg = 0;
706		el->el_chared.c_vcmd.action = NOP;
707		if (el->el_flags & UNBUFFERED)
708			break;
709	}
710
711	terminal__flush(el);		/* flush any buffered output */
712	/* make sure the tty is set up correctly */
713	if ((el->el_flags & UNBUFFERED) == 0) {
714		read_finish(el);
715		*nread = num != -1 ? num : 0;
716	} else {
717		*nread = (int)(el->el_line.lastchar - el->el_line.buffer);
718	}
719	goto done;
720noedit:
721	el->el_line.cursor = el->el_line.lastchar = cp;
722	*cp = '\0';
723	*nread = (int)(el->el_line.cursor - el->el_line.buffer);
724done:
725	if (*nread == 0) {
726		if (num == -1) {
727			*nread = -1;
728			errno = el->el_errno;
729		}
730		return NULL;
731	} else
732		return el->el_line.buffer;
733}
734