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