xref: /netbsd-src/lib/libedit/tty.c (revision f5d3fbbc6ff4a77159fb268d247bd94cb7d7e332)
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