xref: /openbsd-src/lib/libedit/tty.c (revision db3296cf5c1dd9058ceecc3a29fe4aaa0bd26000)
1 /*	$OpenBSD: tty.c,v 1.8 2003/06/02 20:18:40 millert Exp $	*/
2 /*	$NetBSD: tty.c,v 1.3 1997/04/11 17:52:49 christos Exp $	*/
3 
4 /*-
5  * Copyright (c) 1992, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * This code is derived from software contributed to Berkeley by
9  * Christos Zoulas of Cornell University.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 #if !defined(lint) && !defined(SCCSID)
37 #if 0
38 static char sccsid[] = "@(#)tty.c	8.1 (Berkeley) 6/4/93";
39 #else
40 static const char rcsid[] = "$OpenBSD: tty.c,v 1.8 2003/06/02 20:18:40 millert Exp $";
41 #endif
42 #endif /* not lint && not SCCSID */
43 
44 /*
45  * tty.c: tty interface stuff
46  */
47 #include "sys.h"
48 #include "tty.h"
49 #include "el.h"
50 
51 typedef struct ttymodes_t {
52     char *m_name;
53     u_int m_value;
54     int   m_type;
55 } ttymodes_t;
56 
57 typedef struct ttymap_t {
58     int nch, och;		 /* Internal and termio rep of chars */
59     el_action_t bind[3]; 	/* emacs, vi, and vi-cmd */
60 } ttymap_t;
61 
62 
63 private ttyperm_t ttyperm = {
64     {
65 	{ "iflag:", ICRNL, (INLCR|IGNCR) },
66 	{ "oflag:", (OPOST|ONLCR), ONLRET },
67 	{ "cflag:", 0, 0 },
68 	{ "lflag:", (ISIG|ICANON|ECHO|ECHOE|ECHOCTL|IEXTEN),
69 		    (NOFLSH|ECHONL|EXTPROC|FLUSHO) },
70 	{ "chars:", 	0, 0 },
71     },
72     {
73 	{ "iflag:", (INLCR|ICRNL), IGNCR },
74 	{ "oflag:", (OPOST|ONLCR), ONLRET },
75 	{ "cflag:", 0, 0 },
76 	{ "lflag:", ISIG,
77 		    (NOFLSH|ICANON|ECHO|ECHOK|ECHONL|EXTPROC|IEXTEN|FLUSHO) },
78 	{ "chars:", (C_SH(C_MIN)|C_SH(C_TIME)|C_SH(C_SWTCH)|C_SH(C_DSWTCH)|
79 		     C_SH(C_SUSP)|C_SH(C_DSUSP)|C_SH(C_EOL)|C_SH(C_DISCARD)|
80 		     C_SH(C_PGOFF)|C_SH(C_PAGE)|C_SH(C_STATUS)), 0 }
81     },
82     {
83 	{ "iflag:", 0, IXON | IXOFF },
84 	{ "oflag:", 0, 0 },
85 	{ "cflag:", 0, 0 },
86 	{ "lflag:", 0, ISIG | IEXTEN },
87 	{ "chars:", 0, 0 },
88     }
89 };
90 
91 private ttychar_t ttychar = {
92     {
93 	CINTR,		 CQUIT, 	 CERASE, 	   CKILL,
94 	CEOF, 		 CEOL, 		 CEOL2, 	   CSWTCH,
95 	CDSWTCH,	 CERASE2,	 CSTART, 	   CSTOP,
96 	CWERASE, 	 CSUSP, 	 CDSUSP, 	   CREPRINT,
97 	CDISCARD, 	 CLNEXT,	 CSTATUS,	   CPAGE,
98 	CPGOFF,		 CKILL2, 	 CBRK, 		   CMIN,
99 	CTIME
100     },
101     {
102 	CINTR, 		 CQUIT, 	  CERASE, 	   CKILL,
103 	_POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE,
104 	_POSIX_VDISABLE, CERASE2,	  CSTART, 	   CSTOP,
105 	_POSIX_VDISABLE, CSUSP,           _POSIX_VDISABLE, _POSIX_VDISABLE,
106 	CDISCARD, 	 _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE,
107 	_POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE, 1,
108 	0
109     },
110     {
111 	0,		 0,		  0,		   0,
112 	0,		 0,		  0,		   0,
113 	0,		 0,		  0,		   0,
114 	0,		 0,		  0,		   0,
115 	0,		 0,		  0,		   0,
116 	0,		 0,		  0,		   0,
117 	0
118     }
119 };
120 
121 private ttymap_t tty_map[] = {
122 #ifdef VERASE
123 	{ C_ERASE,   VERASE,
124 	    { ED_DELETE_PREV_CHAR, VI_DELETE_PREV_CHAR, ED_PREV_CHAR } },
125 #endif /* VERASE */
126 #ifdef VERASE2
127 	{ C_ERASE2,  VERASE2,
128 	    { ED_DELETE_PREV_CHAR, VI_DELETE_PREV_CHAR, ED_PREV_CHAR } },
129 #endif /* VERASE2 */
130 #ifdef VKILL
131     	{ C_KILL,    VKILL,
132 	    { EM_KILL_LINE, VI_KILL_LINE_PREV, ED_UNASSIGNED } },
133 #endif /* VKILL */
134 #ifdef VKILL2
135     	{ C_KILL2,   VKILL2,
136 	    { EM_KILL_LINE, VI_KILL_LINE_PREV, ED_UNASSIGNED } },
137 #endif /* VKILL2 */
138 #ifdef VEOF
139     	{ C_EOF,     VEOF,
140 	    { EM_DELETE_OR_LIST, VI_LIST_OR_EOF, ED_UNASSIGNED } },
141 #endif /* VEOF */
142 #ifdef VWERASE
143     	{ C_WERASE,  VWERASE,
144 	    { ED_DELETE_PREV_WORD, ED_DELETE_PREV_WORD, ED_PREV_WORD } },
145 #endif /* VWERASE */
146 #ifdef VREPRINT
147    	{ C_REPRINT, VREPRINT,
148 	    { ED_REDISPLAY, ED_INSERT, ED_REDISPLAY } },
149 #endif /* VREPRINT */
150 #ifdef VLNEXT
151     	{ C_LNEXT,   VLNEXT,
152 	    { ED_QUOTED_INSERT, ED_QUOTED_INSERT, ED_UNASSIGNED } },
153 #endif /* VLNEXT */
154 	{ -1,	     -1,
155 	    { ED_UNASSIGNED, ED_UNASSIGNED, ED_UNASSIGNED } }
156     };
157 
158 private ttymodes_t ttymodes[] = {
159 # ifdef	IGNBRK
160     { "ignbrk",	IGNBRK,	M_INP },
161 # endif /* IGNBRK */
162 # ifdef	BRKINT
163     { "brkint",	BRKINT,	M_INP },
164 # endif /* BRKINT */
165 # ifdef	IGNPAR
166     { "ignpar",	IGNPAR,	M_INP },
167 # endif /* IGNPAR */
168 # ifdef	PARMRK
169     { "parmrk",	PARMRK,	M_INP },
170 # endif /* PARMRK */
171 # ifdef	INPCK
172     { "inpck",	INPCK,	M_INP },
173 # endif /* INPCK */
174 # ifdef	ISTRIP
175     { "istrip",	ISTRIP,	M_INP },
176 # endif /* ISTRIP */
177 # ifdef	INLCR
178     { "inlcr",	INLCR,	M_INP },
179 # endif /* INLCR */
180 # ifdef	IGNCR
181     { "igncr",	IGNCR,	M_INP },
182 # endif /* IGNCR */
183 # ifdef	ICRNL
184     { "icrnl",	ICRNL,	M_INP },
185 # endif /* ICRNL */
186 # ifdef	IUCLC
187     { "iuclc",	IUCLC,	M_INP },
188 # endif /* IUCLC */
189 # ifdef	IXON
190     { "ixon",	IXON,	M_INP },
191 # endif /* IXON */
192 # ifdef	IXANY
193     { "ixany",	IXANY,	M_INP },
194 # endif /* IXANY */
195 # ifdef	IXOFF
196     { "ixoff",	IXOFF,	M_INP },
197 # endif /* IXOFF */
198 # ifdef  IMAXBEL
199     { "imaxbel",IMAXBEL,M_INP },
200 # endif /* IMAXBEL */
201 
202 # ifdef	OPOST
203     { "opost",	OPOST,	M_OUT },
204 # endif /* OPOST */
205 # ifdef	OLCUC
206     { "olcuc",	OLCUC,	M_OUT },
207 # endif /* OLCUC */
208 # ifdef	ONLCR
209     { "onlcr",	ONLCR,	M_OUT },
210 # endif /* ONLCR */
211 # ifdef	OCRNL
212     { "ocrnl",	OCRNL,	M_OUT },
213 # endif /* OCRNL */
214 # ifdef	ONOCR
215     { "onocr",	ONOCR,	M_OUT },
216 # endif /* ONOCR */
217 # ifdef ONOEOT
218     { "onoeot",	ONOEOT,	M_OUT },
219 # endif /* ONOEOT */
220 # ifdef	ONLRET
221     { "onlret",	ONLRET,	M_OUT },
222 # endif /* ONLRET */
223 # ifdef	OFILL
224     { "ofill",	OFILL,	M_OUT },
225 # endif /* OFILL */
226 # ifdef	OFDEL
227     { "ofdel",	OFDEL,	M_OUT },
228 # endif /* OFDEL */
229 # ifdef	NLDLY
230     { "nldly",	NLDLY,	M_OUT },
231 # endif /* NLDLY */
232 # ifdef	CRDLY
233     { "crdly",	CRDLY,	M_OUT },
234 # endif /* CRDLY */
235 # ifdef	TABDLY
236     { "tabdly",	TABDLY,	M_OUT },
237 # endif /* TABDLY */
238 # ifdef	XTABS
239     { "xtabs",	XTABS,	M_OUT },
240 # endif /* XTABS */
241 # ifdef	BSDLY
242     { "bsdly",	BSDLY,	M_OUT },
243 # endif /* BSDLY */
244 # ifdef	VTDLY
245     { "vtdly",	VTDLY,	M_OUT },
246 # endif /* VTDLY */
247 # ifdef	FFDLY
248     { "ffdly",	FFDLY,	M_OUT },
249 # endif /* FFDLY */
250 # ifdef	PAGEOUT
251     { "pageout",PAGEOUT,M_OUT },
252 # endif /* PAGEOUT */
253 # ifdef	WRAP
254     { "wrap",	WRAP,	M_OUT },
255 # endif /* WRAP */
256 
257 # ifdef	CIGNORE
258     { "cignore",CIGNORE,M_CTL },
259 # endif /* CBAUD */
260 # ifdef	CBAUD
261     { "cbaud",	CBAUD,	M_CTL },
262 # endif /* CBAUD */
263 # ifdef	CSTOPB
264     { "cstopb",	CSTOPB,	M_CTL },
265 # endif /* CSTOPB */
266 # ifdef	CREAD
267     { "cread",	CREAD,	M_CTL },
268 # endif /* CREAD */
269 # ifdef	PARENB
270     { "parenb",	PARENB,	M_CTL },
271 # endif /* PARENB */
272 # ifdef	PARODD
273     { "parodd",	PARODD,	M_CTL },
274 # endif /* PARODD */
275 # ifdef	HUPCL
276     { "hupcl",	HUPCL,	M_CTL },
277 # endif /* HUPCL */
278 # ifdef	CLOCAL
279     { "clocal",	CLOCAL,	M_CTL },
280 # endif /* CLOCAL */
281 # ifdef	LOBLK
282     { "loblk",	LOBLK,	M_CTL },
283 # endif /* LOBLK */
284 # ifdef	CIBAUD
285     { "cibaud",	CIBAUD,	M_CTL },
286 # endif /* CIBAUD */
287 # ifdef CRTSCTS
288 #  ifdef CCTS_OFLOW
289     { "ccts_oflow",CCTS_OFLOW,M_CTL },
290 #  else
291     { "crtscts",CRTSCTS,M_CTL },
292 #  endif /* CCTS_OFLOW */
293 # endif /* CRTSCTS */
294 # ifdef CRTS_IFLOW
295     { "crts_iflow",CRTS_IFLOW,M_CTL },
296 # endif /* CRTS_IFLOW */
297 # ifdef MDMBUF
298     { "mdmbuf",	MDMBUF,	M_CTL },
299 # endif /* MDMBUF */
300 # ifdef RCV1EN
301     { "rcv1en",	RCV1EN,	M_CTL },
302 # endif /* RCV1EN */
303 # ifdef XMT1EN
304     { "xmt1en",	XMT1EN,	M_CTL },
305 # endif /* XMT1EN */
306 
307 # ifdef	ISIG
308     { "isig",	ISIG,	M_LIN },
309 # endif /* ISIG */
310 # ifdef	ICANON
311     { "icanon",	ICANON,	M_LIN },
312 # endif /* ICANON */
313 # ifdef	XCASE
314     { "xcase",	XCASE,	M_LIN },
315 # endif /* XCASE */
316 # ifdef	ECHO
317     { "echo",	ECHO,	M_LIN },
318 # endif /* ECHO */
319 # ifdef	ECHOE
320     { "echoe",	ECHOE,	M_LIN },
321 # endif /* ECHOE */
322 # ifdef	ECHOK
323     { "echok",	ECHOK,	M_LIN },
324 # endif /* ECHOK */
325 # ifdef	ECHONL
326     { "echonl",	ECHONL,	M_LIN },
327 # endif /* ECHONL */
328 # ifdef	NOFLSH
329     { "noflsh",	NOFLSH,	M_LIN },
330 # endif /* NOFLSH */
331 # ifdef	TOSTOP
332     { "tostop",	TOSTOP,	M_LIN },
333 # endif /* TOSTOP */
334 # ifdef	ECHOCTL
335     { "echoctl",ECHOCTL,M_LIN },
336 # endif /* ECHOCTL */
337 # ifdef	ECHOPRT
338     { "echoprt",ECHOPRT,M_LIN },
339 # endif /* ECHOPRT */
340 # ifdef	ECHOKE
341     { "echoke",	ECHOKE,	M_LIN },
342 # endif /* ECHOKE */
343 # ifdef	DEFECHO
344     { "defecho",DEFECHO,M_LIN },
345 # endif /* DEFECHO */
346 # ifdef	FLUSHO
347     { "flusho",	FLUSHO,	M_LIN },
348 # endif /* FLUSHO */
349 # ifdef	PENDIN
350     { "pendin",	PENDIN,	M_LIN },
351 # endif /* PENDIN */
352 # ifdef	IEXTEN
353     { "iexten",	IEXTEN,	M_LIN },
354 # endif /* IEXTEN */
355 # ifdef	NOKERNINFO
356     { "nokerninfo",NOKERNINFO,M_LIN },
357 # endif /* NOKERNINFO */
358 # ifdef	ALTWERASE
359     { "altwerase",ALTWERASE,M_LIN },
360 # endif /* ALTWERASE */
361 # ifdef	EXTPROC
362     { "extproc",EXTPROC, M_LIN },
363 # endif /* EXTPROC */
364 
365 # if defined(VINTR)
366     { "intr",		C_SH(C_INTR), 	M_CHAR },
367 # endif /* VINTR */
368 # if defined(VQUIT)
369     { "quit",		C_SH(C_QUIT), 	M_CHAR },
370 # endif /* VQUIT */
371 # if defined(VERASE)
372     { "erase",		C_SH(C_ERASE), 	M_CHAR },
373 # endif /* VERASE */
374 # if defined(VKILL)
375     { "kill",		C_SH(C_KILL), 	M_CHAR },
376 # endif /* VKILL */
377 # if defined(VEOF)
378     { "eof",		C_SH(C_EOF), 	M_CHAR },
379 # endif /* VEOF */
380 # if defined(VEOL)
381     { "eol",		C_SH(C_EOL), 	M_CHAR },
382 # endif /* VEOL */
383 # if defined(VEOL2)
384     { "eol2",		C_SH(C_EOL2), 	M_CHAR },
385 # endif  /* VEOL2 */
386 # if defined(VSWTCH)
387     { "swtch",		C_SH(C_SWTCH), 	M_CHAR },
388 # endif /* VSWTCH */
389 # if defined(VDSWTCH)
390     { "dswtch",		C_SH(C_DSWTCH),	M_CHAR },
391 # endif /* VDSWTCH */
392 # if defined(VERASE2)
393     { "erase2",		C_SH(C_ERASE2),	M_CHAR },
394 # endif /* VERASE2 */
395 # if defined(VSTART)
396     { "start",		C_SH(C_START), 	M_CHAR },
397 # endif /* VSTART */
398 # if defined(VSTOP)
399     { "stop",		C_SH(C_STOP), 	M_CHAR },
400 # endif /* VSTOP */
401 # if defined(VWERASE)
402     { "werase",		C_SH(C_WERASE),	M_CHAR },
403 # endif /* VWERASE */
404 # if defined(VSUSP)
405     { "susp",		C_SH(C_SUSP), 	M_CHAR },
406 # endif /* VSUSP */
407 # if defined(VDSUSP)
408     { "dsusp",		C_SH(C_DSUSP), 	M_CHAR },
409 # endif /* VDSUSP */
410 # if defined(VREPRINT)
411     { "reprint",	C_SH(C_REPRINT),M_CHAR },
412 # endif /* VREPRINT */
413 # if defined(VDISCARD)
414     { "discard",	C_SH(C_DISCARD),M_CHAR },
415 # endif /* VDISCARD */
416 # if defined(VLNEXT)
417     { "lnext",		C_SH(C_LNEXT), 	M_CHAR },
418 # endif /* VLNEXT */
419 # if defined(VSTATUS)
420     { "status",		C_SH(C_STATUS),	M_CHAR },
421 # endif /* VSTATUS */
422 # if defined(VPAGE)
423     { "page",		C_SH(C_PAGE), 	M_CHAR },
424 # endif /* VPAGE */
425 # if defined(VPGOFF)
426     { "pgoff",		C_SH(C_PGOFF), 	M_CHAR },
427 # endif /* VPGOFF */
428 # if defined(VKILL2)
429     { "kill2",		C_SH(C_KILL2), 	M_CHAR },
430 # endif /* VKILL2 */
431 # if defined(VBRK)
432     { "brk",		C_SH(C_BRK), 	M_CHAR },
433 # endif /* VBRK */
434 # if defined(VMIN)
435     { "min",		C_SH(C_MIN), 	M_CHAR },
436 # endif /* VMIN */
437 # if defined(VTIME)
438     { "time",		C_SH(C_TIME), 	M_CHAR },
439 # endif /* VTIME */
440     { NULL, 0, -1 },
441 };
442 
443 
444 
445 #define tty_getty(el, td) tcgetattr((el)->el_infd, (td))
446 #define tty_setty(el, td) tcsetattr((el)->el_infd, TCSADRAIN, (td))
447 
448 #define tty__gettabs(td)     ((((td)->c_oflag & TAB3) == TAB3) ? 0 : 1)
449 #define tty__geteightbit(td) (((td)->c_cflag & CSIZE) == CS8)
450 #define tty__cooked_mode(td) ((td)->c_lflag & ICANON)
451 
452 private void    tty__getchar(struct termios *, unsigned char *);
453 private void    tty__setchar(struct termios *, unsigned char *);
454 private speed_t tty__getspeed(struct termios *);
455 private int     tty_setup(EditLine *);
456 
457 #define t_qu t_ts
458 
459 
460 /* tty_setup():
461  *	Get the tty parameters and initialize the editing state
462  */
463 private int
464 tty_setup(el)
465     EditLine *el;
466 {
467     int rst = 1;
468     if (tty_getty(el, &el->el_tty.t_ed) == -1) {
469 #ifdef DEBUG_TTY
470 	(void)fprintf(el->el_errfile,
471 		       "tty_setup: tty_getty: %s\n", strerror(errno));
472 #endif /* DEBUG_TTY */
473 	return(-1);
474     }
475     el->el_tty.t_ts    = el->el_tty.t_ex = el->el_tty.t_ed;
476 
477     el->el_tty.t_speed = tty__getspeed(&el->el_tty.t_ex);
478     el->el_tty.t_tabs  = tty__gettabs(&el->el_tty.t_ex);
479     el->el_tty.t_eight = tty__geteightbit(&el->el_tty.t_ex);
480 
481     el->el_tty.t_ex.c_iflag &= ~el->el_tty.t_t[EX_IO][M_INP].t_clrmask;
482     el->el_tty.t_ex.c_iflag |=  el->el_tty.t_t[EX_IO][M_INP].t_setmask;
483 
484     el->el_tty.t_ex.c_oflag &= ~el->el_tty.t_t[EX_IO][M_OUT].t_clrmask;
485     el->el_tty.t_ex.c_oflag |=  el->el_tty.t_t[EX_IO][M_OUT].t_setmask;
486 
487     el->el_tty.t_ex.c_cflag &= ~el->el_tty.t_t[EX_IO][M_CTL].t_clrmask;
488     el->el_tty.t_ex.c_cflag |=  el->el_tty.t_t[EX_IO][M_CTL].t_setmask;
489 
490     el->el_tty.t_ex.c_lflag &= ~el->el_tty.t_t[EX_IO][M_LIN].t_clrmask;
491     el->el_tty.t_ex.c_lflag |=  el->el_tty.t_t[EX_IO][M_LIN].t_setmask;
492 
493     /*
494      * Reset the tty chars to reasonable defaults
495      * If they are disabled, then enable them.
496      */
497     if (rst) {
498         if (tty__cooked_mode(&el->el_tty.t_ts)) {
499             tty__getchar(&el->el_tty.t_ts, el->el_tty.t_c[TS_IO]);
500             /*
501              * Don't affect CMIN and CTIME for the editor mode
502              */
503             for (rst = 0; rst < C_NCC - 2; rst++)
504                 if (el->el_tty.t_c[TS_IO][rst] != el->el_tty.t_vdisable &&
505                     el->el_tty.t_c[ED_IO][rst] != el->el_tty.t_vdisable)
506                     el->el_tty.t_c[ED_IO][rst]  = el->el_tty.t_c[TS_IO][rst];
507             for (rst = 0; rst < C_NCC; rst++)
508                 if (el->el_tty.t_c[TS_IO][rst] != el->el_tty.t_vdisable &&
509                     el->el_tty.t_c[EX_IO][rst] != el->el_tty.t_vdisable)
510                     el->el_tty.t_c[EX_IO][rst]  = el->el_tty.t_c[TS_IO][rst];
511         }
512         tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]);
513         if (tty_setty(el, &el->el_tty.t_ex) == -1) {
514 #ifdef DEBUG_TTY
515             (void)fprintf(el->el_errfile, "tty_setup: tty_setty: %s\n",
516 			   strerror(errno));
517 #endif /* DEBUG_TTY */
518             return(-1);
519         }
520     }
521     else
522         tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]);
523 
524     el->el_tty.t_ed.c_iflag &= ~el->el_tty.t_t[ED_IO][M_INP].t_clrmask;
525     el->el_tty.t_ed.c_iflag |=  el->el_tty.t_t[ED_IO][M_INP].t_setmask;
526 
527     el->el_tty.t_ed.c_oflag &= ~el->el_tty.t_t[ED_IO][M_OUT].t_clrmask;
528     el->el_tty.t_ed.c_oflag |=  el->el_tty.t_t[ED_IO][M_OUT].t_setmask;
529 
530     el->el_tty.t_ed.c_cflag &= ~el->el_tty.t_t[ED_IO][M_CTL].t_clrmask;
531     el->el_tty.t_ed.c_cflag |=  el->el_tty.t_t[ED_IO][M_CTL].t_setmask;
532 
533     el->el_tty.t_ed.c_lflag &= ~el->el_tty.t_t[ED_IO][M_LIN].t_clrmask;
534     el->el_tty.t_ed.c_lflag |=  el->el_tty.t_t[ED_IO][M_LIN].t_setmask;
535 
536     tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]);
537     return 0;
538 }
539 
540 protected int
541 tty_init(el)
542     EditLine *el;
543 {
544     el->el_tty.t_mode     = EX_IO;
545     el->el_tty.t_vdisable = _POSIX_VDISABLE;
546     (void)memcpy(el->el_tty.t_t, ttyperm, sizeof(ttyperm_t));
547     (void)memcpy(el->el_tty.t_c, ttychar, sizeof(ttychar_t));
548     return tty_setup(el);
549 } /* end tty_init */
550 
551 
552 /* tty_end():
553  *	Restore the tty to its original settings
554  */
555 protected void
556 /*ARGSUSED*/
557 tty_end(el)
558     EditLine *el;
559 {
560     /* XXX: Maybe reset to an initial state? */
561 }
562 
563 
564 /* tty__getspeed():
565  *	Get the tty speed
566  */
567 private speed_t
568 tty__getspeed(td)
569     struct termios *td;
570 {
571     speed_t spd;
572 
573     if ((spd = cfgetispeed(td)) == 0)
574 	spd = cfgetospeed(td);
575     return spd;
576 } /* end tty__getspeed */
577 
578 
579 /* tty__getchar():
580  *	Get the tty characters
581  */
582 private void
583 tty__getchar(td, s)
584     struct termios *td;
585     unsigned char *s;
586 {
587 # ifdef VINTR
588     s[C_INTR]	= td->c_cc[VINTR];
589 # endif /* VINTR */
590 # ifdef VQUIT
591     s[C_QUIT]	= td->c_cc[VQUIT];
592 # endif /* VQUIT */
593 # ifdef VERASE
594     s[C_ERASE]	= td->c_cc[VERASE];
595 # endif /* VERASE */
596 # ifdef VKILL
597     s[C_KILL]	= td->c_cc[VKILL];
598 # endif /* VKILL */
599 # ifdef VEOF
600     s[C_EOF]	= td->c_cc[VEOF];
601 # endif /* VEOF */
602 # ifdef VEOL
603     s[C_EOL]	= td->c_cc[VEOL];
604 # endif /* VEOL */
605 # ifdef VEOL2
606     s[C_EOL2]	= td->c_cc[VEOL2];
607 # endif  /* VEOL2 */
608 # ifdef VSWTCH
609     s[C_SWTCH]	= td->c_cc[VSWTCH];
610 # endif /* VSWTCH */
611 # ifdef VDSWTCH
612     s[C_DSWTCH]	= td->c_cc[VDSWTCH];
613 # endif /* VDSWTCH */
614 # ifdef VERASE2
615     s[C_ERASE2]	= td->c_cc[VERASE2];
616 # endif /* VERASE2 */
617 # ifdef VSTART
618     s[C_START]	= td->c_cc[VSTART];
619 # endif /* VSTART */
620 # ifdef VSTOP
621     s[C_STOP]	= td->c_cc[VSTOP];
622 # endif /* VSTOP */
623 # ifdef VWERASE
624     s[C_WERASE]	= td->c_cc[VWERASE];
625 # endif /* VWERASE */
626 # ifdef VSUSP
627     s[C_SUSP]	= td->c_cc[VSUSP];
628 # endif /* VSUSP */
629 # ifdef VDSUSP
630     s[C_DSUSP]	= td->c_cc[VDSUSP];
631 # endif /* VDSUSP */
632 # ifdef VREPRINT
633     s[C_REPRINT]= td->c_cc[VREPRINT];
634 # endif /* VREPRINT */
635 # ifdef VDISCARD
636     s[C_DISCARD]= td->c_cc[VDISCARD];
637 # endif /* VDISCARD */
638 # ifdef VLNEXT
639     s[C_LNEXT]	= td->c_cc[VLNEXT];
640 # endif /* VLNEXT */
641 # ifdef VSTATUS
642     s[C_STATUS]	= td->c_cc[VSTATUS];
643 # endif /* VSTATUS */
644 # ifdef VPAGE
645     s[C_PAGE]	= td->c_cc[VPAGE];
646 # endif /* VPAGE */
647 # ifdef VPGOFF
648     s[C_PGOFF]	= td->c_cc[VPGOFF];
649 # endif /* VPGOFF */
650 # ifdef VKILL2
651     s[C_KILL2]	= td->c_cc[VKILL2];
652 # endif /* KILL2 */
653 # ifdef VMIN
654     s[C_MIN]	= td->c_cc[VMIN];
655 # endif /* VMIN */
656 # ifdef VTIME
657     s[C_TIME]	= td->c_cc[VTIME];
658 # endif /* VTIME */
659 } /* tty__getchar */
660 
661 
662 /* tty__setchar():
663  *	Set the tty characters
664  */
665 private void
666 tty__setchar(td, s)
667     struct termios *td;
668     unsigned char *s;
669 {
670 # ifdef VINTR
671     td->c_cc[VINTR]	= s[C_INTR];
672 # endif /* VINTR */
673 # ifdef VQUIT
674     td->c_cc[VQUIT]	= s[C_QUIT];
675 # endif /* VQUIT */
676 # ifdef VERASE
677     td->c_cc[VERASE]	= s[C_ERASE];
678 # endif /* VERASE */
679 # ifdef VKILL
680     td->c_cc[VKILL]	= s[C_KILL];
681 # endif /* VKILL */
682 # ifdef VEOF
683     td->c_cc[VEOF]	= s[C_EOF];
684 # endif /* VEOF */
685 # ifdef VEOL
686     td->c_cc[VEOL]	= s[C_EOL];
687 # endif /* VEOL */
688 # ifdef VEOL2
689     td->c_cc[VEOL2]	= s[C_EOL2];
690 # endif  /* VEOL2 */
691 # ifdef VSWTCH
692     td->c_cc[VSWTCH]	= s[C_SWTCH];
693 # endif /* VSWTCH */
694 # ifdef VDSWTCH
695     td->c_cc[VDSWTCH]	= s[C_DSWTCH];
696 # endif /* VDSWTCH */
697 # ifdef VERASE2
698     td->c_cc[VERASE2]	= s[C_ERASE2];
699 # endif /* VERASE2 */
700 # ifdef VSTART
701     td->c_cc[VSTART]	= s[C_START];
702 # endif /* VSTART */
703 # ifdef VSTOP
704     td->c_cc[VSTOP]	= s[C_STOP];
705 # endif /* VSTOP */
706 # ifdef VWERASE
707     td->c_cc[VWERASE]	= s[C_WERASE];
708 # endif /* VWERASE */
709 # ifdef VSUSP
710     td->c_cc[VSUSP]	= s[C_SUSP];
711 # endif /* VSUSP */
712 # ifdef VDSUSP
713     td->c_cc[VDSUSP]	= s[C_DSUSP];
714 # endif /* VDSUSP */
715 # ifdef VREPRINT
716     td->c_cc[VREPRINT]	= s[C_REPRINT];
717 # endif /* VREPRINT */
718 # ifdef VDISCARD
719     td->c_cc[VDISCARD]	= s[C_DISCARD];
720 # endif /* VDISCARD */
721 # ifdef VLNEXT
722     td->c_cc[VLNEXT]	= s[C_LNEXT];
723 # endif /* VLNEXT */
724 # ifdef VSTATUS
725     td->c_cc[VSTATUS]	= s[C_STATUS];
726 # endif /* VSTATUS */
727 # ifdef VPAGE
728     td->c_cc[VPAGE]	= s[C_PAGE];
729 # endif /* VPAGE */
730 # ifdef VPGOFF
731     td->c_cc[VPGOFF]	= s[C_PGOFF];
732 # endif /* VPGOFF */
733 # ifdef VKILL2
734     td->c_cc[VKILL2]	= s[C_KILL2];
735 # endif /* VKILL2 */
736 # ifdef VMIN
737     td->c_cc[VMIN]	= s[C_MIN];
738 # endif /* VMIN */
739 # ifdef VTIME
740     td->c_cc[VTIME]	= s[C_TIME];
741 # endif /* VTIME */
742 } /* tty__setchar */
743 
744 
745 /* tty_bind_char():
746  *	Rebind the editline functions
747  */
748 protected void
749 tty_bind_char(el, force)
750     EditLine *el;
751     int force;
752 {
753     unsigned char *t_n = el->el_tty.t_c[ED_IO];
754     unsigned char *t_o = el->el_tty.t_ed.c_cc;
755     unsigned char new[2], old[2];
756     ttymap_t *tp;
757     el_action_t  *dmap, *dalt, *map, *alt;
758     new[1] = old[1] = '\0';
759 
760 
761     map = el->el_map.key;
762     alt = el->el_map.alt;
763     if (el->el_map.type == MAP_VI) {
764 	dmap = el->el_map.vii;
765 	dalt = el->el_map.vic;
766     }
767     else {
768 	dmap = el->el_map.emacs;
769 	dalt = NULL;
770     }
771 
772     for (tp = tty_map; tp->nch != -1; tp++) {
773 	new[0] = t_n[tp->nch];
774 	old[0] = t_o[tp->och];
775 	if (new[0] == old[0] && !force)
776 	    continue;
777 	/* Put the old default binding back, and set the new binding */
778 	key_clear(el, map, old);
779 	map[old[0]] = dmap[old[0]];
780 	key_clear(el, map, new);
781 	/* MAP_VI == 1, MAP_EMACS == 0... */
782 	map[new[0]] = tp->bind[el->el_map.type];
783 	if (dalt) {
784 	    key_clear(el, alt, old);
785 	    alt[old[0]] = dalt[old[0]];
786 	    key_clear(el, alt, new);
787 	    alt[new[0]] = tp->bind[el->el_map.type+1];
788 	}
789     }
790 }
791 
792 /* tty_rawmode():
793  * 	Set terminal into 1 character at a time mode.
794  */
795 protected int
796 tty_rawmode(el)
797     EditLine *el;
798 {
799     if (el->el_tty.t_mode == ED_IO)
800 	return (0);
801 
802     if (tty_getty(el, &el->el_tty.t_ts) == -1) {
803 #ifdef DEBUG_TTY
804 	(void)fprintf(el->el_errfile, "tty_rawmode: tty_getty: %s\n", strerror(errno));
805 #endif /* DEBUG_TTY */
806 	return(-1);
807     }
808 
809     /*
810      * We always keep up with the eight bit setting and the speed of the
811      * tty. But only we only believe changes that are made to cooked mode!
812      */
813     el->el_tty.t_eight = tty__geteightbit(&el->el_tty.t_ts);
814     el->el_tty.t_speed = tty__getspeed(&el->el_tty.t_ts);
815 
816     if (tty__getspeed(&el->el_tty.t_ex) != el->el_tty.t_speed ||
817 	tty__getspeed(&el->el_tty.t_ed) != el->el_tty.t_speed) {
818 	(void)cfsetispeed(&el->el_tty.t_ex, el->el_tty.t_speed);
819 	(void)cfsetospeed(&el->el_tty.t_ex, el->el_tty.t_speed);
820 	(void)cfsetispeed(&el->el_tty.t_ed, el->el_tty.t_speed);
821 	(void)cfsetospeed(&el->el_tty.t_ed, el->el_tty.t_speed);
822     }
823 
824     if (tty__cooked_mode(&el->el_tty.t_ts)) {
825 	if (el->el_tty.t_ts.c_cflag != el->el_tty.t_ex.c_cflag) {
826 	    el->el_tty.t_ex.c_cflag  = el->el_tty.t_ts.c_cflag;
827 	    el->el_tty.t_ex.c_cflag &= ~el->el_tty.t_t[EX_IO][M_CTL].t_clrmask;
828 	    el->el_tty.t_ex.c_cflag |=  el->el_tty.t_t[EX_IO][M_CTL].t_setmask;
829 
830 	    el->el_tty.t_ed.c_cflag  = el->el_tty.t_ts.c_cflag;
831 	    el->el_tty.t_ed.c_cflag &= ~el->el_tty.t_t[ED_IO][M_CTL].t_clrmask;
832 	    el->el_tty.t_ed.c_cflag |=  el->el_tty.t_t[ED_IO][M_CTL].t_setmask;
833 	}
834 
835 	if ((el->el_tty.t_ts.c_lflag != el->el_tty.t_ex.c_lflag) &&
836 	    (el->el_tty.t_ts.c_lflag != el->el_tty.t_ed.c_lflag)) {
837 	    el->el_tty.t_ex.c_lflag = el->el_tty.t_ts.c_lflag;
838 	    el->el_tty.t_ex.c_lflag &= ~el->el_tty.t_t[EX_IO][M_LIN].t_clrmask;
839 	    el->el_tty.t_ex.c_lflag |=  el->el_tty.t_t[EX_IO][M_LIN].t_setmask;
840 
841 	    el->el_tty.t_ed.c_lflag = el->el_tty.t_ts.c_lflag;
842 	    el->el_tty.t_ed.c_lflag &= ~el->el_tty.t_t[ED_IO][M_LIN].t_clrmask;
843 	    el->el_tty.t_ed.c_lflag |=  el->el_tty.t_t[ED_IO][M_LIN].t_setmask;
844 	}
845 
846 	if ((el->el_tty.t_ts.c_iflag != el->el_tty.t_ex.c_iflag) &&
847 	    (el->el_tty.t_ts.c_iflag != el->el_tty.t_ed.c_iflag)) {
848 	    el->el_tty.t_ex.c_iflag = el->el_tty.t_ts.c_iflag;
849 	    el->el_tty.t_ex.c_iflag &= ~el->el_tty.t_t[EX_IO][M_INP].t_clrmask;
850 	    el->el_tty.t_ex.c_iflag |=  el->el_tty.t_t[EX_IO][M_INP].t_setmask;
851 
852 	    el->el_tty.t_ed.c_iflag = el->el_tty.t_ts.c_iflag;
853 	    el->el_tty.t_ed.c_iflag &= ~el->el_tty.t_t[ED_IO][M_INP].t_clrmask;
854 	    el->el_tty.t_ed.c_iflag |=  el->el_tty.t_t[ED_IO][M_INP].t_setmask;
855 	}
856 
857 	if ((el->el_tty.t_ts.c_oflag != el->el_tty.t_ex.c_oflag) &&
858 	    (el->el_tty.t_ts.c_oflag != el->el_tty.t_ed.c_oflag)) {
859 	    el->el_tty.t_ex.c_oflag = el->el_tty.t_ts.c_oflag;
860 	    el->el_tty.t_ex.c_oflag &= ~el->el_tty.t_t[EX_IO][M_OUT].t_clrmask;
861 	    el->el_tty.t_ex.c_oflag |=  el->el_tty.t_t[EX_IO][M_OUT].t_setmask;
862 
863 	    el->el_tty.t_ed.c_oflag = el->el_tty.t_ts.c_oflag;
864 	    el->el_tty.t_ed.c_oflag &= ~el->el_tty.t_t[ED_IO][M_OUT].t_clrmask;
865 	    el->el_tty.t_ed.c_oflag |=  el->el_tty.t_t[ED_IO][M_OUT].t_setmask;
866 	}
867 
868 	if (tty__gettabs(&el->el_tty.t_ex) == 0)
869 	    el->el_tty.t_tabs = 0;
870 	else
871 	    el->el_tty.t_tabs = EL_CAN_TAB ? 1 : 0;
872 
873 	{
874 	    int i;
875 
876 	    tty__getchar(&el->el_tty.t_ts, el->el_tty.t_c[TS_IO]);
877 	    /*
878 	     * Check if the user made any changes.
879 	     * If he did, then propagate the changes to the
880 	     * edit and execute data structures.
881 	     */
882 	    for (i = 0; i < C_NCC; i++)
883 		if (el->el_tty.t_c[TS_IO][i] != el->el_tty.t_c[EX_IO][i])
884 		    break;
885 
886 	    if (i != C_NCC) {
887 		/*
888 		 * Propagate changes only to the unprotected chars
889 		 * that have been modified just now.
890 		 */
891 		for (i = 0; i < C_NCC; i++) {
892 		    if (!((el->el_tty.t_t[ED_IO][M_CHAR].t_setmask & C_SH(i)))
893 		      && (el->el_tty.t_c[TS_IO][i] != el->el_tty.t_c[EX_IO][i]))
894 			el->el_tty.t_c[ED_IO][i] = el->el_tty.t_c[TS_IO][i];
895 		    if (el->el_tty.t_t[ED_IO][M_CHAR].t_clrmask & C_SH(i))
896 			el->el_tty.t_c[ED_IO][i] = el->el_tty.t_vdisable;
897 		}
898 		tty_bind_char(el, 0);
899 		tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]);
900 
901 		for (i = 0; i < C_NCC; i++) {
902 		    if (!((el->el_tty.t_t[EX_IO][M_CHAR].t_setmask & C_SH(i)))
903 		      && (el->el_tty.t_c[TS_IO][i] != el->el_tty.t_c[EX_IO][i]))
904 			el->el_tty.t_c[EX_IO][i] = el->el_tty.t_c[TS_IO][i];
905 		    if (el->el_tty.t_t[EX_IO][M_CHAR].t_clrmask & C_SH(i))
906 			el->el_tty.t_c[EX_IO][i] = el->el_tty.t_vdisable;
907 		}
908 		tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]);
909 	    }
910 
911 	}
912     }
913 
914     if (tty_setty(el, &el->el_tty.t_ed) == -1) {
915 #ifdef DEBUG_TTY
916 	(void)fprintf(el->el_errfile, "tty_rawmode: tty_setty: %s\n",
917 		       strerror(errno));
918 #endif /* DEBUG_TTY */
919 	return -1;
920     }
921     el->el_tty.t_mode = ED_IO;
922     return (0);
923 } /* end tty_rawmode */
924 
925 
926 /* tty_cookedmode():
927  *	Set the tty back to normal mode
928  */
929 protected int
930 tty_cookedmode(el)
931     EditLine *el;
932 {				/* set tty in normal setup */
933     if (el->el_tty.t_mode == EX_IO)
934 	return (0);
935 
936     if (tty_setty(el, &el->el_tty.t_ex) == -1) {
937 #ifdef DEBUG_TTY
938 	(void)fprintf(el->el_errfile, "tty_cookedmode: tty_setty: %s\n",
939 		       strerror(errno));
940 #endif /* DEBUG_TTY */
941 	return -1;
942     }
943     el->el_tty.t_mode = EX_IO;
944     return (0);
945 } /* end tty_cookedmode */
946 
947 
948 /* tty_quotemode():
949  *	Turn on quote mode
950  */
951 protected int
952 tty_quotemode(el)
953     EditLine *el;
954 {
955     if (el->el_tty.t_mode == QU_IO)
956 	return 0;
957 
958     el->el_tty.t_qu = el->el_tty.t_ed;
959 
960     el->el_tty.t_qu.c_iflag &= ~el->el_tty.t_t[QU_IO][M_INP].t_clrmask;
961     el->el_tty.t_qu.c_iflag |=  el->el_tty.t_t[QU_IO][M_INP].t_setmask;
962 
963     el->el_tty.t_qu.c_oflag &= ~el->el_tty.t_t[QU_IO][M_OUT].t_clrmask;
964     el->el_tty.t_qu.c_oflag |=  el->el_tty.t_t[QU_IO][M_OUT].t_setmask;
965 
966     el->el_tty.t_qu.c_cflag &= ~el->el_tty.t_t[QU_IO][M_CTL].t_clrmask;
967     el->el_tty.t_qu.c_cflag |=  el->el_tty.t_t[QU_IO][M_CTL].t_setmask;
968 
969     el->el_tty.t_qu.c_lflag &= ~el->el_tty.t_t[QU_IO][M_LIN].t_clrmask;
970     el->el_tty.t_qu.c_lflag |=  el->el_tty.t_t[QU_IO][M_LIN].t_setmask;
971 
972     if (tty_setty(el, &el->el_tty.t_qu) == -1) {
973 #ifdef DEBUG_TTY
974 	(void)fprintf(el->el_errfile, "QuoteModeOn: tty_setty: %s\n",
975 		       strerror(errno));
976 #endif /* DEBUG_TTY */
977 	return -1;
978     }
979     el->el_tty.t_mode = QU_IO;
980     return 0;
981 } /* end tty_quotemode */
982 
983 
984 /* tty_noquotemode():
985  *	Turn off quote mode
986  */
987 protected int
988 tty_noquotemode(el)
989     EditLine *el;
990 {
991     if (el->el_tty.t_mode != QU_IO)
992 	return 0;
993     if (tty_setty(el, &el->el_tty.t_ed) == -1) {
994 #ifdef DEBUG_TTY
995 	(void)fprintf(el->el_errfile, "QuoteModeOff: tty_setty: %s\n",
996 		       strerror(errno));
997 #endif /* DEBUG_TTY */
998 	return -1;
999     }
1000     el->el_tty.t_mode = ED_IO;
1001     return 0;
1002 }
1003 
1004 /* tty_stty():
1005  *	Stty builtin
1006  */
1007 protected int
1008 /*ARGSUSED*/
1009 tty_stty(el, argc, argv)
1010     EditLine *el;
1011     int argc;
1012     char **argv;
1013 {
1014     ttymodes_t *m;
1015     char x, *d;
1016     int aflag = 0;
1017     char *s;
1018     char *name;
1019     int z = EX_IO;
1020 
1021     if (argv == NULL)
1022 	return -1;
1023     name = *argv++;
1024 
1025     while (argv && *argv && argv[0][0] == '-' && argv[0][2] == '\0')
1026 	switch (argv[0][1]) {
1027 	case 'a':
1028 	    aflag++;
1029 	    argv++;
1030 	    break;
1031 	case 'd':
1032 	    argv++;
1033 	    z = ED_IO;
1034 	    break;
1035 	case 'x':
1036 	    argv++;
1037 	    z = EX_IO;
1038 	    break;
1039 	case 'q':
1040 	    argv++;
1041 	    z = QU_IO;
1042 	    break;
1043 	default:
1044 	    (void)fprintf(el->el_errfile, "%s: Unknown switch `%c'.\n",
1045 			   name, argv[0][1]);
1046 	    return -1;
1047 	}
1048 
1049     if (!argv || !*argv) {
1050 	int i = -1;
1051 	int len = 0, st = 0, cu;
1052 	for (m = ttymodes; m->m_name; m++) {
1053 	    if (m->m_type != i) {
1054 		(void)fprintf(el->el_outfile, "%s%s", i != -1 ? "\n" : "",
1055 			el->el_tty.t_t[z][m->m_type].t_name);
1056 		i = m->m_type;
1057 		st = len = strlen(el->el_tty.t_t[z][m->m_type].t_name);
1058 	    }
1059 
1060 	    x = (el->el_tty.t_t[z][i].t_setmask & m->m_value) ? '+' : '\0';
1061 	    x = (el->el_tty.t_t[z][i].t_clrmask & m->m_value) ? '-' : x;
1062 
1063 	    if (x != '\0' || aflag) {
1064 
1065 		cu = strlen(m->m_name) + (x != '\0') + 1;
1066 
1067 		if (len + cu >= el->el_term.t_size.h) {
1068 		    (void)fprintf(el->el_outfile, "\n%*s", st, "");
1069 		    len = st + cu;
1070 		}
1071 		else
1072 		    len += cu;
1073 
1074 		if (x != '\0')
1075 		    (void)fprintf(el->el_outfile, "%c%s ", x, m->m_name);
1076 		else
1077 		    (void)fprintf(el->el_outfile, "%s ", m->m_name);
1078 	    }
1079 	}
1080 	(void)fprintf(el->el_outfile, "\n");
1081 	return 0;
1082     }
1083 
1084     while (argv && (s = *argv++)) {
1085 	switch (*s) {
1086 	case '+':
1087 	case '-':
1088 	    x = *s++;
1089 	    break;
1090 	default:
1091 	    x = '\0';
1092 	    break;
1093 	}
1094 	d = s;
1095 	for (m = ttymodes; m->m_name; m++)
1096 	    if (strcmp(m->m_name, d) == 0)
1097 		break;
1098 
1099 	if (!m->m_name)  {
1100 	    (void)fprintf(el->el_errfile, "%s: Invalid argument `%s'.\n",
1101 			   name, d);
1102 	    return -1;
1103 	}
1104 
1105 	switch (x) {
1106 	case '+':
1107 	    el->el_tty.t_t[z][m->m_type].t_setmask |= m->m_value;
1108 	    el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value;
1109 	    break;
1110 	case '-':
1111 	    el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value;
1112 	    el->el_tty.t_t[z][m->m_type].t_clrmask |= m->m_value;
1113 	    break;
1114 	default:
1115 	    el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value;
1116 	    el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value;
1117 	    break;
1118 	}
1119     }
1120     return 0;
1121 } /* end tty_stty */
1122 
1123 
1124 #ifdef notyet
1125 /* tty_printchar():
1126  *	DEbugging routine to print the tty characters
1127  */
1128 private void
1129 tty_printchar(el, s)
1130     EditLine *el;
1131     unsigned char *s;
1132 {
1133     ttyperm_t *m;
1134     int i;
1135 
1136     for (i = 0; i < C_NCC; i++) {
1137 	for (m = el->el_tty.t_t; m->m_name; m++)
1138 	    if (m->m_type == M_CHAR && C_SH(i) == m->m_value)
1139 		break;
1140 	if (m->m_name)
1141 	    (void)fprintf(el->el_errfile, "%s ^%c ", m->m_name, s[i] + 'A'-1);
1142 	if (i % 5 == 0)
1143 	    (void)fprintf(el->el_errfile, "\n");
1144     }
1145     (void)fprintf(el->el_errfile, "\n");
1146 }
1147 #endif /* notyet */
1148