xref: /netbsd-src/lib/libedit/tty.c (revision 5aefcfdc06931dd97e76246d2fe0302f7b3fe094)
1 /*	$NetBSD: tty.c,v 1.13 2000/09/04 22:06:33 lukem 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.13 2000/09/04 22:06:33 lukem 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(struct termios *, unsigned char *);
460 private void	tty__setchar(struct termios *, unsigned char *);
461 private speed_t	tty__getspeed(struct termios *);
462 private int	tty_setup(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(EditLine *el)
472 {
473 	int rst = 1;
474 
475 	if (el->el_flags & EDIT_DISABLED)
476 		return (0);
477 
478 	if (tty_getty(el, &el->el_tty.t_ed) == -1) {
479 #ifdef DEBUG_TTY
480 		(void) fprintf(el->el_errfile,
481 		    "tty_setup: tty_getty: %s\n", strerror(errno));
482 #endif /* DEBUG_TTY */
483 		return (-1);
484 	}
485 	el->el_tty.t_ts = el->el_tty.t_ex = el->el_tty.t_ed;
486 
487 	el->el_tty.t_speed = tty__getspeed(&el->el_tty.t_ex);
488 	el->el_tty.t_tabs = tty__gettabs(&el->el_tty.t_ex);
489 	el->el_tty.t_eight = tty__geteightbit(&el->el_tty.t_ex);
490 
491 	el->el_tty.t_ex.c_iflag &= ~el->el_tty.t_t[EX_IO][MD_INP].t_clrmask;
492 	el->el_tty.t_ex.c_iflag |= el->el_tty.t_t[EX_IO][MD_INP].t_setmask;
493 
494 	el->el_tty.t_ex.c_oflag &= ~el->el_tty.t_t[EX_IO][MD_OUT].t_clrmask;
495 	el->el_tty.t_ex.c_oflag |= el->el_tty.t_t[EX_IO][MD_OUT].t_setmask;
496 
497 	el->el_tty.t_ex.c_cflag &= ~el->el_tty.t_t[EX_IO][MD_CTL].t_clrmask;
498 	el->el_tty.t_ex.c_cflag |= el->el_tty.t_t[EX_IO][MD_CTL].t_setmask;
499 
500 	el->el_tty.t_ex.c_lflag &= ~el->el_tty.t_t[EX_IO][MD_LIN].t_clrmask;
501 	el->el_tty.t_ex.c_lflag |= el->el_tty.t_t[EX_IO][MD_LIN].t_setmask;
502 
503 	/*
504          * Reset the tty chars to reasonable defaults
505          * If they are disabled, then enable them.
506          */
507 	if (rst) {
508 		if (tty__cooked_mode(&el->el_tty.t_ts)) {
509 			tty__getchar(&el->el_tty.t_ts, el->el_tty.t_c[TS_IO]);
510 			/*
511 	                 * Don't affect CMIN and CTIME for the editor mode
512 	                 */
513 			for (rst = 0; rst < C_NCC - 2; rst++)
514 				if (el->el_tty.t_c[TS_IO][rst] !=
515 				      el->el_tty.t_vdisable
516 				    && el->el_tty.t_c[ED_IO][rst] !=
517 				      el->el_tty.t_vdisable)
518 					el->el_tty.t_c[ED_IO][rst] =
519 					    el->el_tty.t_c[TS_IO][rst];
520 			for (rst = 0; rst < C_NCC; rst++)
521 				if (el->el_tty.t_c[TS_IO][rst] !=
522 				    el->el_tty.t_vdisable)
523 					el->el_tty.t_c[EX_IO][rst] =
524 					    el->el_tty.t_c[TS_IO][rst];
525 		}
526 		tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]);
527 		if (tty_setty(el, &el->el_tty.t_ex) == -1) {
528 #ifdef DEBUG_TTY
529 			(void) fprintf(el->el_errfile,
530 			    "tty_setup: tty_setty: %s\n",
531 			    strerror(errno));
532 #endif /* DEBUG_TTY */
533 			return (-1);
534 		}
535 	} else
536 		tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]);
537 
538 	el->el_tty.t_ed.c_iflag &= ~el->el_tty.t_t[ED_IO][MD_INP].t_clrmask;
539 	el->el_tty.t_ed.c_iflag |= el->el_tty.t_t[ED_IO][MD_INP].t_setmask;
540 
541 	el->el_tty.t_ed.c_oflag &= ~el->el_tty.t_t[ED_IO][MD_OUT].t_clrmask;
542 	el->el_tty.t_ed.c_oflag |= el->el_tty.t_t[ED_IO][MD_OUT].t_setmask;
543 
544 	el->el_tty.t_ed.c_cflag &= ~el->el_tty.t_t[ED_IO][MD_CTL].t_clrmask;
545 	el->el_tty.t_ed.c_cflag |= el->el_tty.t_t[ED_IO][MD_CTL].t_setmask;
546 
547 	el->el_tty.t_ed.c_lflag &= ~el->el_tty.t_t[ED_IO][MD_LIN].t_clrmask;
548 	el->el_tty.t_ed.c_lflag |= el->el_tty.t_t[ED_IO][MD_LIN].t_setmask;
549 
550 	tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]);
551 	tty_bind_char(el, 1);
552 	return (0);
553 }
554 
555 protected int
556 tty_init(EditLine *el)
557 {
558 
559 	el->el_tty.t_mode = EX_IO;
560 	el->el_tty.t_vdisable = _POSIX_VDISABLE;
561 	(void) memcpy(el->el_tty.t_t, ttyperm, sizeof(ttyperm_t));
562 	(void) memcpy(el->el_tty.t_c, ttychar, sizeof(ttychar_t));
563 	return (tty_setup(el));
564 }
565 
566 
567 /* tty_end():
568  *	Restore the tty to its original settings
569  */
570 protected void
571 /*ARGSUSED*/
572 tty_end(EditLine *el)
573 {
574 
575 	/* XXX: Maybe reset to an initial state? */
576 }
577 
578 
579 /* tty__getspeed():
580  *	Get the tty speed
581  */
582 private speed_t
583 tty__getspeed(struct termios *td)
584 {
585 	speed_t spd;
586 
587 	if ((spd = cfgetispeed(td)) == 0)
588 		spd = cfgetospeed(td);
589 	return (spd);
590 }
591 
592 
593 /* tty__getchar():
594  *	Get the tty characters
595  */
596 private void
597 tty__getchar(struct termios *td, unsigned char *s)
598 {
599 
600 #ifdef VINTR
601 	s[C_INTR] = td->c_cc[VINTR];
602 #endif /* VINTR */
603 #ifdef VQUIT
604 	s[C_QUIT] = td->c_cc[VQUIT];
605 #endif /* VQUIT */
606 #ifdef VERASE
607 	s[C_ERASE] = td->c_cc[VERASE];
608 #endif /* VERASE */
609 #ifdef VKILL
610 	s[C_KILL] = td->c_cc[VKILL];
611 #endif /* VKILL */
612 #ifdef VEOF
613 	s[C_EOF] = td->c_cc[VEOF];
614 #endif /* VEOF */
615 #ifdef VEOL
616 	s[C_EOL] = td->c_cc[VEOL];
617 #endif /* VEOL */
618 #ifdef VEOL2
619 	s[C_EOL2] = td->c_cc[VEOL2];
620 #endif /* VEOL2 */
621 #ifdef VSWTCH
622 	s[C_SWTCH] = td->c_cc[VSWTCH];
623 #endif /* VSWTCH */
624 #ifdef VDSWTCH
625 	s[C_DSWTCH] = td->c_cc[VDSWTCH];
626 #endif /* VDSWTCH */
627 #ifdef VERASE2
628 	s[C_ERASE2] = td->c_cc[VERASE2];
629 #endif /* VERASE2 */
630 #ifdef VSTART
631 	s[C_START] = td->c_cc[VSTART];
632 #endif /* VSTART */
633 #ifdef VSTOP
634 	s[C_STOP] = td->c_cc[VSTOP];
635 #endif /* VSTOP */
636 #ifdef VWERASE
637 	s[C_WERASE] = td->c_cc[VWERASE];
638 #endif /* VWERASE */
639 #ifdef VSUSP
640 	s[C_SUSP] = td->c_cc[VSUSP];
641 #endif /* VSUSP */
642 #ifdef VDSUSP
643 	s[C_DSUSP] = td->c_cc[VDSUSP];
644 #endif /* VDSUSP */
645 #ifdef VREPRINT
646 	s[C_REPRINT] = td->c_cc[VREPRINT];
647 #endif /* VREPRINT */
648 #ifdef VDISCARD
649 	s[C_DISCARD] = td->c_cc[VDISCARD];
650 #endif /* VDISCARD */
651 #ifdef VLNEXT
652 	s[C_LNEXT] = td->c_cc[VLNEXT];
653 #endif /* VLNEXT */
654 #ifdef VSTATUS
655 	s[C_STATUS] = td->c_cc[VSTATUS];
656 #endif /* VSTATUS */
657 #ifdef VPAGE
658 	s[C_PAGE] = td->c_cc[VPAGE];
659 #endif /* VPAGE */
660 #ifdef VPGOFF
661 	s[C_PGOFF] = td->c_cc[VPGOFF];
662 #endif /* VPGOFF */
663 #ifdef VKILL2
664 	s[C_KILL2] = td->c_cc[VKILL2];
665 #endif /* KILL2 */
666 #ifdef VMIN
667 	s[C_MIN] = td->c_cc[VMIN];
668 #endif /* VMIN */
669 #ifdef VTIME
670 	s[C_TIME] = td->c_cc[VTIME];
671 #endif /* VTIME */
672 }				/* tty__getchar */
673 
674 
675 /* tty__setchar():
676  *	Set the tty characters
677  */
678 private void
679 tty__setchar(struct termios *td, unsigned char *s)
680 {
681 
682 #ifdef VINTR
683 	td->c_cc[VINTR] = s[C_INTR];
684 #endif /* VINTR */
685 #ifdef VQUIT
686 	td->c_cc[VQUIT] = s[C_QUIT];
687 #endif /* VQUIT */
688 #ifdef VERASE
689 	td->c_cc[VERASE] = s[C_ERASE];
690 #endif /* VERASE */
691 #ifdef VKILL
692 	td->c_cc[VKILL] = s[C_KILL];
693 #endif /* VKILL */
694 #ifdef VEOF
695 	td->c_cc[VEOF] = s[C_EOF];
696 #endif /* VEOF */
697 #ifdef VEOL
698 	td->c_cc[VEOL] = s[C_EOL];
699 #endif /* VEOL */
700 #ifdef VEOL2
701 	td->c_cc[VEOL2] = s[C_EOL2];
702 #endif /* VEOL2 */
703 #ifdef VSWTCH
704 	td->c_cc[VSWTCH] = s[C_SWTCH];
705 #endif /* VSWTCH */
706 #ifdef VDSWTCH
707 	td->c_cc[VDSWTCH] = s[C_DSWTCH];
708 #endif /* VDSWTCH */
709 #ifdef VERASE2
710 	td->c_cc[VERASE2] = s[C_ERASE2];
711 #endif /* VERASE2 */
712 #ifdef VSTART
713 	td->c_cc[VSTART] = s[C_START];
714 #endif /* VSTART */
715 #ifdef VSTOP
716 	td->c_cc[VSTOP] = s[C_STOP];
717 #endif /* VSTOP */
718 #ifdef VWERASE
719 	td->c_cc[VWERASE] = s[C_WERASE];
720 #endif /* VWERASE */
721 #ifdef VSUSP
722 	td->c_cc[VSUSP] = s[C_SUSP];
723 #endif /* VSUSP */
724 #ifdef VDSUSP
725 	td->c_cc[VDSUSP] = s[C_DSUSP];
726 #endif /* VDSUSP */
727 #ifdef VREPRINT
728 	td->c_cc[VREPRINT] = s[C_REPRINT];
729 #endif /* VREPRINT */
730 #ifdef VDISCARD
731 	td->c_cc[VDISCARD] = s[C_DISCARD];
732 #endif /* VDISCARD */
733 #ifdef VLNEXT
734 	td->c_cc[VLNEXT] = s[C_LNEXT];
735 #endif /* VLNEXT */
736 #ifdef VSTATUS
737 	td->c_cc[VSTATUS] = s[C_STATUS];
738 #endif /* VSTATUS */
739 #ifdef VPAGE
740 	td->c_cc[VPAGE] = s[C_PAGE];
741 #endif /* VPAGE */
742 #ifdef VPGOFF
743 	td->c_cc[VPGOFF] = s[C_PGOFF];
744 #endif /* VPGOFF */
745 #ifdef VKILL2
746 	td->c_cc[VKILL2] = s[C_KILL2];
747 #endif /* VKILL2 */
748 #ifdef VMIN
749 	td->c_cc[VMIN] = s[C_MIN];
750 #endif /* VMIN */
751 #ifdef VTIME
752 	td->c_cc[VTIME] = s[C_TIME];
753 #endif /* VTIME */
754 }				/* tty__setchar */
755 
756 
757 /* tty_bind_char():
758  *	Rebind the editline functions
759  */
760 protected void
761 tty_bind_char(EditLine *el, int force)
762 {
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 	map = el->el_map.key;
772 	alt = el->el_map.alt;
773 	if (el->el_map.type == MAP_VI) {
774 		dmap = el->el_map.vii;
775 		dalt = el->el_map.vic;
776 	} else {
777 		dmap = el->el_map.emacs;
778 		dalt = NULL;
779 	}
780 
781 	for (tp = tty_map; tp->nch != -1; tp++) {
782 		new[0] = t_n[tp->nch];
783 		old[0] = t_o[tp->och];
784 		if (new[0] == old[0] && !force)
785 			continue;
786 		/* Put the old default binding back, and set the new binding */
787 		key_clear(el, map, old);
788 		map[(int) old[0]] = dmap[(int) old[0]];
789 		key_clear(el, map, new);
790 		/* MAP_VI == 1, MAP_EMACS == 0... */
791 		map[(int) new[0]] = tp->bind[(int) el->el_map.type];
792 		if (dalt) {
793 			key_clear(el, alt, old);
794 			alt[(int) old[0]] = dalt[(int) old[0]];
795 			key_clear(el, alt, new);
796 			alt[(int) new[0]] = tp->bind[(int) el->el_map.type + 1];
797 		}
798 	}
799 }
800 
801 
802 /* tty_rawmode():
803  * 	Set terminal into 1 character at a time mode.
804  */
805 protected int
806 tty_rawmode(EditLine *el)
807 {
808 
809 	if (el->el_tty.t_mode == ED_IO || el->el_tty.t_mode == QU_IO)
810 		return (0);
811 
812 	if (el->el_flags & EDIT_DISABLED)
813 		return (0);
814 
815 	if (tty_getty(el, &el->el_tty.t_ts) == -1) {
816 #ifdef DEBUG_TTY
817 		(void) fprintf(el->el_errfile, "tty_rawmode: tty_getty: %s\n",
818 		    strerror(errno));
819 #endif /* DEBUG_TTY */
820 		return (-1);
821 	}
822 	/*
823          * We always keep up with the eight bit setting and the speed of the
824          * tty. But only we only believe changes that are made to cooked mode!
825          */
826 	el->el_tty.t_eight = tty__geteightbit(&el->el_tty.t_ts);
827 	el->el_tty.t_speed = tty__getspeed(&el->el_tty.t_ts);
828 
829 	if (tty__getspeed(&el->el_tty.t_ex) != el->el_tty.t_speed ||
830 	    tty__getspeed(&el->el_tty.t_ed) != el->el_tty.t_speed) {
831 		(void) cfsetispeed(&el->el_tty.t_ex, el->el_tty.t_speed);
832 		(void) cfsetospeed(&el->el_tty.t_ex, el->el_tty.t_speed);
833 		(void) cfsetispeed(&el->el_tty.t_ed, el->el_tty.t_speed);
834 		(void) cfsetospeed(&el->el_tty.t_ed, el->el_tty.t_speed);
835 	}
836 	if (tty__cooked_mode(&el->el_tty.t_ts)) {
837 		if (el->el_tty.t_ts.c_cflag != el->el_tty.t_ex.c_cflag) {
838 			el->el_tty.t_ex.c_cflag =
839 			    el->el_tty.t_ts.c_cflag;
840 			el->el_tty.t_ex.c_cflag &=
841 			    ~el->el_tty.t_t[EX_IO][MD_CTL].t_clrmask;
842 			el->el_tty.t_ex.c_cflag |=
843 			    el->el_tty.t_t[EX_IO][MD_CTL].t_setmask;
844 
845 			el->el_tty.t_ed.c_cflag =
846 			    el->el_tty.t_ts.c_cflag;
847 			el->el_tty.t_ed.c_cflag &=
848 			    ~el->el_tty.t_t[ED_IO][MD_CTL].t_clrmask;
849 			el->el_tty.t_ed.c_cflag |=
850 			    el->el_tty.t_t[ED_IO][MD_CTL].t_setmask;
851 		}
852 		if ((el->el_tty.t_ts.c_lflag != el->el_tty.t_ex.c_lflag) &&
853 		    (el->el_tty.t_ts.c_lflag != el->el_tty.t_ed.c_lflag)) {
854 			el->el_tty.t_ex.c_lflag =
855 			    el->el_tty.t_ts.c_lflag;
856 			el->el_tty.t_ex.c_lflag &=
857 			    ~el->el_tty.t_t[EX_IO][MD_LIN].t_clrmask;
858 			el->el_tty.t_ex.c_lflag |=
859 			    el->el_tty.t_t[EX_IO][MD_LIN].t_setmask;
860 
861 			el->el_tty.t_ed.c_lflag =
862 			    el->el_tty.t_ts.c_lflag;
863 			el->el_tty.t_ed.c_lflag &=
864 			    ~el->el_tty.t_t[ED_IO][MD_LIN].t_clrmask;
865 			el->el_tty.t_ed.c_lflag |=
866 			    el->el_tty.t_t[ED_IO][MD_LIN].t_setmask;
867 		}
868 		if ((el->el_tty.t_ts.c_iflag != el->el_tty.t_ex.c_iflag) &&
869 		    (el->el_tty.t_ts.c_iflag != el->el_tty.t_ed.c_iflag)) {
870 			el->el_tty.t_ex.c_iflag =
871 			    el->el_tty.t_ts.c_iflag;
872 			el->el_tty.t_ex.c_iflag &=
873 			    ~el->el_tty.t_t[EX_IO][MD_INP].t_clrmask;
874 			el->el_tty.t_ex.c_iflag |=
875 			    el->el_tty.t_t[EX_IO][MD_INP].t_setmask;
876 
877 			el->el_tty.t_ed.c_iflag =
878 			    el->el_tty.t_ts.c_iflag;
879 			el->el_tty.t_ed.c_iflag &=
880 			    ~el->el_tty.t_t[ED_IO][MD_INP].t_clrmask;
881 			el->el_tty.t_ed.c_iflag |=
882 			    el->el_tty.t_t[ED_IO][MD_INP].t_setmask;
883 		}
884 		if ((el->el_tty.t_ts.c_oflag != el->el_tty.t_ex.c_oflag) &&
885 		    (el->el_tty.t_ts.c_oflag != el->el_tty.t_ed.c_oflag)) {
886 			el->el_tty.t_ex.c_oflag =
887 			    el->el_tty.t_ts.c_oflag;
888 			el->el_tty.t_ex.c_oflag &=
889 			    ~el->el_tty.t_t[EX_IO][MD_OUT].t_clrmask;
890 			el->el_tty.t_ex.c_oflag |=
891 			    el->el_tty.t_t[EX_IO][MD_OUT].t_setmask;
892 
893 			el->el_tty.t_ed.c_oflag =
894 			    el->el_tty.t_ts.c_oflag;
895 			el->el_tty.t_ed.c_oflag &=
896 			    ~el->el_tty.t_t[ED_IO][MD_OUT].t_clrmask;
897 			el->el_tty.t_ed.c_oflag |=
898 			    el->el_tty.t_t[ED_IO][MD_OUT].t_setmask;
899 		}
900 		if (tty__gettabs(&el->el_tty.t_ex) == 0)
901 			el->el_tty.t_tabs = 0;
902 		else
903 			el->el_tty.t_tabs = EL_CAN_TAB ? 1 : 0;
904 
905 		{
906 			int i;
907 
908 			tty__getchar(&el->el_tty.t_ts, el->el_tty.t_c[TS_IO]);
909 			/*
910 		         * Check if the user made any changes.
911 		         * If he did, then propagate the changes to the
912 		         * edit and execute data structures.
913 		         */
914 			for (i = 0; i < C_NCC; i++)
915 				if (el->el_tty.t_c[TS_IO][i] !=
916 				    el->el_tty.t_c[EX_IO][i])
917 					break;
918 
919 			if (i != C_NCC) {
920 				/*
921 				 * Propagate changes only to the unprotected
922 				 * chars that have been modified just now.
923 				 */
924 				for (i = 0; i < C_NCC; i++) {
925 					if (!((el->el_tty.t_t[ED_IO][MD_CHAR].t_setmask & C_SH(i)))
926 					    && (el->el_tty.t_c[TS_IO][i] != el->el_tty.t_c[EX_IO][i]))
927 						el->el_tty.t_c[ED_IO][i] = el->el_tty.t_c[TS_IO][i];
928 					if (el->el_tty.t_t[ED_IO][MD_CHAR].t_clrmask & C_SH(i))
929 						el->el_tty.t_c[ED_IO][i] = el->el_tty.t_vdisable;
930 				}
931 				tty_bind_char(el, 0);
932 				tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]);
933 
934 				for (i = 0; i < C_NCC; i++) {
935 					if (!((el->el_tty.t_t[EX_IO][MD_CHAR].t_setmask & C_SH(i)))
936 					    && (el->el_tty.t_c[TS_IO][i] != el->el_tty.t_c[EX_IO][i]))
937 						el->el_tty.t_c[EX_IO][i] = el->el_tty.t_c[TS_IO][i];
938 					if (el->el_tty.t_t[EX_IO][MD_CHAR].t_clrmask & C_SH(i))
939 						el->el_tty.t_c[EX_IO][i] = el->el_tty.t_vdisable;
940 				}
941 				tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]);
942 			}
943 		}
944 	}
945 	if (tty_setty(el, &el->el_tty.t_ed) == -1) {
946 #ifdef DEBUG_TTY
947 		(void) fprintf(el->el_errfile, "tty_rawmode: tty_setty: %s\n",
948 		    strerror(errno));
949 #endif /* DEBUG_TTY */
950 		return (-1);
951 	}
952 	el->el_tty.t_mode = ED_IO;
953 	return (0);
954 }
955 
956 
957 /* tty_cookedmode():
958  *	Set the tty back to normal mode
959  */
960 protected int
961 tty_cookedmode(EditLine *el)
962 {				/* set tty in normal setup */
963 
964 	if (el->el_tty.t_mode == EX_IO)
965 		return (0);
966 
967 	if (el->el_flags & EDIT_DISABLED)
968 		return (0);
969 
970 	if (tty_setty(el, &el->el_tty.t_ex) == -1) {
971 #ifdef DEBUG_TTY
972 		(void) fprintf(el->el_errfile,
973 		    "tty_cookedmode: tty_setty: %s\n",
974 		    strerror(errno));
975 #endif /* DEBUG_TTY */
976 		return (-1);
977 	}
978 	el->el_tty.t_mode = EX_IO;
979 	return (0);
980 }
981 
982 
983 /* tty_quotemode():
984  *	Turn on quote mode
985  */
986 protected int
987 tty_quotemode(EditLine *el)
988 {
989 	if (el->el_tty.t_mode == QU_IO)
990 		return (0);
991 
992 	el->el_tty.t_qu = el->el_tty.t_ed;
993 
994 	el->el_tty.t_qu.c_iflag &= ~el->el_tty.t_t[QU_IO][MD_INP].t_clrmask;
995 	el->el_tty.t_qu.c_iflag |= el->el_tty.t_t[QU_IO][MD_INP].t_setmask;
996 
997 	el->el_tty.t_qu.c_oflag &= ~el->el_tty.t_t[QU_IO][MD_OUT].t_clrmask;
998 	el->el_tty.t_qu.c_oflag |= el->el_tty.t_t[QU_IO][MD_OUT].t_setmask;
999 
1000 	el->el_tty.t_qu.c_cflag &= ~el->el_tty.t_t[QU_IO][MD_CTL].t_clrmask;
1001 	el->el_tty.t_qu.c_cflag |= el->el_tty.t_t[QU_IO][MD_CTL].t_setmask;
1002 
1003 	el->el_tty.t_qu.c_lflag &= ~el->el_tty.t_t[QU_IO][MD_LIN].t_clrmask;
1004 	el->el_tty.t_qu.c_lflag |= el->el_tty.t_t[QU_IO][MD_LIN].t_setmask;
1005 
1006 	if (tty_setty(el, &el->el_tty.t_qu) == -1) {
1007 #ifdef DEBUG_TTY
1008 		(void) fprintf(el->el_errfile, "QuoteModeOn: tty_setty: %s\n",
1009 		    strerror(errno));
1010 #endif /* DEBUG_TTY */
1011 		return (-1);
1012 	}
1013 	el->el_tty.t_mode = QU_IO;
1014 	return (0);
1015 }
1016 
1017 
1018 /* tty_noquotemode():
1019  *	Turn off quote mode
1020  */
1021 protected int
1022 tty_noquotemode(EditLine *el)
1023 {
1024 
1025 	if (el->el_tty.t_mode != QU_IO)
1026 		return (0);
1027 	if (tty_setty(el, &el->el_tty.t_ed) == -1) {
1028 #ifdef DEBUG_TTY
1029 		(void) fprintf(el->el_errfile, "QuoteModeOff: tty_setty: %s\n",
1030 		    strerror(errno));
1031 #endif /* DEBUG_TTY */
1032 		return (-1);
1033 	}
1034 	el->el_tty.t_mode = ED_IO;
1035 	return (0);
1036 }
1037 
1038 
1039 /* tty_stty():
1040  *	Stty builtin
1041  */
1042 protected int
1043 /*ARGSUSED*/
1044 tty_stty(EditLine *el, int argc, char **argv)
1045 {
1046 	ttymodes_t *m;
1047 	char x, *d;
1048 	int aflag = 0;
1049 	char *s;
1050 	char *name;
1051 	int z = EX_IO;
1052 
1053 	if (argv == NULL)
1054 		return (-1);
1055 	name = *argv++;
1056 
1057 	while (argv && *argv && argv[0][0] == '-' && argv[0][2] == '\0')
1058 		switch (argv[0][1]) {
1059 		case 'a':
1060 			aflag++;
1061 			argv++;
1062 			break;
1063 		case 'd':
1064 			argv++;
1065 			z = ED_IO;
1066 			break;
1067 		case 'x':
1068 			argv++;
1069 			z = EX_IO;
1070 			break;
1071 		case 'q':
1072 			argv++;
1073 			z = QU_IO;
1074 			break;
1075 		default:
1076 			(void) fprintf(el->el_errfile,
1077 			    "%s: Unknown switch `%c'.\n",
1078 			    name, argv[0][1]);
1079 			return (-1);
1080 		}
1081 
1082 	if (!argv || !*argv) {
1083 		int i = -1;
1084 		int len = 0, st = 0, cu;
1085 		for (m = ttymodes; m->m_name; m++) {
1086 			if (m->m_type != i) {
1087 				(void) fprintf(el->el_outfile, "%s%s",
1088 				    i != -1 ? "\n" : "",
1089 				    el->el_tty.t_t[z][m->m_type].t_name);
1090 				i = m->m_type;
1091 				st = len =
1092 				    strlen(el->el_tty.t_t[z][m->m_type].t_name);
1093 			}
1094 			x = (el->el_tty.t_t[z][i].t_setmask & m->m_value)
1095 			    ?  '+' : '\0';
1096 			x = (el->el_tty.t_t[z][i].t_clrmask & m->m_value)
1097 			    ? '-' : x;
1098 
1099 			if (x != '\0' || aflag) {
1100 
1101 				cu = strlen(m->m_name) + (x != '\0') + 1;
1102 
1103 				if (len + cu >= el->el_term.t_size.h) {
1104 					(void) fprintf(el->el_outfile, "\n%*s",
1105 					    st, "");
1106 					len = st + cu;
1107 				} else
1108 					len += cu;
1109 
1110 				if (x != '\0')
1111 					(void) fprintf(el->el_outfile, "%c%s ",
1112 					    x, m->m_name);
1113 				else
1114 					(void) fprintf(el->el_outfile, "%s ",
1115 					    m->m_name);
1116 			}
1117 		}
1118 		(void) fprintf(el->el_outfile, "\n");
1119 		return (0);
1120 	}
1121 	while (argv && (s = *argv++)) {
1122 		switch (*s) {
1123 		case '+':
1124 		case '-':
1125 			x = *s++;
1126 			break;
1127 		default:
1128 			x = '\0';
1129 			break;
1130 		}
1131 		d = s;
1132 		for (m = ttymodes; m->m_name; m++)
1133 			if (strcmp(m->m_name, d) == 0)
1134 				break;
1135 
1136 		if (!m->m_name) {
1137 			(void) fprintf(el->el_errfile,
1138 			    "%s: Invalid argument `%s'.\n", name, d);
1139 			return (-1);
1140 		}
1141 		switch (x) {
1142 		case '+':
1143 			el->el_tty.t_t[z][m->m_type].t_setmask |= m->m_value;
1144 			el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value;
1145 			break;
1146 		case '-':
1147 			el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value;
1148 			el->el_tty.t_t[z][m->m_type].t_clrmask |= m->m_value;
1149 			break;
1150 		default:
1151 			el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value;
1152 			el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value;
1153 			break;
1154 		}
1155 	}
1156 	return (0);
1157 }
1158 
1159 
1160 #ifdef notyet
1161 /* tty_printchar():
1162  *	DEbugging routine to print the tty characters
1163  */
1164 private void
1165 tty_printchar(EditLine *el, unsigned char *s)
1166 {
1167 	ttyperm_t *m;
1168 	int i;
1169 
1170 	for (i = 0; i < C_NCC; i++) {
1171 		for (m = el->el_tty.t_t; m->m_name; m++)
1172 			if (m->m_type == MD_CHAR && C_SH(i) == m->m_value)
1173 				break;
1174 		if (m->m_name)
1175 			(void) fprintf(el->el_errfile, "%s ^%c ",
1176 			    m->m_name, s[i] + 'A' - 1);
1177 		if (i % 5 == 0)
1178 			(void) fprintf(el->el_errfile, "\n");
1179 	}
1180 	(void) fprintf(el->el_errfile, "\n");
1181 }
1182 #endif /* notyet */
1183