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