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