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