xref: /openbsd-src/lib/libedit/tty.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
1 /*	$OpenBSD: tty.c,v 1.10 2003/11/25 20:12:38 otto Exp $	*/
2 /*	$NetBSD: tty.c,v 1.20 2003/10/18 22:37:24 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 #if !defined(lint) && !defined(SCCSID)
38 #if 0
39 static char sccsid[] = "@(#)tty.c	8.1 (Berkeley) 6/4/93";
40 #else
41 static const char rcsid[] = "$OpenBSD: tty.c,v 1.10 2003/11/25 20:12:38 otto Exp $";
42 #endif
43 #endif /* not lint && not SCCSID */
44 
45 /*
46  * tty.c: tty interface stuff
47  */
48 #include "tty.h"
49 #include "el.h"
50 
51 typedef struct ttymodes_t {
52 	const char *m_name;
53 	u_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 	{ED_DELETE_PREV_CHAR, VI_DELETE_PREV_CHAR, ED_PREV_CHAR}},
125 #endif /* VERASE */
126 #ifdef VERASE2
127 	{C_ERASE2, VERASE2,
128 	{ED_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_getty(el, td)	tcgetattr((el)->el_infd, (td))
449 #define	tty_setty(el, td)	tcsetattr((el)->el_infd, TCSADRAIN, (td))
450 
451 #define	tty__gettabs(td)	((((td)->c_oflag & TAB3) == TAB3) ? 0 : 1)
452 #define	tty__geteightbit(td)	(((td)->c_cflag & CSIZE) == CS8)
453 #define	tty__cooked_mode(td)	((td)->c_lflag & ICANON)
454 
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 
464 /* tty_setup():
465  *	Get the tty parameters and initialize the editing state
466  */
467 private int
468 tty_setup(EditLine *el)
469 {
470 	int rst = 1;
471 
472 	if (el->el_flags & EDIT_DISABLED)
473 		return (0);
474 
475 	if (tty_getty(el, &el->el_tty.t_ed) == -1) {
476 #ifdef DEBUG_TTY
477 		(void) fprintf(el->el_errfile,
478 		    "tty_setup: tty_getty: %s\n", strerror(errno));
479 #endif /* DEBUG_TTY */
480 		return (-1);
481 	}
482 	el->el_tty.t_ts = el->el_tty.t_ex = el->el_tty.t_ed;
483 
484 	el->el_tty.t_speed = tty__getspeed(&el->el_tty.t_ex);
485 	el->el_tty.t_tabs = tty__gettabs(&el->el_tty.t_ex);
486 	el->el_tty.t_eight = tty__geteightbit(&el->el_tty.t_ex);
487 
488 	el->el_tty.t_ex.c_iflag &= ~el->el_tty.t_t[EX_IO][MD_INP].t_clrmask;
489 	el->el_tty.t_ex.c_iflag |= el->el_tty.t_t[EX_IO][MD_INP].t_setmask;
490 
491 	el->el_tty.t_ex.c_oflag &= ~el->el_tty.t_t[EX_IO][MD_OUT].t_clrmask;
492 	el->el_tty.t_ex.c_oflag |= el->el_tty.t_t[EX_IO][MD_OUT].t_setmask;
493 
494 	el->el_tty.t_ex.c_cflag &= ~el->el_tty.t_t[EX_IO][MD_CTL].t_clrmask;
495 	el->el_tty.t_ex.c_cflag |= el->el_tty.t_t[EX_IO][MD_CTL].t_setmask;
496 
497 	el->el_tty.t_ex.c_lflag &= ~el->el_tty.t_t[EX_IO][MD_LIN].t_clrmask;
498 	el->el_tty.t_ex.c_lflag |= el->el_tty.t_t[EX_IO][MD_LIN].t_setmask;
499 
500 	/*
501          * Reset the tty chars to reasonable defaults
502          * If they are disabled, then enable them.
503          */
504 	if (rst) {
505 		if (tty__cooked_mode(&el->el_tty.t_ts)) {
506 			tty__getchar(&el->el_tty.t_ts, el->el_tty.t_c[TS_IO]);
507 			/*
508 	                 * Don't affect CMIN and CTIME for the editor mode
509 	                 */
510 			for (rst = 0; rst < C_NCC - 2; rst++)
511 				if (el->el_tty.t_c[TS_IO][rst] !=
512 				      el->el_tty.t_vdisable
513 				    && el->el_tty.t_c[ED_IO][rst] !=
514 				      el->el_tty.t_vdisable)
515 					el->el_tty.t_c[ED_IO][rst] =
516 					    el->el_tty.t_c[TS_IO][rst];
517 			for (rst = 0; rst < C_NCC; rst++)
518 				if (el->el_tty.t_c[TS_IO][rst] !=
519 				    el->el_tty.t_vdisable)
520 					el->el_tty.t_c[EX_IO][rst] =
521 					    el->el_tty.t_c[TS_IO][rst];
522 		}
523 		tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]);
524 		if (tty_setty(el, &el->el_tty.t_ex) == -1) {
525 #ifdef DEBUG_TTY
526 			(void) fprintf(el->el_errfile,
527 			    "tty_setup: tty_setty: %s\n",
528 			    strerror(errno));
529 #endif /* DEBUG_TTY */
530 			return (-1);
531 		}
532 	} else
533 		tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]);
534 
535 	el->el_tty.t_ed.c_iflag &= ~el->el_tty.t_t[ED_IO][MD_INP].t_clrmask;
536 	el->el_tty.t_ed.c_iflag |= el->el_tty.t_t[ED_IO][MD_INP].t_setmask;
537 
538 	el->el_tty.t_ed.c_oflag &= ~el->el_tty.t_t[ED_IO][MD_OUT].t_clrmask;
539 	el->el_tty.t_ed.c_oflag |= el->el_tty.t_t[ED_IO][MD_OUT].t_setmask;
540 
541 	el->el_tty.t_ed.c_cflag &= ~el->el_tty.t_t[ED_IO][MD_CTL].t_clrmask;
542 	el->el_tty.t_ed.c_cflag |= el->el_tty.t_t[ED_IO][MD_CTL].t_setmask;
543 
544 	el->el_tty.t_ed.c_lflag &= ~el->el_tty.t_t[ED_IO][MD_LIN].t_clrmask;
545 	el->el_tty.t_ed.c_lflag |= el->el_tty.t_t[ED_IO][MD_LIN].t_setmask;
546 
547 	tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]);
548 	tty_bind_char(el, 1);
549 	return (0);
550 }
551 
552 protected int
553 tty_init(EditLine *el)
554 {
555 
556 	el->el_tty.t_mode = EX_IO;
557 	el->el_tty.t_vdisable = _POSIX_VDISABLE;
558 	(void) memcpy(el->el_tty.t_t, ttyperm, sizeof(ttyperm_t));
559 	(void) memcpy(el->el_tty.t_c, ttychar, sizeof(ttychar_t));
560 	return (tty_setup(el));
561 }
562 
563 
564 /* tty_end():
565  *	Restore the tty to its original settings
566  */
567 protected void
568 /*ARGSUSED*/
569 tty_end(EditLine *el __attribute__((__unused__)))
570 {
571 
572 	/* XXX: Maybe reset to an initial state? */
573 }
574 
575 
576 /* tty__getspeed():
577  *	Get the tty speed
578  */
579 private speed_t
580 tty__getspeed(struct termios *td)
581 {
582 	speed_t spd;
583 
584 	if ((spd = cfgetispeed(td)) == 0)
585 		spd = cfgetospeed(td);
586 	return (spd);
587 }
588 
589 /* tty__getspeed():
590  *	Return the index of the asked char in the c_cc array
591  */
592 private int
593 tty__getcharindex(int i)
594 {
595 	switch (i) {
596 #ifdef VINTR
597 	case C_INTR:
598 		return VINTR;
599 #endif /* VINTR */
600 #ifdef VQUIT
601 	case C_QUIT:
602 		return VQUIT;
603 #endif /* VQUIT */
604 #ifdef VERASE
605 	case C_ERASE:
606 		return VERASE;
607 #endif /* VERASE */
608 #ifdef VKILL
609 	case C_KILL:
610 		return VKILL;
611 #endif /* VKILL */
612 #ifdef VEOF
613 	case C_EOF:
614 		return VEOF;
615 #endif /* VEOF */
616 #ifdef VEOL
617 	case C_EOL:
618 		return VEOL;
619 #endif /* VEOL */
620 #ifdef VEOL2
621 	case C_EOL2:
622 		return VEOL2;
623 #endif /* VEOL2 */
624 #ifdef VSWTCH
625 	case C_SWTCH:
626 		return VSWTCH;
627 #endif /* VSWTCH */
628 #ifdef VDSWTCH
629 	case C_DSWTCH:
630 		return VDSWTCH;
631 #endif /* VDSWTCH */
632 #ifdef VERASE2
633 	case C_ERASE2:
634 		return VERASE2;
635 #endif /* VERASE2 */
636 #ifdef VSTART
637 	case C_START:
638 		return VSTART;
639 #endif /* VSTART */
640 #ifdef VSTOP
641 	case C_STOP:
642 		return VSTOP;
643 #endif /* VSTOP */
644 #ifdef VWERASE
645 	case C_WERASE:
646 		return VWERASE;
647 #endif /* VWERASE */
648 #ifdef VSUSP
649 	case C_SUSP:
650 		return VSUSP;
651 #endif /* VSUSP */
652 #ifdef VDSUSP
653 	case C_DSUSP:
654 		return VDSUSP;
655 #endif /* VDSUSP */
656 #ifdef VREPRINT
657 	case C_REPRINT:
658 		return VREPRINT;
659 #endif /* VREPRINT */
660 #ifdef VDISCARD
661 	case C_DISCARD:
662 		return VDISCARD;
663 #endif /* VDISCARD */
664 #ifdef VLNEXT
665 	case C_LNEXT:
666 		return VLNEXT;
667 #endif /* VLNEXT */
668 #ifdef VSTATUS
669 	case C_STATUS:
670 		return VSTATUS;
671 #endif /* VSTATUS */
672 #ifdef VPAGE
673 	case C_PAGE:
674 		return VPAGE;
675 #endif /* VPAGE */
676 #ifdef VPGOFF
677 	case C_PGOFF:
678 		return VPGOFF;
679 #endif /* VPGOFF */
680 #ifdef VKILL2
681 	case C_KILL2:
682 		return VKILL2;
683 #endif /* KILL2 */
684 #ifdef VMIN
685 	case C_MIN:
686 		return VMIN;
687 #endif /* VMIN */
688 #ifdef VTIME
689 	case C_TIME:
690 		return VTIME;
691 #endif /* VTIME */
692 	default:
693 		return -1;
694 	}
695 }
696 
697 /* tty__getchar():
698  *	Get the tty characters
699  */
700 private void
701 tty__getchar(struct termios *td, unsigned char *s)
702 {
703 
704 #ifdef VINTR
705 	s[C_INTR] = td->c_cc[VINTR];
706 #endif /* VINTR */
707 #ifdef VQUIT
708 	s[C_QUIT] = td->c_cc[VQUIT];
709 #endif /* VQUIT */
710 #ifdef VERASE
711 	s[C_ERASE] = td->c_cc[VERASE];
712 #endif /* VERASE */
713 #ifdef VKILL
714 	s[C_KILL] = td->c_cc[VKILL];
715 #endif /* VKILL */
716 #ifdef VEOF
717 	s[C_EOF] = td->c_cc[VEOF];
718 #endif /* VEOF */
719 #ifdef VEOL
720 	s[C_EOL] = td->c_cc[VEOL];
721 #endif /* VEOL */
722 #ifdef VEOL2
723 	s[C_EOL2] = td->c_cc[VEOL2];
724 #endif /* VEOL2 */
725 #ifdef VSWTCH
726 	s[C_SWTCH] = td->c_cc[VSWTCH];
727 #endif /* VSWTCH */
728 #ifdef VDSWTCH
729 	s[C_DSWTCH] = td->c_cc[VDSWTCH];
730 #endif /* VDSWTCH */
731 #ifdef VERASE2
732 	s[C_ERASE2] = td->c_cc[VERASE2];
733 #endif /* VERASE2 */
734 #ifdef VSTART
735 	s[C_START] = td->c_cc[VSTART];
736 #endif /* VSTART */
737 #ifdef VSTOP
738 	s[C_STOP] = td->c_cc[VSTOP];
739 #endif /* VSTOP */
740 #ifdef VWERASE
741 	s[C_WERASE] = td->c_cc[VWERASE];
742 #endif /* VWERASE */
743 #ifdef VSUSP
744 	s[C_SUSP] = td->c_cc[VSUSP];
745 #endif /* VSUSP */
746 #ifdef VDSUSP
747 	s[C_DSUSP] = td->c_cc[VDSUSP];
748 #endif /* VDSUSP */
749 #ifdef VREPRINT
750 	s[C_REPRINT] = td->c_cc[VREPRINT];
751 #endif /* VREPRINT */
752 #ifdef VDISCARD
753 	s[C_DISCARD] = td->c_cc[VDISCARD];
754 #endif /* VDISCARD */
755 #ifdef VLNEXT
756 	s[C_LNEXT] = td->c_cc[VLNEXT];
757 #endif /* VLNEXT */
758 #ifdef VSTATUS
759 	s[C_STATUS] = td->c_cc[VSTATUS];
760 #endif /* VSTATUS */
761 #ifdef VPAGE
762 	s[C_PAGE] = td->c_cc[VPAGE];
763 #endif /* VPAGE */
764 #ifdef VPGOFF
765 	s[C_PGOFF] = td->c_cc[VPGOFF];
766 #endif /* VPGOFF */
767 #ifdef VKILL2
768 	s[C_KILL2] = td->c_cc[VKILL2];
769 #endif /* KILL2 */
770 #ifdef VMIN
771 	s[C_MIN] = td->c_cc[VMIN];
772 #endif /* VMIN */
773 #ifdef VTIME
774 	s[C_TIME] = td->c_cc[VTIME];
775 #endif /* VTIME */
776 }				/* tty__getchar */
777 
778 
779 /* tty__setchar():
780  *	Set the tty characters
781  */
782 private void
783 tty__setchar(struct termios *td, unsigned char *s)
784 {
785 
786 #ifdef VINTR
787 	td->c_cc[VINTR] = s[C_INTR];
788 #endif /* VINTR */
789 #ifdef VQUIT
790 	td->c_cc[VQUIT] = s[C_QUIT];
791 #endif /* VQUIT */
792 #ifdef VERASE
793 	td->c_cc[VERASE] = s[C_ERASE];
794 #endif /* VERASE */
795 #ifdef VKILL
796 	td->c_cc[VKILL] = s[C_KILL];
797 #endif /* VKILL */
798 #ifdef VEOF
799 	td->c_cc[VEOF] = s[C_EOF];
800 #endif /* VEOF */
801 #ifdef VEOL
802 	td->c_cc[VEOL] = s[C_EOL];
803 #endif /* VEOL */
804 #ifdef VEOL2
805 	td->c_cc[VEOL2] = s[C_EOL2];
806 #endif /* VEOL2 */
807 #ifdef VSWTCH
808 	td->c_cc[VSWTCH] = s[C_SWTCH];
809 #endif /* VSWTCH */
810 #ifdef VDSWTCH
811 	td->c_cc[VDSWTCH] = s[C_DSWTCH];
812 #endif /* VDSWTCH */
813 #ifdef VERASE2
814 	td->c_cc[VERASE2] = s[C_ERASE2];
815 #endif /* VERASE2 */
816 #ifdef VSTART
817 	td->c_cc[VSTART] = s[C_START];
818 #endif /* VSTART */
819 #ifdef VSTOP
820 	td->c_cc[VSTOP] = s[C_STOP];
821 #endif /* VSTOP */
822 #ifdef VWERASE
823 	td->c_cc[VWERASE] = s[C_WERASE];
824 #endif /* VWERASE */
825 #ifdef VSUSP
826 	td->c_cc[VSUSP] = s[C_SUSP];
827 #endif /* VSUSP */
828 #ifdef VDSUSP
829 	td->c_cc[VDSUSP] = s[C_DSUSP];
830 #endif /* VDSUSP */
831 #ifdef VREPRINT
832 	td->c_cc[VREPRINT] = s[C_REPRINT];
833 #endif /* VREPRINT */
834 #ifdef VDISCARD
835 	td->c_cc[VDISCARD] = s[C_DISCARD];
836 #endif /* VDISCARD */
837 #ifdef VLNEXT
838 	td->c_cc[VLNEXT] = s[C_LNEXT];
839 #endif /* VLNEXT */
840 #ifdef VSTATUS
841 	td->c_cc[VSTATUS] = s[C_STATUS];
842 #endif /* VSTATUS */
843 #ifdef VPAGE
844 	td->c_cc[VPAGE] = s[C_PAGE];
845 #endif /* VPAGE */
846 #ifdef VPGOFF
847 	td->c_cc[VPGOFF] = s[C_PGOFF];
848 #endif /* VPGOFF */
849 #ifdef VKILL2
850 	td->c_cc[VKILL2] = s[C_KILL2];
851 #endif /* VKILL2 */
852 #ifdef VMIN
853 	td->c_cc[VMIN] = s[C_MIN];
854 #endif /* VMIN */
855 #ifdef VTIME
856 	td->c_cc[VTIME] = s[C_TIME];
857 #endif /* VTIME */
858 }				/* tty__setchar */
859 
860 
861 /* tty_bind_char():
862  *	Rebind the editline functions
863  */
864 protected void
865 tty_bind_char(EditLine *el, int force)
866 {
867 
868 	unsigned char *t_n = el->el_tty.t_c[ED_IO];
869 	unsigned char *t_o = el->el_tty.t_ed.c_cc;
870 	unsigned char new[2], old[2];
871 	const ttymap_t *tp;
872 	el_action_t *map, *alt;
873 	const el_action_t *dmap, *dalt;
874 	new[1] = old[1] = '\0';
875 
876 	map = el->el_map.key;
877 	alt = el->el_map.alt;
878 	if (el->el_map.type == MAP_VI) {
879 		dmap = el->el_map.vii;
880 		dalt = el->el_map.vic;
881 	} else {
882 		dmap = el->el_map.emacs;
883 		dalt = NULL;
884 	}
885 
886 	for (tp = tty_map; tp->nch != -1; tp++) {
887 		new[0] = t_n[tp->nch];
888 		old[0] = t_o[tp->och];
889 		if (new[0] == old[0] && !force)
890 			continue;
891 		/* Put the old default binding back, and set the new binding */
892 		key_clear(el, map, (char *)old);
893 		map[old[0]] = dmap[old[0]];
894 		key_clear(el, map, (char *)new);
895 		/* MAP_VI == 1, MAP_EMACS == 0... */
896 		map[new[0]] = tp->bind[el->el_map.type];
897 		if (dalt) {
898 			key_clear(el, alt, (char *)old);
899 			alt[old[0]] = dalt[old[0]];
900 			key_clear(el, alt, (char *)new);
901 			alt[new[0]] = tp->bind[el->el_map.type + 1];
902 		}
903 	}
904 }
905 
906 
907 /* tty_rawmode():
908  * 	Set terminal into 1 character at a time mode.
909  */
910 protected int
911 tty_rawmode(EditLine *el)
912 {
913 
914 	if (el->el_tty.t_mode == ED_IO || el->el_tty.t_mode == QU_IO)
915 		return (0);
916 
917 	if (el->el_flags & EDIT_DISABLED)
918 		return (0);
919 
920 	if (tty_getty(el, &el->el_tty.t_ts) == -1) {
921 #ifdef DEBUG_TTY
922 		(void) fprintf(el->el_errfile, "tty_rawmode: tty_getty: %s\n",
923 		    strerror(errno));
924 #endif /* DEBUG_TTY */
925 		return (-1);
926 	}
927 	/*
928          * We always keep up with the eight bit setting and the speed of the
929          * tty. But only we only believe changes that are made to cooked mode!
930          */
931 	el->el_tty.t_eight = tty__geteightbit(&el->el_tty.t_ts);
932 	el->el_tty.t_speed = tty__getspeed(&el->el_tty.t_ts);
933 
934 	if (tty__getspeed(&el->el_tty.t_ex) != el->el_tty.t_speed ||
935 	    tty__getspeed(&el->el_tty.t_ed) != el->el_tty.t_speed) {
936 		(void) cfsetispeed(&el->el_tty.t_ex, el->el_tty.t_speed);
937 		(void) cfsetospeed(&el->el_tty.t_ex, el->el_tty.t_speed);
938 		(void) cfsetispeed(&el->el_tty.t_ed, el->el_tty.t_speed);
939 		(void) cfsetospeed(&el->el_tty.t_ed, el->el_tty.t_speed);
940 	}
941 	if (tty__cooked_mode(&el->el_tty.t_ts)) {
942 		if (el->el_tty.t_ts.c_cflag != el->el_tty.t_ex.c_cflag) {
943 			el->el_tty.t_ex.c_cflag =
944 			    el->el_tty.t_ts.c_cflag;
945 			el->el_tty.t_ex.c_cflag &=
946 			    ~el->el_tty.t_t[EX_IO][MD_CTL].t_clrmask;
947 			el->el_tty.t_ex.c_cflag |=
948 			    el->el_tty.t_t[EX_IO][MD_CTL].t_setmask;
949 
950 			el->el_tty.t_ed.c_cflag =
951 			    el->el_tty.t_ts.c_cflag;
952 			el->el_tty.t_ed.c_cflag &=
953 			    ~el->el_tty.t_t[ED_IO][MD_CTL].t_clrmask;
954 			el->el_tty.t_ed.c_cflag |=
955 			    el->el_tty.t_t[ED_IO][MD_CTL].t_setmask;
956 		}
957 		if ((el->el_tty.t_ts.c_lflag != el->el_tty.t_ex.c_lflag) &&
958 		    (el->el_tty.t_ts.c_lflag != el->el_tty.t_ed.c_lflag)) {
959 			el->el_tty.t_ex.c_lflag =
960 			    el->el_tty.t_ts.c_lflag;
961 			el->el_tty.t_ex.c_lflag &=
962 			    ~el->el_tty.t_t[EX_IO][MD_LIN].t_clrmask;
963 			el->el_tty.t_ex.c_lflag |=
964 			    el->el_tty.t_t[EX_IO][MD_LIN].t_setmask;
965 
966 			el->el_tty.t_ed.c_lflag =
967 			    el->el_tty.t_ts.c_lflag;
968 			el->el_tty.t_ed.c_lflag &=
969 			    ~el->el_tty.t_t[ED_IO][MD_LIN].t_clrmask;
970 			el->el_tty.t_ed.c_lflag |=
971 			    el->el_tty.t_t[ED_IO][MD_LIN].t_setmask;
972 		}
973 		if ((el->el_tty.t_ts.c_iflag != el->el_tty.t_ex.c_iflag) &&
974 		    (el->el_tty.t_ts.c_iflag != el->el_tty.t_ed.c_iflag)) {
975 			el->el_tty.t_ex.c_iflag =
976 			    el->el_tty.t_ts.c_iflag;
977 			el->el_tty.t_ex.c_iflag &=
978 			    ~el->el_tty.t_t[EX_IO][MD_INP].t_clrmask;
979 			el->el_tty.t_ex.c_iflag |=
980 			    el->el_tty.t_t[EX_IO][MD_INP].t_setmask;
981 
982 			el->el_tty.t_ed.c_iflag =
983 			    el->el_tty.t_ts.c_iflag;
984 			el->el_tty.t_ed.c_iflag &=
985 			    ~el->el_tty.t_t[ED_IO][MD_INP].t_clrmask;
986 			el->el_tty.t_ed.c_iflag |=
987 			    el->el_tty.t_t[ED_IO][MD_INP].t_setmask;
988 		}
989 		if ((el->el_tty.t_ts.c_oflag != el->el_tty.t_ex.c_oflag) &&
990 		    (el->el_tty.t_ts.c_oflag != el->el_tty.t_ed.c_oflag)) {
991 			el->el_tty.t_ex.c_oflag =
992 			    el->el_tty.t_ts.c_oflag;
993 			el->el_tty.t_ex.c_oflag &=
994 			    ~el->el_tty.t_t[EX_IO][MD_OUT].t_clrmask;
995 			el->el_tty.t_ex.c_oflag |=
996 			    el->el_tty.t_t[EX_IO][MD_OUT].t_setmask;
997 
998 			el->el_tty.t_ed.c_oflag =
999 			    el->el_tty.t_ts.c_oflag;
1000 			el->el_tty.t_ed.c_oflag &=
1001 			    ~el->el_tty.t_t[ED_IO][MD_OUT].t_clrmask;
1002 			el->el_tty.t_ed.c_oflag |=
1003 			    el->el_tty.t_t[ED_IO][MD_OUT].t_setmask;
1004 		}
1005 		if (tty__gettabs(&el->el_tty.t_ex) == 0)
1006 			el->el_tty.t_tabs = 0;
1007 		else
1008 			el->el_tty.t_tabs = EL_CAN_TAB ? 1 : 0;
1009 
1010 		{
1011 			int i;
1012 
1013 			tty__getchar(&el->el_tty.t_ts, el->el_tty.t_c[TS_IO]);
1014 			/*
1015 		         * Check if the user made any changes.
1016 		         * If he did, then propagate the changes to the
1017 		         * edit and execute data structures.
1018 		         */
1019 			for (i = 0; i < C_NCC; i++)
1020 				if (el->el_tty.t_c[TS_IO][i] !=
1021 				    el->el_tty.t_c[EX_IO][i])
1022 					break;
1023 
1024 			if (i != C_NCC) {
1025 				/*
1026 				 * Propagate changes only to the unprotected
1027 				 * chars that have been modified just now.
1028 				 */
1029 				for (i = 0; i < C_NCC; i++) {
1030 					if (!((el->el_tty.t_t[ED_IO][MD_CHAR].t_setmask & C_SH(i)))
1031 					    && (el->el_tty.t_c[TS_IO][i] != el->el_tty.t_c[EX_IO][i]))
1032 						el->el_tty.t_c[ED_IO][i] = el->el_tty.t_c[TS_IO][i];
1033 					if (el->el_tty.t_t[ED_IO][MD_CHAR].t_clrmask & C_SH(i))
1034 						el->el_tty.t_c[ED_IO][i] = el->el_tty.t_vdisable;
1035 				}
1036 				tty_bind_char(el, 0);
1037 				tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]);
1038 
1039 				for (i = 0; i < C_NCC; i++) {
1040 					if (!((el->el_tty.t_t[EX_IO][MD_CHAR].t_setmask & C_SH(i)))
1041 					    && (el->el_tty.t_c[TS_IO][i] != el->el_tty.t_c[EX_IO][i]))
1042 						el->el_tty.t_c[EX_IO][i] = el->el_tty.t_c[TS_IO][i];
1043 					if (el->el_tty.t_t[EX_IO][MD_CHAR].t_clrmask & C_SH(i))
1044 						el->el_tty.t_c[EX_IO][i] = el->el_tty.t_vdisable;
1045 				}
1046 				tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]);
1047 			}
1048 		}
1049 	}
1050 	if (tty_setty(el, &el->el_tty.t_ed) == -1) {
1051 #ifdef DEBUG_TTY
1052 		(void) fprintf(el->el_errfile, "tty_rawmode: tty_setty: %s\n",
1053 		    strerror(errno));
1054 #endif /* DEBUG_TTY */
1055 		return (-1);
1056 	}
1057 	el->el_tty.t_mode = ED_IO;
1058 	return (0);
1059 }
1060 
1061 
1062 /* tty_cookedmode():
1063  *	Set the tty back to normal mode
1064  */
1065 protected int
1066 tty_cookedmode(EditLine *el)
1067 {				/* set tty in normal setup */
1068 
1069 	if (el->el_tty.t_mode == EX_IO)
1070 		return (0);
1071 
1072 	if (el->el_flags & EDIT_DISABLED)
1073 		return (0);
1074 
1075 	if (tty_setty(el, &el->el_tty.t_ex) == -1) {
1076 #ifdef DEBUG_TTY
1077 		(void) fprintf(el->el_errfile,
1078 		    "tty_cookedmode: tty_setty: %s\n",
1079 		    strerror(errno));
1080 #endif /* DEBUG_TTY */
1081 		return (-1);
1082 	}
1083 	el->el_tty.t_mode = EX_IO;
1084 	return (0);
1085 }
1086 
1087 
1088 /* tty_quotemode():
1089  *	Turn on quote mode
1090  */
1091 protected int
1092 tty_quotemode(EditLine *el)
1093 {
1094 	if (el->el_tty.t_mode == QU_IO)
1095 		return (0);
1096 
1097 	el->el_tty.t_qu = el->el_tty.t_ed;
1098 
1099 	el->el_tty.t_qu.c_iflag &= ~el->el_tty.t_t[QU_IO][MD_INP].t_clrmask;
1100 	el->el_tty.t_qu.c_iflag |= el->el_tty.t_t[QU_IO][MD_INP].t_setmask;
1101 
1102 	el->el_tty.t_qu.c_oflag &= ~el->el_tty.t_t[QU_IO][MD_OUT].t_clrmask;
1103 	el->el_tty.t_qu.c_oflag |= el->el_tty.t_t[QU_IO][MD_OUT].t_setmask;
1104 
1105 	el->el_tty.t_qu.c_cflag &= ~el->el_tty.t_t[QU_IO][MD_CTL].t_clrmask;
1106 	el->el_tty.t_qu.c_cflag |= el->el_tty.t_t[QU_IO][MD_CTL].t_setmask;
1107 
1108 	el->el_tty.t_qu.c_lflag &= ~el->el_tty.t_t[QU_IO][MD_LIN].t_clrmask;
1109 	el->el_tty.t_qu.c_lflag |= el->el_tty.t_t[QU_IO][MD_LIN].t_setmask;
1110 
1111 	if (tty_setty(el, &el->el_tty.t_qu) == -1) {
1112 #ifdef DEBUG_TTY
1113 		(void) fprintf(el->el_errfile, "QuoteModeOn: tty_setty: %s\n",
1114 		    strerror(errno));
1115 #endif /* DEBUG_TTY */
1116 		return (-1);
1117 	}
1118 	el->el_tty.t_mode = QU_IO;
1119 	return (0);
1120 }
1121 
1122 
1123 /* tty_noquotemode():
1124  *	Turn off quote mode
1125  */
1126 protected int
1127 tty_noquotemode(EditLine *el)
1128 {
1129 
1130 	if (el->el_tty.t_mode != QU_IO)
1131 		return (0);
1132 	if (tty_setty(el, &el->el_tty.t_ed) == -1) {
1133 #ifdef DEBUG_TTY
1134 		(void) fprintf(el->el_errfile, "QuoteModeOff: tty_setty: %s\n",
1135 		    strerror(errno));
1136 #endif /* DEBUG_TTY */
1137 		return (-1);
1138 	}
1139 	el->el_tty.t_mode = ED_IO;
1140 	return (0);
1141 }
1142 
1143 
1144 /* tty_stty():
1145  *	Stty builtin
1146  */
1147 protected int
1148 /*ARGSUSED*/
1149 tty_stty(EditLine *el, int argc __attribute__((__unused__)), const char **argv)
1150 {
1151 	const ttymodes_t *m;
1152 	char x;
1153 	int aflag = 0;
1154 	const char *s, *d;
1155 	const char *name;
1156 	struct termios *tios = &el->el_tty.t_ex;
1157 	int z = EX_IO;
1158 
1159 	if (argv == NULL)
1160 		return (-1);
1161 	name = *argv++;
1162 
1163 	while (argv && *argv && argv[0][0] == '-' && argv[0][2] == '\0')
1164 		switch (argv[0][1]) {
1165 		case 'a':
1166 			aflag++;
1167 			argv++;
1168 			break;
1169 		case 'd':
1170 			argv++;
1171 			tios = &el->el_tty.t_ed;
1172 			z = ED_IO;
1173 			break;
1174 		case 'x':
1175 			argv++;
1176 			tios = &el->el_tty.t_ex;
1177 			z = EX_IO;
1178 			break;
1179 		case 'q':
1180 			argv++;
1181 			tios = &el->el_tty.t_ts;
1182 			z = QU_IO;
1183 			break;
1184 		default:
1185 			(void) fprintf(el->el_errfile,
1186 			    "%s: Unknown switch `%c'.\n",
1187 			    name, argv[0][1]);
1188 			return (-1);
1189 		}
1190 
1191 	if (!argv || !*argv) {
1192 		int i = -1;
1193 		int len = 0, st = 0, cu;
1194 		for (m = ttymodes; m->m_name; m++) {
1195 			if (m->m_type != i) {
1196 				(void) fprintf(el->el_outfile, "%s%s",
1197 				    i != -1 ? "\n" : "",
1198 				    el->el_tty.t_t[z][m->m_type].t_name);
1199 				i = m->m_type;
1200 				st = len =
1201 				    strlen(el->el_tty.t_t[z][m->m_type].t_name);
1202 			}
1203 			x = (el->el_tty.t_t[z][i].t_setmask & m->m_value)
1204 			    ?  '+' : '\0';
1205 			x = (el->el_tty.t_t[z][i].t_clrmask & m->m_value)
1206 			    ? '-' : x;
1207 
1208 			if (x != '\0' || aflag) {
1209 
1210 				cu = strlen(m->m_name) + (x != '\0') + 1;
1211 
1212 				if (len + cu >= el->el_term.t_size.h) {
1213 					(void) fprintf(el->el_outfile, "\n%*s",
1214 					    st, "");
1215 					len = st + cu;
1216 				} else
1217 					len += cu;
1218 
1219 				if (x != '\0')
1220 					(void) fprintf(el->el_outfile, "%c%s ",
1221 					    x, m->m_name);
1222 				else
1223 					(void) fprintf(el->el_outfile, "%s ",
1224 					    m->m_name);
1225 			}
1226 		}
1227 		(void) fprintf(el->el_outfile, "\n");
1228 		return (0);
1229 	}
1230 	while (argv && (s = *argv++)) {
1231 		char *p;
1232 		switch (*s) {
1233 		case '+':
1234 		case '-':
1235 			x = *s++;
1236 			break;
1237 		default:
1238 			x = '\0';
1239 			break;
1240 		}
1241 		d = s;
1242 		if ((p = strchr(s, '=')) != NULL)
1243 			*p++ = '\0';
1244 		for (m = ttymodes; m->m_name; m++)
1245 			if (strcmp(m->m_name, d) == 0 &&
1246 			    (p == NULL || m->m_type == MD_CHAR))
1247 				break;
1248 
1249 		if (!m->m_name) {
1250 			(void) fprintf(el->el_errfile,
1251 			    "%s: Invalid argument `%s'.\n", name, d);
1252 			return (-1);
1253 		}
1254 		if (p) {
1255 			int c = ffs((int)m->m_value);
1256 			int v = *p ? parse__escape((const char **const) &p) :
1257 			    el->el_tty.t_vdisable;
1258 			c--;
1259 			c = tty__getcharindex(c);
1260 			tios->c_cc[c] = v;
1261 			continue;
1262 		}
1263 		switch (x) {
1264 		case '+':
1265 			el->el_tty.t_t[z][m->m_type].t_setmask |= m->m_value;
1266 			el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value;
1267 			break;
1268 		case '-':
1269 			el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value;
1270 			el->el_tty.t_t[z][m->m_type].t_clrmask |= m->m_value;
1271 			break;
1272 		default:
1273 			el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value;
1274 			el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value;
1275 			break;
1276 		}
1277 	}
1278 	return (0);
1279 }
1280 
1281 
1282 #ifdef notyet
1283 /* tty_printchar():
1284  *	DEbugging routine to print the tty characters
1285  */
1286 private void
1287 tty_printchar(EditLine *el, unsigned char *s)
1288 {
1289 	ttyperm_t *m;
1290 	int i;
1291 
1292 	for (i = 0; i < C_NCC; i++) {
1293 		for (m = el->el_tty.t_t; m->m_name; m++)
1294 			if (m->m_type == MD_CHAR && C_SH(i) == m->m_value)
1295 				break;
1296 		if (m->m_name)
1297 			(void) fprintf(el->el_errfile, "%s ^%c ",
1298 			    m->m_name, s[i] + 'A' - 1);
1299 		if (i % 5 == 0)
1300 			(void) fprintf(el->el_errfile, "\n");
1301 	}
1302 	(void) fprintf(el->el_errfile, "\n");
1303 }
1304 #endif /* notyet */
1305