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