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