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