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