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