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