xref: /netbsd-src/lib/libedit/tty.c (revision d0fed6c87ddc40a8bffa6f99e7433ddfc864dd83)
1 /*	$NetBSD: tty.c,v 1.3 1997/04/11 17:52:49 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 #if !defined(lint) && !defined(SCCSID)
40 #if 0
41 static char sccsid[] = "@(#)tty.c	8.1 (Berkeley) 6/4/93";
42 #else
43 static char rcsid[] = "$NetBSD: tty.c,v 1.3 1997/04/11 17:52:49 christos Exp $";
44 #endif
45 #endif /* not lint && not SCCSID */
46 
47 /*
48  * tty.c: tty interface stuff
49  */
50 #include "sys.h"
51 #include "tty.h"
52 #include "el.h"
53 
54 typedef struct ttymodes_t {
55     char *m_name;
56     u_int m_value;
57     int   m_type;
58 } ttymodes_t;
59 
60 typedef struct ttymap_t {
61     int nch, och;		 /* Internal and termio rep of chars */
62     el_action_t bind[3]; 	/* emacs, vi, and vi-cmd */
63 } ttymap_t;
64 
65 
66 private ttyperm_t ttyperm = {
67     {
68 	{ "iflag:", ICRNL, (INLCR|IGNCR) },
69 	{ "oflag:", (OPOST|ONLCR), ONLRET },
70 	{ "cflag:", 0, 0 },
71 	{ "lflag:", (ISIG|ICANON|ECHO|ECHOE|ECHOCTL|IEXTEN),
72 		    (NOFLSH|ECHONL|EXTPROC|FLUSHO) },
73 	{ "chars:", 	0, 0 },
74     },
75     {
76 	{ "iflag:", (INLCR|ICRNL), IGNCR },
77 	{ "oflag:", (OPOST|ONLCR), ONLRET },
78 	{ "cflag:", 0, 0 },
79 	{ "lflag:", ISIG,
80 		    (NOFLSH|ICANON|ECHO|ECHOK|ECHONL|EXTPROC|IEXTEN|FLUSHO) },
81 	{ "chars:", (C_SH(C_MIN)|C_SH(C_TIME)|C_SH(C_SWTCH)|C_SH(C_DSWTCH)|
82 		     C_SH(C_SUSP)|C_SH(C_DSUSP)|C_SH(C_EOL)|C_SH(C_DISCARD)|
83 		     C_SH(C_PGOFF)|C_SH(C_PAGE)|C_SH(C_STATUS)), 0 }
84     },
85     {
86 	{ "iflag:", 0, IXON | IXOFF },
87 	{ "oflag:", 0, 0 },
88 	{ "cflag:", 0, 0 },
89 	{ "lflag:", 0, ISIG | IEXTEN },
90 	{ "chars:", 0, 0 },
91     }
92 };
93 
94 private ttychar_t ttychar = {
95     {
96 	CINTR,		 CQUIT, 	 CERASE, 	   CKILL,
97 	CEOF, 		 CEOL, 		 CEOL2, 	   CSWTCH,
98 	CDSWTCH,	 CERASE2,	 CSTART, 	   CSTOP,
99 	CWERASE, 	 CSUSP, 	 CDSUSP, 	   CREPRINT,
100 	CDISCARD, 	 CLNEXT,	 CSTATUS,	   CPAGE,
101 	CPGOFF,		 CKILL2, 	 CBRK, 		   CMIN,
102 	CTIME
103     },
104     {
105 	CINTR, 		 CQUIT, 	  CERASE, 	   CKILL,
106 	_POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE,
107 	_POSIX_VDISABLE, CERASE2,	  CSTART, 	   CSTOP,
108 	_POSIX_VDISABLE, CSUSP,           _POSIX_VDISABLE, _POSIX_VDISABLE,
109 	CDISCARD, 	 _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE,
110 	_POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE, 1,
111 	0
112     },
113     {
114 	0,		 0,		  0,		   0,
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
121     }
122 };
123 
124 private ttymap_t tty_map[] = {
125 #ifdef VERASE
126 	{ C_ERASE,   VERASE,
127 	    { ED_DELETE_PREV_CHAR, VI_DELETE_PREV_CHAR, ED_PREV_CHAR } },
128 #endif /* VERASE */
129 #ifdef VERASE2
130 	{ C_ERASE2,  VERASE2,
131 	    { ED_DELETE_PREV_CHAR, VI_DELETE_PREV_CHAR, ED_PREV_CHAR } },
132 #endif /* VERASE2 */
133 #ifdef VKILL
134     	{ C_KILL,    VKILL,
135 	    { EM_KILL_LINE, VI_KILL_LINE_PREV, ED_UNASSIGNED } },
136 #endif /* VKILL */
137 #ifdef VKILL2
138     	{ C_KILL2,   VKILL2,
139 	    { EM_KILL_LINE, VI_KILL_LINE_PREV, ED_UNASSIGNED } },
140 #endif /* VKILL2 */
141 #ifdef VEOF
142     	{ C_EOF,     VEOF,
143 	    { EM_DELETE_OR_LIST, VI_LIST_OR_EOF, ED_UNASSIGNED } },
144 #endif /* VEOF */
145 #ifdef VWERASE
146     	{ C_WERASE,  VWERASE,
147 	    { ED_DELETE_PREV_WORD, ED_DELETE_PREV_WORD, ED_PREV_WORD } },
148 #endif /* VWERASE */
149 #ifdef VREPRINT
150    	{ C_REPRINT, VREPRINT,
151 	    { ED_REDISPLAY, ED_INSERT, ED_REDISPLAY } },
152 #endif /* VREPRINT */
153 #ifdef VLNEXT
154     	{ C_LNEXT,   VLNEXT,
155 	    { ED_QUOTED_INSERT, ED_QUOTED_INSERT, ED_UNASSIGNED } },
156 #endif /* VLNEXT */
157 	{ -1,	     -1,
158 	    { ED_UNASSIGNED, ED_UNASSIGNED, ED_UNASSIGNED } }
159     };
160 
161 private ttymodes_t ttymodes[] = {
162 # ifdef	IGNBRK
163     { "ignbrk",	IGNBRK,	M_INP },
164 # endif /* IGNBRK */
165 # ifdef	BRKINT
166     { "brkint",	BRKINT,	M_INP },
167 # endif /* BRKINT */
168 # ifdef	IGNPAR
169     { "ignpar",	IGNPAR,	M_INP },
170 # endif /* IGNPAR */
171 # ifdef	PARMRK
172     { "parmrk",	PARMRK,	M_INP },
173 # endif /* PARMRK */
174 # ifdef	INPCK
175     { "inpck",	INPCK,	M_INP },
176 # endif /* INPCK */
177 # ifdef	ISTRIP
178     { "istrip",	ISTRIP,	M_INP },
179 # endif /* ISTRIP */
180 # ifdef	INLCR
181     { "inlcr",	INLCR,	M_INP },
182 # endif /* INLCR */
183 # ifdef	IGNCR
184     { "igncr",	IGNCR,	M_INP },
185 # endif /* IGNCR */
186 # ifdef	ICRNL
187     { "icrnl",	ICRNL,	M_INP },
188 # endif /* ICRNL */
189 # ifdef	IUCLC
190     { "iuclc",	IUCLC,	M_INP },
191 # endif /* IUCLC */
192 # ifdef	IXON
193     { "ixon",	IXON,	M_INP },
194 # endif /* IXON */
195 # ifdef	IXANY
196     { "ixany",	IXANY,	M_INP },
197 # endif /* IXANY */
198 # ifdef	IXOFF
199     { "ixoff",	IXOFF,	M_INP },
200 # endif /* IXOFF */
201 # ifdef  IMAXBEL
202     { "imaxbel",IMAXBEL,M_INP },
203 # endif /* IMAXBEL */
204 
205 # ifdef	OPOST
206     { "opost",	OPOST,	M_OUT },
207 # endif /* OPOST */
208 # ifdef	OLCUC
209     { "olcuc",	OLCUC,	M_OUT },
210 # endif /* OLCUC */
211 # ifdef	ONLCR
212     { "onlcr",	ONLCR,	M_OUT },
213 # endif /* ONLCR */
214 # ifdef	OCRNL
215     { "ocrnl",	OCRNL,	M_OUT },
216 # endif /* OCRNL */
217 # ifdef	ONOCR
218     { "onocr",	ONOCR,	M_OUT },
219 # endif /* ONOCR */
220 # ifdef ONOEOT
221     { "onoeot",	ONOEOT,	M_OUT },
222 # endif /* ONOEOT */
223 # ifdef	ONLRET
224     { "onlret",	ONLRET,	M_OUT },
225 # endif /* ONLRET */
226 # ifdef	OFILL
227     { "ofill",	OFILL,	M_OUT },
228 # endif /* OFILL */
229 # ifdef	OFDEL
230     { "ofdel",	OFDEL,	M_OUT },
231 # endif /* OFDEL */
232 # ifdef	NLDLY
233     { "nldly",	NLDLY,	M_OUT },
234 # endif /* NLDLY */
235 # ifdef	CRDLY
236     { "crdly",	CRDLY,	M_OUT },
237 # endif /* CRDLY */
238 # ifdef	TABDLY
239     { "tabdly",	TABDLY,	M_OUT },
240 # endif /* TABDLY */
241 # ifdef	XTABS
242     { "xtabs",	XTABS,	M_OUT },
243 # endif /* XTABS */
244 # ifdef	BSDLY
245     { "bsdly",	BSDLY,	M_OUT },
246 # endif /* BSDLY */
247 # ifdef	VTDLY
248     { "vtdly",	VTDLY,	M_OUT },
249 # endif /* VTDLY */
250 # ifdef	FFDLY
251     { "ffdly",	FFDLY,	M_OUT },
252 # endif /* FFDLY */
253 # ifdef	PAGEOUT
254     { "pageout",PAGEOUT,M_OUT },
255 # endif /* PAGEOUT */
256 # ifdef	WRAP
257     { "wrap",	WRAP,	M_OUT },
258 # endif /* WRAP */
259 
260 # ifdef	CIGNORE
261     { "cignore",CIGNORE,M_CTL },
262 # endif /* CBAUD */
263 # ifdef	CBAUD
264     { "cbaud",	CBAUD,	M_CTL },
265 # endif /* CBAUD */
266 # ifdef	CSTOPB
267     { "cstopb",	CSTOPB,	M_CTL },
268 # endif /* CSTOPB */
269 # ifdef	CREAD
270     { "cread",	CREAD,	M_CTL },
271 # endif /* CREAD */
272 # ifdef	PARENB
273     { "parenb",	PARENB,	M_CTL },
274 # endif /* PARENB */
275 # ifdef	PARODD
276     { "parodd",	PARODD,	M_CTL },
277 # endif /* PARODD */
278 # ifdef	HUPCL
279     { "hupcl",	HUPCL,	M_CTL },
280 # endif /* HUPCL */
281 # ifdef	CLOCAL
282     { "clocal",	CLOCAL,	M_CTL },
283 # endif /* CLOCAL */
284 # ifdef	LOBLK
285     { "loblk",	LOBLK,	M_CTL },
286 # endif /* LOBLK */
287 # ifdef	CIBAUD
288     { "cibaud",	CIBAUD,	M_CTL },
289 # endif /* CIBAUD */
290 # ifdef CRTSCTS
291 #  ifdef CCTS_OFLOW
292     { "ccts_oflow",CCTS_OFLOW,M_CTL },
293 #  else
294     { "crtscts",CRTSCTS,M_CTL },
295 #  endif /* CCTS_OFLOW */
296 # endif /* CRTSCTS */
297 # ifdef CRTS_IFLOW
298     { "crts_iflow",CRTS_IFLOW,M_CTL },
299 # endif /* CRTS_IFLOW */
300 # ifdef MDMBUF
301     { "mdmbuf",	MDMBUF,	M_CTL },
302 # endif /* MDMBUF */
303 # ifdef RCV1EN
304     { "rcv1en",	RCV1EN,	M_CTL },
305 # endif /* RCV1EN */
306 # ifdef XMT1EN
307     { "xmt1en",	XMT1EN,	M_CTL },
308 # endif /* XMT1EN */
309 
310 # ifdef	ISIG
311     { "isig",	ISIG,	M_LIN },
312 # endif /* ISIG */
313 # ifdef	ICANON
314     { "icanon",	ICANON,	M_LIN },
315 # endif /* ICANON */
316 # ifdef	XCASE
317     { "xcase",	XCASE,	M_LIN },
318 # endif /* XCASE */
319 # ifdef	ECHO
320     { "echo",	ECHO,	M_LIN },
321 # endif /* ECHO */
322 # ifdef	ECHOE
323     { "echoe",	ECHOE,	M_LIN },
324 # endif /* ECHOE */
325 # ifdef	ECHOK
326     { "echok",	ECHOK,	M_LIN },
327 # endif /* ECHOK */
328 # ifdef	ECHONL
329     { "echonl",	ECHONL,	M_LIN },
330 # endif /* ECHONL */
331 # ifdef	NOFLSH
332     { "noflsh",	NOFLSH,	M_LIN },
333 # endif /* NOFLSH */
334 # ifdef	TOSTOP
335     { "tostop",	TOSTOP,	M_LIN },
336 # endif /* TOSTOP */
337 # ifdef	ECHOCTL
338     { "echoctl",ECHOCTL,M_LIN },
339 # endif /* ECHOCTL */
340 # ifdef	ECHOPRT
341     { "echoprt",ECHOPRT,M_LIN },
342 # endif /* ECHOPRT */
343 # ifdef	ECHOKE
344     { "echoke",	ECHOKE,	M_LIN },
345 # endif /* ECHOKE */
346 # ifdef	DEFECHO
347     { "defecho",DEFECHO,M_LIN },
348 # endif /* DEFECHO */
349 # ifdef	FLUSHO
350     { "flusho",	FLUSHO,	M_LIN },
351 # endif /* FLUSHO */
352 # ifdef	PENDIN
353     { "pendin",	PENDIN,	M_LIN },
354 # endif /* PENDIN */
355 # ifdef	IEXTEN
356     { "iexten",	IEXTEN,	M_LIN },
357 # endif /* IEXTEN */
358 # ifdef	NOKERNINFO
359     { "nokerninfo",NOKERNINFO,M_LIN },
360 # endif /* NOKERNINFO */
361 # ifdef	ALTWERASE
362     { "altwerase",ALTWERASE,M_LIN },
363 # endif /* ALTWERASE */
364 # ifdef	EXTPROC
365     { "extproc",EXTPROC, M_LIN },
366 # endif /* EXTPROC */
367 
368 # if defined(VINTR)
369     { "intr",		C_SH(C_INTR), 	M_CHAR },
370 # endif /* VINTR */
371 # if defined(VQUIT)
372     { "quit",		C_SH(C_QUIT), 	M_CHAR },
373 # endif /* VQUIT */
374 # if defined(VERASE)
375     { "erase",		C_SH(C_ERASE), 	M_CHAR },
376 # endif /* VERASE */
377 # if defined(VKILL)
378     { "kill",		C_SH(C_KILL), 	M_CHAR },
379 # endif /* VKILL */
380 # if defined(VEOF)
381     { "eof",		C_SH(C_EOF), 	M_CHAR },
382 # endif /* VEOF */
383 # if defined(VEOL)
384     { "eol",		C_SH(C_EOL), 	M_CHAR },
385 # endif /* VEOL */
386 # if defined(VEOL2)
387     { "eol2",		C_SH(C_EOL2), 	M_CHAR },
388 # endif  /* VEOL2 */
389 # if defined(VSWTCH)
390     { "swtch",		C_SH(C_SWTCH), 	M_CHAR },
391 # endif /* VSWTCH */
392 # if defined(VDSWTCH)
393     { "dswtch",		C_SH(C_DSWTCH),	M_CHAR },
394 # endif /* VDSWTCH */
395 # if defined(VERASE2)
396     { "erase2",		C_SH(C_ERASE2),	M_CHAR },
397 # endif /* VERASE2 */
398 # if defined(VSTART)
399     { "start",		C_SH(C_START), 	M_CHAR },
400 # endif /* VSTART */
401 # if defined(VSTOP)
402     { "stop",		C_SH(C_STOP), 	M_CHAR },
403 # endif /* VSTOP */
404 # if defined(VWERASE)
405     { "werase",		C_SH(C_WERASE),	M_CHAR },
406 # endif /* VWERASE */
407 # if defined(VSUSP)
408     { "susp",		C_SH(C_SUSP), 	M_CHAR },
409 # endif /* VSUSP */
410 # if defined(VDSUSP)
411     { "dsusp",		C_SH(C_DSUSP), 	M_CHAR },
412 # endif /* VDSUSP */
413 # if defined(VREPRINT)
414     { "reprint",	C_SH(C_REPRINT),M_CHAR },
415 # endif /* VREPRINT */
416 # if defined(VDISCARD)
417     { "discard",	C_SH(C_DISCARD),M_CHAR },
418 # endif /* VDISCARD */
419 # if defined(VLNEXT)
420     { "lnext",		C_SH(C_LNEXT), 	M_CHAR },
421 # endif /* VLNEXT */
422 # if defined(VSTATUS)
423     { "status",		C_SH(C_STATUS),	M_CHAR },
424 # endif /* VSTATUS */
425 # if defined(VPAGE)
426     { "page",		C_SH(C_PAGE), 	M_CHAR },
427 # endif /* VPAGE */
428 # if defined(VPGOFF)
429     { "pgoff",		C_SH(C_PGOFF), 	M_CHAR },
430 # endif /* VPGOFF */
431 # if defined(VKILL2)
432     { "kill2",		C_SH(C_KILL2), 	M_CHAR },
433 # endif /* VKILL2 */
434 # if defined(VBRK)
435     { "brk",		C_SH(C_BRK), 	M_CHAR },
436 # endif /* VBRK */
437 # if defined(VMIN)
438     { "min",		C_SH(C_MIN), 	M_CHAR },
439 # endif /* VMIN */
440 # if defined(VTIME)
441     { "time",		C_SH(C_TIME), 	M_CHAR },
442 # endif /* VTIME */
443     { NULL, 0, -1 },
444 };
445 
446 
447 
448 #define tty_getty(el, td) tcgetattr((el)->el_infd, (td))
449 #define tty_setty(el, td) tcsetattr((el)->el_infd, TCSADRAIN, (td))
450 
451 #define tty__gettabs(td)     ((((td)->c_oflag & TAB3) == TAB3) ? 0 : 1)
452 #define tty__geteightbit(td) (((td)->c_cflag & CSIZE) == CS8)
453 #define tty__cooked_mode(td) ((td)->c_lflag & ICANON)
454 
455 private void    tty__getchar	__P((struct termios *, unsigned char *));
456 private void    tty__setchar	__P((struct termios *, unsigned char *));
457 private speed_t tty__getspeed	__P((struct termios *));
458 private int     tty_setup	__P((EditLine *));
459 
460 #define t_qu t_ts
461 
462 
463 /* tty_setup():
464  *	Get the tty parameters and initialize the editing state
465  */
466 private int
467 tty_setup(el)
468     EditLine *el;
469 {
470     int rst = 1;
471     if (tty_getty(el, &el->el_tty.t_ed) == -1) {
472 #ifdef DEBUG_TTY
473 	(void) fprintf(el->el_errfile,
474 		       "tty_setup: tty_getty: %s\n", strerror(errno));
475 #endif /* DEBUG_TTY */
476 	return(-1);
477     }
478     el->el_tty.t_ts    = el->el_tty.t_ex = el->el_tty.t_ed;
479 
480     el->el_tty.t_speed = tty__getspeed(&el->el_tty.t_ex);
481     el->el_tty.t_tabs  = tty__gettabs(&el->el_tty.t_ex);
482     el->el_tty.t_eight = tty__geteightbit(&el->el_tty.t_ex);
483 
484     el->el_tty.t_ex.c_iflag &= ~el->el_tty.t_t[EX_IO][M_INP].t_clrmask;
485     el->el_tty.t_ex.c_iflag |=  el->el_tty.t_t[EX_IO][M_INP].t_setmask;
486 
487     el->el_tty.t_ex.c_oflag &= ~el->el_tty.t_t[EX_IO][M_OUT].t_clrmask;
488     el->el_tty.t_ex.c_oflag |=  el->el_tty.t_t[EX_IO][M_OUT].t_setmask;
489 
490     el->el_tty.t_ex.c_cflag &= ~el->el_tty.t_t[EX_IO][M_CTL].t_clrmask;
491     el->el_tty.t_ex.c_cflag |=  el->el_tty.t_t[EX_IO][M_CTL].t_setmask;
492 
493     el->el_tty.t_ex.c_lflag &= ~el->el_tty.t_t[EX_IO][M_LIN].t_clrmask;
494     el->el_tty.t_ex.c_lflag |=  el->el_tty.t_t[EX_IO][M_LIN].t_setmask;
495 
496     /*
497      * Reset the tty chars to reasonable defaults
498      * If they are disabled, then enable them.
499      */
500     if (rst) {
501         if (tty__cooked_mode(&el->el_tty.t_ts)) {
502             tty__getchar(&el->el_tty.t_ts, el->el_tty.t_c[TS_IO]);
503             /*
504              * Don't affect CMIN and CTIME for the editor mode
505              */
506             for (rst = 0; rst < C_NCC - 2; rst++)
507                 if (el->el_tty.t_c[TS_IO][rst] != el->el_tty.t_vdisable &&
508                     el->el_tty.t_c[ED_IO][rst] != el->el_tty.t_vdisable)
509                     el->el_tty.t_c[ED_IO][rst]  = el->el_tty.t_c[TS_IO][rst];
510             for (rst = 0; rst < C_NCC; rst++)
511                 if (el->el_tty.t_c[TS_IO][rst] != el->el_tty.t_vdisable &&
512                     el->el_tty.t_c[EX_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 
917     if (tty_setty(el, &el->el_tty.t_ed) == -1) {
918 #ifdef DEBUG_TTY
919 	(void) fprintf(el->el_errfile, "tty_rawmode: tty_setty: %s\n",
920 		       strerror(errno));
921 #endif /* DEBUG_TTY */
922 	return -1;
923     }
924     el->el_tty.t_mode = ED_IO;
925     return (0);
926 } /* end tty_rawmode */
927 
928 
929 /* tty_cookedmode():
930  *	Set the tty back to normal mode
931  */
932 protected int
933 tty_cookedmode(el)
934     EditLine *el;
935 {				/* set tty in normal setup */
936     if (el->el_tty.t_mode == EX_IO)
937 	return (0);
938 
939     if (tty_setty(el, &el->el_tty.t_ex) == -1) {
940 #ifdef DEBUG_TTY
941 	(void) fprintf(el->el_errfile, "tty_cookedmode: tty_setty: %s\n",
942 		       strerror(errno));
943 #endif /* DEBUG_TTY */
944 	return -1;
945     }
946     el->el_tty.t_mode = EX_IO;
947     return (0);
948 } /* end tty_cookedmode */
949 
950 
951 /* tty_quotemode():
952  *	Turn on quote mode
953  */
954 protected int
955 tty_quotemode(el)
956     EditLine *el;
957 {
958     if (el->el_tty.t_mode == QU_IO)
959 	return 0;
960 
961     el->el_tty.t_qu = el->el_tty.t_ed;
962 
963     el->el_tty.t_qu.c_iflag &= ~el->el_tty.t_t[QU_IO][M_INP].t_clrmask;
964     el->el_tty.t_qu.c_iflag |=  el->el_tty.t_t[QU_IO][M_INP].t_setmask;
965 
966     el->el_tty.t_qu.c_oflag &= ~el->el_tty.t_t[QU_IO][M_OUT].t_clrmask;
967     el->el_tty.t_qu.c_oflag |=  el->el_tty.t_t[QU_IO][M_OUT].t_setmask;
968 
969     el->el_tty.t_qu.c_cflag &= ~el->el_tty.t_t[QU_IO][M_CTL].t_clrmask;
970     el->el_tty.t_qu.c_cflag |=  el->el_tty.t_t[QU_IO][M_CTL].t_setmask;
971 
972     el->el_tty.t_qu.c_lflag &= ~el->el_tty.t_t[QU_IO][M_LIN].t_clrmask;
973     el->el_tty.t_qu.c_lflag |=  el->el_tty.t_t[QU_IO][M_LIN].t_setmask;
974 
975     if (tty_setty(el, &el->el_tty.t_qu) == -1) {
976 #ifdef DEBUG_TTY
977 	(void) fprintf(el->el_errfile, "QuoteModeOn: tty_setty: %s\n",
978 		       strerror(errno));
979 #endif /* DEBUG_TTY */
980 	return -1;
981     }
982     el->el_tty.t_mode = QU_IO;
983     return 0;
984 } /* end tty_quotemode */
985 
986 
987 /* tty_noquotemode():
988  *	Turn off quote mode
989  */
990 protected int
991 tty_noquotemode(el)
992     EditLine *el;
993 {
994     if (el->el_tty.t_mode != QU_IO)
995 	return 0;
996     if (tty_setty(el, &el->el_tty.t_ed) == -1) {
997 #ifdef DEBUG_TTY
998 	(void) fprintf(el->el_errfile, "QuoteModeOff: tty_setty: %s\n",
999 		       strerror(errno));
1000 #endif /* DEBUG_TTY */
1001 	return -1;
1002     }
1003     el->el_tty.t_mode = ED_IO;
1004     return 0;
1005 }
1006 
1007 /* tty_stty():
1008  *	Stty builtin
1009  */
1010 protected int
1011 /*ARGSUSED*/
1012 tty_stty(el, argc, argv)
1013     EditLine *el;
1014     int argc;
1015     char **argv;
1016 {
1017     ttymodes_t *m;
1018     char x, *d;
1019     int aflag = 0;
1020     char *s;
1021     char *name;
1022     int z = EX_IO;
1023 
1024     if (argv == NULL)
1025 	return -1;
1026     name = *argv++;
1027 
1028     while (argv && *argv && argv[0][0] == '-' && argv[0][2] == '\0')
1029 	switch (argv[0][1]) {
1030 	case 'a':
1031 	    aflag++;
1032 	    argv++;
1033 	    break;
1034 	case 'd':
1035 	    argv++;
1036 	    z = ED_IO;
1037 	    break;
1038 	case 'x':
1039 	    argv++;
1040 	    z = EX_IO;
1041 	    break;
1042 	case 'q':
1043 	    argv++;
1044 	    z = QU_IO;
1045 	    break;
1046 	default:
1047 	    (void) fprintf(el->el_errfile, "%s: Unknown switch `%c'.\n",
1048 			   name, argv[0][1]);
1049 	    return -1;
1050 	}
1051 
1052     if (!argv || !*argv) {
1053 	int i = -1;
1054 	int len = 0, st = 0, cu;
1055 	for (m = ttymodes; m->m_name; m++) {
1056 	    if (m->m_type != i) {
1057 		(void) fprintf(el->el_outfile, "%s%s", i != -1 ? "\n" : "",
1058 			el->el_tty.t_t[z][m->m_type].t_name);
1059 		i = m->m_type;
1060 		st = len = strlen(el->el_tty.t_t[z][m->m_type].t_name);
1061 	    }
1062 
1063 	    x = (el->el_tty.t_t[z][i].t_setmask & m->m_value) ? '+' : '\0';
1064 	    x = (el->el_tty.t_t[z][i].t_clrmask & m->m_value) ? '-' : x;
1065 
1066 	    if (x != '\0' || aflag) {
1067 
1068 		cu = strlen(m->m_name) + (x != '\0') + 1;
1069 
1070 		if (len + cu >= el->el_term.t_size.h) {
1071 		    (void) fprintf(el->el_outfile, "\n%*s", st, "");
1072 		    len = st + cu;
1073 		}
1074 		else
1075 		    len += cu;
1076 
1077 		if (x != '\0')
1078 		    (void) fprintf(el->el_outfile, "%c%s ", x, m->m_name);
1079 		else
1080 		    (void) fprintf(el->el_outfile, "%s ", m->m_name);
1081 	    }
1082 	}
1083 	(void) fprintf(el->el_outfile, "\n");
1084 	return 0;
1085     }
1086 
1087     while (argv && (s = *argv++)) {
1088 	switch (*s) {
1089 	case '+':
1090 	case '-':
1091 	    x = *s++;
1092 	    break;
1093 	default:
1094 	    x = '\0';
1095 	    break;
1096 	}
1097 	d = s;
1098 	for (m = ttymodes; m->m_name; m++)
1099 	    if (strcmp(m->m_name, d) == 0)
1100 		break;
1101 
1102 	if (!m->m_name)  {
1103 	    (void) fprintf(el->el_errfile, "%s: Invalid argument `%s'.\n",
1104 			   name, d);
1105 	    return -1;
1106 	}
1107 
1108 	switch (x) {
1109 	case '+':
1110 	    el->el_tty.t_t[z][m->m_type].t_setmask |= m->m_value;
1111 	    el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value;
1112 	    break;
1113 	case '-':
1114 	    el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value;
1115 	    el->el_tty.t_t[z][m->m_type].t_clrmask |= m->m_value;
1116 	    break;
1117 	default:
1118 	    el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value;
1119 	    el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value;
1120 	    break;
1121 	}
1122     }
1123     return 0;
1124 } /* end tty_stty */
1125 
1126 
1127 #ifdef notyet
1128 /* tty_printchar():
1129  *	DEbugging routine to print the tty characters
1130  */
1131 private void
1132 tty_printchar(el, s)
1133     EditLine *el;
1134     unsigned char *s;
1135 {
1136     ttyperm_t *m;
1137     int i;
1138 
1139     for (i = 0; i < C_NCC; i++) {
1140 	for (m = el->el_tty.t_t; m->m_name; m++)
1141 	    if (m->m_type == M_CHAR && C_SH(i) == m->m_value)
1142 		break;
1143 	if (m->m_name)
1144 	    (void) fprintf(el->el_errfile, "%s ^%c ", m->m_name, s[i] + 'A'-1);
1145 	if (i % 5 == 0)
1146 	    (void) fprintf(el->el_errfile, "\n");
1147     }
1148     (void) fprintf(el->el_errfile, "\n");
1149 }
1150 #endif /* notyet */
1151