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