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