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