Home | History | Annotate | Line # | Download | only in libedit
tty.c revision 1.5
      1 /*	$NetBSD: tty.c,v 1.5 1997/10/09 19:16:04 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.5 1997/10/09 19:16:04 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_c[TS_IO][rst];
    514         }
    515         tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]);
    516         if (tty_setty(el, &el->el_tty.t_ex) == -1) {
    517 #ifdef DEBUG_TTY
    518             (void) fprintf(el->el_errfile, "tty_setup: tty_setty: %s\n",
    519 			   strerror(errno));
    520 #endif /* DEBUG_TTY */
    521             return(-1);
    522         }
    523     }
    524     else
    525         tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]);
    526 
    527     el->el_tty.t_ed.c_iflag &= ~el->el_tty.t_t[ED_IO][M_INP].t_clrmask;
    528     el->el_tty.t_ed.c_iflag |=  el->el_tty.t_t[ED_IO][M_INP].t_setmask;
    529 
    530     el->el_tty.t_ed.c_oflag &= ~el->el_tty.t_t[ED_IO][M_OUT].t_clrmask;
    531     el->el_tty.t_ed.c_oflag |=  el->el_tty.t_t[ED_IO][M_OUT].t_setmask;
    532 
    533     el->el_tty.t_ed.c_cflag &= ~el->el_tty.t_t[ED_IO][M_CTL].t_clrmask;
    534     el->el_tty.t_ed.c_cflag |=  el->el_tty.t_t[ED_IO][M_CTL].t_setmask;
    535 
    536     el->el_tty.t_ed.c_lflag &= ~el->el_tty.t_t[ED_IO][M_LIN].t_clrmask;
    537     el->el_tty.t_ed.c_lflag |=  el->el_tty.t_t[ED_IO][M_LIN].t_setmask;
    538 
    539     tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]);
    540     return 0;
    541 }
    542 
    543 protected int
    544 tty_init(el)
    545     EditLine *el;
    546 {
    547     el->el_tty.t_mode     = EX_IO;
    548     el->el_tty.t_vdisable = _POSIX_VDISABLE;
    549     (void) memcpy(el->el_tty.t_t, ttyperm, sizeof(ttyperm_t));
    550     (void) memcpy(el->el_tty.t_c, ttychar, sizeof(ttychar_t));
    551     return tty_setup(el);
    552 } /* end tty_init */
    553 
    554 
    555 /* tty_end():
    556  *	Restore the tty to its original settings
    557  */
    558 protected void
    559 /*ARGSUSED*/
    560 tty_end(el)
    561     EditLine *el;
    562 {
    563     /* XXX: Maybe reset to an initial state? */
    564 }
    565 
    566 
    567 /* tty__getspeed():
    568  *	Get the tty speed
    569  */
    570 private speed_t
    571 tty__getspeed(td)
    572     struct termios *td;
    573 {
    574     speed_t spd;
    575 
    576     if ((spd = cfgetispeed(td)) == 0)
    577 	spd = cfgetospeed(td);
    578     return spd;
    579 } /* end tty__getspeed */
    580 
    581 
    582 /* tty__getchar():
    583  *	Get the tty characters
    584  */
    585 private void
    586 tty__getchar(td, s)
    587     struct termios *td;
    588     unsigned char *s;
    589 {
    590 # ifdef VINTR
    591     s[C_INTR]	= td->c_cc[VINTR];
    592 # endif /* VINTR */
    593 # ifdef VQUIT
    594     s[C_QUIT]	= td->c_cc[VQUIT];
    595 # endif /* VQUIT */
    596 # ifdef VERASE
    597     s[C_ERASE]	= td->c_cc[VERASE];
    598 # endif /* VERASE */
    599 # ifdef VKILL
    600     s[C_KILL]	= td->c_cc[VKILL];
    601 # endif /* VKILL */
    602 # ifdef VEOF
    603     s[C_EOF]	= td->c_cc[VEOF];
    604 # endif /* VEOF */
    605 # ifdef VEOL
    606     s[C_EOL]	= td->c_cc[VEOL];
    607 # endif /* VEOL */
    608 # ifdef VEOL2
    609     s[C_EOL2]	= td->c_cc[VEOL2];
    610 # endif  /* VEOL2 */
    611 # ifdef VSWTCH
    612     s[C_SWTCH]	= td->c_cc[VSWTCH];
    613 # endif /* VSWTCH */
    614 # ifdef VDSWTCH
    615     s[C_DSWTCH]	= td->c_cc[VDSWTCH];
    616 # endif /* VDSWTCH */
    617 # ifdef VERASE2
    618     s[C_ERASE2]	= td->c_cc[VERASE2];
    619 # endif /* VERASE2 */
    620 # ifdef VSTART
    621     s[C_START]	= td->c_cc[VSTART];
    622 # endif /* VSTART */
    623 # ifdef VSTOP
    624     s[C_STOP]	= td->c_cc[VSTOP];
    625 # endif /* VSTOP */
    626 # ifdef VWERASE
    627     s[C_WERASE]	= td->c_cc[VWERASE];
    628 # endif /* VWERASE */
    629 # ifdef VSUSP
    630     s[C_SUSP]	= td->c_cc[VSUSP];
    631 # endif /* VSUSP */
    632 # ifdef VDSUSP
    633     s[C_DSUSP]	= td->c_cc[VDSUSP];
    634 # endif /* VDSUSP */
    635 # ifdef VREPRINT
    636     s[C_REPRINT]= td->c_cc[VREPRINT];
    637 # endif /* VREPRINT */
    638 # ifdef VDISCARD
    639     s[C_DISCARD]= td->c_cc[VDISCARD];
    640 # endif /* VDISCARD */
    641 # ifdef VLNEXT
    642     s[C_LNEXT]	= td->c_cc[VLNEXT];
    643 # endif /* VLNEXT */
    644 # ifdef VSTATUS
    645     s[C_STATUS]	= td->c_cc[VSTATUS];
    646 # endif /* VSTATUS */
    647 # ifdef VPAGE
    648     s[C_PAGE]	= td->c_cc[VPAGE];
    649 # endif /* VPAGE */
    650 # ifdef VPGOFF
    651     s[C_PGOFF]	= td->c_cc[VPGOFF];
    652 # endif /* VPGOFF */
    653 # ifdef VKILL2
    654     s[C_KILL2]	= td->c_cc[VKILL2];
    655 # endif /* KILL2 */
    656 # ifdef VMIN
    657     s[C_MIN]	= td->c_cc[VMIN];
    658 # endif /* VMIN */
    659 # ifdef VTIME
    660     s[C_TIME]	= td->c_cc[VTIME];
    661 # endif /* VTIME */
    662 } /* tty__getchar */
    663 
    664 
    665 /* tty__setchar():
    666  *	Set the tty characters
    667  */
    668 private void
    669 tty__setchar(td, s)
    670     struct termios *td;
    671     unsigned char *s;
    672 {
    673 # ifdef VINTR
    674     td->c_cc[VINTR]	= s[C_INTR];
    675 # endif /* VINTR */
    676 # ifdef VQUIT
    677     td->c_cc[VQUIT]	= s[C_QUIT];
    678 # endif /* VQUIT */
    679 # ifdef VERASE
    680     td->c_cc[VERASE]	= s[C_ERASE];
    681 # endif /* VERASE */
    682 # ifdef VKILL
    683     td->c_cc[VKILL]	= s[C_KILL];
    684 # endif /* VKILL */
    685 # ifdef VEOF
    686     td->c_cc[VEOF]	= s[C_EOF];
    687 # endif /* VEOF */
    688 # ifdef VEOL
    689     td->c_cc[VEOL]	= s[C_EOL];
    690 # endif /* VEOL */
    691 # ifdef VEOL2
    692     td->c_cc[VEOL2]	= s[C_EOL2];
    693 # endif  /* VEOL2 */
    694 # ifdef VSWTCH
    695     td->c_cc[VSWTCH]	= s[C_SWTCH];
    696 # endif /* VSWTCH */
    697 # ifdef VDSWTCH
    698     td->c_cc[VDSWTCH]	= s[C_DSWTCH];
    699 # endif /* VDSWTCH */
    700 # ifdef VERASE2
    701     td->c_cc[VERASE2]	= s[C_ERASE2];
    702 # endif /* VERASE2 */
    703 # ifdef VSTART
    704     td->c_cc[VSTART]	= s[C_START];
    705 # endif /* VSTART */
    706 # ifdef VSTOP
    707     td->c_cc[VSTOP]	= s[C_STOP];
    708 # endif /* VSTOP */
    709 # ifdef VWERASE
    710     td->c_cc[VWERASE]	= s[C_WERASE];
    711 # endif /* VWERASE */
    712 # ifdef VSUSP
    713     td->c_cc[VSUSP]	= s[C_SUSP];
    714 # endif /* VSUSP */
    715 # ifdef VDSUSP
    716     td->c_cc[VDSUSP]	= s[C_DSUSP];
    717 # endif /* VDSUSP */
    718 # ifdef VREPRINT
    719     td->c_cc[VREPRINT]	= s[C_REPRINT];
    720 # endif /* VREPRINT */
    721 # ifdef VDISCARD
    722     td->c_cc[VDISCARD]	= s[C_DISCARD];
    723 # endif /* VDISCARD */
    724 # ifdef VLNEXT
    725     td->c_cc[VLNEXT]	= s[C_LNEXT];
    726 # endif /* VLNEXT */
    727 # ifdef VSTATUS
    728     td->c_cc[VSTATUS]	= s[C_STATUS];
    729 # endif /* VSTATUS */
    730 # ifdef VPAGE
    731     td->c_cc[VPAGE]	= s[C_PAGE];
    732 # endif /* VPAGE */
    733 # ifdef VPGOFF
    734     td->c_cc[VPGOFF]	= s[C_PGOFF];
    735 # endif /* VPGOFF */
    736 # ifdef VKILL2
    737     td->c_cc[VKILL2]	= s[C_KILL2];
    738 # endif /* VKILL2 */
    739 # ifdef VMIN
    740     td->c_cc[VMIN]	= s[C_MIN];
    741 # endif /* VMIN */
    742 # ifdef VTIME
    743     td->c_cc[VTIME]	= s[C_TIME];
    744 # endif /* VTIME */
    745 } /* tty__setchar */
    746 
    747 
    748 /* tty_bind_char():
    749  *	Rebind the editline functions
    750  */
    751 protected void
    752 tty_bind_char(el, force)
    753     EditLine *el;
    754     int force;
    755 {
    756     unsigned char *t_n = el->el_tty.t_c[ED_IO];
    757     unsigned char *t_o = el->el_tty.t_ed.c_cc;
    758     char new[2], old[2];
    759     ttymap_t *tp;
    760     el_action_t  *dmap, *dalt, *map, *alt;
    761     new[1] = old[1] = '\0';
    762 
    763 
    764     map = el->el_map.key;
    765     alt = el->el_map.alt;
    766     if (el->el_map.type == MAP_VI) {
    767 	dmap = el->el_map.vii;
    768 	dalt = el->el_map.vic;
    769     }
    770     else {
    771 	dmap = el->el_map.emacs;
    772 	dalt = NULL;
    773     }
    774 
    775     for (tp = tty_map; tp->nch != -1; tp++) {
    776 	new[0] = t_n[tp->nch];
    777 	old[0] = t_o[tp->och];
    778 	if (new[0] == old[0] && !force)
    779 	    continue;
    780 	/* Put the old default binding back, and set the new binding */
    781 	key_clear(el, map, old);
    782 	map[old[0]] = dmap[old[0]];
    783 	key_clear(el, map, new);
    784 	/* MAP_VI == 1, MAP_EMACS == 0... */
    785 	map[new[0]] = tp->bind[el->el_map.type];
    786 	if (dalt) {
    787 	    key_clear(el, alt, old);
    788 	    alt[old[0]] = dalt[old[0]];
    789 	    key_clear(el, alt, new);
    790 	    alt[new[0]] = tp->bind[el->el_map.type+1];
    791 	}
    792     }
    793 }
    794 
    795 /* tty_rawmode():
    796  * 	Set terminal into 1 character at a time mode.
    797  */
    798 protected int
    799 tty_rawmode(el)
    800     EditLine *el;
    801 {
    802     if (el->el_tty.t_mode == ED_IO)
    803 	return (0);
    804 
    805     if (tty_getty(el, &el->el_tty.t_ts) == -1) {
    806 #ifdef DEBUG_TTY
    807 	(void) fprintf(el->el_errfile, "tty_rawmode: tty_getty: %s\n", strerror(errno));
    808 #endif /* DEBUG_TTY */
    809 	return(-1);
    810     }
    811 
    812     /*
    813      * We always keep up with the eight bit setting and the speed of the
    814      * tty. But only we only believe changes that are made to cooked mode!
    815      */
    816     el->el_tty.t_eight = tty__geteightbit(&el->el_tty.t_ts);
    817     el->el_tty.t_speed = tty__getspeed(&el->el_tty.t_ts);
    818 
    819     if (tty__getspeed(&el->el_tty.t_ex) != el->el_tty.t_speed ||
    820 	tty__getspeed(&el->el_tty.t_ed) != el->el_tty.t_speed) {
    821 	(void) cfsetispeed(&el->el_tty.t_ex, el->el_tty.t_speed);
    822 	(void) cfsetospeed(&el->el_tty.t_ex, el->el_tty.t_speed);
    823 	(void) cfsetispeed(&el->el_tty.t_ed, el->el_tty.t_speed);
    824 	(void) cfsetospeed(&el->el_tty.t_ed, el->el_tty.t_speed);
    825     }
    826 
    827     if (tty__cooked_mode(&el->el_tty.t_ts)) {
    828 	if (el->el_tty.t_ts.c_cflag != el->el_tty.t_ex.c_cflag) {
    829 	    el->el_tty.t_ex.c_cflag  = el->el_tty.t_ts.c_cflag;
    830 	    el->el_tty.t_ex.c_cflag &= ~el->el_tty.t_t[EX_IO][M_CTL].t_clrmask;
    831 	    el->el_tty.t_ex.c_cflag |=  el->el_tty.t_t[EX_IO][M_CTL].t_setmask;
    832 
    833 	    el->el_tty.t_ed.c_cflag  = el->el_tty.t_ts.c_cflag;
    834 	    el->el_tty.t_ed.c_cflag &= ~el->el_tty.t_t[ED_IO][M_CTL].t_clrmask;
    835 	    el->el_tty.t_ed.c_cflag |=  el->el_tty.t_t[ED_IO][M_CTL].t_setmask;
    836 	}
    837 
    838 	if ((el->el_tty.t_ts.c_lflag != el->el_tty.t_ex.c_lflag) &&
    839 	    (el->el_tty.t_ts.c_lflag != el->el_tty.t_ed.c_lflag)) {
    840 	    el->el_tty.t_ex.c_lflag = el->el_tty.t_ts.c_lflag;
    841 	    el->el_tty.t_ex.c_lflag &= ~el->el_tty.t_t[EX_IO][M_LIN].t_clrmask;
    842 	    el->el_tty.t_ex.c_lflag |=  el->el_tty.t_t[EX_IO][M_LIN].t_setmask;
    843 
    844 	    el->el_tty.t_ed.c_lflag = el->el_tty.t_ts.c_lflag;
    845 	    el->el_tty.t_ed.c_lflag &= ~el->el_tty.t_t[ED_IO][M_LIN].t_clrmask;
    846 	    el->el_tty.t_ed.c_lflag |=  el->el_tty.t_t[ED_IO][M_LIN].t_setmask;
    847 	}
    848 
    849 	if ((el->el_tty.t_ts.c_iflag != el->el_tty.t_ex.c_iflag) &&
    850 	    (el->el_tty.t_ts.c_iflag != el->el_tty.t_ed.c_iflag)) {
    851 	    el->el_tty.t_ex.c_iflag = el->el_tty.t_ts.c_iflag;
    852 	    el->el_tty.t_ex.c_iflag &= ~el->el_tty.t_t[EX_IO][M_INP].t_clrmask;
    853 	    el->el_tty.t_ex.c_iflag |=  el->el_tty.t_t[EX_IO][M_INP].t_setmask;
    854 
    855 	    el->el_tty.t_ed.c_iflag = el->el_tty.t_ts.c_iflag;
    856 	    el->el_tty.t_ed.c_iflag &= ~el->el_tty.t_t[ED_IO][M_INP].t_clrmask;
    857 	    el->el_tty.t_ed.c_iflag |=  el->el_tty.t_t[ED_IO][M_INP].t_setmask;
    858 	}
    859 
    860 	if ((el->el_tty.t_ts.c_oflag != el->el_tty.t_ex.c_oflag) &&
    861 	    (el->el_tty.t_ts.c_oflag != el->el_tty.t_ed.c_oflag)) {
    862 	    el->el_tty.t_ex.c_oflag = el->el_tty.t_ts.c_oflag;
    863 	    el->el_tty.t_ex.c_oflag &= ~el->el_tty.t_t[EX_IO][M_OUT].t_clrmask;
    864 	    el->el_tty.t_ex.c_oflag |=  el->el_tty.t_t[EX_IO][M_OUT].t_setmask;
    865 
    866 	    el->el_tty.t_ed.c_oflag = el->el_tty.t_ts.c_oflag;
    867 	    el->el_tty.t_ed.c_oflag &= ~el->el_tty.t_t[ED_IO][M_OUT].t_clrmask;
    868 	    el->el_tty.t_ed.c_oflag |=  el->el_tty.t_t[ED_IO][M_OUT].t_setmask;
    869 	}
    870 
    871 	if (tty__gettabs(&el->el_tty.t_ex) == 0)
    872 	    el->el_tty.t_tabs = 0;
    873 	else
    874 	    el->el_tty.t_tabs = EL_CAN_TAB ? 1 : 0;
    875 
    876 	{
    877 	    int i;
    878 
    879 	    tty__getchar(&el->el_tty.t_ts, el->el_tty.t_c[TS_IO]);
    880 	    /*
    881 	     * Check if the user made any changes.
    882 	     * If he did, then propagate the changes to the
    883 	     * edit and execute data structures.
    884 	     */
    885 	    for (i = 0; i < C_NCC; i++)
    886 		if (el->el_tty.t_c[TS_IO][i] != el->el_tty.t_c[EX_IO][i])
    887 		    break;
    888 
    889 	    if (i != C_NCC) {
    890 		/*
    891 		 * Propagate changes only to the unprotected chars
    892 		 * that have been modified just now.
    893 		 */
    894 		for (i = 0; i < C_NCC; i++) {
    895 		    if (!((el->el_tty.t_t[ED_IO][M_CHAR].t_setmask & C_SH(i)))
    896 		      && (el->el_tty.t_c[TS_IO][i] != el->el_tty.t_c[EX_IO][i]))
    897 			el->el_tty.t_c[ED_IO][i] = el->el_tty.t_c[TS_IO][i];
    898 		    if (el->el_tty.t_t[ED_IO][M_CHAR].t_clrmask & C_SH(i))
    899 			el->el_tty.t_c[ED_IO][i] = el->el_tty.t_vdisable;
    900 		}
    901 		tty_bind_char(el, 0);
    902 		tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]);
    903 
    904 		for (i = 0; i < C_NCC; i++) {
    905 		    if (!((el->el_tty.t_t[EX_IO][M_CHAR].t_setmask & C_SH(i)))
    906 		      && (el->el_tty.t_c[TS_IO][i] != el->el_tty.t_c[EX_IO][i]))
    907 			el->el_tty.t_c[EX_IO][i] = el->el_tty.t_c[TS_IO][i];
    908 		    if (el->el_tty.t_t[EX_IO][M_CHAR].t_clrmask & C_SH(i))
    909 			el->el_tty.t_c[EX_IO][i] = el->el_tty.t_vdisable;
    910 		}
    911 		tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]);
    912 	    }
    913 	}
    914     }
    915 
    916     if (tty_setty(el, &el->el_tty.t_ed) == -1) {
    917 #ifdef DEBUG_TTY
    918 	(void) fprintf(el->el_errfile, "tty_rawmode: tty_setty: %s\n",
    919 		       strerror(errno));
    920 #endif /* DEBUG_TTY */
    921 	return -1;
    922     }
    923     el->el_tty.t_mode = ED_IO;
    924     return (0);
    925 } /* end tty_rawmode */
    926 
    927 
    928 /* tty_cookedmode():
    929  *	Set the tty back to normal mode
    930  */
    931 protected int
    932 tty_cookedmode(el)
    933     EditLine *el;
    934 {				/* set tty in normal setup */
    935     if (el->el_tty.t_mode == EX_IO)
    936 	return (0);
    937 
    938     if (tty_setty(el, &el->el_tty.t_ex) == -1) {
    939 #ifdef DEBUG_TTY
    940 	(void) fprintf(el->el_errfile, "tty_cookedmode: tty_setty: %s\n",
    941 		       strerror(errno));
    942 #endif /* DEBUG_TTY */
    943 	return -1;
    944     }
    945     el->el_tty.t_mode = EX_IO;
    946     return (0);
    947 } /* end tty_cookedmode */
    948 
    949 
    950 /* tty_quotemode():
    951  *	Turn on quote mode
    952  */
    953 protected int
    954 tty_quotemode(el)
    955     EditLine *el;
    956 {
    957     if (el->el_tty.t_mode == QU_IO)
    958 	return 0;
    959 
    960     el->el_tty.t_qu = el->el_tty.t_ed;
    961 
    962     el->el_tty.t_qu.c_iflag &= ~el->el_tty.t_t[QU_IO][M_INP].t_clrmask;
    963     el->el_tty.t_qu.c_iflag |=  el->el_tty.t_t[QU_IO][M_INP].t_setmask;
    964 
    965     el->el_tty.t_qu.c_oflag &= ~el->el_tty.t_t[QU_IO][M_OUT].t_clrmask;
    966     el->el_tty.t_qu.c_oflag |=  el->el_tty.t_t[QU_IO][M_OUT].t_setmask;
    967 
    968     el->el_tty.t_qu.c_cflag &= ~el->el_tty.t_t[QU_IO][M_CTL].t_clrmask;
    969     el->el_tty.t_qu.c_cflag |=  el->el_tty.t_t[QU_IO][M_CTL].t_setmask;
    970 
    971     el->el_tty.t_qu.c_lflag &= ~el->el_tty.t_t[QU_IO][M_LIN].t_clrmask;
    972     el->el_tty.t_qu.c_lflag |=  el->el_tty.t_t[QU_IO][M_LIN].t_setmask;
    973 
    974     if (tty_setty(el, &el->el_tty.t_qu) == -1) {
    975 #ifdef DEBUG_TTY
    976 	(void) fprintf(el->el_errfile, "QuoteModeOn: tty_setty: %s\n",
    977 		       strerror(errno));
    978 #endif /* DEBUG_TTY */
    979 	return -1;
    980     }
    981     el->el_tty.t_mode = QU_IO;
    982     return 0;
    983 } /* end tty_quotemode */
    984 
    985 
    986 /* tty_noquotemode():
    987  *	Turn off quote mode
    988  */
    989 protected int
    990 tty_noquotemode(el)
    991     EditLine *el;
    992 {
    993     if (el->el_tty.t_mode != QU_IO)
    994 	return 0;
    995     if (tty_setty(el, &el->el_tty.t_ed) == -1) {
    996 #ifdef DEBUG_TTY
    997 	(void) fprintf(el->el_errfile, "QuoteModeOff: tty_setty: %s\n",
    998 		       strerror(errno));
    999 #endif /* DEBUG_TTY */
   1000 	return -1;
   1001     }
   1002     el->el_tty.t_mode = ED_IO;
   1003     return 0;
   1004 }
   1005 
   1006 /* tty_stty():
   1007  *	Stty builtin
   1008  */
   1009 protected int
   1010 /*ARGSUSED*/
   1011 tty_stty(el, argc, argv)
   1012     EditLine *el;
   1013     int argc;
   1014     char **argv;
   1015 {
   1016     ttymodes_t *m;
   1017     char x, *d;
   1018     int aflag = 0;
   1019     char *s;
   1020     char *name;
   1021     int z = EX_IO;
   1022 
   1023     if (argv == NULL)
   1024 	return -1;
   1025     name = *argv++;
   1026 
   1027     while (argv && *argv && argv[0][0] == '-' && argv[0][2] == '\0')
   1028 	switch (argv[0][1]) {
   1029 	case 'a':
   1030 	    aflag++;
   1031 	    argv++;
   1032 	    break;
   1033 	case 'd':
   1034 	    argv++;
   1035 	    z = ED_IO;
   1036 	    break;
   1037 	case 'x':
   1038 	    argv++;
   1039 	    z = EX_IO;
   1040 	    break;
   1041 	case 'q':
   1042 	    argv++;
   1043 	    z = QU_IO;
   1044 	    break;
   1045 	default:
   1046 	    (void) fprintf(el->el_errfile, "%s: Unknown switch `%c'.\n",
   1047 			   name, argv[0][1]);
   1048 	    return -1;
   1049 	}
   1050 
   1051     if (!argv || !*argv) {
   1052 	int i = -1;
   1053 	int len = 0, st = 0, cu;
   1054 	for (m = ttymodes; m->m_name; m++) {
   1055 	    if (m->m_type != i) {
   1056 		(void) fprintf(el->el_outfile, "%s%s", i != -1 ? "\n" : "",
   1057 			el->el_tty.t_t[z][m->m_type].t_name);
   1058 		i = m->m_type;
   1059 		st = len = strlen(el->el_tty.t_t[z][m->m_type].t_name);
   1060 	    }
   1061 
   1062 	    x = (el->el_tty.t_t[z][i].t_setmask & m->m_value) ? '+' : '\0';
   1063 	    x = (el->el_tty.t_t[z][i].t_clrmask & m->m_value) ? '-' : x;
   1064 
   1065 	    if (x != '\0' || aflag) {
   1066 
   1067 		cu = strlen(m->m_name) + (x != '\0') + 1;
   1068 
   1069 		if (len + cu >= el->el_term.t_size.h) {
   1070 		    (void) fprintf(el->el_outfile, "\n%*s", st, "");
   1071 		    len = st + cu;
   1072 		}
   1073 		else
   1074 		    len += cu;
   1075 
   1076 		if (x != '\0')
   1077 		    (void) fprintf(el->el_outfile, "%c%s ", x, m->m_name);
   1078 		else
   1079 		    (void) fprintf(el->el_outfile, "%s ", m->m_name);
   1080 	    }
   1081 	}
   1082 	(void) fprintf(el->el_outfile, "\n");
   1083 	return 0;
   1084     }
   1085 
   1086     while (argv && (s = *argv++)) {
   1087 	switch (*s) {
   1088 	case '+':
   1089 	case '-':
   1090 	    x = *s++;
   1091 	    break;
   1092 	default:
   1093 	    x = '\0';
   1094 	    break;
   1095 	}
   1096 	d = s;
   1097 	for (m = ttymodes; m->m_name; m++)
   1098 	    if (strcmp(m->m_name, d) == 0)
   1099 		break;
   1100 
   1101 	if (!m->m_name)  {
   1102 	    (void) fprintf(el->el_errfile, "%s: Invalid argument `%s'.\n",
   1103 			   name, d);
   1104 	    return -1;
   1105 	}
   1106 
   1107 	switch (x) {
   1108 	case '+':
   1109 	    el->el_tty.t_t[z][m->m_type].t_setmask |= m->m_value;
   1110 	    el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value;
   1111 	    break;
   1112 	case '-':
   1113 	    el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value;
   1114 	    el->el_tty.t_t[z][m->m_type].t_clrmask |= m->m_value;
   1115 	    break;
   1116 	default:
   1117 	    el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value;
   1118 	    el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value;
   1119 	    break;
   1120 	}
   1121     }
   1122     return 0;
   1123 } /* end tty_stty */
   1124 
   1125 
   1126 #ifdef notyet
   1127 /* tty_printchar():
   1128  *	DEbugging routine to print the tty characters
   1129  */
   1130 private void
   1131 tty_printchar(el, s)
   1132     EditLine *el;
   1133     unsigned char *s;
   1134 {
   1135     ttyperm_t *m;
   1136     int i;
   1137 
   1138     for (i = 0; i < C_NCC; i++) {
   1139 	for (m = el->el_tty.t_t; m->m_name; m++)
   1140 	    if (m->m_type == M_CHAR && C_SH(i) == m->m_value)
   1141 		break;
   1142 	if (m->m_name)
   1143 	    (void) fprintf(el->el_errfile, "%s ^%c ", m->m_name, s[i] + 'A'-1);
   1144 	if (i % 5 == 0)
   1145 	    (void) fprintf(el->el_errfile, "\n");
   1146     }
   1147     (void) fprintf(el->el_errfile, "\n");
   1148 }
   1149 #endif /* notyet */
   1150