1 /**	$MirOS: src/lib/libedit/tty.c,v 1.2 2005/04/19 15:16:17 tg Exp $ */
2 /*	$OpenBSD: tty.c,v 1.10 2003/11/25 20:12:38 otto Exp $	*/
3 /*	$NetBSD: tty.c,v 1.21 2004/08/13 12:10:39 mycroft Exp $	*/
4 
5 /*-
6  * Copyright (c) 1992, 1993
7  *	The Regents of the University of California.  All rights reserved.
8  *
9  * This code is derived from software contributed to Berkeley by
10  * Christos Zoulas of Cornell University.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  * 3. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36 
37 #include "config.h"
38 
39 /*
40  * tty.c: tty interface stuff
41  */
42 #include <assert.h>
43 #include "tty.h"
44 #include "el.h"
45 
46 __SCCSID("@(#)tty.c	8.1 (Berkeley) 6/4/93");
47 __RCSID("$MirOS: src/lib/libedit/tty.c,v 1.2 2005/04/19 15:16:17 tg Exp $");
48 
49 typedef struct ttymodes_t {
50 	const char *m_name;
51 	u_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 	{ED_DELETE_PREV_CHAR, VI_DELETE_PREV_CHAR, ED_PREV_CHAR}},
123 #endif /* VERASE */
124 #ifdef VERASE2
125 	{C_ERASE2, VERASE2,
126 	{ED_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_getty(el, td)	tcgetattr((el)->el_infd, (td))
447 #define	tty_setty(el, td)	tcsetattr((el)->el_infd, TCSADRAIN, (td))
448 
449 #define	tty__gettabs(td)	((((td)->c_oflag & TAB3) == TAB3) ? 0 : 1)
450 #define	tty__geteightbit(td)	(((td)->c_cflag & CSIZE) == CS8)
451 #define	tty__cooked_mode(td)	((td)->c_lflag & ICANON)
452 
453 private int	tty__getcharindex(int);
454 private void	tty__getchar(struct termios *, unsigned char *);
455 private void	tty__setchar(struct termios *, unsigned char *);
456 private speed_t	tty__getspeed(struct termios *);
457 private int	tty_setup(EditLine *);
458 
459 #define	t_qu	t_ts
460 
461 
462 /* tty_setup():
463  *	Get the tty parameters and initialize the editing state
464  */
465 private int
tty_setup(EditLine * el)466 tty_setup(EditLine *el)
467 {
468 	int rst = 1;
469 
470 	if (el->el_flags & EDIT_DISABLED)
471 		return (0);
472 
473 	if (tty_getty(el, &el->el_tty.t_ed) == -1) {
474 #ifdef DEBUG_TTY
475 		(void) fprintf(el->el_errfile,
476 		    "tty_setup: tty_getty: %s\n", strerror(errno));
477 #endif /* DEBUG_TTY */
478 		return (-1);
479 	}
480 	el->el_tty.t_ts = el->el_tty.t_ex = el->el_tty.t_ed;
481 
482 	el->el_tty.t_speed = tty__getspeed(&el->el_tty.t_ex);
483 	el->el_tty.t_tabs = tty__gettabs(&el->el_tty.t_ex);
484 	el->el_tty.t_eight = tty__geteightbit(&el->el_tty.t_ex);
485 
486 	el->el_tty.t_ex.c_iflag &= ~el->el_tty.t_t[EX_IO][MD_INP].t_clrmask;
487 	el->el_tty.t_ex.c_iflag |= el->el_tty.t_t[EX_IO][MD_INP].t_setmask;
488 
489 	el->el_tty.t_ex.c_oflag &= ~el->el_tty.t_t[EX_IO][MD_OUT].t_clrmask;
490 	el->el_tty.t_ex.c_oflag |= el->el_tty.t_t[EX_IO][MD_OUT].t_setmask;
491 
492 	el->el_tty.t_ex.c_cflag &= ~el->el_tty.t_t[EX_IO][MD_CTL].t_clrmask;
493 	el->el_tty.t_ex.c_cflag |= el->el_tty.t_t[EX_IO][MD_CTL].t_setmask;
494 
495 	el->el_tty.t_ex.c_lflag &= ~el->el_tty.t_t[EX_IO][MD_LIN].t_clrmask;
496 	el->el_tty.t_ex.c_lflag |= el->el_tty.t_t[EX_IO][MD_LIN].t_setmask;
497 
498 	/*
499          * Reset the tty chars to reasonable defaults
500          * If they are disabled, then enable them.
501          */
502 	if (rst) {
503 		if (tty__cooked_mode(&el->el_tty.t_ts)) {
504 			tty__getchar(&el->el_tty.t_ts, el->el_tty.t_c[TS_IO]);
505 			/*
506 	                 * Don't affect CMIN and CTIME for the editor mode
507 	                 */
508 			for (rst = 0; rst < C_NCC - 2; rst++)
509 				if (el->el_tty.t_c[TS_IO][rst] !=
510 				      el->el_tty.t_vdisable
511 				    && el->el_tty.t_c[ED_IO][rst] !=
512 				      el->el_tty.t_vdisable)
513 					el->el_tty.t_c[ED_IO][rst] =
514 					    el->el_tty.t_c[TS_IO][rst];
515 			for (rst = 0; rst < C_NCC; rst++)
516 				if (el->el_tty.t_c[TS_IO][rst] !=
517 				    el->el_tty.t_vdisable)
518 					el->el_tty.t_c[EX_IO][rst] =
519 					    el->el_tty.t_c[TS_IO][rst];
520 		}
521 		tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]);
522 		if (tty_setty(el, &el->el_tty.t_ex) == -1) {
523 #ifdef DEBUG_TTY
524 			(void) fprintf(el->el_errfile,
525 			    "tty_setup: tty_setty: %s\n",
526 			    strerror(errno));
527 #endif /* DEBUG_TTY */
528 			return (-1);
529 		}
530 	} else
531 		tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]);
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)567 tty_end(EditLine *el __attribute__((__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_ex) != el->el_tty.t_speed ||
933 	    tty__getspeed(&el->el_tty.t_ed) != el->el_tty.t_speed) {
934 		(void) cfsetispeed(&el->el_tty.t_ex, el->el_tty.t_speed);
935 		(void) cfsetospeed(&el->el_tty.t_ex, el->el_tty.t_speed);
936 		(void) cfsetispeed(&el->el_tty.t_ed, el->el_tty.t_speed);
937 		(void) cfsetospeed(&el->el_tty.t_ed, el->el_tty.t_speed);
938 	}
939 	if (tty__cooked_mode(&el->el_tty.t_ts)) {
940 		if (el->el_tty.t_ts.c_cflag != el->el_tty.t_ex.c_cflag) {
941 			el->el_tty.t_ex.c_cflag =
942 			    el->el_tty.t_ts.c_cflag;
943 			el->el_tty.t_ex.c_cflag &=
944 			    ~el->el_tty.t_t[EX_IO][MD_CTL].t_clrmask;
945 			el->el_tty.t_ex.c_cflag |=
946 			    el->el_tty.t_t[EX_IO][MD_CTL].t_setmask;
947 
948 			el->el_tty.t_ed.c_cflag =
949 			    el->el_tty.t_ts.c_cflag;
950 			el->el_tty.t_ed.c_cflag &=
951 			    ~el->el_tty.t_t[ED_IO][MD_CTL].t_clrmask;
952 			el->el_tty.t_ed.c_cflag |=
953 			    el->el_tty.t_t[ED_IO][MD_CTL].t_setmask;
954 		}
955 		if ((el->el_tty.t_ts.c_lflag != el->el_tty.t_ex.c_lflag) &&
956 		    (el->el_tty.t_ts.c_lflag != el->el_tty.t_ed.c_lflag)) {
957 			el->el_tty.t_ex.c_lflag =
958 			    el->el_tty.t_ts.c_lflag;
959 			el->el_tty.t_ex.c_lflag &=
960 			    ~el->el_tty.t_t[EX_IO][MD_LIN].t_clrmask;
961 			el->el_tty.t_ex.c_lflag |=
962 			    el->el_tty.t_t[EX_IO][MD_LIN].t_setmask;
963 
964 			el->el_tty.t_ed.c_lflag =
965 			    el->el_tty.t_ts.c_lflag;
966 			el->el_tty.t_ed.c_lflag &=
967 			    ~el->el_tty.t_t[ED_IO][MD_LIN].t_clrmask;
968 			el->el_tty.t_ed.c_lflag |=
969 			    el->el_tty.t_t[ED_IO][MD_LIN].t_setmask;
970 		}
971 		if ((el->el_tty.t_ts.c_iflag != el->el_tty.t_ex.c_iflag) &&
972 		    (el->el_tty.t_ts.c_iflag != el->el_tty.t_ed.c_iflag)) {
973 			el->el_tty.t_ex.c_iflag =
974 			    el->el_tty.t_ts.c_iflag;
975 			el->el_tty.t_ex.c_iflag &=
976 			    ~el->el_tty.t_t[EX_IO][MD_INP].t_clrmask;
977 			el->el_tty.t_ex.c_iflag |=
978 			    el->el_tty.t_t[EX_IO][MD_INP].t_setmask;
979 
980 			el->el_tty.t_ed.c_iflag =
981 			    el->el_tty.t_ts.c_iflag;
982 			el->el_tty.t_ed.c_iflag &=
983 			    ~el->el_tty.t_t[ED_IO][MD_INP].t_clrmask;
984 			el->el_tty.t_ed.c_iflag |=
985 			    el->el_tty.t_t[ED_IO][MD_INP].t_setmask;
986 		}
987 		if ((el->el_tty.t_ts.c_oflag != el->el_tty.t_ex.c_oflag) &&
988 		    (el->el_tty.t_ts.c_oflag != el->el_tty.t_ed.c_oflag)) {
989 			el->el_tty.t_ex.c_oflag =
990 			    el->el_tty.t_ts.c_oflag;
991 			el->el_tty.t_ex.c_oflag &=
992 			    ~el->el_tty.t_t[EX_IO][MD_OUT].t_clrmask;
993 			el->el_tty.t_ex.c_oflag |=
994 			    el->el_tty.t_t[EX_IO][MD_OUT].t_setmask;
995 
996 			el->el_tty.t_ed.c_oflag =
997 			    el->el_tty.t_ts.c_oflag;
998 			el->el_tty.t_ed.c_oflag &=
999 			    ~el->el_tty.t_t[ED_IO][MD_OUT].t_clrmask;
1000 			el->el_tty.t_ed.c_oflag |=
1001 			    el->el_tty.t_t[ED_IO][MD_OUT].t_setmask;
1002 		}
1003 		if (tty__gettabs(&el->el_tty.t_ex) == 0)
1004 			el->el_tty.t_tabs = 0;
1005 		else
1006 			el->el_tty.t_tabs = EL_CAN_TAB ? 1 : 0;
1007 
1008 		{
1009 			int i;
1010 
1011 			tty__getchar(&el->el_tty.t_ts, el->el_tty.t_c[TS_IO]);
1012 			/*
1013 		         * Check if the user made any changes.
1014 		         * If he did, then propagate the changes to the
1015 		         * edit and execute data structures.
1016 		         */
1017 			for (i = 0; i < C_NCC; i++)
1018 				if (el->el_tty.t_c[TS_IO][i] !=
1019 				    el->el_tty.t_c[EX_IO][i])
1020 					break;
1021 
1022 			if (i != C_NCC) {
1023 				/*
1024 				 * Propagate changes only to the unprotected
1025 				 * chars that have been modified just now.
1026 				 */
1027 				for (i = 0; i < C_NCC; i++) {
1028 					if (!((el->el_tty.t_t[ED_IO][MD_CHAR].t_setmask & C_SH(i)))
1029 					    && (el->el_tty.t_c[TS_IO][i] != el->el_tty.t_c[EX_IO][i]))
1030 						el->el_tty.t_c[ED_IO][i] = el->el_tty.t_c[TS_IO][i];
1031 					if (el->el_tty.t_t[ED_IO][MD_CHAR].t_clrmask & C_SH(i))
1032 						el->el_tty.t_c[ED_IO][i] = el->el_tty.t_vdisable;
1033 				}
1034 				tty_bind_char(el, 0);
1035 				tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]);
1036 
1037 				for (i = 0; i < C_NCC; i++) {
1038 					if (!((el->el_tty.t_t[EX_IO][MD_CHAR].t_setmask & C_SH(i)))
1039 					    && (el->el_tty.t_c[TS_IO][i] != el->el_tty.t_c[EX_IO][i]))
1040 						el->el_tty.t_c[EX_IO][i] = el->el_tty.t_c[TS_IO][i];
1041 					if (el->el_tty.t_t[EX_IO][MD_CHAR].t_clrmask & C_SH(i))
1042 						el->el_tty.t_c[EX_IO][i] = el->el_tty.t_vdisable;
1043 				}
1044 				tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]);
1045 			}
1046 		}
1047 	}
1048 	if (tty_setty(el, &el->el_tty.t_ed) == -1) {
1049 #ifdef DEBUG_TTY
1050 		(void) fprintf(el->el_errfile, "tty_rawmode: tty_setty: %s\n",
1051 		    strerror(errno));
1052 #endif /* DEBUG_TTY */
1053 		return (-1);
1054 	}
1055 	el->el_tty.t_mode = ED_IO;
1056 	return (0);
1057 }
1058 
1059 
1060 /* tty_cookedmode():
1061  *	Set the tty back to normal mode
1062  */
1063 protected int
tty_cookedmode(EditLine * el)1064 tty_cookedmode(EditLine *el)
1065 {				/* set tty in normal setup */
1066 
1067 	if (el->el_tty.t_mode == EX_IO)
1068 		return (0);
1069 
1070 	if (el->el_flags & EDIT_DISABLED)
1071 		return (0);
1072 
1073 	if (tty_setty(el, &el->el_tty.t_ex) == -1) {
1074 #ifdef DEBUG_TTY
1075 		(void) fprintf(el->el_errfile,
1076 		    "tty_cookedmode: tty_setty: %s\n",
1077 		    strerror(errno));
1078 #endif /* DEBUG_TTY */
1079 		return (-1);
1080 	}
1081 	el->el_tty.t_mode = EX_IO;
1082 	return (0);
1083 }
1084 
1085 
1086 /* tty_quotemode():
1087  *	Turn on quote mode
1088  */
1089 protected int
tty_quotemode(EditLine * el)1090 tty_quotemode(EditLine *el)
1091 {
1092 	if (el->el_tty.t_mode == QU_IO)
1093 		return (0);
1094 
1095 	el->el_tty.t_qu = el->el_tty.t_ed;
1096 
1097 	el->el_tty.t_qu.c_iflag &= ~el->el_tty.t_t[QU_IO][MD_INP].t_clrmask;
1098 	el->el_tty.t_qu.c_iflag |= el->el_tty.t_t[QU_IO][MD_INP].t_setmask;
1099 
1100 	el->el_tty.t_qu.c_oflag &= ~el->el_tty.t_t[QU_IO][MD_OUT].t_clrmask;
1101 	el->el_tty.t_qu.c_oflag |= el->el_tty.t_t[QU_IO][MD_OUT].t_setmask;
1102 
1103 	el->el_tty.t_qu.c_cflag &= ~el->el_tty.t_t[QU_IO][MD_CTL].t_clrmask;
1104 	el->el_tty.t_qu.c_cflag |= el->el_tty.t_t[QU_IO][MD_CTL].t_setmask;
1105 
1106 	el->el_tty.t_qu.c_lflag &= ~el->el_tty.t_t[QU_IO][MD_LIN].t_clrmask;
1107 	el->el_tty.t_qu.c_lflag |= el->el_tty.t_t[QU_IO][MD_LIN].t_setmask;
1108 
1109 	if (tty_setty(el, &el->el_tty.t_qu) == -1) {
1110 #ifdef DEBUG_TTY
1111 		(void) fprintf(el->el_errfile, "QuoteModeOn: tty_setty: %s\n",
1112 		    strerror(errno));
1113 #endif /* DEBUG_TTY */
1114 		return (-1);
1115 	}
1116 	el->el_tty.t_mode = QU_IO;
1117 	return (0);
1118 }
1119 
1120 
1121 /* tty_noquotemode():
1122  *	Turn off quote mode
1123  */
1124 protected int
tty_noquotemode(EditLine * el)1125 tty_noquotemode(EditLine *el)
1126 {
1127 
1128 	if (el->el_tty.t_mode != QU_IO)
1129 		return (0);
1130 	if (tty_setty(el, &el->el_tty.t_ed) == -1) {
1131 #ifdef DEBUG_TTY
1132 		(void) fprintf(el->el_errfile, "QuoteModeOff: tty_setty: %s\n",
1133 		    strerror(errno));
1134 #endif /* DEBUG_TTY */
1135 		return (-1);
1136 	}
1137 	el->el_tty.t_mode = ED_IO;
1138 	return (0);
1139 }
1140 
1141 
1142 /* tty_stty():
1143  *	Stty builtin
1144  */
1145 protected int
1146 /*ARGSUSED*/
tty_stty(EditLine * el,int argc,const char ** argv)1147 tty_stty(EditLine *el, int argc __attribute__((__unused__)), const char **argv)
1148 {
1149 	const ttymodes_t *m;
1150 	char x;
1151 	int aflag = 0;
1152 	const char *s, *d;
1153 	const char *name;
1154 	struct termios *tios = &el->el_tty.t_ex;
1155 	int z = EX_IO;
1156 
1157 	if (argv == NULL)
1158 		return (-1);
1159 	name = *argv++;
1160 
1161 	while (argv && *argv && argv[0][0] == '-' && argv[0][2] == '\0')
1162 		switch (argv[0][1]) {
1163 		case 'a':
1164 			aflag++;
1165 			argv++;
1166 			break;
1167 		case 'd':
1168 			argv++;
1169 			tios = &el->el_tty.t_ed;
1170 			z = ED_IO;
1171 			break;
1172 		case 'x':
1173 			argv++;
1174 			tios = &el->el_tty.t_ex;
1175 			z = EX_IO;
1176 			break;
1177 		case 'q':
1178 			argv++;
1179 			tios = &el->el_tty.t_ts;
1180 			z = QU_IO;
1181 			break;
1182 		default:
1183 			(void) fprintf(el->el_errfile,
1184 			    "%s: Unknown switch `%c'.\n",
1185 			    name, argv[0][1]);
1186 			return (-1);
1187 		}
1188 
1189 	if (!argv || !*argv) {
1190 		int i = -1;
1191 		int len = 0, st = 0, cu;
1192 		for (m = ttymodes; m->m_name; m++) {
1193 			if (m->m_type != i) {
1194 				(void) fprintf(el->el_outfile, "%s%s",
1195 				    i != -1 ? "\n" : "",
1196 				    el->el_tty.t_t[z][m->m_type].t_name);
1197 				i = m->m_type;
1198 				st = len =
1199 				    strlen(el->el_tty.t_t[z][m->m_type].t_name);
1200 			}
1201 			x = (el->el_tty.t_t[z][i].t_setmask & m->m_value)
1202 			    ?  '+' : '\0';
1203 			x = (el->el_tty.t_t[z][i].t_clrmask & m->m_value)
1204 			    ? '-' : x;
1205 
1206 			if (x != '\0' || aflag) {
1207 
1208 				cu = strlen(m->m_name) + (x != '\0') + 1;
1209 
1210 				if (len + cu >= el->el_term.t_size.h) {
1211 					(void) fprintf(el->el_outfile, "\n%*s",
1212 					    st, "");
1213 					len = st + cu;
1214 				} else
1215 					len += cu;
1216 
1217 				if (x != '\0')
1218 					(void) fprintf(el->el_outfile, "%c%s ",
1219 					    x, m->m_name);
1220 				else
1221 					(void) fprintf(el->el_outfile, "%s ",
1222 					    m->m_name);
1223 			}
1224 		}
1225 		(void) fprintf(el->el_outfile, "\n");
1226 		return (0);
1227 	}
1228 	while (argv && (s = *argv++)) {
1229 		char *p;
1230 		switch (*s) {
1231 		case '+':
1232 		case '-':
1233 			x = *s++;
1234 			break;
1235 		default:
1236 			x = '\0';
1237 			break;
1238 		}
1239 		d = s;
1240 		if ((p = strchr(s, '=')) != NULL)
1241 			*p++ = '\0';
1242 		for (m = ttymodes; m->m_name; m++)
1243 			if (strcmp(m->m_name, d) == 0 &&
1244 			    (p == NULL || m->m_type == MD_CHAR))
1245 				break;
1246 
1247 		if (!m->m_name) {
1248 			(void) fprintf(el->el_errfile,
1249 			    "%s: Invalid argument `%s'.\n", name, d);
1250 			return (-1);
1251 		}
1252 		if (p) {
1253 			int c = ffs((int)m->m_value);
1254 			int v = *p ? parse__escape((const char **const) &p) :
1255 			    el->el_tty.t_vdisable;
1256 			assert(c-- != 0);
1257 			c = tty__getcharindex(c);
1258 			assert(c != -1);
1259 			tios->c_cc[c] = v;
1260 			continue;
1261 		}
1262 		switch (x) {
1263 		case '+':
1264 			el->el_tty.t_t[z][m->m_type].t_setmask |= m->m_value;
1265 			el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value;
1266 			break;
1267 		case '-':
1268 			el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value;
1269 			el->el_tty.t_t[z][m->m_type].t_clrmask |= m->m_value;
1270 			break;
1271 		default:
1272 			el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value;
1273 			el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value;
1274 			break;
1275 		}
1276 	}
1277 	return (0);
1278 }
1279 
1280 
1281 #ifdef notyet
1282 /* tty_printchar():
1283  *	DEbugging routine to print the tty characters
1284  */
1285 private void
tty_printchar(EditLine * el,unsigned char * s)1286 tty_printchar(EditLine *el, unsigned char *s)
1287 {
1288 	ttyperm_t *m;
1289 	int i;
1290 
1291 	for (i = 0; i < C_NCC; i++) {
1292 		for (m = el->el_tty.t_t; m->m_name; m++)
1293 			if (m->m_type == MD_CHAR && C_SH(i) == m->m_value)
1294 				break;
1295 		if (m->m_name)
1296 			(void) fprintf(el->el_errfile, "%s ^%c ",
1297 			    m->m_name, s[i] + 'A' - 1);
1298 		if (i % 5 == 0)
1299 			(void) fprintf(el->el_errfile, "\n");
1300 	}
1301 	(void) fprintf(el->el_errfile, "\n");
1302 }
1303 #endif /* notyet */
1304