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