xref: /netbsd-src/lib/libedit/tty.c (revision 2a399c6883d870daece976daec6ffa7bb7f934ce)
1 /*	$NetBSD: tty.c,v 1.6 1997/10/20 08:07:56 scottr 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.6 1997/10/20 08:07:56 scottr 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 CDTRCTS
302     { "cdtrcts",CDTRCTS,M_CTL },
303 # endif /* CDTRCTS */
304 # ifdef MDMBUF
305     { "mdmbuf",	MDMBUF,	M_CTL },
306 # endif /* MDMBUF */
307 # ifdef RCV1EN
308     { "rcv1en",	RCV1EN,	M_CTL },
309 # endif /* RCV1EN */
310 # ifdef XMT1EN
311     { "xmt1en",	XMT1EN,	M_CTL },
312 # endif /* XMT1EN */
313 
314 # ifdef	ISIG
315     { "isig",	ISIG,	M_LIN },
316 # endif /* ISIG */
317 # ifdef	ICANON
318     { "icanon",	ICANON,	M_LIN },
319 # endif /* ICANON */
320 # ifdef	XCASE
321     { "xcase",	XCASE,	M_LIN },
322 # endif /* XCASE */
323 # ifdef	ECHO
324     { "echo",	ECHO,	M_LIN },
325 # endif /* ECHO */
326 # ifdef	ECHOE
327     { "echoe",	ECHOE,	M_LIN },
328 # endif /* ECHOE */
329 # ifdef	ECHOK
330     { "echok",	ECHOK,	M_LIN },
331 # endif /* ECHOK */
332 # ifdef	ECHONL
333     { "echonl",	ECHONL,	M_LIN },
334 # endif /* ECHONL */
335 # ifdef	NOFLSH
336     { "noflsh",	NOFLSH,	M_LIN },
337 # endif /* NOFLSH */
338 # ifdef	TOSTOP
339     { "tostop",	TOSTOP,	M_LIN },
340 # endif /* TOSTOP */
341 # ifdef	ECHOCTL
342     { "echoctl",ECHOCTL,M_LIN },
343 # endif /* ECHOCTL */
344 # ifdef	ECHOPRT
345     { "echoprt",ECHOPRT,M_LIN },
346 # endif /* ECHOPRT */
347 # ifdef	ECHOKE
348     { "echoke",	ECHOKE,	M_LIN },
349 # endif /* ECHOKE */
350 # ifdef	DEFECHO
351     { "defecho",DEFECHO,M_LIN },
352 # endif /* DEFECHO */
353 # ifdef	FLUSHO
354     { "flusho",	FLUSHO,	M_LIN },
355 # endif /* FLUSHO */
356 # ifdef	PENDIN
357     { "pendin",	PENDIN,	M_LIN },
358 # endif /* PENDIN */
359 # ifdef	IEXTEN
360     { "iexten",	IEXTEN,	M_LIN },
361 # endif /* IEXTEN */
362 # ifdef	NOKERNINFO
363     { "nokerninfo",NOKERNINFO,M_LIN },
364 # endif /* NOKERNINFO */
365 # ifdef	ALTWERASE
366     { "altwerase",ALTWERASE,M_LIN },
367 # endif /* ALTWERASE */
368 # ifdef	EXTPROC
369     { "extproc",EXTPROC, M_LIN },
370 # endif /* EXTPROC */
371 
372 # if defined(VINTR)
373     { "intr",		C_SH(C_INTR), 	M_CHAR },
374 # endif /* VINTR */
375 # if defined(VQUIT)
376     { "quit",		C_SH(C_QUIT), 	M_CHAR },
377 # endif /* VQUIT */
378 # if defined(VERASE)
379     { "erase",		C_SH(C_ERASE), 	M_CHAR },
380 # endif /* VERASE */
381 # if defined(VKILL)
382     { "kill",		C_SH(C_KILL), 	M_CHAR },
383 # endif /* VKILL */
384 # if defined(VEOF)
385     { "eof",		C_SH(C_EOF), 	M_CHAR },
386 # endif /* VEOF */
387 # if defined(VEOL)
388     { "eol",		C_SH(C_EOL), 	M_CHAR },
389 # endif /* VEOL */
390 # if defined(VEOL2)
391     { "eol2",		C_SH(C_EOL2), 	M_CHAR },
392 # endif  /* VEOL2 */
393 # if defined(VSWTCH)
394     { "swtch",		C_SH(C_SWTCH), 	M_CHAR },
395 # endif /* VSWTCH */
396 # if defined(VDSWTCH)
397     { "dswtch",		C_SH(C_DSWTCH),	M_CHAR },
398 # endif /* VDSWTCH */
399 # if defined(VERASE2)
400     { "erase2",		C_SH(C_ERASE2),	M_CHAR },
401 # endif /* VERASE2 */
402 # if defined(VSTART)
403     { "start",		C_SH(C_START), 	M_CHAR },
404 # endif /* VSTART */
405 # if defined(VSTOP)
406     { "stop",		C_SH(C_STOP), 	M_CHAR },
407 # endif /* VSTOP */
408 # if defined(VWERASE)
409     { "werase",		C_SH(C_WERASE),	M_CHAR },
410 # endif /* VWERASE */
411 # if defined(VSUSP)
412     { "susp",		C_SH(C_SUSP), 	M_CHAR },
413 # endif /* VSUSP */
414 # if defined(VDSUSP)
415     { "dsusp",		C_SH(C_DSUSP), 	M_CHAR },
416 # endif /* VDSUSP */
417 # if defined(VREPRINT)
418     { "reprint",	C_SH(C_REPRINT),M_CHAR },
419 # endif /* VREPRINT */
420 # if defined(VDISCARD)
421     { "discard",	C_SH(C_DISCARD),M_CHAR },
422 # endif /* VDISCARD */
423 # if defined(VLNEXT)
424     { "lnext",		C_SH(C_LNEXT), 	M_CHAR },
425 # endif /* VLNEXT */
426 # if defined(VSTATUS)
427     { "status",		C_SH(C_STATUS),	M_CHAR },
428 # endif /* VSTATUS */
429 # if defined(VPAGE)
430     { "page",		C_SH(C_PAGE), 	M_CHAR },
431 # endif /* VPAGE */
432 # if defined(VPGOFF)
433     { "pgoff",		C_SH(C_PGOFF), 	M_CHAR },
434 # endif /* VPGOFF */
435 # if defined(VKILL2)
436     { "kill2",		C_SH(C_KILL2), 	M_CHAR },
437 # endif /* VKILL2 */
438 # if defined(VBRK)
439     { "brk",		C_SH(C_BRK), 	M_CHAR },
440 # endif /* VBRK */
441 # if defined(VMIN)
442     { "min",		C_SH(C_MIN), 	M_CHAR },
443 # endif /* VMIN */
444 # if defined(VTIME)
445     { "time",		C_SH(C_TIME), 	M_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][M_INP].t_clrmask;
489     el->el_tty.t_ex.c_iflag |=  el->el_tty.t_t[EX_IO][M_INP].t_setmask;
490 
491     el->el_tty.t_ex.c_oflag &= ~el->el_tty.t_t[EX_IO][M_OUT].t_clrmask;
492     el->el_tty.t_ex.c_oflag |=  el->el_tty.t_t[EX_IO][M_OUT].t_setmask;
493 
494     el->el_tty.t_ex.c_cflag &= ~el->el_tty.t_t[EX_IO][M_CTL].t_clrmask;
495     el->el_tty.t_ex.c_cflag |=  el->el_tty.t_t[EX_IO][M_CTL].t_setmask;
496 
497     el->el_tty.t_ex.c_lflag &= ~el->el_tty.t_t[EX_IO][M_LIN].t_clrmask;
498     el->el_tty.t_ex.c_lflag |=  el->el_tty.t_t[EX_IO][M_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][M_INP].t_clrmask;
531     el->el_tty.t_ed.c_iflag |=  el->el_tty.t_t[ED_IO][M_INP].t_setmask;
532 
533     el->el_tty.t_ed.c_oflag &= ~el->el_tty.t_t[ED_IO][M_OUT].t_clrmask;
534     el->el_tty.t_ed.c_oflag |=  el->el_tty.t_t[ED_IO][M_OUT].t_setmask;
535 
536     el->el_tty.t_ed.c_cflag &= ~el->el_tty.t_t[ED_IO][M_CTL].t_clrmask;
537     el->el_tty.t_ed.c_cflag |=  el->el_tty.t_t[ED_IO][M_CTL].t_setmask;
538 
539     el->el_tty.t_ed.c_lflag &= ~el->el_tty.t_t[ED_IO][M_LIN].t_clrmask;
540     el->el_tty.t_ed.c_lflag |=  el->el_tty.t_t[ED_IO][M_LIN].t_setmask;
541 
542     tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]);
543     return 0;
544 }
545 
546 protected int
547 tty_init(el)
548     EditLine *el;
549 {
550     el->el_tty.t_mode     = EX_IO;
551     el->el_tty.t_vdisable = _POSIX_VDISABLE;
552     (void) memcpy(el->el_tty.t_t, ttyperm, sizeof(ttyperm_t));
553     (void) memcpy(el->el_tty.t_c, ttychar, sizeof(ttychar_t));
554     return tty_setup(el);
555 } /* end tty_init */
556 
557 
558 /* tty_end():
559  *	Restore the tty to its original settings
560  */
561 protected void
562 /*ARGSUSED*/
563 tty_end(el)
564     EditLine *el;
565 {
566     /* XXX: Maybe reset to an initial state? */
567 }
568 
569 
570 /* tty__getspeed():
571  *	Get the tty speed
572  */
573 private speed_t
574 tty__getspeed(td)
575     struct termios *td;
576 {
577     speed_t spd;
578 
579     if ((spd = cfgetispeed(td)) == 0)
580 	spd = cfgetospeed(td);
581     return spd;
582 } /* end tty__getspeed */
583 
584 
585 /* tty__getchar():
586  *	Get the tty characters
587  */
588 private void
589 tty__getchar(td, s)
590     struct termios *td;
591     unsigned char *s;
592 {
593 # ifdef VINTR
594     s[C_INTR]	= td->c_cc[VINTR];
595 # endif /* VINTR */
596 # ifdef VQUIT
597     s[C_QUIT]	= td->c_cc[VQUIT];
598 # endif /* VQUIT */
599 # ifdef VERASE
600     s[C_ERASE]	= td->c_cc[VERASE];
601 # endif /* VERASE */
602 # ifdef VKILL
603     s[C_KILL]	= td->c_cc[VKILL];
604 # endif /* VKILL */
605 # ifdef VEOF
606     s[C_EOF]	= td->c_cc[VEOF];
607 # endif /* VEOF */
608 # ifdef VEOL
609     s[C_EOL]	= td->c_cc[VEOL];
610 # endif /* VEOL */
611 # ifdef VEOL2
612     s[C_EOL2]	= td->c_cc[VEOL2];
613 # endif  /* VEOL2 */
614 # ifdef VSWTCH
615     s[C_SWTCH]	= td->c_cc[VSWTCH];
616 # endif /* VSWTCH */
617 # ifdef VDSWTCH
618     s[C_DSWTCH]	= td->c_cc[VDSWTCH];
619 # endif /* VDSWTCH */
620 # ifdef VERASE2
621     s[C_ERASE2]	= td->c_cc[VERASE2];
622 # endif /* VERASE2 */
623 # ifdef VSTART
624     s[C_START]	= td->c_cc[VSTART];
625 # endif /* VSTART */
626 # ifdef VSTOP
627     s[C_STOP]	= td->c_cc[VSTOP];
628 # endif /* VSTOP */
629 # ifdef VWERASE
630     s[C_WERASE]	= td->c_cc[VWERASE];
631 # endif /* VWERASE */
632 # ifdef VSUSP
633     s[C_SUSP]	= td->c_cc[VSUSP];
634 # endif /* VSUSP */
635 # ifdef VDSUSP
636     s[C_DSUSP]	= td->c_cc[VDSUSP];
637 # endif /* VDSUSP */
638 # ifdef VREPRINT
639     s[C_REPRINT]= td->c_cc[VREPRINT];
640 # endif /* VREPRINT */
641 # ifdef VDISCARD
642     s[C_DISCARD]= td->c_cc[VDISCARD];
643 # endif /* VDISCARD */
644 # ifdef VLNEXT
645     s[C_LNEXT]	= td->c_cc[VLNEXT];
646 # endif /* VLNEXT */
647 # ifdef VSTATUS
648     s[C_STATUS]	= td->c_cc[VSTATUS];
649 # endif /* VSTATUS */
650 # ifdef VPAGE
651     s[C_PAGE]	= td->c_cc[VPAGE];
652 # endif /* VPAGE */
653 # ifdef VPGOFF
654     s[C_PGOFF]	= td->c_cc[VPGOFF];
655 # endif /* VPGOFF */
656 # ifdef VKILL2
657     s[C_KILL2]	= td->c_cc[VKILL2];
658 # endif /* KILL2 */
659 # ifdef VMIN
660     s[C_MIN]	= td->c_cc[VMIN];
661 # endif /* VMIN */
662 # ifdef VTIME
663     s[C_TIME]	= td->c_cc[VTIME];
664 # endif /* VTIME */
665 } /* tty__getchar */
666 
667 
668 /* tty__setchar():
669  *	Set the tty characters
670  */
671 private void
672 tty__setchar(td, s)
673     struct termios *td;
674     unsigned char *s;
675 {
676 # ifdef VINTR
677     td->c_cc[VINTR]	= s[C_INTR];
678 # endif /* VINTR */
679 # ifdef VQUIT
680     td->c_cc[VQUIT]	= s[C_QUIT];
681 # endif /* VQUIT */
682 # ifdef VERASE
683     td->c_cc[VERASE]	= s[C_ERASE];
684 # endif /* VERASE */
685 # ifdef VKILL
686     td->c_cc[VKILL]	= s[C_KILL];
687 # endif /* VKILL */
688 # ifdef VEOF
689     td->c_cc[VEOF]	= s[C_EOF];
690 # endif /* VEOF */
691 # ifdef VEOL
692     td->c_cc[VEOL]	= s[C_EOL];
693 # endif /* VEOL */
694 # ifdef VEOL2
695     td->c_cc[VEOL2]	= s[C_EOL2];
696 # endif  /* VEOL2 */
697 # ifdef VSWTCH
698     td->c_cc[VSWTCH]	= s[C_SWTCH];
699 # endif /* VSWTCH */
700 # ifdef VDSWTCH
701     td->c_cc[VDSWTCH]	= s[C_DSWTCH];
702 # endif /* VDSWTCH */
703 # ifdef VERASE2
704     td->c_cc[VERASE2]	= s[C_ERASE2];
705 # endif /* VERASE2 */
706 # ifdef VSTART
707     td->c_cc[VSTART]	= s[C_START];
708 # endif /* VSTART */
709 # ifdef VSTOP
710     td->c_cc[VSTOP]	= s[C_STOP];
711 # endif /* VSTOP */
712 # ifdef VWERASE
713     td->c_cc[VWERASE]	= s[C_WERASE];
714 # endif /* VWERASE */
715 # ifdef VSUSP
716     td->c_cc[VSUSP]	= s[C_SUSP];
717 # endif /* VSUSP */
718 # ifdef VDSUSP
719     td->c_cc[VDSUSP]	= s[C_DSUSP];
720 # endif /* VDSUSP */
721 # ifdef VREPRINT
722     td->c_cc[VREPRINT]	= s[C_REPRINT];
723 # endif /* VREPRINT */
724 # ifdef VDISCARD
725     td->c_cc[VDISCARD]	= s[C_DISCARD];
726 # endif /* VDISCARD */
727 # ifdef VLNEXT
728     td->c_cc[VLNEXT]	= s[C_LNEXT];
729 # endif /* VLNEXT */
730 # ifdef VSTATUS
731     td->c_cc[VSTATUS]	= s[C_STATUS];
732 # endif /* VSTATUS */
733 # ifdef VPAGE
734     td->c_cc[VPAGE]	= s[C_PAGE];
735 # endif /* VPAGE */
736 # ifdef VPGOFF
737     td->c_cc[VPGOFF]	= s[C_PGOFF];
738 # endif /* VPGOFF */
739 # ifdef VKILL2
740     td->c_cc[VKILL2]	= s[C_KILL2];
741 # endif /* VKILL2 */
742 # ifdef VMIN
743     td->c_cc[VMIN]	= s[C_MIN];
744 # endif /* VMIN */
745 # ifdef VTIME
746     td->c_cc[VTIME]	= s[C_TIME];
747 # endif /* VTIME */
748 } /* tty__setchar */
749 
750 
751 /* tty_bind_char():
752  *	Rebind the editline functions
753  */
754 protected void
755 tty_bind_char(el, force)
756     EditLine *el;
757     int force;
758 {
759     unsigned char *t_n = el->el_tty.t_c[ED_IO];
760     unsigned char *t_o = el->el_tty.t_ed.c_cc;
761     char new[2], old[2];
762     ttymap_t *tp;
763     el_action_t  *dmap, *dalt, *map, *alt;
764     new[1] = old[1] = '\0';
765 
766 
767     map = el->el_map.key;
768     alt = el->el_map.alt;
769     if (el->el_map.type == MAP_VI) {
770 	dmap = el->el_map.vii;
771 	dalt = el->el_map.vic;
772     }
773     else {
774 	dmap = el->el_map.emacs;
775 	dalt = NULL;
776     }
777 
778     for (tp = tty_map; tp->nch != -1; tp++) {
779 	new[0] = t_n[tp->nch];
780 	old[0] = t_o[tp->och];
781 	if (new[0] == old[0] && !force)
782 	    continue;
783 	/* Put the old default binding back, and set the new binding */
784 	key_clear(el, map, old);
785 	map[old[0]] = dmap[old[0]];
786 	key_clear(el, map, new);
787 	/* MAP_VI == 1, MAP_EMACS == 0... */
788 	map[new[0]] = tp->bind[el->el_map.type];
789 	if (dalt) {
790 	    key_clear(el, alt, old);
791 	    alt[old[0]] = dalt[old[0]];
792 	    key_clear(el, alt, new);
793 	    alt[new[0]] = tp->bind[el->el_map.type+1];
794 	}
795     }
796 }
797 
798 /* tty_rawmode():
799  * 	Set terminal into 1 character at a time mode.
800  */
801 protected int
802 tty_rawmode(el)
803     EditLine *el;
804 {
805     if (el->el_tty.t_mode == ED_IO)
806 	return (0);
807 
808     if (tty_getty(el, &el->el_tty.t_ts) == -1) {
809 #ifdef DEBUG_TTY
810 	(void) fprintf(el->el_errfile, "tty_rawmode: tty_getty: %s\n", strerror(errno));
811 #endif /* DEBUG_TTY */
812 	return(-1);
813     }
814 
815     /*
816      * We always keep up with the eight bit setting and the speed of the
817      * tty. But only we only believe changes that are made to cooked mode!
818      */
819     el->el_tty.t_eight = tty__geteightbit(&el->el_tty.t_ts);
820     el->el_tty.t_speed = tty__getspeed(&el->el_tty.t_ts);
821 
822     if (tty__getspeed(&el->el_tty.t_ex) != el->el_tty.t_speed ||
823 	tty__getspeed(&el->el_tty.t_ed) != el->el_tty.t_speed) {
824 	(void) cfsetispeed(&el->el_tty.t_ex, el->el_tty.t_speed);
825 	(void) cfsetospeed(&el->el_tty.t_ex, el->el_tty.t_speed);
826 	(void) cfsetispeed(&el->el_tty.t_ed, el->el_tty.t_speed);
827 	(void) cfsetospeed(&el->el_tty.t_ed, el->el_tty.t_speed);
828     }
829 
830     if (tty__cooked_mode(&el->el_tty.t_ts)) {
831 	if (el->el_tty.t_ts.c_cflag != el->el_tty.t_ex.c_cflag) {
832 	    el->el_tty.t_ex.c_cflag  = el->el_tty.t_ts.c_cflag;
833 	    el->el_tty.t_ex.c_cflag &= ~el->el_tty.t_t[EX_IO][M_CTL].t_clrmask;
834 	    el->el_tty.t_ex.c_cflag |=  el->el_tty.t_t[EX_IO][M_CTL].t_setmask;
835 
836 	    el->el_tty.t_ed.c_cflag  = el->el_tty.t_ts.c_cflag;
837 	    el->el_tty.t_ed.c_cflag &= ~el->el_tty.t_t[ED_IO][M_CTL].t_clrmask;
838 	    el->el_tty.t_ed.c_cflag |=  el->el_tty.t_t[ED_IO][M_CTL].t_setmask;
839 	}
840 
841 	if ((el->el_tty.t_ts.c_lflag != el->el_tty.t_ex.c_lflag) &&
842 	    (el->el_tty.t_ts.c_lflag != el->el_tty.t_ed.c_lflag)) {
843 	    el->el_tty.t_ex.c_lflag = el->el_tty.t_ts.c_lflag;
844 	    el->el_tty.t_ex.c_lflag &= ~el->el_tty.t_t[EX_IO][M_LIN].t_clrmask;
845 	    el->el_tty.t_ex.c_lflag |=  el->el_tty.t_t[EX_IO][M_LIN].t_setmask;
846 
847 	    el->el_tty.t_ed.c_lflag = el->el_tty.t_ts.c_lflag;
848 	    el->el_tty.t_ed.c_lflag &= ~el->el_tty.t_t[ED_IO][M_LIN].t_clrmask;
849 	    el->el_tty.t_ed.c_lflag |=  el->el_tty.t_t[ED_IO][M_LIN].t_setmask;
850 	}
851 
852 	if ((el->el_tty.t_ts.c_iflag != el->el_tty.t_ex.c_iflag) &&
853 	    (el->el_tty.t_ts.c_iflag != el->el_tty.t_ed.c_iflag)) {
854 	    el->el_tty.t_ex.c_iflag = el->el_tty.t_ts.c_iflag;
855 	    el->el_tty.t_ex.c_iflag &= ~el->el_tty.t_t[EX_IO][M_INP].t_clrmask;
856 	    el->el_tty.t_ex.c_iflag |=  el->el_tty.t_t[EX_IO][M_INP].t_setmask;
857 
858 	    el->el_tty.t_ed.c_iflag = el->el_tty.t_ts.c_iflag;
859 	    el->el_tty.t_ed.c_iflag &= ~el->el_tty.t_t[ED_IO][M_INP].t_clrmask;
860 	    el->el_tty.t_ed.c_iflag |=  el->el_tty.t_t[ED_IO][M_INP].t_setmask;
861 	}
862 
863 	if ((el->el_tty.t_ts.c_oflag != el->el_tty.t_ex.c_oflag) &&
864 	    (el->el_tty.t_ts.c_oflag != el->el_tty.t_ed.c_oflag)) {
865 	    el->el_tty.t_ex.c_oflag = el->el_tty.t_ts.c_oflag;
866 	    el->el_tty.t_ex.c_oflag &= ~el->el_tty.t_t[EX_IO][M_OUT].t_clrmask;
867 	    el->el_tty.t_ex.c_oflag |=  el->el_tty.t_t[EX_IO][M_OUT].t_setmask;
868 
869 	    el->el_tty.t_ed.c_oflag = el->el_tty.t_ts.c_oflag;
870 	    el->el_tty.t_ed.c_oflag &= ~el->el_tty.t_t[ED_IO][M_OUT].t_clrmask;
871 	    el->el_tty.t_ed.c_oflag |=  el->el_tty.t_t[ED_IO][M_OUT].t_setmask;
872 	}
873 
874 	if (tty__gettabs(&el->el_tty.t_ex) == 0)
875 	    el->el_tty.t_tabs = 0;
876 	else
877 	    el->el_tty.t_tabs = EL_CAN_TAB ? 1 : 0;
878 
879 	{
880 	    int i;
881 
882 	    tty__getchar(&el->el_tty.t_ts, el->el_tty.t_c[TS_IO]);
883 	    /*
884 	     * Check if the user made any changes.
885 	     * If he did, then propagate the changes to the
886 	     * edit and execute data structures.
887 	     */
888 	    for (i = 0; i < C_NCC; i++)
889 		if (el->el_tty.t_c[TS_IO][i] != el->el_tty.t_c[EX_IO][i])
890 		    break;
891 
892 	    if (i != C_NCC) {
893 		/*
894 		 * Propagate changes only to the unprotected chars
895 		 * that have been modified just now.
896 		 */
897 		for (i = 0; i < C_NCC; i++) {
898 		    if (!((el->el_tty.t_t[ED_IO][M_CHAR].t_setmask & C_SH(i)))
899 		      && (el->el_tty.t_c[TS_IO][i] != el->el_tty.t_c[EX_IO][i]))
900 			el->el_tty.t_c[ED_IO][i] = el->el_tty.t_c[TS_IO][i];
901 		    if (el->el_tty.t_t[ED_IO][M_CHAR].t_clrmask & C_SH(i))
902 			el->el_tty.t_c[ED_IO][i] = el->el_tty.t_vdisable;
903 		}
904 		tty_bind_char(el, 0);
905 		tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]);
906 
907 		for (i = 0; i < C_NCC; i++) {
908 		    if (!((el->el_tty.t_t[EX_IO][M_CHAR].t_setmask & C_SH(i)))
909 		      && (el->el_tty.t_c[TS_IO][i] != el->el_tty.t_c[EX_IO][i]))
910 			el->el_tty.t_c[EX_IO][i] = el->el_tty.t_c[TS_IO][i];
911 		    if (el->el_tty.t_t[EX_IO][M_CHAR].t_clrmask & C_SH(i))
912 			el->el_tty.t_c[EX_IO][i] = el->el_tty.t_vdisable;
913 		}
914 		tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]);
915 	    }
916 	}
917     }
918 
919     if (tty_setty(el, &el->el_tty.t_ed) == -1) {
920 #ifdef DEBUG_TTY
921 	(void) fprintf(el->el_errfile, "tty_rawmode: tty_setty: %s\n",
922 		       strerror(errno));
923 #endif /* DEBUG_TTY */
924 	return -1;
925     }
926     el->el_tty.t_mode = ED_IO;
927     return (0);
928 } /* end tty_rawmode */
929 
930 
931 /* tty_cookedmode():
932  *	Set the tty back to normal mode
933  */
934 protected int
935 tty_cookedmode(el)
936     EditLine *el;
937 {				/* set tty in normal setup */
938     if (el->el_tty.t_mode == EX_IO)
939 	return (0);
940 
941     if (tty_setty(el, &el->el_tty.t_ex) == -1) {
942 #ifdef DEBUG_TTY
943 	(void) fprintf(el->el_errfile, "tty_cookedmode: tty_setty: %s\n",
944 		       strerror(errno));
945 #endif /* DEBUG_TTY */
946 	return -1;
947     }
948     el->el_tty.t_mode = EX_IO;
949     return (0);
950 } /* end tty_cookedmode */
951 
952 
953 /* tty_quotemode():
954  *	Turn on quote mode
955  */
956 protected int
957 tty_quotemode(el)
958     EditLine *el;
959 {
960     if (el->el_tty.t_mode == QU_IO)
961 	return 0;
962 
963     el->el_tty.t_qu = el->el_tty.t_ed;
964 
965     el->el_tty.t_qu.c_iflag &= ~el->el_tty.t_t[QU_IO][M_INP].t_clrmask;
966     el->el_tty.t_qu.c_iflag |=  el->el_tty.t_t[QU_IO][M_INP].t_setmask;
967 
968     el->el_tty.t_qu.c_oflag &= ~el->el_tty.t_t[QU_IO][M_OUT].t_clrmask;
969     el->el_tty.t_qu.c_oflag |=  el->el_tty.t_t[QU_IO][M_OUT].t_setmask;
970 
971     el->el_tty.t_qu.c_cflag &= ~el->el_tty.t_t[QU_IO][M_CTL].t_clrmask;
972     el->el_tty.t_qu.c_cflag |=  el->el_tty.t_t[QU_IO][M_CTL].t_setmask;
973 
974     el->el_tty.t_qu.c_lflag &= ~el->el_tty.t_t[QU_IO][M_LIN].t_clrmask;
975     el->el_tty.t_qu.c_lflag |=  el->el_tty.t_t[QU_IO][M_LIN].t_setmask;
976 
977     if (tty_setty(el, &el->el_tty.t_qu) == -1) {
978 #ifdef DEBUG_TTY
979 	(void) fprintf(el->el_errfile, "QuoteModeOn: tty_setty: %s\n",
980 		       strerror(errno));
981 #endif /* DEBUG_TTY */
982 	return -1;
983     }
984     el->el_tty.t_mode = QU_IO;
985     return 0;
986 } /* end tty_quotemode */
987 
988 
989 /* tty_noquotemode():
990  *	Turn off quote mode
991  */
992 protected int
993 tty_noquotemode(el)
994     EditLine *el;
995 {
996     if (el->el_tty.t_mode != QU_IO)
997 	return 0;
998     if (tty_setty(el, &el->el_tty.t_ed) == -1) {
999 #ifdef DEBUG_TTY
1000 	(void) fprintf(el->el_errfile, "QuoteModeOff: tty_setty: %s\n",
1001 		       strerror(errno));
1002 #endif /* DEBUG_TTY */
1003 	return -1;
1004     }
1005     el->el_tty.t_mode = ED_IO;
1006     return 0;
1007 }
1008 
1009 /* tty_stty():
1010  *	Stty builtin
1011  */
1012 protected int
1013 /*ARGSUSED*/
1014 tty_stty(el, argc, argv)
1015     EditLine *el;
1016     int argc;
1017     char **argv;
1018 {
1019     ttymodes_t *m;
1020     char x, *d;
1021     int aflag = 0;
1022     char *s;
1023     char *name;
1024     int z = EX_IO;
1025 
1026     if (argv == NULL)
1027 	return -1;
1028     name = *argv++;
1029 
1030     while (argv && *argv && argv[0][0] == '-' && argv[0][2] == '\0')
1031 	switch (argv[0][1]) {
1032 	case 'a':
1033 	    aflag++;
1034 	    argv++;
1035 	    break;
1036 	case 'd':
1037 	    argv++;
1038 	    z = ED_IO;
1039 	    break;
1040 	case 'x':
1041 	    argv++;
1042 	    z = EX_IO;
1043 	    break;
1044 	case 'q':
1045 	    argv++;
1046 	    z = QU_IO;
1047 	    break;
1048 	default:
1049 	    (void) fprintf(el->el_errfile, "%s: Unknown switch `%c'.\n",
1050 			   name, argv[0][1]);
1051 	    return -1;
1052 	}
1053 
1054     if (!argv || !*argv) {
1055 	int i = -1;
1056 	int len = 0, st = 0, cu;
1057 	for (m = ttymodes; m->m_name; m++) {
1058 	    if (m->m_type != i) {
1059 		(void) fprintf(el->el_outfile, "%s%s", i != -1 ? "\n" : "",
1060 			el->el_tty.t_t[z][m->m_type].t_name);
1061 		i = m->m_type;
1062 		st = len = strlen(el->el_tty.t_t[z][m->m_type].t_name);
1063 	    }
1064 
1065 	    x = (el->el_tty.t_t[z][i].t_setmask & m->m_value) ? '+' : '\0';
1066 	    x = (el->el_tty.t_t[z][i].t_clrmask & m->m_value) ? '-' : x;
1067 
1068 	    if (x != '\0' || aflag) {
1069 
1070 		cu = strlen(m->m_name) + (x != '\0') + 1;
1071 
1072 		if (len + cu >= el->el_term.t_size.h) {
1073 		    (void) fprintf(el->el_outfile, "\n%*s", st, "");
1074 		    len = st + cu;
1075 		}
1076 		else
1077 		    len += cu;
1078 
1079 		if (x != '\0')
1080 		    (void) fprintf(el->el_outfile, "%c%s ", x, m->m_name);
1081 		else
1082 		    (void) fprintf(el->el_outfile, "%s ", m->m_name);
1083 	    }
1084 	}
1085 	(void) fprintf(el->el_outfile, "\n");
1086 	return 0;
1087     }
1088 
1089     while (argv && (s = *argv++)) {
1090 	switch (*s) {
1091 	case '+':
1092 	case '-':
1093 	    x = *s++;
1094 	    break;
1095 	default:
1096 	    x = '\0';
1097 	    break;
1098 	}
1099 	d = s;
1100 	for (m = ttymodes; m->m_name; m++)
1101 	    if (strcmp(m->m_name, d) == 0)
1102 		break;
1103 
1104 	if (!m->m_name)  {
1105 	    (void) fprintf(el->el_errfile, "%s: Invalid argument `%s'.\n",
1106 			   name, d);
1107 	    return -1;
1108 	}
1109 
1110 	switch (x) {
1111 	case '+':
1112 	    el->el_tty.t_t[z][m->m_type].t_setmask |= m->m_value;
1113 	    el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value;
1114 	    break;
1115 	case '-':
1116 	    el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value;
1117 	    el->el_tty.t_t[z][m->m_type].t_clrmask |= m->m_value;
1118 	    break;
1119 	default:
1120 	    el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value;
1121 	    el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value;
1122 	    break;
1123 	}
1124     }
1125     return 0;
1126 } /* end tty_stty */
1127 
1128 
1129 #ifdef notyet
1130 /* tty_printchar():
1131  *	DEbugging routine to print the tty characters
1132  */
1133 private void
1134 tty_printchar(el, s)
1135     EditLine *el;
1136     unsigned char *s;
1137 {
1138     ttyperm_t *m;
1139     int i;
1140 
1141     for (i = 0; i < C_NCC; i++) {
1142 	for (m = el->el_tty.t_t; m->m_name; m++)
1143 	    if (m->m_type == M_CHAR && C_SH(i) == m->m_value)
1144 		break;
1145 	if (m->m_name)
1146 	    (void) fprintf(el->el_errfile, "%s ^%c ", m->m_name, s[i] + 'A'-1);
1147 	if (i % 5 == 0)
1148 	    (void) fprintf(el->el_errfile, "\n");
1149     }
1150     (void) fprintf(el->el_errfile, "\n");
1151 }
1152 #endif /* notyet */
1153