Home | History | Annotate | Line # | Download | only in libedit
tty.c revision 1.58
      1 /*	$NetBSD: tty.c,v 1.58 2016/02/27 18:13:21 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.58 2016/02/27 18:13:21 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 	el->el_tty.t_initialized = 0;
    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 	el->el_tty.t_initialized = 1;
    565 	return 0;
    566 }
    567 
    568 protected int
    569 tty_init(EditLine *el)
    570 {
    571 
    572 	el->el_tty.t_mode = EX_IO;
    573 	el->el_tty.t_vdisable = _POSIX_VDISABLE;
    574 	(void) memcpy(el->el_tty.t_t, ttyperm, sizeof(ttyperm_t));
    575 	(void) memcpy(el->el_tty.t_c, ttychar, sizeof(ttychar_t));
    576 	return tty_setup(el);
    577 }
    578 
    579 
    580 /* tty_end():
    581  *	Restore the tty to its original settings
    582  */
    583 protected void
    584 /*ARGSUSED*/
    585 tty_end(EditLine *el)
    586 {
    587 	if (el->el_flags & EDIT_DISABLED)
    588 		return;
    589 
    590 	if (el->el_tty.t_initialized)
    591 		return;
    592 
    593 	if (tty_setty(el, TCSAFLUSH, &el->el_tty.t_or) == -1) {
    594 #ifdef DEBUG_TTY
    595 		(void) fprintf(el->el_errfile,
    596 		    "%s: tty_setty: %s\n", __func__, strerror(errno));
    597 #endif /* DEBUG_TTY */
    598 	}
    599 }
    600 
    601 
    602 /* tty__getspeed():
    603  *	Get the tty speed
    604  */
    605 private speed_t
    606 tty__getspeed(struct termios *td)
    607 {
    608 	speed_t spd;
    609 
    610 	if ((spd = cfgetispeed(td)) == 0)
    611 		spd = cfgetospeed(td);
    612 	return spd;
    613 }
    614 
    615 /* tty__getspeed():
    616  *	Return the index of the asked char in the c_cc array
    617  */
    618 private int
    619 tty__getcharindex(int i)
    620 {
    621 	switch (i) {
    622 #ifdef VINTR
    623 	case C_INTR:
    624 		return VINTR;
    625 #endif /* VINTR */
    626 #ifdef VQUIT
    627 	case C_QUIT:
    628 		return VQUIT;
    629 #endif /* VQUIT */
    630 #ifdef VERASE
    631 	case C_ERASE:
    632 		return VERASE;
    633 #endif /* VERASE */
    634 #ifdef VKILL
    635 	case C_KILL:
    636 		return VKILL;
    637 #endif /* VKILL */
    638 #ifdef VEOF
    639 	case C_EOF:
    640 		return VEOF;
    641 #endif /* VEOF */
    642 #ifdef VEOL
    643 	case C_EOL:
    644 		return VEOL;
    645 #endif /* VEOL */
    646 #ifdef VEOL2
    647 	case C_EOL2:
    648 		return VEOL2;
    649 #endif /* VEOL2 */
    650 #ifdef VSWTCH
    651 	case C_SWTCH:
    652 		return VSWTCH;
    653 #endif /* VSWTCH */
    654 #ifdef VDSWTCH
    655 	case C_DSWTCH:
    656 		return VDSWTCH;
    657 #endif /* VDSWTCH */
    658 #ifdef VERASE2
    659 	case C_ERASE2:
    660 		return VERASE2;
    661 #endif /* VERASE2 */
    662 #ifdef VSTART
    663 	case C_START:
    664 		return VSTART;
    665 #endif /* VSTART */
    666 #ifdef VSTOP
    667 	case C_STOP:
    668 		return VSTOP;
    669 #endif /* VSTOP */
    670 #ifdef VWERASE
    671 	case C_WERASE:
    672 		return VWERASE;
    673 #endif /* VWERASE */
    674 #ifdef VSUSP
    675 	case C_SUSP:
    676 		return VSUSP;
    677 #endif /* VSUSP */
    678 #ifdef VDSUSP
    679 	case C_DSUSP:
    680 		return VDSUSP;
    681 #endif /* VDSUSP */
    682 #ifdef VREPRINT
    683 	case C_REPRINT:
    684 		return VREPRINT;
    685 #endif /* VREPRINT */
    686 #ifdef VDISCARD
    687 	case C_DISCARD:
    688 		return VDISCARD;
    689 #endif /* VDISCARD */
    690 #ifdef VLNEXT
    691 	case C_LNEXT:
    692 		return VLNEXT;
    693 #endif /* VLNEXT */
    694 #ifdef VSTATUS
    695 	case C_STATUS:
    696 		return VSTATUS;
    697 #endif /* VSTATUS */
    698 #ifdef VPAGE
    699 	case C_PAGE:
    700 		return VPAGE;
    701 #endif /* VPAGE */
    702 #ifdef VPGOFF
    703 	case C_PGOFF:
    704 		return VPGOFF;
    705 #endif /* VPGOFF */
    706 #ifdef VKILL2
    707 	case C_KILL2:
    708 		return VKILL2;
    709 #endif /* KILL2 */
    710 #ifdef VMIN
    711 	case C_MIN:
    712 		return VMIN;
    713 #endif /* VMIN */
    714 #ifdef VTIME
    715 	case C_TIME:
    716 		return VTIME;
    717 #endif /* VTIME */
    718 	default:
    719 		return -1;
    720 	}
    721 }
    722 
    723 /* tty__getchar():
    724  *	Get the tty characters
    725  */
    726 private void
    727 tty__getchar(struct termios *td, unsigned char *s)
    728 {
    729 
    730 #ifdef VINTR
    731 	s[C_INTR] = td->c_cc[VINTR];
    732 #endif /* VINTR */
    733 #ifdef VQUIT
    734 	s[C_QUIT] = td->c_cc[VQUIT];
    735 #endif /* VQUIT */
    736 #ifdef VERASE
    737 	s[C_ERASE] = td->c_cc[VERASE];
    738 #endif /* VERASE */
    739 #ifdef VKILL
    740 	s[C_KILL] = td->c_cc[VKILL];
    741 #endif /* VKILL */
    742 #ifdef VEOF
    743 	s[C_EOF] = td->c_cc[VEOF];
    744 #endif /* VEOF */
    745 #ifdef VEOL
    746 	s[C_EOL] = td->c_cc[VEOL];
    747 #endif /* VEOL */
    748 #ifdef VEOL2
    749 	s[C_EOL2] = td->c_cc[VEOL2];
    750 #endif /* VEOL2 */
    751 #ifdef VSWTCH
    752 	s[C_SWTCH] = td->c_cc[VSWTCH];
    753 #endif /* VSWTCH */
    754 #ifdef VDSWTCH
    755 	s[C_DSWTCH] = td->c_cc[VDSWTCH];
    756 #endif /* VDSWTCH */
    757 #ifdef VERASE2
    758 	s[C_ERASE2] = td->c_cc[VERASE2];
    759 #endif /* VERASE2 */
    760 #ifdef VSTART
    761 	s[C_START] = td->c_cc[VSTART];
    762 #endif /* VSTART */
    763 #ifdef VSTOP
    764 	s[C_STOP] = td->c_cc[VSTOP];
    765 #endif /* VSTOP */
    766 #ifdef VWERASE
    767 	s[C_WERASE] = td->c_cc[VWERASE];
    768 #endif /* VWERASE */
    769 #ifdef VSUSP
    770 	s[C_SUSP] = td->c_cc[VSUSP];
    771 #endif /* VSUSP */
    772 #ifdef VDSUSP
    773 	s[C_DSUSP] = td->c_cc[VDSUSP];
    774 #endif /* VDSUSP */
    775 #ifdef VREPRINT
    776 	s[C_REPRINT] = td->c_cc[VREPRINT];
    777 #endif /* VREPRINT */
    778 #ifdef VDISCARD
    779 	s[C_DISCARD] = td->c_cc[VDISCARD];
    780 #endif /* VDISCARD */
    781 #ifdef VLNEXT
    782 	s[C_LNEXT] = td->c_cc[VLNEXT];
    783 #endif /* VLNEXT */
    784 #ifdef VSTATUS
    785 	s[C_STATUS] = td->c_cc[VSTATUS];
    786 #endif /* VSTATUS */
    787 #ifdef VPAGE
    788 	s[C_PAGE] = td->c_cc[VPAGE];
    789 #endif /* VPAGE */
    790 #ifdef VPGOFF
    791 	s[C_PGOFF] = td->c_cc[VPGOFF];
    792 #endif /* VPGOFF */
    793 #ifdef VKILL2
    794 	s[C_KILL2] = td->c_cc[VKILL2];
    795 #endif /* KILL2 */
    796 #ifdef VMIN
    797 	s[C_MIN] = td->c_cc[VMIN];
    798 #endif /* VMIN */
    799 #ifdef VTIME
    800 	s[C_TIME] = td->c_cc[VTIME];
    801 #endif /* VTIME */
    802 }				/* tty__getchar */
    803 
    804 
    805 /* tty__setchar():
    806  *	Set the tty characters
    807  */
    808 private void
    809 tty__setchar(struct termios *td, unsigned char *s)
    810 {
    811 
    812 #ifdef VINTR
    813 	td->c_cc[VINTR] = s[C_INTR];
    814 #endif /* VINTR */
    815 #ifdef VQUIT
    816 	td->c_cc[VQUIT] = s[C_QUIT];
    817 #endif /* VQUIT */
    818 #ifdef VERASE
    819 	td->c_cc[VERASE] = s[C_ERASE];
    820 #endif /* VERASE */
    821 #ifdef VKILL
    822 	td->c_cc[VKILL] = s[C_KILL];
    823 #endif /* VKILL */
    824 #ifdef VEOF
    825 	td->c_cc[VEOF] = s[C_EOF];
    826 #endif /* VEOF */
    827 #ifdef VEOL
    828 	td->c_cc[VEOL] = s[C_EOL];
    829 #endif /* VEOL */
    830 #ifdef VEOL2
    831 	td->c_cc[VEOL2] = s[C_EOL2];
    832 #endif /* VEOL2 */
    833 #ifdef VSWTCH
    834 	td->c_cc[VSWTCH] = s[C_SWTCH];
    835 #endif /* VSWTCH */
    836 #ifdef VDSWTCH
    837 	td->c_cc[VDSWTCH] = s[C_DSWTCH];
    838 #endif /* VDSWTCH */
    839 #ifdef VERASE2
    840 	td->c_cc[VERASE2] = s[C_ERASE2];
    841 #endif /* VERASE2 */
    842 #ifdef VSTART
    843 	td->c_cc[VSTART] = s[C_START];
    844 #endif /* VSTART */
    845 #ifdef VSTOP
    846 	td->c_cc[VSTOP] = s[C_STOP];
    847 #endif /* VSTOP */
    848 #ifdef VWERASE
    849 	td->c_cc[VWERASE] = s[C_WERASE];
    850 #endif /* VWERASE */
    851 #ifdef VSUSP
    852 	td->c_cc[VSUSP] = s[C_SUSP];
    853 #endif /* VSUSP */
    854 #ifdef VDSUSP
    855 	td->c_cc[VDSUSP] = s[C_DSUSP];
    856 #endif /* VDSUSP */
    857 #ifdef VREPRINT
    858 	td->c_cc[VREPRINT] = s[C_REPRINT];
    859 #endif /* VREPRINT */
    860 #ifdef VDISCARD
    861 	td->c_cc[VDISCARD] = s[C_DISCARD];
    862 #endif /* VDISCARD */
    863 #ifdef VLNEXT
    864 	td->c_cc[VLNEXT] = s[C_LNEXT];
    865 #endif /* VLNEXT */
    866 #ifdef VSTATUS
    867 	td->c_cc[VSTATUS] = s[C_STATUS];
    868 #endif /* VSTATUS */
    869 #ifdef VPAGE
    870 	td->c_cc[VPAGE] = s[C_PAGE];
    871 #endif /* VPAGE */
    872 #ifdef VPGOFF
    873 	td->c_cc[VPGOFF] = s[C_PGOFF];
    874 #endif /* VPGOFF */
    875 #ifdef VKILL2
    876 	td->c_cc[VKILL2] = s[C_KILL2];
    877 #endif /* VKILL2 */
    878 #ifdef VMIN
    879 	td->c_cc[VMIN] = s[C_MIN];
    880 #endif /* VMIN */
    881 #ifdef VTIME
    882 	td->c_cc[VTIME] = s[C_TIME];
    883 #endif /* VTIME */
    884 }				/* tty__setchar */
    885 
    886 
    887 /* tty_bind_char():
    888  *	Rebind the editline functions
    889  */
    890 protected void
    891 tty_bind_char(EditLine *el, int force)
    892 {
    893 
    894 	unsigned char *t_n = el->el_tty.t_c[ED_IO];
    895 	unsigned char *t_o = el->el_tty.t_ed.c_cc;
    896 	Char new[2], old[2];
    897 	const ttymap_t *tp;
    898 	el_action_t *map, *alt;
    899 	const el_action_t *dmap, *dalt;
    900 	new[1] = old[1] = '\0';
    901 
    902 	map = el->el_map.key;
    903 	alt = el->el_map.alt;
    904 	if (el->el_map.type == MAP_VI) {
    905 		dmap = el->el_map.vii;
    906 		dalt = el->el_map.vic;
    907 	} else {
    908 		dmap = el->el_map.emacs;
    909 		dalt = NULL;
    910 	}
    911 
    912 	for (tp = tty_map; tp->nch != (wint_t)-1; tp++) {
    913 		new[0] = (Char)t_n[tp->nch];
    914 		old[0] = (Char)t_o[tp->och];
    915 		if (new[0] == old[0] && !force)
    916 			continue;
    917 		/* Put the old default binding back, and set the new binding */
    918 		keymacro_clear(el, map, old);
    919 		map[UC(old[0])] = dmap[UC(old[0])];
    920 		keymacro_clear(el, map, new);
    921 		/* MAP_VI == 1, MAP_EMACS == 0... */
    922 		map[UC(new[0])] = tp->bind[el->el_map.type];
    923 		if (dalt) {
    924 			keymacro_clear(el, alt, old);
    925 			alt[UC(old[0])] = dalt[UC(old[0])];
    926 			keymacro_clear(el, alt, new);
    927 			alt[UC(new[0])] = tp->bind[el->el_map.type + 1];
    928 		}
    929 	}
    930 }
    931 
    932 
    933 private tcflag_t *
    934 tty__get_flag(struct termios *t, int kind) {
    935 	switch (kind) {
    936 	case MD_INP:
    937 		return &t->c_iflag;
    938 	case MD_OUT:
    939 		return &t->c_oflag;
    940 	case MD_CTL:
    941 		return &t->c_cflag;
    942 	case MD_LIN:
    943 		return &t->c_lflag;
    944 	default:
    945 		abort();
    946 		/*NOTREACHED*/
    947 	}
    948 }
    949 
    950 
    951 private tcflag_t
    952 tty_update_flag(EditLine *el, tcflag_t f, int mode, int kind)
    953 {
    954 	f &= ~el->el_tty.t_t[mode][kind].t_clrmask;
    955 	f |= el->el_tty.t_t[mode][kind].t_setmask;
    956 	return f;
    957 }
    958 
    959 
    960 private void
    961 tty_update_flags(EditLine *el, int kind)
    962 {
    963 	tcflag_t *tt, *ed, *ex;
    964 	tt = tty__get_flag(&el->el_tty.t_ts, kind);
    965 	ed = tty__get_flag(&el->el_tty.t_ed, kind);
    966 	ex = tty__get_flag(&el->el_tty.t_ex, kind);
    967 
    968 	if (*tt != *ex && (kind != MD_CTL || *tt != *ed)) {
    969 		*ed = tty_update_flag(el, *tt, ED_IO, kind);
    970 		*ex = tty_update_flag(el, *tt, EX_IO, kind);
    971 	}
    972 }
    973 
    974 
    975 private void
    976 tty_update_char(EditLine *el, int mode, int c) {
    977 	if (!((el->el_tty.t_t[mode][MD_CHAR].t_setmask & C_SH(c)))
    978 	    && (el->el_tty.t_c[TS_IO][c] != el->el_tty.t_c[EX_IO][c]))
    979 		el->el_tty.t_c[mode][c] = el->el_tty.t_c[TS_IO][c];
    980 	if (el->el_tty.t_t[mode][MD_CHAR].t_clrmask & C_SH(c))
    981 		el->el_tty.t_c[mode][c] = el->el_tty.t_vdisable;
    982 }
    983 
    984 
    985 /* tty_rawmode():
    986  *	Set terminal into 1 character at a time mode.
    987  */
    988 protected int
    989 tty_rawmode(EditLine *el)
    990 {
    991 
    992 	if (el->el_tty.t_mode == ED_IO || el->el_tty.t_mode == QU_IO)
    993 		return 0;
    994 
    995 	if (el->el_flags & EDIT_DISABLED)
    996 		return 0;
    997 
    998 	if (tty_getty(el, &el->el_tty.t_ts) == -1) {
    999 #ifdef DEBUG_TTY
   1000 		(void) fprintf(el->el_errfile, "%s: tty_getty: %s\n", __func__,
   1001 		    strerror(errno));
   1002 #endif /* DEBUG_TTY */
   1003 		return -1;
   1004 	}
   1005 	/*
   1006          * We always keep up with the eight bit setting and the speed of the
   1007          * tty. But we only believe changes that are made to cooked mode!
   1008          */
   1009 	el->el_tty.t_eight = tty__geteightbit(&el->el_tty.t_ts);
   1010 	el->el_tty.t_speed = tty__getspeed(&el->el_tty.t_ts);
   1011 
   1012 	if (tty__getspeed(&el->el_tty.t_ex) != el->el_tty.t_speed ||
   1013 	    tty__getspeed(&el->el_tty.t_ed) != el->el_tty.t_speed) {
   1014 		(void) cfsetispeed(&el->el_tty.t_ex, el->el_tty.t_speed);
   1015 		(void) cfsetospeed(&el->el_tty.t_ex, el->el_tty.t_speed);
   1016 		(void) cfsetispeed(&el->el_tty.t_ed, el->el_tty.t_speed);
   1017 		(void) cfsetospeed(&el->el_tty.t_ed, el->el_tty.t_speed);
   1018 	}
   1019 	if (tty__cooked_mode(&el->el_tty.t_ts)) {
   1020 		int i;
   1021 
   1022 		for (i = MD_INP; i <= MD_LIN; i++)
   1023 			tty_update_flags(el, i);
   1024 
   1025 		if (tty__gettabs(&el->el_tty.t_ex) == 0)
   1026 			el->el_tty.t_tabs = 0;
   1027 		else
   1028 			el->el_tty.t_tabs = EL_CAN_TAB ? 1 : 0;
   1029 
   1030 		tty__getchar(&el->el_tty.t_ts, el->el_tty.t_c[TS_IO]);
   1031 		/*
   1032 		 * Check if the user made any changes.
   1033 		 * If he did, then propagate the changes to the
   1034 		 * edit and execute data structures.
   1035 		 */
   1036 		for (i = 0; i < C_NCC; i++)
   1037 			if (el->el_tty.t_c[TS_IO][i] !=
   1038 			    el->el_tty.t_c[EX_IO][i])
   1039 				break;
   1040 
   1041 		if (i != C_NCC) {
   1042 			/*
   1043 			 * Propagate changes only to the unprotected
   1044 			 * chars that have been modified just now.
   1045 			 */
   1046 			for (i = 0; i < C_NCC; i++)
   1047 				tty_update_char(el, ED_IO, i);
   1048 
   1049 			tty_bind_char(el, 0);
   1050 			tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]);
   1051 
   1052 			for (i = 0; i < C_NCC; i++)
   1053 				tty_update_char(el, EX_IO, i);
   1054 
   1055 			tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]);
   1056 		}
   1057 	}
   1058 	if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ed) == -1) {
   1059 #ifdef DEBUG_TTY
   1060 		(void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", __func__,
   1061 		    strerror(errno));
   1062 #endif /* DEBUG_TTY */
   1063 		return -1;
   1064 	}
   1065 	el->el_tty.t_mode = ED_IO;
   1066 	return 0;
   1067 }
   1068 
   1069 
   1070 /* tty_cookedmode():
   1071  *	Set the tty back to normal mode
   1072  */
   1073 protected int
   1074 tty_cookedmode(EditLine *el)
   1075 {				/* set tty in normal setup */
   1076 
   1077 	if (el->el_tty.t_mode == EX_IO)
   1078 		return 0;
   1079 
   1080 	if (el->el_flags & EDIT_DISABLED)
   1081 		return 0;
   1082 
   1083 	if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ex) == -1) {
   1084 #ifdef DEBUG_TTY
   1085 		(void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", __func__,
   1086 		    strerror(errno));
   1087 #endif /* DEBUG_TTY */
   1088 		return -1;
   1089 	}
   1090 	el->el_tty.t_mode = EX_IO;
   1091 	return 0;
   1092 }
   1093 
   1094 
   1095 /* tty_quotemode():
   1096  *	Turn on quote mode
   1097  */
   1098 protected int
   1099 tty_quotemode(EditLine *el)
   1100 {
   1101 	if (el->el_tty.t_mode == QU_IO)
   1102 		return 0;
   1103 
   1104 	el->el_tty.t_qu = el->el_tty.t_ed;
   1105 
   1106 	tty_setup_flags(el, &el->el_tty.t_qu, QU_IO);
   1107 
   1108 	if (tty_setty(el, TCSADRAIN, &el->el_tty.t_qu) == -1) {
   1109 #ifdef DEBUG_TTY
   1110 		(void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", __func__,
   1111 		    strerror(errno));
   1112 #endif /* DEBUG_TTY */
   1113 		return -1;
   1114 	}
   1115 	el->el_tty.t_mode = QU_IO;
   1116 	return 0;
   1117 }
   1118 
   1119 
   1120 /* tty_noquotemode():
   1121  *	Turn off quote mode
   1122  */
   1123 protected int
   1124 tty_noquotemode(EditLine *el)
   1125 {
   1126 
   1127 	if (el->el_tty.t_mode != QU_IO)
   1128 		return 0;
   1129 	if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ed) == -1) {
   1130 #ifdef DEBUG_TTY
   1131 		(void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", __func__,
   1132 		    strerror(errno));
   1133 #endif /* DEBUG_TTY */
   1134 		return -1;
   1135 	}
   1136 	el->el_tty.t_mode = ED_IO;
   1137 	return 0;
   1138 }
   1139 
   1140 
   1141 /* tty_stty():
   1142  *	Stty builtin
   1143  */
   1144 protected int
   1145 /*ARGSUSED*/
   1146 tty_stty(EditLine *el, int argc __attribute__((__unused__)), const Char **argv)
   1147 {
   1148 	const ttymodes_t *m;
   1149 	char x;
   1150 	int aflag = 0;
   1151 	const Char *s, *d;
   1152         char name[EL_BUFSIZ];
   1153 	struct termios *tios = &el->el_tty.t_ex;
   1154 	int z = EX_IO;
   1155 
   1156 	if (argv == NULL)
   1157 		return -1;
   1158 	strncpy(name, ct_encode_string(*argv++, &el->el_scratch), sizeof(name));
   1159         name[sizeof(name) - 1] = '\0';
   1160 
   1161 	while (argv && *argv && argv[0][0] == '-' && argv[0][2] == '\0')
   1162 		switch (argv[0][1]) {
   1163 		case 'a':
   1164 			aflag++;
   1165 			argv++;
   1166 			break;
   1167 		case 'd':
   1168 			argv++;
   1169 			tios = &el->el_tty.t_ed;
   1170 			z = ED_IO;
   1171 			break;
   1172 		case 'x':
   1173 			argv++;
   1174 			tios = &el->el_tty.t_ex;
   1175 			z = EX_IO;
   1176 			break;
   1177 		case 'q':
   1178 			argv++;
   1179 			tios = &el->el_tty.t_ts;
   1180 			z = QU_IO;
   1181 			break;
   1182 		default:
   1183 			(void) fprintf(el->el_errfile,
   1184 			    "%s: Unknown switch `%lc'.\n",
   1185 			    name, (wint_t)argv[0][1]);
   1186 			return -1;
   1187 		}
   1188 
   1189 	if (!argv || !*argv) {
   1190 		int i = -1;
   1191 		size_t len = 0, st = 0, cu;
   1192 		for (m = ttymodes; m->m_name; m++) {
   1193 			if (m->m_type != i) {
   1194 				(void) fprintf(el->el_outfile, "%s%s",
   1195 				    i != -1 ? "\n" : "",
   1196 				    el->el_tty.t_t[z][m->m_type].t_name);
   1197 				i = m->m_type;
   1198 				st = len =
   1199 				    strlen(el->el_tty.t_t[z][m->m_type].t_name);
   1200 			}
   1201 			if (i != -1) {
   1202 			    x = (el->el_tty.t_t[z][i].t_setmask & m->m_value)
   1203 				?  '+' : '\0';
   1204 
   1205 			    if (el->el_tty.t_t[z][i].t_clrmask & m->m_value)
   1206 				x = '-';
   1207 			} else {
   1208 			    x = '\0';
   1209 			}
   1210 
   1211 			if (x != '\0' || aflag) {
   1212 
   1213 				cu = strlen(m->m_name) + (x != '\0') + 1;
   1214 
   1215 				if (len + cu >=
   1216 				    (size_t)el->el_terminal.t_size.h) {
   1217 					(void) fprintf(el->el_outfile, "\n%*s",
   1218 					    (int)st, "");
   1219 					len = st + cu;
   1220 				} else
   1221 					len += cu;
   1222 
   1223 				if (x != '\0')
   1224 					(void) fprintf(el->el_outfile, "%c%s ",
   1225 					    x, m->m_name);
   1226 				else
   1227 					(void) fprintf(el->el_outfile, "%s ",
   1228 					    m->m_name);
   1229 			}
   1230 		}
   1231 		(void) fprintf(el->el_outfile, "\n");
   1232 		return 0;
   1233 	}
   1234 	while (argv && (s = *argv++)) {
   1235 		const Char *p;
   1236 		switch (*s) {
   1237 		case '+':
   1238 		case '-':
   1239 			x = (char)*s++;
   1240 			break;
   1241 		default:
   1242 			x = '\0';
   1243 			break;
   1244 		}
   1245 		d = s;
   1246 		p = Strchr(s, '=');
   1247 		for (m = ttymodes; m->m_name; m++)
   1248 			if ((p ? strncmp(m->m_name, ct_encode_string(d,
   1249 			    &el->el_scratch), (size_t)(p - d)) :
   1250 			    strcmp(m->m_name, ct_encode_string(d,
   1251 			    &el->el_scratch))) == 0 &&
   1252 			    (p == NULL || m->m_type == MD_CHAR))
   1253 				break;
   1254 
   1255 		if (!m->m_name) {
   1256 			(void) fprintf(el->el_errfile,
   1257 			    "%s: Invalid argument `" FSTR "'.\n", name, d);
   1258 			return -1;
   1259 		}
   1260 		if (p) {
   1261 			int c = ffs((int)m->m_value);
   1262 			int v = *++p ? parse__escape(&p) :
   1263 			    el->el_tty.t_vdisable;
   1264 			assert(c != 0);
   1265 			c--;
   1266 			c = tty__getcharindex(c);
   1267 			assert(c != -1);
   1268 			tios->c_cc[c] = (cc_t)v;
   1269 			continue;
   1270 		}
   1271 		switch (x) {
   1272 		case '+':
   1273 			el->el_tty.t_t[z][m->m_type].t_setmask |= m->m_value;
   1274 			el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value;
   1275 			break;
   1276 		case '-':
   1277 			el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value;
   1278 			el->el_tty.t_t[z][m->m_type].t_clrmask |= m->m_value;
   1279 			break;
   1280 		default:
   1281 			el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value;
   1282 			el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value;
   1283 			break;
   1284 		}
   1285 	}
   1286 
   1287 	tty_setup_flags(el, tios, z);
   1288 	if (el->el_tty.t_mode == z) {
   1289 		if (tty_setty(el, TCSADRAIN, tios) == -1) {
   1290 #ifdef DEBUG_TTY
   1291 			(void) fprintf(el->el_errfile, "%s: tty_setty: %s\n",
   1292 			    __func__, strerror(errno));
   1293 #endif /* DEBUG_TTY */
   1294 			return -1;
   1295 		}
   1296 	}
   1297 
   1298 	return 0;
   1299 }
   1300 
   1301 
   1302 #ifdef notyet
   1303 /* tty_printchar():
   1304  *	DEbugging routine to print the tty characters
   1305  */
   1306 private void
   1307 tty_printchar(EditLine *el, unsigned char *s)
   1308 {
   1309 	ttyperm_t *m;
   1310 	int i;
   1311 
   1312 	for (i = 0; i < C_NCC; i++) {
   1313 		for (m = el->el_tty.t_t; m->m_name; m++)
   1314 			if (m->m_type == MD_CHAR && C_SH(i) == m->m_value)
   1315 				break;
   1316 		if (m->m_name)
   1317 			(void) fprintf(el->el_errfile, "%s ^%c ",
   1318 			    m->m_name, s[i] + 'A' - 1);
   1319 		if (i % 5 == 0)
   1320 			(void) fprintf(el->el_errfile, "\n");
   1321 	}
   1322 	(void) fprintf(el->el_errfile, "\n");
   1323 }
   1324 #endif /* notyet */
   1325 
   1326 
   1327 private void
   1328 tty_setup_flags(EditLine *el, struct termios *tios, int mode)
   1329 {
   1330 	int kind;
   1331 	for (kind = MD_INP; kind <= MD_LIN; kind++) {
   1332 		tcflag_t *f = tty__get_flag(tios, kind);
   1333 		*f = tty_update_flag(el, *f, mode, kind);
   1334 	}
   1335 }
   1336