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