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