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