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