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