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