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