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