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