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