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