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