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