1/*	$NetBSD: read.c,v 1.106 2019/07/23 10:18:52 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.106 2019/07/23 10:18:52 christos Exp $");
41#endif
42#endif /* not lint && not SCCSID */
43
44/*
45 * read.c: Terminal read functions
46 */
47#include <ctype.h>
48#include <errno.h>
49#include <fcntl.h>
50#include <limits.h>
51#include <stdlib.h>
52#include <string.h>
53#include <unistd.h>
54
55#include "el.h"
56#include "fcns.h"
57#include "read.h"
58
59#define	EL_MAXMACRO	10
60
61struct macros {
62	wchar_t	**macro;
63	int	  level;
64	int	  offset;
65};
66
67struct el_read_t {
68	struct macros	 macros;
69	el_rfunc_t	 read_char;	/* Function to read a character. */
70	int		 read_errno;
71};
72
73static int	read__fixio(int, int);
74static int	read_char(EditLine *, wchar_t *);
75static int	read_getcmd(EditLine *, el_action_t *, wchar_t *);
76static void	read_clearmacros(struct macros *);
77static void	read_pop(struct macros *);
78static const wchar_t *noedit_wgets(EditLine *, int *);
79
80/* read_init():
81 *	Initialize the read stuff
82 */
83libedit_private int
84read_init(EditLine *el)
85{
86	struct macros *ma;
87
88	if ((el->el_read = el_malloc(sizeof(*el->el_read))) == NULL)
89		return -1;
90
91	ma = &el->el_read->macros;
92	if ((ma->macro = el_calloc(EL_MAXMACRO, sizeof(*ma->macro))) == NULL) {
93		free(el->el_read);
94		return -1;
95	}
96	ma->level = -1;
97	ma->offset = 0;
98
99	/* builtin read_char */
100	el->el_read->read_char = read_char;
101	return 0;
102}
103
104/* el_read_end():
105 *	Free the data structures used by the read stuff.
106 */
107libedit_private void
108read_end(struct el_read_t *el_read)
109{
110	read_clearmacros(&el_read->macros);
111	el_free(el_read->macros.macro);
112	el_read->macros.macro = NULL;
113	el_free(el_read);
114}
115
116/* el_read_setfn():
117 *	Set the read char function to the one provided.
118 *	If it is set to EL_BUILTIN_GETCFN, then reset to the builtin one.
119 */
120libedit_private int
121el_read_setfn(struct el_read_t *el_read, el_rfunc_t rc)
122{
123	el_read->read_char = (rc == EL_BUILTIN_GETCFN) ? read_char : rc;
124	return 0;
125}
126
127
128/* el_read_getfn():
129 *	return the current read char function, or EL_BUILTIN_GETCFN
130 *	if it is the default one
131 */
132libedit_private el_rfunc_t
133el_read_getfn(struct el_read_t *el_read)
134{
135       return el_read->read_char == read_char ?
136	    EL_BUILTIN_GETCFN : el_read->read_char;
137}
138
139
140/* read__fixio():
141 *	Try to recover from a read error
142 */
143/* ARGSUSED */
144static int
145read__fixio(int fd __attribute__((__unused__)), int e)
146{
147
148	switch (e) {
149	case -1:		/* Make sure that the code is reachable */
150
151#ifdef EWOULDBLOCK
152	case EWOULDBLOCK:
153#ifndef TRY_AGAIN
154#define TRY_AGAIN
155#endif
156#endif /* EWOULDBLOCK */
157
158#if defined(POSIX) && defined(EAGAIN)
159#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
160	case EAGAIN:
161#ifndef TRY_AGAIN
162#define TRY_AGAIN
163#endif
164#endif /* EWOULDBLOCK && EWOULDBLOCK != EAGAIN */
165#endif /* POSIX && EAGAIN */
166
167		e = 0;
168#ifdef TRY_AGAIN
169#if defined(F_SETFL) && defined(O_NDELAY)
170		if ((e = fcntl(fd, F_GETFL, 0)) == -1)
171			return -1;
172
173		if (fcntl(fd, F_SETFL, e & ~O_NDELAY) == -1)
174			return -1;
175		else
176			e = 1;
177#endif /* F_SETFL && O_NDELAY */
178
179#ifdef FIONBIO
180		{
181			int zero = 0;
182
183			if (ioctl(fd, FIONBIO, &zero) == -1)
184				return -1;
185			else
186				e = 1;
187		}
188#endif /* FIONBIO */
189
190#endif /* TRY_AGAIN */
191		return e ? 0 : -1;
192
193	case EINTR:
194		return 0;
195
196	default:
197		return -1;
198	}
199}
200
201
202/* el_push():
203 *	Push a macro
204 */
205void
206el_wpush(EditLine *el, const wchar_t *str)
207{
208	struct macros *ma = &el->el_read->macros;
209
210	if (str != NULL && ma->level + 1 < EL_MAXMACRO) {
211		ma->level++;
212		if ((ma->macro[ma->level] = wcsdup(str)) != NULL)
213			return;
214		ma->level--;
215	}
216	terminal_beep(el);
217	terminal__flush(el);
218}
219
220
221/* read_getcmd():
222 *	Get next command from the input stream,
223 *	return 0 on success or -1 on EOF or error.
224 *	Character values > 255 are not looked up in the map, but inserted.
225 */
226static int
227read_getcmd(EditLine *el, el_action_t *cmdnum, wchar_t *ch)
228{
229	static const wchar_t meta = (wchar_t)0x80;
230	el_action_t cmd;
231
232	do {
233		if (el_wgetc(el, ch) != 1)
234			return -1;
235
236#ifdef	KANJI
237		if ((*ch & meta)) {
238			el->el_state.metanext = 0;
239			cmd = CcViMap[' '];
240			break;
241		} else
242#endif /* KANJI */
243
244		if (el->el_state.metanext) {
245			el->el_state.metanext = 0;
246			*ch |= meta;
247		}
248		if (*ch >= N_KEYS)
249			cmd = ED_INSERT;
250		else
251			cmd = el->el_map.current[(unsigned char) *ch];
252		if (cmd == ED_SEQUENCE_LEAD_IN) {
253			keymacro_value_t val;
254			switch (keymacro_get(el, ch, &val)) {
255			case XK_CMD:
256				cmd = val.cmd;
257				break;
258			case XK_STR:
259				el_wpush(el, val.str);
260				break;
261			case XK_NOD:
262				return -1;
263			default:
264				EL_ABORT((el->el_errfile, "Bad XK_ type \n"));
265				break;
266			}
267		}
268	} while (cmd == ED_SEQUENCE_LEAD_IN);
269	*cmdnum = cmd;
270	return 0;
271}
272
273/* read_char():
274 *	Read a character from the tty.
275 */
276static int
277read_char(EditLine *el, wchar_t *cp)
278{
279	ssize_t num_read;
280	int tried = 0;
281	char cbuf[MB_LEN_MAX];
282	size_t cbp = 0;
283	int save_errno = errno;
284
285 again:
286	el->el_signal->sig_no = 0;
287	while ((num_read = read(el->el_infd, cbuf + cbp, (size_t)1)) == -1) {
288		int e = errno;
289		switch (el->el_signal->sig_no) {
290		case SIGCONT:
291			el_wset(el, EL_REFRESH);
292			/*FALLTHROUGH*/
293		case SIGWINCH:
294			sig_set(el);
295			goto again;
296		default:
297			break;
298		}
299		if (!tried && read__fixio(el->el_infd, e) == 0) {
300			errno = save_errno;
301			tried = 1;
302		} else {
303			errno = e;
304			*cp = L'\0';
305			return -1;
306		}
307	}
308
309	/* Test for EOF */
310	if (num_read == 0) {
311		*cp = L'\0';
312		return 0;
313	}
314
315	for (;;) {
316		mbstate_t mbs;
317
318		++cbp;
319		/* This only works because UTF8 is stateless. */
320		memset(&mbs, 0, sizeof(mbs));
321		switch (mbrtowc(cp, cbuf, cbp, &mbs)) {
322		case (size_t)-1:
323			if (cbp > 1) {
324				/*
325				 * Invalid sequence, discard all bytes
326				 * except the last one.
327				 */
328				cbuf[0] = cbuf[cbp - 1];
329				cbp = 0;
330				break;
331			} else {
332				/* Invalid byte, discard it. */
333				cbp = 0;
334				goto again;
335			}
336		case (size_t)-2:
337			if (cbp >= MB_LEN_MAX) {
338				errno = EILSEQ;
339				*cp = L'\0';
340				return -1;
341			}
342			/* Incomplete sequence, read another byte. */
343			goto again;
344		default:
345			/* Valid character, process it. */
346			return 1;
347		}
348	}
349}
350
351/* read_pop():
352 *	Pop a macro from the stack
353 */
354static void
355read_pop(struct macros *ma)
356{
357	int i;
358
359	el_free(ma->macro[0]);
360	for (i = 0; i < ma->level; i++)
361		ma->macro[i] = ma->macro[i + 1];
362	ma->level--;
363	ma->offset = 0;
364}
365
366static void
367read_clearmacros(struct macros *ma)
368{
369	while (ma->level >= 0)
370		el_free(ma->macro[ma->level--]);
371	ma->offset = 0;
372}
373
374/* el_wgetc():
375 *	Read a wide character
376 */
377int
378el_wgetc(EditLine *el, wchar_t *cp)
379{
380	struct macros *ma = &el->el_read->macros;
381	int num_read;
382
383	terminal__flush(el);
384	for (;;) {
385		if (ma->level < 0)
386			break;
387
388		if (ma->macro[0][ma->offset] == '\0') {
389			read_pop(ma);
390			continue;
391		}
392
393		*cp = ma->macro[0][ma->offset++];
394
395		if (ma->macro[0][ma->offset] == '\0') {
396			/* Needed for QuoteMode On */
397			read_pop(ma);
398		}
399
400		return 1;
401	}
402
403	if (tty_rawmode(el) < 0)/* make sure the tty is set up correctly */
404		return 0;
405
406	num_read = (*el->el_read->read_char)(el, cp);
407
408	/*
409	 * Remember the original reason of a read failure
410	 * such that el_wgets() can restore it after doing
411	 * various cleanup operation that might change errno.
412	 */
413	if (num_read < 0)
414		el->el_read->read_errno = errno;
415
416	return num_read;
417}
418
419libedit_private void
420read_prepare(EditLine *el)
421{
422	if (el->el_flags & HANDLE_SIGNALS)
423		sig_set(el);
424	if (el->el_flags & NO_TTY)
425		return;
426	if ((el->el_flags & (UNBUFFERED|EDIT_DISABLED)) == UNBUFFERED)
427		tty_rawmode(el);
428
429	/* This is relatively cheap, and things go terribly wrong if
430	   we have the wrong size. */
431	el_resize(el);
432	re_clear_display(el);	/* reset the display stuff */
433	ch_reset(el);
434	re_refresh(el);		/* print the prompt */
435
436	if (el->el_flags & UNBUFFERED)
437		terminal__flush(el);
438}
439
440libedit_private void
441read_finish(EditLine *el)
442{
443	if ((el->el_flags & UNBUFFERED) == 0)
444		(void) tty_cookedmode(el);
445	if (el->el_flags & HANDLE_SIGNALS)
446		sig_clr(el);
447}
448
449static const wchar_t *
450noedit_wgets(EditLine *el, int *nread)
451{
452	el_line_t	*lp = &el->el_line;
453	int		 num;
454
455	while ((num = (*el->el_read->read_char)(el, lp->lastchar)) == 1) {
456		if (lp->lastchar + 1 >= lp->limit &&
457		    !ch_enlargebufs(el, (size_t)2))
458			break;
459		lp->lastchar++;
460		if (el->el_flags & UNBUFFERED ||
461		    lp->lastchar[-1] == '\r' ||
462		    lp->lastchar[-1] == '\n')
463			break;
464	}
465	if (num == -1 && errno == EINTR)
466		lp->lastchar = lp->buffer;
467	lp->cursor = lp->lastchar;
468	*lp->lastchar = '\0';
469	*nread = (int)(lp->lastchar - lp->buffer);
470	return *nread ? lp->buffer : NULL;
471}
472
473const wchar_t *
474el_wgets(EditLine *el, int *nread)
475{
476	int retval;
477	el_action_t cmdnum = 0;
478	int num;		/* how many chars we have read at NL */
479	wchar_t ch;
480	int nrb;
481
482	if (nread == NULL)
483		nread = &nrb;
484	*nread = 0;
485	el->el_read->read_errno = 0;
486
487	if (el->el_flags & NO_TTY) {
488		el->el_line.lastchar = el->el_line.buffer;
489		return noedit_wgets(el, nread);
490	}
491
492#ifdef FIONREAD
493	if (el->el_tty.t_mode == EX_IO && el->el_read->macros.level < 0) {
494		int chrs = 0;
495
496		(void) ioctl(el->el_infd, FIONREAD, &chrs);
497		if (chrs == 0) {
498			if (tty_rawmode(el) < 0) {
499				errno = 0;
500				*nread = 0;
501				return NULL;
502			}
503		}
504	}
505#endif /* FIONREAD */
506
507	if ((el->el_flags & UNBUFFERED) == 0)
508		read_prepare(el);
509
510	if (el->el_flags & EDIT_DISABLED) {
511		if ((el->el_flags & UNBUFFERED) == 0)
512			el->el_line.lastchar = el->el_line.buffer;
513		terminal__flush(el);
514		return noedit_wgets(el, nread);
515	}
516
517	for (num = -1; num == -1;) {  /* while still editing this line */
518		/* if EOF or error */
519		if (read_getcmd(el, &cmdnum, &ch) == -1)
520			break;
521		if ((size_t)cmdnum >= el->el_map.nfunc) /* BUG CHECK command */
522			continue;	/* try again */
523		/* now do the real command */
524		/* vi redo needs these way down the levels... */
525		el->el_state.thiscmd = cmdnum;
526		el->el_state.thisch = ch;
527		if (el->el_map.type == MAP_VI &&
528		    el->el_map.current == el->el_map.key &&
529		    el->el_chared.c_redo.pos < el->el_chared.c_redo.lim) {
530			if (cmdnum == VI_DELETE_PREV_CHAR &&
531			    el->el_chared.c_redo.pos != el->el_chared.c_redo.buf
532			    && iswprint(el->el_chared.c_redo.pos[-1]))
533				el->el_chared.c_redo.pos--;
534			else
535				*el->el_chared.c_redo.pos++ = ch;
536		}
537		retval = (*el->el_map.func[cmdnum]) (el, ch);
538
539		/* save the last command here */
540		el->el_state.lastcmd = cmdnum;
541
542		/* use any return value */
543		switch (retval) {
544		case CC_CURSOR:
545			re_refresh_cursor(el);
546			break;
547
548		case CC_REDISPLAY:
549			re_clear_lines(el);
550			re_clear_display(el);
551			/* FALLTHROUGH */
552
553		case CC_REFRESH:
554			re_refresh(el);
555			break;
556
557		case CC_REFRESH_BEEP:
558			re_refresh(el);
559			terminal_beep(el);
560			break;
561
562		case CC_NORM:	/* normal char */
563			break;
564
565		case CC_ARGHACK:	/* Suggested by Rich Salz */
566			/* <rsalz@pineapple.bbn.com> */
567			continue;	/* keep going... */
568
569		case CC_EOF:	/* end of file typed */
570			if ((el->el_flags & UNBUFFERED) == 0)
571				num = 0;
572			else if (num == -1) {
573				*el->el_line.lastchar++ = CONTROL('d');
574				el->el_line.cursor = el->el_line.lastchar;
575				num = 1;
576			}
577			break;
578
579		case CC_NEWLINE:	/* normal end of line */
580			num = (int)(el->el_line.lastchar - el->el_line.buffer);
581			break;
582
583		case CC_FATAL:	/* fatal error, reset to known state */
584			/* put (real) cursor in a known place */
585			re_clear_display(el);	/* reset the display stuff */
586			ch_reset(el);	/* reset the input pointers */
587			read_clearmacros(&el->el_read->macros);
588			re_refresh(el); /* print the prompt again */
589			break;
590
591		case CC_ERROR:
592		default:	/* functions we don't know about */
593			terminal_beep(el);
594			terminal__flush(el);
595			break;
596		}
597		el->el_state.argument = 1;
598		el->el_state.doingarg = 0;
599		el->el_chared.c_vcmd.action = NOP;
600		if (el->el_flags & UNBUFFERED)
601			break;
602	}
603
604	terminal__flush(el);		/* flush any buffered output */
605	/* make sure the tty is set up correctly */
606	if ((el->el_flags & UNBUFFERED) == 0) {
607		read_finish(el);
608		*nread = num != -1 ? num : 0;
609	} else
610		*nread = (int)(el->el_line.lastchar - el->el_line.buffer);
611
612	if (*nread == 0) {
613		if (num == -1) {
614			*nread = -1;
615			if (el->el_read->read_errno)
616				errno = el->el_read->read_errno;
617		}
618		return NULL;
619	} else
620		return el->el_line.buffer;
621}
622