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