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