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