xref: /netbsd-src/lib/libedit/tty.c (revision b1c86f5f087524e68db12794ee9c3e3da1ab17a0)
1 /*	$NetBSD: tty.c,v 1.33 2010/04/18 21:17:22 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
38 static char sccsid[] = "@(#)tty.c	8.1 (Berkeley) 6/4/93";
39 #else
40 __RCSID("$NetBSD: tty.c,v 1.33 2010/04/18 21:17:22 christos Exp $");
41 #endif
42 #endif /* not lint && not SCCSID */
43 
44 /*
45  * tty.c: tty interface stuff
46  */
47 #include <assert.h>
48 #include <errno.h>
49 #include <strings.h>	/* for ffs */
50 #include "el.h"
51 #include "tty.h"
52 
53 typedef struct ttymodes_t {
54 	const char *m_name;
55 	unsigned int m_value;
56 	int m_type;
57 }          ttymodes_t;
58 
59 typedef struct ttymap_t {
60 	Int nch, och;		/* Internal and termio rep of chars */
61 	el_action_t bind[3];	/* emacs, vi, and vi-cmd */
62 } ttymap_t;
63 
64 
65 private const ttyperm_t ttyperm = {
66 	{
67 		{"iflag:", ICRNL, (INLCR | IGNCR)},
68 		{"oflag:", (OPOST | ONLCR), ONLRET},
69 		{"cflag:", 0, 0},
70 		{"lflag:", (ISIG | ICANON | ECHO | ECHOE | ECHOCTL | IEXTEN),
71 		(NOFLSH | ECHONL | EXTPROC | FLUSHO)},
72 		{"chars:", 0, 0},
73 	},
74 	{
75 		{"iflag:", (INLCR | ICRNL), IGNCR},
76 		{"oflag:", (OPOST | ONLCR), ONLRET},
77 		{"cflag:", 0, 0},
78 		{"lflag:", ISIG,
79 		(NOFLSH | ICANON | ECHO | ECHOK | ECHONL | EXTPROC | IEXTEN | FLUSHO)},
80 		{"chars:", (C_SH(C_MIN) | C_SH(C_TIME) | C_SH(C_SWTCH) | C_SH(C_DSWTCH) |
81 			    C_SH(C_SUSP) | C_SH(C_DSUSP) | C_SH(C_EOL) | C_SH(C_DISCARD) |
82 		    C_SH(C_PGOFF) | C_SH(C_PAGE) | C_SH(C_STATUS)), 0}
83 	},
84 	{
85 		{"iflag:", 0, IXON | IXOFF | INLCR | ICRNL},
86 		{"oflag:", 0, 0},
87 		{"cflag:", 0, 0},
88 		{"lflag:", 0, ISIG | IEXTEN},
89 		{"chars:", 0, 0},
90 	}
91 };
92 
93 private const ttychar_t ttychar = {
94 	{
95 		CINTR, CQUIT, CERASE, CKILL,
96 		CEOF, CEOL, CEOL2, CSWTCH,
97 		CDSWTCH, CERASE2, CSTART, CSTOP,
98 		CWERASE, CSUSP, CDSUSP, CREPRINT,
99 		CDISCARD, CLNEXT, CSTATUS, CPAGE,
100 		CPGOFF, CKILL2, CBRK, CMIN,
101 		CTIME
102 	},
103 	{
104 		CINTR, CQUIT, CERASE, CKILL,
105 		_POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE,
106 		_POSIX_VDISABLE, CERASE2, CSTART, CSTOP,
107 		_POSIX_VDISABLE, CSUSP, _POSIX_VDISABLE, _POSIX_VDISABLE,
108 		CDISCARD, _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE,
109 		_POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE, 1,
110 		0
111 	},
112 	{
113 		0, 0, 0, 0,
114 		0, 0, 0, 0,
115 		0, 0, 0, 0,
116 		0, 0, 0, 0,
117 		0, 0, 0, 0,
118 		0, 0, 0, 0,
119 		0
120 	}
121 };
122 
123 private const ttymap_t tty_map[] = {
124 #ifdef VERASE
125 	{C_ERASE, VERASE,
126 	{EM_DELETE_PREV_CHAR, VI_DELETE_PREV_CHAR, ED_PREV_CHAR}},
127 #endif /* VERASE */
128 #ifdef VERASE2
129 	{C_ERASE2, VERASE2,
130 	{EM_DELETE_PREV_CHAR, VI_DELETE_PREV_CHAR, ED_PREV_CHAR}},
131 #endif /* VERASE2 */
132 #ifdef VKILL
133 	{C_KILL, VKILL,
134 	{EM_KILL_LINE, VI_KILL_LINE_PREV, ED_UNASSIGNED}},
135 #endif /* VKILL */
136 #ifdef VKILL2
137 	{C_KILL2, VKILL2,
138 	{EM_KILL_LINE, VI_KILL_LINE_PREV, ED_UNASSIGNED}},
139 #endif /* VKILL2 */
140 #ifdef VEOF
141 	{C_EOF, VEOF,
142 	{EM_DELETE_OR_LIST, VI_LIST_OR_EOF, ED_UNASSIGNED}},
143 #endif /* VEOF */
144 #ifdef VWERASE
145 	{C_WERASE, VWERASE,
146 	{ED_DELETE_PREV_WORD, ED_DELETE_PREV_WORD, ED_PREV_WORD}},
147 #endif /* VWERASE */
148 #ifdef VREPRINT
149 	{C_REPRINT, VREPRINT,
150 	{ED_REDISPLAY, ED_INSERT, ED_REDISPLAY}},
151 #endif /* VREPRINT */
152 #ifdef VLNEXT
153 	{C_LNEXT, VLNEXT,
154 	{ED_QUOTED_INSERT, ED_QUOTED_INSERT, ED_UNASSIGNED}},
155 #endif /* VLNEXT */
156 	{-1, -1,
157 	{ED_UNASSIGNED, ED_UNASSIGNED, ED_UNASSIGNED}}
158 };
159 
160 private const ttymodes_t ttymodes[] = {
161 #ifdef	IGNBRK
162 	{"ignbrk", IGNBRK, MD_INP},
163 #endif /* IGNBRK */
164 #ifdef	BRKINT
165 	{"brkint", BRKINT, MD_INP},
166 #endif /* BRKINT */
167 #ifdef	IGNPAR
168 	{"ignpar", IGNPAR, MD_INP},
169 #endif /* IGNPAR */
170 #ifdef	PARMRK
171 	{"parmrk", PARMRK, MD_INP},
172 #endif /* PARMRK */
173 #ifdef	INPCK
174 	{"inpck", INPCK, MD_INP},
175 #endif /* INPCK */
176 #ifdef	ISTRIP
177 	{"istrip", ISTRIP, MD_INP},
178 #endif /* ISTRIP */
179 #ifdef	INLCR
180 	{"inlcr", INLCR, MD_INP},
181 #endif /* INLCR */
182 #ifdef	IGNCR
183 	{"igncr", IGNCR, MD_INP},
184 #endif /* IGNCR */
185 #ifdef	ICRNL
186 	{"icrnl", ICRNL, MD_INP},
187 #endif /* ICRNL */
188 #ifdef	IUCLC
189 	{"iuclc", IUCLC, MD_INP},
190 #endif /* IUCLC */
191 #ifdef	IXON
192 	{"ixon", IXON, MD_INP},
193 #endif /* IXON */
194 #ifdef	IXANY
195 	{"ixany", IXANY, MD_INP},
196 #endif /* IXANY */
197 #ifdef	IXOFF
198 	{"ixoff", IXOFF, MD_INP},
199 #endif /* IXOFF */
200 #ifdef  IMAXBEL
201 	{"imaxbel", IMAXBEL, MD_INP},
202 #endif /* IMAXBEL */
203 
204 #ifdef	OPOST
205 	{"opost", OPOST, MD_OUT},
206 #endif /* OPOST */
207 #ifdef	OLCUC
208 	{"olcuc", OLCUC, MD_OUT},
209 #endif /* OLCUC */
210 #ifdef	ONLCR
211 	{"onlcr", ONLCR, MD_OUT},
212 #endif /* ONLCR */
213 #ifdef	OCRNL
214 	{"ocrnl", OCRNL, MD_OUT},
215 #endif /* OCRNL */
216 #ifdef	ONOCR
217 	{"onocr", ONOCR, MD_OUT},
218 #endif /* ONOCR */
219 #ifdef ONOEOT
220 	{"onoeot", ONOEOT, MD_OUT},
221 #endif /* ONOEOT */
222 #ifdef	ONLRET
223 	{"onlret", ONLRET, MD_OUT},
224 #endif /* ONLRET */
225 #ifdef	OFILL
226 	{"ofill", OFILL, MD_OUT},
227 #endif /* OFILL */
228 #ifdef	OFDEL
229 	{"ofdel", OFDEL, MD_OUT},
230 #endif /* OFDEL */
231 #ifdef	NLDLY
232 	{"nldly", NLDLY, MD_OUT},
233 #endif /* NLDLY */
234 #ifdef	CRDLY
235 	{"crdly", CRDLY, MD_OUT},
236 #endif /* CRDLY */
237 #ifdef	TABDLY
238 	{"tabdly", TABDLY, MD_OUT},
239 #endif /* TABDLY */
240 #ifdef	XTABS
241 	{"xtabs", XTABS, MD_OUT},
242 #endif /* XTABS */
243 #ifdef	BSDLY
244 	{"bsdly", BSDLY, MD_OUT},
245 #endif /* BSDLY */
246 #ifdef	VTDLY
247 	{"vtdly", VTDLY, MD_OUT},
248 #endif /* VTDLY */
249 #ifdef	FFDLY
250 	{"ffdly", FFDLY, MD_OUT},
251 #endif /* FFDLY */
252 #ifdef	PAGEOUT
253 	{"pageout", PAGEOUT, MD_OUT},
254 #endif /* PAGEOUT */
255 #ifdef	WRAP
256 	{"wrap", WRAP, MD_OUT},
257 #endif /* WRAP */
258 
259 #ifdef	CIGNORE
260 	{"cignore", CIGNORE, MD_CTL},
261 #endif /* CBAUD */
262 #ifdef	CBAUD
263 	{"cbaud", CBAUD, MD_CTL},
264 #endif /* CBAUD */
265 #ifdef	CSTOPB
266 	{"cstopb", CSTOPB, MD_CTL},
267 #endif /* CSTOPB */
268 #ifdef	CREAD
269 	{"cread", CREAD, MD_CTL},
270 #endif /* CREAD */
271 #ifdef	PARENB
272 	{"parenb", PARENB, MD_CTL},
273 #endif /* PARENB */
274 #ifdef	PARODD
275 	{"parodd", PARODD, MD_CTL},
276 #endif /* PARODD */
277 #ifdef	HUPCL
278 	{"hupcl", HUPCL, MD_CTL},
279 #endif /* HUPCL */
280 #ifdef	CLOCAL
281 	{"clocal", CLOCAL, MD_CTL},
282 #endif /* CLOCAL */
283 #ifdef	LOBLK
284 	{"loblk", LOBLK, MD_CTL},
285 #endif /* LOBLK */
286 #ifdef	CIBAUD
287 	{"cibaud", CIBAUD, MD_CTL},
288 #endif /* CIBAUD */
289 #ifdef CRTSCTS
290 #ifdef CCTS_OFLOW
291 	{"ccts_oflow", CCTS_OFLOW, MD_CTL},
292 #else
293 	{"crtscts", CRTSCTS, MD_CTL},
294 #endif /* CCTS_OFLOW */
295 #endif /* CRTSCTS */
296 #ifdef CRTS_IFLOW
297 	{"crts_iflow", CRTS_IFLOW, MD_CTL},
298 #endif /* CRTS_IFLOW */
299 #ifdef CDTRCTS
300 	{"cdtrcts", CDTRCTS, MD_CTL},
301 #endif /* CDTRCTS */
302 #ifdef MDMBUF
303 	{"mdmbuf", MDMBUF, MD_CTL},
304 #endif /* MDMBUF */
305 #ifdef RCV1EN
306 	{"rcv1en", RCV1EN, MD_CTL},
307 #endif /* RCV1EN */
308 #ifdef XMT1EN
309 	{"xmt1en", XMT1EN, MD_CTL},
310 #endif /* XMT1EN */
311 
312 #ifdef	ISIG
313 	{"isig", ISIG, MD_LIN},
314 #endif /* ISIG */
315 #ifdef	ICANON
316 	{"icanon", ICANON, MD_LIN},
317 #endif /* ICANON */
318 #ifdef	XCASE
319 	{"xcase", XCASE, MD_LIN},
320 #endif /* XCASE */
321 #ifdef	ECHO
322 	{"echo", ECHO, MD_LIN},
323 #endif /* ECHO */
324 #ifdef	ECHOE
325 	{"echoe", ECHOE, MD_LIN},
326 #endif /* ECHOE */
327 #ifdef	ECHOK
328 	{"echok", ECHOK, MD_LIN},
329 #endif /* ECHOK */
330 #ifdef	ECHONL
331 	{"echonl", ECHONL, MD_LIN},
332 #endif /* ECHONL */
333 #ifdef	NOFLSH
334 	{"noflsh", NOFLSH, MD_LIN},
335 #endif /* NOFLSH */
336 #ifdef	TOSTOP
337 	{"tostop", TOSTOP, MD_LIN},
338 #endif /* TOSTOP */
339 #ifdef	ECHOCTL
340 	{"echoctl", ECHOCTL, MD_LIN},
341 #endif /* ECHOCTL */
342 #ifdef	ECHOPRT
343 	{"echoprt", ECHOPRT, MD_LIN},
344 #endif /* ECHOPRT */
345 #ifdef	ECHOKE
346 	{"echoke", ECHOKE, MD_LIN},
347 #endif /* ECHOKE */
348 #ifdef	DEFECHO
349 	{"defecho", DEFECHO, MD_LIN},
350 #endif /* DEFECHO */
351 #ifdef	FLUSHO
352 	{"flusho", FLUSHO, MD_LIN},
353 #endif /* FLUSHO */
354 #ifdef	PENDIN
355 	{"pendin", PENDIN, MD_LIN},
356 #endif /* PENDIN */
357 #ifdef	IEXTEN
358 	{"iexten", IEXTEN, MD_LIN},
359 #endif /* IEXTEN */
360 #ifdef	NOKERNINFO
361 	{"nokerninfo", NOKERNINFO, MD_LIN},
362 #endif /* NOKERNINFO */
363 #ifdef	ALTWERASE
364 	{"altwerase", ALTWERASE, MD_LIN},
365 #endif /* ALTWERASE */
366 #ifdef	EXTPROC
367 	{"extproc", EXTPROC, MD_LIN},
368 #endif /* EXTPROC */
369 
370 #if defined(VINTR)
371 	{"intr", C_SH(C_INTR), MD_CHAR},
372 #endif /* VINTR */
373 #if defined(VQUIT)
374 	{"quit", C_SH(C_QUIT), MD_CHAR},
375 #endif /* VQUIT */
376 #if defined(VERASE)
377 	{"erase", C_SH(C_ERASE), MD_CHAR},
378 #endif /* VERASE */
379 #if defined(VKILL)
380 	{"kill", C_SH(C_KILL), MD_CHAR},
381 #endif /* VKILL */
382 #if defined(VEOF)
383 	{"eof", C_SH(C_EOF), MD_CHAR},
384 #endif /* VEOF */
385 #if defined(VEOL)
386 	{"eol", C_SH(C_EOL), MD_CHAR},
387 #endif /* VEOL */
388 #if defined(VEOL2)
389 	{"eol2", C_SH(C_EOL2), MD_CHAR},
390 #endif /* VEOL2 */
391 #if defined(VSWTCH)
392 	{"swtch", C_SH(C_SWTCH), MD_CHAR},
393 #endif /* VSWTCH */
394 #if defined(VDSWTCH)
395 	{"dswtch", C_SH(C_DSWTCH), MD_CHAR},
396 #endif /* VDSWTCH */
397 #if defined(VERASE2)
398 	{"erase2", C_SH(C_ERASE2), MD_CHAR},
399 #endif /* VERASE2 */
400 #if defined(VSTART)
401 	{"start", C_SH(C_START), MD_CHAR},
402 #endif /* VSTART */
403 #if defined(VSTOP)
404 	{"stop", C_SH(C_STOP), MD_CHAR},
405 #endif /* VSTOP */
406 #if defined(VWERASE)
407 	{"werase", C_SH(C_WERASE), MD_CHAR},
408 #endif /* VWERASE */
409 #if defined(VSUSP)
410 	{"susp", C_SH(C_SUSP), MD_CHAR},
411 #endif /* VSUSP */
412 #if defined(VDSUSP)
413 	{"dsusp", C_SH(C_DSUSP), MD_CHAR},
414 #endif /* VDSUSP */
415 #if defined(VREPRINT)
416 	{"reprint", C_SH(C_REPRINT), MD_CHAR},
417 #endif /* VREPRINT */
418 #if defined(VDISCARD)
419 	{"discard", C_SH(C_DISCARD), MD_CHAR},
420 #endif /* VDISCARD */
421 #if defined(VLNEXT)
422 	{"lnext", C_SH(C_LNEXT), MD_CHAR},
423 #endif /* VLNEXT */
424 #if defined(VSTATUS)
425 	{"status", C_SH(C_STATUS), MD_CHAR},
426 #endif /* VSTATUS */
427 #if defined(VPAGE)
428 	{"page", C_SH(C_PAGE), MD_CHAR},
429 #endif /* VPAGE */
430 #if defined(VPGOFF)
431 	{"pgoff", C_SH(C_PGOFF), MD_CHAR},
432 #endif /* VPGOFF */
433 #if defined(VKILL2)
434 	{"kill2", C_SH(C_KILL2), MD_CHAR},
435 #endif /* VKILL2 */
436 #if defined(VBRK)
437 	{"brk", C_SH(C_BRK), MD_CHAR},
438 #endif /* VBRK */
439 #if defined(VMIN)
440 	{"min", C_SH(C_MIN), MD_CHAR},
441 #endif /* VMIN */
442 #if defined(VTIME)
443 	{"time", C_SH(C_TIME), MD_CHAR},
444 #endif /* VTIME */
445 	{NULL, 0, -1},
446 };
447 
448 
449 
450 #define	tty__gettabs(td)	((((td)->c_oflag & TAB3) == TAB3) ? 0 : 1)
451 #define	tty__geteightbit(td)	(((td)->c_cflag & CSIZE) == CS8)
452 #define	tty__cooked_mode(td)	((td)->c_lflag & ICANON)
453 
454 private int	tty_getty(EditLine *, struct termios *);
455 private int	tty_setty(EditLine *, int, const struct termios *);
456 private int	tty__getcharindex(int);
457 private void	tty__getchar(struct termios *, unsigned char *);
458 private void	tty__setchar(struct termios *, unsigned char *);
459 private speed_t	tty__getspeed(struct termios *);
460 private int	tty_setup(EditLine *);
461 
462 #define	t_qu	t_ts
463 
464 /* tty_getty():
465  *	Wrapper for tcgetattr to handle EINTR
466  */
467 private int
468 tty_getty(EditLine *el, struct termios *t)
469 {
470 	int rv;
471 	while ((rv = tcgetattr(el->el_infd, t)) == -1 && errno == EINTR)
472 		continue;
473 	return rv;
474 }
475 
476 /* tty_setty():
477  *	Wrapper for tcsetattr to handle EINTR
478  */
479 private int
480 tty_setty(EditLine *el, int action, const struct termios *t)
481 {
482 	int rv;
483 	while ((rv = tcsetattr(el->el_infd, action, t)) == -1 && errno == EINTR)
484 		continue;
485 	return rv;
486 }
487 
488 /* tty_setup():
489  *	Get the tty parameters and initialize the editing state
490  */
491 private int
492 tty_setup(EditLine *el)
493 {
494 	int rst = 1;
495 
496 	if (el->el_flags & EDIT_DISABLED)
497 		return (0);
498 
499 	if (tty_getty(el, &el->el_tty.t_ed) == -1) {
500 #ifdef DEBUG_TTY
501 		(void) fprintf(el->el_errfile,
502 		    "tty_setup: tty_getty: %s\n", strerror(errno));
503 #endif /* DEBUG_TTY */
504 		return (-1);
505 	}
506 	el->el_tty.t_ts = el->el_tty.t_ex = el->el_tty.t_ed;
507 
508 	el->el_tty.t_speed = tty__getspeed(&el->el_tty.t_ex);
509 	el->el_tty.t_tabs = tty__gettabs(&el->el_tty.t_ex);
510 	el->el_tty.t_eight = tty__geteightbit(&el->el_tty.t_ex);
511 
512 	el->el_tty.t_ex.c_iflag &= ~el->el_tty.t_t[EX_IO][MD_INP].t_clrmask;
513 	el->el_tty.t_ex.c_iflag |= el->el_tty.t_t[EX_IO][MD_INP].t_setmask;
514 
515 	el->el_tty.t_ex.c_oflag &= ~el->el_tty.t_t[EX_IO][MD_OUT].t_clrmask;
516 	el->el_tty.t_ex.c_oflag |= el->el_tty.t_t[EX_IO][MD_OUT].t_setmask;
517 
518 	el->el_tty.t_ex.c_cflag &= ~el->el_tty.t_t[EX_IO][MD_CTL].t_clrmask;
519 	el->el_tty.t_ex.c_cflag |= el->el_tty.t_t[EX_IO][MD_CTL].t_setmask;
520 
521 	el->el_tty.t_ex.c_lflag &= ~el->el_tty.t_t[EX_IO][MD_LIN].t_clrmask;
522 	el->el_tty.t_ex.c_lflag |= el->el_tty.t_t[EX_IO][MD_LIN].t_setmask;
523 
524 	/*
525          * Reset the tty chars to reasonable defaults
526          * If they are disabled, then enable them.
527          */
528 	if (rst) {
529 		if (tty__cooked_mode(&el->el_tty.t_ts)) {
530 			tty__getchar(&el->el_tty.t_ts, el->el_tty.t_c[TS_IO]);
531 			/*
532 	                 * Don't affect CMIN and CTIME for the editor mode
533 	                 */
534 			for (rst = 0; rst < C_NCC - 2; rst++)
535 				if (el->el_tty.t_c[TS_IO][rst] !=
536 				      el->el_tty.t_vdisable
537 				    && el->el_tty.t_c[ED_IO][rst] !=
538 				      el->el_tty.t_vdisable)
539 					el->el_tty.t_c[ED_IO][rst] =
540 					    el->el_tty.t_c[TS_IO][rst];
541 			for (rst = 0; rst < C_NCC; rst++)
542 				if (el->el_tty.t_c[TS_IO][rst] !=
543 				    el->el_tty.t_vdisable)
544 					el->el_tty.t_c[EX_IO][rst] =
545 					    el->el_tty.t_c[TS_IO][rst];
546 		}
547 		tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]);
548 		if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ex) == -1) {
549 #ifdef DEBUG_TTY
550 			(void) fprintf(el->el_errfile,
551 			    "tty_setup: tty_setty: %s\n",
552 			    strerror(errno));
553 #endif /* DEBUG_TTY */
554 			return (-1);
555 		}
556 	}
557 #ifdef notdef
558 	else
559 		tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]);
560 #endif
561 
562 	el->el_tty.t_ed.c_iflag &= ~el->el_tty.t_t[ED_IO][MD_INP].t_clrmask;
563 	el->el_tty.t_ed.c_iflag |= el->el_tty.t_t[ED_IO][MD_INP].t_setmask;
564 
565 	el->el_tty.t_ed.c_oflag &= ~el->el_tty.t_t[ED_IO][MD_OUT].t_clrmask;
566 	el->el_tty.t_ed.c_oflag |= el->el_tty.t_t[ED_IO][MD_OUT].t_setmask;
567 
568 	el->el_tty.t_ed.c_cflag &= ~el->el_tty.t_t[ED_IO][MD_CTL].t_clrmask;
569 	el->el_tty.t_ed.c_cflag |= el->el_tty.t_t[ED_IO][MD_CTL].t_setmask;
570 
571 	el->el_tty.t_ed.c_lflag &= ~el->el_tty.t_t[ED_IO][MD_LIN].t_clrmask;
572 	el->el_tty.t_ed.c_lflag |= el->el_tty.t_t[ED_IO][MD_LIN].t_setmask;
573 
574 	tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]);
575 	tty_bind_char(el, 1);
576 	return (0);
577 }
578 
579 protected int
580 tty_init(EditLine *el)
581 {
582 
583 	el->el_tty.t_mode = EX_IO;
584 	el->el_tty.t_vdisable = _POSIX_VDISABLE;
585 	(void) memcpy(el->el_tty.t_t, ttyperm, sizeof(ttyperm_t));
586 	(void) memcpy(el->el_tty.t_c, ttychar, sizeof(ttychar_t));
587 	return (tty_setup(el));
588 }
589 
590 
591 /* tty_end():
592  *	Restore the tty to its original settings
593  */
594 protected void
595 /*ARGSUSED*/
596 tty_end(EditLine *el __attribute__((__unused__)))
597 {
598 
599 	/* XXX: Maybe reset to an initial state? */
600 }
601 
602 
603 /* tty__getspeed():
604  *	Get the tty speed
605  */
606 private speed_t
607 tty__getspeed(struct termios *td)
608 {
609 	speed_t spd;
610 
611 	if ((spd = cfgetispeed(td)) == 0)
612 		spd = cfgetospeed(td);
613 	return (spd);
614 }
615 
616 /* tty__getspeed():
617  *	Return the index of the asked char in the c_cc array
618  */
619 private int
620 tty__getcharindex(int i)
621 {
622 	switch (i) {
623 #ifdef VINTR
624 	case C_INTR:
625 		return VINTR;
626 #endif /* VINTR */
627 #ifdef VQUIT
628 	case C_QUIT:
629 		return VQUIT;
630 #endif /* VQUIT */
631 #ifdef VERASE
632 	case C_ERASE:
633 		return VERASE;
634 #endif /* VERASE */
635 #ifdef VKILL
636 	case C_KILL:
637 		return VKILL;
638 #endif /* VKILL */
639 #ifdef VEOF
640 	case C_EOF:
641 		return VEOF;
642 #endif /* VEOF */
643 #ifdef VEOL
644 	case C_EOL:
645 		return VEOL;
646 #endif /* VEOL */
647 #ifdef VEOL2
648 	case C_EOL2:
649 		return VEOL2;
650 #endif /* VEOL2 */
651 #ifdef VSWTCH
652 	case C_SWTCH:
653 		return VSWTCH;
654 #endif /* VSWTCH */
655 #ifdef VDSWTCH
656 	case C_DSWTCH:
657 		return VDSWTCH;
658 #endif /* VDSWTCH */
659 #ifdef VERASE2
660 	case C_ERASE2:
661 		return VERASE2;
662 #endif /* VERASE2 */
663 #ifdef VSTART
664 	case C_START:
665 		return VSTART;
666 #endif /* VSTART */
667 #ifdef VSTOP
668 	case C_STOP:
669 		return VSTOP;
670 #endif /* VSTOP */
671 #ifdef VWERASE
672 	case C_WERASE:
673 		return VWERASE;
674 #endif /* VWERASE */
675 #ifdef VSUSP
676 	case C_SUSP:
677 		return VSUSP;
678 #endif /* VSUSP */
679 #ifdef VDSUSP
680 	case C_DSUSP:
681 		return VDSUSP;
682 #endif /* VDSUSP */
683 #ifdef VREPRINT
684 	case C_REPRINT:
685 		return VREPRINT;
686 #endif /* VREPRINT */
687 #ifdef VDISCARD
688 	case C_DISCARD:
689 		return VDISCARD;
690 #endif /* VDISCARD */
691 #ifdef VLNEXT
692 	case C_LNEXT:
693 		return VLNEXT;
694 #endif /* VLNEXT */
695 #ifdef VSTATUS
696 	case C_STATUS:
697 		return VSTATUS;
698 #endif /* VSTATUS */
699 #ifdef VPAGE
700 	case C_PAGE:
701 		return VPAGE;
702 #endif /* VPAGE */
703 #ifdef VPGOFF
704 	case C_PGOFF:
705 		return VPGOFF;
706 #endif /* VPGOFF */
707 #ifdef VKILL2
708 	case C_KILL2:
709 		return VKILL2;
710 #endif /* KILL2 */
711 #ifdef VMIN
712 	case C_MIN:
713 		return VMIN;
714 #endif /* VMIN */
715 #ifdef VTIME
716 	case C_TIME:
717 		return VTIME;
718 #endif /* VTIME */
719 	default:
720 		return -1;
721 	}
722 }
723 
724 /* tty__getchar():
725  *	Get the tty characters
726  */
727 private void
728 tty__getchar(struct termios *td, unsigned char *s)
729 {
730 
731 #ifdef VINTR
732 	s[C_INTR] = td->c_cc[VINTR];
733 #endif /* VINTR */
734 #ifdef VQUIT
735 	s[C_QUIT] = td->c_cc[VQUIT];
736 #endif /* VQUIT */
737 #ifdef VERASE
738 	s[C_ERASE] = td->c_cc[VERASE];
739 #endif /* VERASE */
740 #ifdef VKILL
741 	s[C_KILL] = td->c_cc[VKILL];
742 #endif /* VKILL */
743 #ifdef VEOF
744 	s[C_EOF] = td->c_cc[VEOF];
745 #endif /* VEOF */
746 #ifdef VEOL
747 	s[C_EOL] = td->c_cc[VEOL];
748 #endif /* VEOL */
749 #ifdef VEOL2
750 	s[C_EOL2] = td->c_cc[VEOL2];
751 #endif /* VEOL2 */
752 #ifdef VSWTCH
753 	s[C_SWTCH] = td->c_cc[VSWTCH];
754 #endif /* VSWTCH */
755 #ifdef VDSWTCH
756 	s[C_DSWTCH] = td->c_cc[VDSWTCH];
757 #endif /* VDSWTCH */
758 #ifdef VERASE2
759 	s[C_ERASE2] = td->c_cc[VERASE2];
760 #endif /* VERASE2 */
761 #ifdef VSTART
762 	s[C_START] = td->c_cc[VSTART];
763 #endif /* VSTART */
764 #ifdef VSTOP
765 	s[C_STOP] = td->c_cc[VSTOP];
766 #endif /* VSTOP */
767 #ifdef VWERASE
768 	s[C_WERASE] = td->c_cc[VWERASE];
769 #endif /* VWERASE */
770 #ifdef VSUSP
771 	s[C_SUSP] = td->c_cc[VSUSP];
772 #endif /* VSUSP */
773 #ifdef VDSUSP
774 	s[C_DSUSP] = td->c_cc[VDSUSP];
775 #endif /* VDSUSP */
776 #ifdef VREPRINT
777 	s[C_REPRINT] = td->c_cc[VREPRINT];
778 #endif /* VREPRINT */
779 #ifdef VDISCARD
780 	s[C_DISCARD] = td->c_cc[VDISCARD];
781 #endif /* VDISCARD */
782 #ifdef VLNEXT
783 	s[C_LNEXT] = td->c_cc[VLNEXT];
784 #endif /* VLNEXT */
785 #ifdef VSTATUS
786 	s[C_STATUS] = td->c_cc[VSTATUS];
787 #endif /* VSTATUS */
788 #ifdef VPAGE
789 	s[C_PAGE] = td->c_cc[VPAGE];
790 #endif /* VPAGE */
791 #ifdef VPGOFF
792 	s[C_PGOFF] = td->c_cc[VPGOFF];
793 #endif /* VPGOFF */
794 #ifdef VKILL2
795 	s[C_KILL2] = td->c_cc[VKILL2];
796 #endif /* KILL2 */
797 #ifdef VMIN
798 	s[C_MIN] = td->c_cc[VMIN];
799 #endif /* VMIN */
800 #ifdef VTIME
801 	s[C_TIME] = td->c_cc[VTIME];
802 #endif /* VTIME */
803 }				/* tty__getchar */
804 
805 
806 /* tty__setchar():
807  *	Set the tty characters
808  */
809 private void
810 tty__setchar(struct termios *td, unsigned char *s)
811 {
812 
813 #ifdef VINTR
814 	td->c_cc[VINTR] = s[C_INTR];
815 #endif /* VINTR */
816 #ifdef VQUIT
817 	td->c_cc[VQUIT] = s[C_QUIT];
818 #endif /* VQUIT */
819 #ifdef VERASE
820 	td->c_cc[VERASE] = s[C_ERASE];
821 #endif /* VERASE */
822 #ifdef VKILL
823 	td->c_cc[VKILL] = s[C_KILL];
824 #endif /* VKILL */
825 #ifdef VEOF
826 	td->c_cc[VEOF] = s[C_EOF];
827 #endif /* VEOF */
828 #ifdef VEOL
829 	td->c_cc[VEOL] = s[C_EOL];
830 #endif /* VEOL */
831 #ifdef VEOL2
832 	td->c_cc[VEOL2] = s[C_EOL2];
833 #endif /* VEOL2 */
834 #ifdef VSWTCH
835 	td->c_cc[VSWTCH] = s[C_SWTCH];
836 #endif /* VSWTCH */
837 #ifdef VDSWTCH
838 	td->c_cc[VDSWTCH] = s[C_DSWTCH];
839 #endif /* VDSWTCH */
840 #ifdef VERASE2
841 	td->c_cc[VERASE2] = s[C_ERASE2];
842 #endif /* VERASE2 */
843 #ifdef VSTART
844 	td->c_cc[VSTART] = s[C_START];
845 #endif /* VSTART */
846 #ifdef VSTOP
847 	td->c_cc[VSTOP] = s[C_STOP];
848 #endif /* VSTOP */
849 #ifdef VWERASE
850 	td->c_cc[VWERASE] = s[C_WERASE];
851 #endif /* VWERASE */
852 #ifdef VSUSP
853 	td->c_cc[VSUSP] = s[C_SUSP];
854 #endif /* VSUSP */
855 #ifdef VDSUSP
856 	td->c_cc[VDSUSP] = s[C_DSUSP];
857 #endif /* VDSUSP */
858 #ifdef VREPRINT
859 	td->c_cc[VREPRINT] = s[C_REPRINT];
860 #endif /* VREPRINT */
861 #ifdef VDISCARD
862 	td->c_cc[VDISCARD] = s[C_DISCARD];
863 #endif /* VDISCARD */
864 #ifdef VLNEXT
865 	td->c_cc[VLNEXT] = s[C_LNEXT];
866 #endif /* VLNEXT */
867 #ifdef VSTATUS
868 	td->c_cc[VSTATUS] = s[C_STATUS];
869 #endif /* VSTATUS */
870 #ifdef VPAGE
871 	td->c_cc[VPAGE] = s[C_PAGE];
872 #endif /* VPAGE */
873 #ifdef VPGOFF
874 	td->c_cc[VPGOFF] = s[C_PGOFF];
875 #endif /* VPGOFF */
876 #ifdef VKILL2
877 	td->c_cc[VKILL2] = s[C_KILL2];
878 #endif /* VKILL2 */
879 #ifdef VMIN
880 	td->c_cc[VMIN] = s[C_MIN];
881 #endif /* VMIN */
882 #ifdef VTIME
883 	td->c_cc[VTIME] = s[C_TIME];
884 #endif /* VTIME */
885 }				/* tty__setchar */
886 
887 
888 /* tty_bind_char():
889  *	Rebind the editline functions
890  */
891 protected void
892 tty_bind_char(EditLine *el, int force)
893 {
894 
895 	unsigned char *t_n = el->el_tty.t_c[ED_IO];
896 	unsigned char *t_o = el->el_tty.t_ed.c_cc;
897 	Char new[2], old[2];
898 	const ttymap_t *tp;
899 	el_action_t *map, *alt;
900 	const el_action_t *dmap, *dalt;
901 	new[1] = old[1] = '\0';
902 
903 	map = el->el_map.key;
904 	alt = el->el_map.alt;
905 	if (el->el_map.type == MAP_VI) {
906 		dmap = el->el_map.vii;
907 		dalt = el->el_map.vic;
908 	} else {
909 		dmap = el->el_map.emacs;
910 		dalt = NULL;
911 	}
912 
913 	for (tp = tty_map; tp->nch != -1; tp++) {
914 		new[0] = t_n[tp->nch];
915 		old[0] = t_o[tp->och];
916 		if (new[0] == old[0] && !force)
917 			continue;
918 		/* Put the old default binding back, and set the new binding */
919 		key_clear(el, map, old);
920 		map[UC(old[0])] = dmap[UC(old[0])];
921 		key_clear(el, map, new);
922 		/* MAP_VI == 1, MAP_EMACS == 0... */
923 		map[UC(new[0])] = tp->bind[el->el_map.type];
924 		if (dalt) {
925 			key_clear(el, alt, old);
926 			alt[UC(old[0])] = dalt[UC(old[0])];
927 			key_clear(el, alt, new);
928 			alt[UC(new[0])] = tp->bind[el->el_map.type + 1];
929 		}
930 	}
931 }
932 
933 
934 /* tty_rawmode():
935  * 	Set terminal into 1 character at a time mode.
936  */
937 protected int
938 tty_rawmode(EditLine *el)
939 {
940 
941 	if (el->el_tty.t_mode == ED_IO || el->el_tty.t_mode == QU_IO)
942 		return (0);
943 
944 	if (el->el_flags & EDIT_DISABLED)
945 		return (0);
946 
947 	if (tty_getty(el, &el->el_tty.t_ts) == -1) {
948 #ifdef DEBUG_TTY
949 		(void) fprintf(el->el_errfile, "tty_rawmode: tty_getty: %s\n",
950 		    strerror(errno));
951 #endif /* DEBUG_TTY */
952 		return (-1);
953 	}
954 	/*
955          * We always keep up with the eight bit setting and the speed of the
956          * tty. But we only believe changes that are made to cooked mode!
957          */
958 	el->el_tty.t_eight = tty__geteightbit(&el->el_tty.t_ts);
959 	el->el_tty.t_speed = tty__getspeed(&el->el_tty.t_ts);
960 
961 	if (tty__getspeed(&el->el_tty.t_ex) != el->el_tty.t_speed ||
962 	    tty__getspeed(&el->el_tty.t_ed) != el->el_tty.t_speed) {
963 		(void) cfsetispeed(&el->el_tty.t_ex, el->el_tty.t_speed);
964 		(void) cfsetospeed(&el->el_tty.t_ex, el->el_tty.t_speed);
965 		(void) cfsetispeed(&el->el_tty.t_ed, el->el_tty.t_speed);
966 		(void) cfsetospeed(&el->el_tty.t_ed, el->el_tty.t_speed);
967 	}
968 	if (tty__cooked_mode(&el->el_tty.t_ts)) {
969 		if (el->el_tty.t_ts.c_cflag != el->el_tty.t_ex.c_cflag) {
970 			el->el_tty.t_ex.c_cflag =
971 			    el->el_tty.t_ts.c_cflag;
972 			el->el_tty.t_ex.c_cflag &=
973 			    ~el->el_tty.t_t[EX_IO][MD_CTL].t_clrmask;
974 			el->el_tty.t_ex.c_cflag |=
975 			    el->el_tty.t_t[EX_IO][MD_CTL].t_setmask;
976 
977 			el->el_tty.t_ed.c_cflag =
978 			    el->el_tty.t_ts.c_cflag;
979 			el->el_tty.t_ed.c_cflag &=
980 			    ~el->el_tty.t_t[ED_IO][MD_CTL].t_clrmask;
981 			el->el_tty.t_ed.c_cflag |=
982 			    el->el_tty.t_t[ED_IO][MD_CTL].t_setmask;
983 		}
984 		if ((el->el_tty.t_ts.c_lflag != el->el_tty.t_ex.c_lflag) &&
985 		    (el->el_tty.t_ts.c_lflag != el->el_tty.t_ed.c_lflag)) {
986 			el->el_tty.t_ex.c_lflag =
987 			    el->el_tty.t_ts.c_lflag;
988 			el->el_tty.t_ex.c_lflag &=
989 			    ~el->el_tty.t_t[EX_IO][MD_LIN].t_clrmask;
990 			el->el_tty.t_ex.c_lflag |=
991 			    el->el_tty.t_t[EX_IO][MD_LIN].t_setmask;
992 
993 			el->el_tty.t_ed.c_lflag =
994 			    el->el_tty.t_ts.c_lflag;
995 			el->el_tty.t_ed.c_lflag &=
996 			    ~el->el_tty.t_t[ED_IO][MD_LIN].t_clrmask;
997 			el->el_tty.t_ed.c_lflag |=
998 			    el->el_tty.t_t[ED_IO][MD_LIN].t_setmask;
999 		}
1000 		if ((el->el_tty.t_ts.c_iflag != el->el_tty.t_ex.c_iflag) &&
1001 		    (el->el_tty.t_ts.c_iflag != el->el_tty.t_ed.c_iflag)) {
1002 			el->el_tty.t_ex.c_iflag =
1003 			    el->el_tty.t_ts.c_iflag;
1004 			el->el_tty.t_ex.c_iflag &=
1005 			    ~el->el_tty.t_t[EX_IO][MD_INP].t_clrmask;
1006 			el->el_tty.t_ex.c_iflag |=
1007 			    el->el_tty.t_t[EX_IO][MD_INP].t_setmask;
1008 
1009 			el->el_tty.t_ed.c_iflag =
1010 			    el->el_tty.t_ts.c_iflag;
1011 			el->el_tty.t_ed.c_iflag &=
1012 			    ~el->el_tty.t_t[ED_IO][MD_INP].t_clrmask;
1013 			el->el_tty.t_ed.c_iflag |=
1014 			    el->el_tty.t_t[ED_IO][MD_INP].t_setmask;
1015 		}
1016 		if ((el->el_tty.t_ts.c_oflag != el->el_tty.t_ex.c_oflag) &&
1017 		    (el->el_tty.t_ts.c_oflag != el->el_tty.t_ed.c_oflag)) {
1018 			el->el_tty.t_ex.c_oflag =
1019 			    el->el_tty.t_ts.c_oflag;
1020 			el->el_tty.t_ex.c_oflag &=
1021 			    ~el->el_tty.t_t[EX_IO][MD_OUT].t_clrmask;
1022 			el->el_tty.t_ex.c_oflag |=
1023 			    el->el_tty.t_t[EX_IO][MD_OUT].t_setmask;
1024 
1025 			el->el_tty.t_ed.c_oflag =
1026 			    el->el_tty.t_ts.c_oflag;
1027 			el->el_tty.t_ed.c_oflag &=
1028 			    ~el->el_tty.t_t[ED_IO][MD_OUT].t_clrmask;
1029 			el->el_tty.t_ed.c_oflag |=
1030 			    el->el_tty.t_t[ED_IO][MD_OUT].t_setmask;
1031 		}
1032 		if (tty__gettabs(&el->el_tty.t_ex) == 0)
1033 			el->el_tty.t_tabs = 0;
1034 		else
1035 			el->el_tty.t_tabs = EL_CAN_TAB ? 1 : 0;
1036 
1037 		{
1038 			int i;
1039 
1040 			tty__getchar(&el->el_tty.t_ts, el->el_tty.t_c[TS_IO]);
1041 			/*
1042 		         * Check if the user made any changes.
1043 		         * If he did, then propagate the changes to the
1044 		         * edit and execute data structures.
1045 		         */
1046 			for (i = 0; i < C_NCC; i++)
1047 				if (el->el_tty.t_c[TS_IO][i] !=
1048 				    el->el_tty.t_c[EX_IO][i])
1049 					break;
1050 
1051 			if (i != C_NCC) {
1052 				/*
1053 				 * Propagate changes only to the unprotected
1054 				 * chars that have been modified just now.
1055 				 */
1056 				for (i = 0; i < C_NCC; i++) {
1057 					if (!((el->el_tty.t_t[ED_IO][MD_CHAR].t_setmask & C_SH(i)))
1058 					    && (el->el_tty.t_c[TS_IO][i] != el->el_tty.t_c[EX_IO][i]))
1059 						el->el_tty.t_c[ED_IO][i] = el->el_tty.t_c[TS_IO][i];
1060 					if (el->el_tty.t_t[ED_IO][MD_CHAR].t_clrmask & C_SH(i))
1061 						el->el_tty.t_c[ED_IO][i] = el->el_tty.t_vdisable;
1062 				}
1063 				tty_bind_char(el, 0);
1064 				tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]);
1065 
1066 				for (i = 0; i < C_NCC; i++) {
1067 					if (!((el->el_tty.t_t[EX_IO][MD_CHAR].t_setmask & C_SH(i)))
1068 					    && (el->el_tty.t_c[TS_IO][i] != el->el_tty.t_c[EX_IO][i]))
1069 						el->el_tty.t_c[EX_IO][i] = el->el_tty.t_c[TS_IO][i];
1070 					if (el->el_tty.t_t[EX_IO][MD_CHAR].t_clrmask & C_SH(i))
1071 						el->el_tty.t_c[EX_IO][i] = el->el_tty.t_vdisable;
1072 				}
1073 				tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]);
1074 			}
1075 		}
1076 	}
1077 	if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ed) == -1) {
1078 #ifdef DEBUG_TTY
1079 		(void) fprintf(el->el_errfile, "tty_rawmode: tty_setty: %s\n",
1080 		    strerror(errno));
1081 #endif /* DEBUG_TTY */
1082 		return (-1);
1083 	}
1084 	el->el_tty.t_mode = ED_IO;
1085 	return (0);
1086 }
1087 
1088 
1089 /* tty_cookedmode():
1090  *	Set the tty back to normal mode
1091  */
1092 protected int
1093 tty_cookedmode(EditLine *el)
1094 {				/* set tty in normal setup */
1095 
1096 	if (el->el_tty.t_mode == EX_IO)
1097 		return (0);
1098 
1099 	if (el->el_flags & EDIT_DISABLED)
1100 		return (0);
1101 
1102 	if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ex) == -1) {
1103 #ifdef DEBUG_TTY
1104 		(void) fprintf(el->el_errfile,
1105 		    "tty_cookedmode: tty_setty: %s\n",
1106 		    strerror(errno));
1107 #endif /* DEBUG_TTY */
1108 		return (-1);
1109 	}
1110 	el->el_tty.t_mode = EX_IO;
1111 	return (0);
1112 }
1113 
1114 
1115 /* tty_quotemode():
1116  *	Turn on quote mode
1117  */
1118 protected int
1119 tty_quotemode(EditLine *el)
1120 {
1121 	if (el->el_tty.t_mode == QU_IO)
1122 		return (0);
1123 
1124 	el->el_tty.t_qu = el->el_tty.t_ed;
1125 
1126 	el->el_tty.t_qu.c_iflag &= ~el->el_tty.t_t[QU_IO][MD_INP].t_clrmask;
1127 	el->el_tty.t_qu.c_iflag |= el->el_tty.t_t[QU_IO][MD_INP].t_setmask;
1128 
1129 	el->el_tty.t_qu.c_oflag &= ~el->el_tty.t_t[QU_IO][MD_OUT].t_clrmask;
1130 	el->el_tty.t_qu.c_oflag |= el->el_tty.t_t[QU_IO][MD_OUT].t_setmask;
1131 
1132 	el->el_tty.t_qu.c_cflag &= ~el->el_tty.t_t[QU_IO][MD_CTL].t_clrmask;
1133 	el->el_tty.t_qu.c_cflag |= el->el_tty.t_t[QU_IO][MD_CTL].t_setmask;
1134 
1135 	el->el_tty.t_qu.c_lflag &= ~el->el_tty.t_t[QU_IO][MD_LIN].t_clrmask;
1136 	el->el_tty.t_qu.c_lflag |= el->el_tty.t_t[QU_IO][MD_LIN].t_setmask;
1137 
1138 	if (tty_setty(el, TCSADRAIN, &el->el_tty.t_qu) == -1) {
1139 #ifdef DEBUG_TTY
1140 		(void) fprintf(el->el_errfile, "QuoteModeOn: tty_setty: %s\n",
1141 		    strerror(errno));
1142 #endif /* DEBUG_TTY */
1143 		return (-1);
1144 	}
1145 	el->el_tty.t_mode = QU_IO;
1146 	return (0);
1147 }
1148 
1149 
1150 /* tty_noquotemode():
1151  *	Turn off quote mode
1152  */
1153 protected int
1154 tty_noquotemode(EditLine *el)
1155 {
1156 
1157 	if (el->el_tty.t_mode != QU_IO)
1158 		return (0);
1159 	if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ed) == -1) {
1160 #ifdef DEBUG_TTY
1161 		(void) fprintf(el->el_errfile, "QuoteModeOff: tty_setty: %s\n",
1162 		    strerror(errno));
1163 #endif /* DEBUG_TTY */
1164 		return (-1);
1165 	}
1166 	el->el_tty.t_mode = ED_IO;
1167 	return (0);
1168 }
1169 
1170 
1171 /* tty_stty():
1172  *	Stty builtin
1173  */
1174 protected int
1175 /*ARGSUSED*/
1176 tty_stty(EditLine *el, int argc __attribute__((__unused__)), const Char **argv)
1177 {
1178 	const ttymodes_t *m;
1179 	char x;
1180 	int aflag = 0;
1181 	const Char *s, *d;
1182         char name[EL_BUFSIZ];
1183 	struct termios *tios = &el->el_tty.t_ex;
1184 	int z = EX_IO;
1185 
1186 	if (argv == NULL)
1187 		return (-1);
1188 	strncpy(name, ct_encode_string(*argv++, &el->el_scratch), sizeof(name));
1189         name[sizeof(name) - 1] = '\0';
1190 
1191 	while (argv && *argv && argv[0][0] == '-' && argv[0][2] == '\0')
1192 		switch (argv[0][1]) {
1193 		case 'a':
1194 			aflag++;
1195 			argv++;
1196 			break;
1197 		case 'd':
1198 			argv++;
1199 			tios = &el->el_tty.t_ed;
1200 			z = ED_IO;
1201 			break;
1202 		case 'x':
1203 			argv++;
1204 			tios = &el->el_tty.t_ex;
1205 			z = EX_IO;
1206 			break;
1207 		case 'q':
1208 			argv++;
1209 			tios = &el->el_tty.t_ts;
1210 			z = QU_IO;
1211 			break;
1212 		default:
1213 			(void) fprintf(el->el_errfile,
1214 			    "%s: Unknown switch `%c'.\n",
1215 			    name, argv[0][1]);
1216 			return (-1);
1217 		}
1218 
1219 	if (!argv || !*argv) {
1220 		int i = -1;
1221 		size_t len = 0, st = 0, cu;
1222 		for (m = ttymodes; m->m_name; m++) {
1223 			if (m->m_type != i) {
1224 				(void) fprintf(el->el_outfile, "%s%s",
1225 				    i != -1 ? "\n" : "",
1226 				    el->el_tty.t_t[z][m->m_type].t_name);
1227 				i = m->m_type;
1228 				st = len =
1229 				    strlen(el->el_tty.t_t[z][m->m_type].t_name);
1230 			}
1231 			if (i != -1) {
1232 			    x = (el->el_tty.t_t[z][i].t_setmask & m->m_value)
1233 				?  '+' : '\0';
1234 			    x = (el->el_tty.t_t[z][i].t_clrmask & m->m_value)
1235 				? '-' : x;
1236 			} else {
1237 			    x = '\0';
1238 			}
1239 
1240 			if (x != '\0' || aflag) {
1241 
1242 				cu = strlen(m->m_name) + (x != '\0') + 1;
1243 
1244 				if (len + cu >= (size_t)el->el_term.t_size.h) {
1245 					(void) fprintf(el->el_outfile, "\n%*s",
1246 					    (int)st, "");
1247 					len = st + cu;
1248 				} else
1249 					len += cu;
1250 
1251 				if (x != '\0')
1252 					(void) fprintf(el->el_outfile, "%c%s ",
1253 					    x, m->m_name);
1254 				else
1255 					(void) fprintf(el->el_outfile, "%s ",
1256 					    m->m_name);
1257 			}
1258 		}
1259 		(void) fprintf(el->el_outfile, "\n");
1260 		return (0);
1261 	}
1262 	while (argv && (s = *argv++)) {
1263 		const Char *p;
1264 		switch (*s) {
1265 		case '+':
1266 		case '-':
1267 			x = *s++;
1268 			break;
1269 		default:
1270 			x = '\0';
1271 			break;
1272 		}
1273 		d = s;
1274 		p = Strchr(s, '=');
1275 		for (m = ttymodes; m->m_name; m++)
1276 			if ((p ? strncmp(m->m_name, ct_encode_string(d, &el->el_scratch), (size_t)(p - d)) :
1277 			    strcmp(m->m_name, ct_encode_string(d, &el->el_scratch))) == 0 &&
1278 			    (p == NULL || m->m_type == MD_CHAR))
1279 				break;
1280 
1281 		if (!m->m_name) {
1282 			(void) fprintf(el->el_errfile,
1283 			    "%s: Invalid argument `" FSTR "'.\n", name, d);
1284 			return (-1);
1285 		}
1286 		if (p) {
1287 			int c = ffs((int)m->m_value);
1288 			int v = *++p ? parse__escape(&p) :
1289 			    el->el_tty.t_vdisable;
1290 			assert(c != 0);
1291 			c--;
1292 			c = tty__getcharindex(c);
1293 			assert(c != -1);
1294 			tios->c_cc[c] = v;
1295 			continue;
1296 		}
1297 		switch (x) {
1298 		case '+':
1299 			el->el_tty.t_t[z][m->m_type].t_setmask |= m->m_value;
1300 			el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value;
1301 			break;
1302 		case '-':
1303 			el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value;
1304 			el->el_tty.t_t[z][m->m_type].t_clrmask |= m->m_value;
1305 			break;
1306 		default:
1307 			el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value;
1308 			el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value;
1309 			break;
1310 		}
1311 	}
1312 
1313 	if (el->el_tty.t_mode == z) {
1314 		if (tty_setty(el, TCSADRAIN, tios) == -1) {
1315 #ifdef DEBUG_TTY
1316 			(void) fprintf(el->el_errfile,
1317 			    "tty_stty: tty_setty: %s\n", strerror(errno));
1318 #endif /* DEBUG_TTY */
1319 			return (-1);
1320 		}
1321 	}
1322 
1323 	return (0);
1324 }
1325 
1326 
1327 #ifdef notyet
1328 /* tty_printchar():
1329  *	DEbugging routine to print the tty characters
1330  */
1331 private void
1332 tty_printchar(EditLine *el, unsigned char *s)
1333 {
1334 	ttyperm_t *m;
1335 	int i;
1336 
1337 	for (i = 0; i < C_NCC; i++) {
1338 		for (m = el->el_tty.t_t; m->m_name; m++)
1339 			if (m->m_type == MD_CHAR && C_SH(i) == m->m_value)
1340 				break;
1341 		if (m->m_name)
1342 			(void) fprintf(el->el_errfile, "%s ^%c ",
1343 			    m->m_name, s[i] + 'A' - 1);
1344 		if (i % 5 == 0)
1345 			(void) fprintf(el->el_errfile, "\n");
1346 	}
1347 	(void) fprintf(el->el_errfile, "\n");
1348 }
1349 #endif /* notyet */
1350