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