1/*-
2 * Copyright (c) 1992, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Christos Zoulas of Cornell University.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 *	$NetBSD: tty.c,v 1.31 2009/07/22 15:58:09 christos Exp $
33 */
34
35#if !defined(lint) && !defined(SCCSID)
36static char sccsid[] = "@(#)tty.c	8.1 (Berkeley) 6/4/93";
37#endif /* not lint && not SCCSID */
38#include <sys/cdefs.h>
39__FBSDID("$FreeBSD$");
40
41/*
42 * tty.c: tty interface stuff
43 */
44#include <assert.h>
45#include "sys.h"
46#include "tty.h"
47#include "el.h"
48
49typedef struct ttymodes_t {
50	const char *m_name;
51	unsigned int m_value;
52	int m_type;
53}          ttymodes_t;
54
55typedef 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
61private 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
89private 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
119private const ttymap_t tty_map[] = {
120#ifdef VERASE
121	{C_ERASE, VERASE,
122	{EM_DELETE_PREV_CHAR, VI_DELETE_PREV_CHAR, ED_PREV_CHAR}},
123#endif /* VERASE */
124#ifdef VERASE2
125	{C_ERASE2, VERASE2,
126	{EM_DELETE_PREV_CHAR, VI_DELETE_PREV_CHAR, ED_PREV_CHAR}},
127#endif /* VERASE2 */
128#ifdef VKILL
129	{C_KILL, VKILL,
130	{EM_KILL_LINE, VI_KILL_LINE_PREV, ED_UNASSIGNED}},
131#endif /* VKILL */
132#ifdef VKILL2
133	{C_KILL2, VKILL2,
134	{EM_KILL_LINE, VI_KILL_LINE_PREV, ED_UNASSIGNED}},
135#endif /* VKILL2 */
136#ifdef VEOF
137	{C_EOF, VEOF,
138	{EM_DELETE_OR_LIST, VI_LIST_OR_EOF, ED_UNASSIGNED}},
139#endif /* VEOF */
140#ifdef VWERASE
141	{C_WERASE, VWERASE,
142	{ED_DELETE_PREV_WORD, ED_DELETE_PREV_WORD, ED_PREV_WORD}},
143#endif /* VWERASE */
144#ifdef VREPRINT
145	{C_REPRINT, VREPRINT,
146	{ED_REDISPLAY, ED_INSERT, ED_REDISPLAY}},
147#endif /* VREPRINT */
148#ifdef VLNEXT
149	{C_LNEXT, VLNEXT,
150	{ED_QUOTED_INSERT, ED_QUOTED_INSERT, ED_UNASSIGNED}},
151#endif /* VLNEXT */
152	{-1, -1,
153	{ED_UNASSIGNED, ED_UNASSIGNED, ED_UNASSIGNED}}
154};
155
156private const ttymodes_t ttymodes[] = {
157#ifdef	IGNBRK
158	{"ignbrk", IGNBRK, MD_INP},
159#endif /* IGNBRK */
160#ifdef	BRKINT
161	{"brkint", BRKINT, MD_INP},
162#endif /* BRKINT */
163#ifdef	IGNPAR
164	{"ignpar", IGNPAR, MD_INP},
165#endif /* IGNPAR */
166#ifdef	PARMRK
167	{"parmrk", PARMRK, MD_INP},
168#endif /* PARMRK */
169#ifdef	INPCK
170	{"inpck", INPCK, MD_INP},
171#endif /* INPCK */
172#ifdef	ISTRIP
173	{"istrip", ISTRIP, MD_INP},
174#endif /* ISTRIP */
175#ifdef	INLCR
176	{"inlcr", INLCR, MD_INP},
177#endif /* INLCR */
178#ifdef	IGNCR
179	{"igncr", IGNCR, MD_INP},
180#endif /* IGNCR */
181#ifdef	ICRNL
182	{"icrnl", ICRNL, MD_INP},
183#endif /* ICRNL */
184#ifdef	IUCLC
185	{"iuclc", IUCLC, MD_INP},
186#endif /* IUCLC */
187#ifdef	IXON
188	{"ixon", IXON, MD_INP},
189#endif /* IXON */
190#ifdef	IXANY
191	{"ixany", IXANY, MD_INP},
192#endif /* IXANY */
193#ifdef	IXOFF
194	{"ixoff", IXOFF, MD_INP},
195#endif /* IXOFF */
196#ifdef  IMAXBEL
197	{"imaxbel", IMAXBEL, MD_INP},
198#endif /* IMAXBEL */
199
200#ifdef	OPOST
201	{"opost", OPOST, MD_OUT},
202#endif /* OPOST */
203#ifdef	OLCUC
204	{"olcuc", OLCUC, MD_OUT},
205#endif /* OLCUC */
206#ifdef	ONLCR
207	{"onlcr", ONLCR, MD_OUT},
208#endif /* ONLCR */
209#ifdef	OCRNL
210	{"ocrnl", OCRNL, MD_OUT},
211#endif /* OCRNL */
212#ifdef	ONOCR
213	{"onocr", ONOCR, MD_OUT},
214#endif /* ONOCR */
215#ifdef ONOEOT
216	{"onoeot", ONOEOT, MD_OUT},
217#endif /* ONOEOT */
218#ifdef	ONLRET
219	{"onlret", ONLRET, MD_OUT},
220#endif /* ONLRET */
221#ifdef	OFILL
222	{"ofill", OFILL, MD_OUT},
223#endif /* OFILL */
224#ifdef	OFDEL
225	{"ofdel", OFDEL, MD_OUT},
226#endif /* OFDEL */
227#ifdef	NLDLY
228	{"nldly", NLDLY, MD_OUT},
229#endif /* NLDLY */
230#ifdef	CRDLY
231	{"crdly", CRDLY, MD_OUT},
232#endif /* CRDLY */
233#ifdef	TABDLY
234	{"tabdly", TABDLY, MD_OUT},
235#endif /* TABDLY */
236#ifdef	XTABS
237	{"xtabs", XTABS, MD_OUT},
238#endif /* XTABS */
239#ifdef	BSDLY
240	{"bsdly", BSDLY, MD_OUT},
241#endif /* BSDLY */
242#ifdef	VTDLY
243	{"vtdly", VTDLY, MD_OUT},
244#endif /* VTDLY */
245#ifdef	FFDLY
246	{"ffdly", FFDLY, MD_OUT},
247#endif /* FFDLY */
248#ifdef	PAGEOUT
249	{"pageout", PAGEOUT, MD_OUT},
250#endif /* PAGEOUT */
251#ifdef	WRAP
252	{"wrap", WRAP, MD_OUT},
253#endif /* WRAP */
254
255#ifdef	CIGNORE
256	{"cignore", CIGNORE, MD_CTL},
257#endif /* CBAUD */
258#ifdef	CBAUD
259	{"cbaud", CBAUD, MD_CTL},
260#endif /* CBAUD */
261#ifdef	CSTOPB
262	{"cstopb", CSTOPB, MD_CTL},
263#endif /* CSTOPB */
264#ifdef	CREAD
265	{"cread", CREAD, MD_CTL},
266#endif /* CREAD */
267#ifdef	PARENB
268	{"parenb", PARENB, MD_CTL},
269#endif /* PARENB */
270#ifdef	PARODD
271	{"parodd", PARODD, MD_CTL},
272#endif /* PARODD */
273#ifdef	HUPCL
274	{"hupcl", HUPCL, MD_CTL},
275#endif /* HUPCL */
276#ifdef	CLOCAL
277	{"clocal", CLOCAL, MD_CTL},
278#endif /* CLOCAL */
279#ifdef	LOBLK
280	{"loblk", LOBLK, MD_CTL},
281#endif /* LOBLK */
282#ifdef	CIBAUD
283	{"cibaud", CIBAUD, MD_CTL},
284#endif /* CIBAUD */
285#ifdef CRTSCTS
286#ifdef CCTS_OFLOW
287	{"ccts_oflow", CCTS_OFLOW, MD_CTL},
288#else
289	{"crtscts", CRTSCTS, MD_CTL},
290#endif /* CCTS_OFLOW */
291#endif /* CRTSCTS */
292#ifdef CRTS_IFLOW
293	{"crts_iflow", CRTS_IFLOW, MD_CTL},
294#endif /* CRTS_IFLOW */
295#ifdef CDTRCTS
296	{"cdtrcts", CDTRCTS, MD_CTL},
297#endif /* CDTRCTS */
298#ifdef MDMBUF
299	{"mdmbuf", MDMBUF, MD_CTL},
300#endif /* MDMBUF */
301#ifdef RCV1EN
302	{"rcv1en", RCV1EN, MD_CTL},
303#endif /* RCV1EN */
304#ifdef XMT1EN
305	{"xmt1en", XMT1EN, MD_CTL},
306#endif /* XMT1EN */
307
308#ifdef	ISIG
309	{"isig", ISIG, MD_LIN},
310#endif /* ISIG */
311#ifdef	ICANON
312	{"icanon", ICANON, MD_LIN},
313#endif /* ICANON */
314#ifdef	XCASE
315	{"xcase", XCASE, MD_LIN},
316#endif /* XCASE */
317#ifdef	ECHO
318	{"echo", ECHO, MD_LIN},
319#endif /* ECHO */
320#ifdef	ECHOE
321	{"echoe", ECHOE, MD_LIN},
322#endif /* ECHOE */
323#ifdef	ECHOK
324	{"echok", ECHOK, MD_LIN},
325#endif /* ECHOK */
326#ifdef	ECHONL
327	{"echonl", ECHONL, MD_LIN},
328#endif /* ECHONL */
329#ifdef	NOFLSH
330	{"noflsh", NOFLSH, MD_LIN},
331#endif /* NOFLSH */
332#ifdef	TOSTOP
333	{"tostop", TOSTOP, MD_LIN},
334#endif /* TOSTOP */
335#ifdef	ECHOCTL
336	{"echoctl", ECHOCTL, MD_LIN},
337#endif /* ECHOCTL */
338#ifdef	ECHOPRT
339	{"echoprt", ECHOPRT, MD_LIN},
340#endif /* ECHOPRT */
341#ifdef	ECHOKE
342	{"echoke", ECHOKE, MD_LIN},
343#endif /* ECHOKE */
344#ifdef	DEFECHO
345	{"defecho", DEFECHO, MD_LIN},
346#endif /* DEFECHO */
347#ifdef	FLUSHO
348	{"flusho", FLUSHO, MD_LIN},
349#endif /* FLUSHO */
350#ifdef	PENDIN
351	{"pendin", PENDIN, MD_LIN},
352#endif /* PENDIN */
353#ifdef	IEXTEN
354	{"iexten", IEXTEN, MD_LIN},
355#endif /* IEXTEN */
356#ifdef	NOKERNINFO
357	{"nokerninfo", NOKERNINFO, MD_LIN},
358#endif /* NOKERNINFO */
359#ifdef	ALTWERASE
360	{"altwerase", ALTWERASE, MD_LIN},
361#endif /* ALTWERASE */
362#ifdef	EXTPROC
363	{"extproc", EXTPROC, MD_LIN},
364#endif /* EXTPROC */
365
366#if defined(VINTR)
367	{"intr", C_SH(C_INTR), MD_CHAR},
368#endif /* VINTR */
369#if defined(VQUIT)
370	{"quit", C_SH(C_QUIT), MD_CHAR},
371#endif /* VQUIT */
372#if defined(VERASE)
373	{"erase", C_SH(C_ERASE), MD_CHAR},
374#endif /* VERASE */
375#if defined(VKILL)
376	{"kill", C_SH(C_KILL), MD_CHAR},
377#endif /* VKILL */
378#if defined(VEOF)
379	{"eof", C_SH(C_EOF), MD_CHAR},
380#endif /* VEOF */
381#if defined(VEOL)
382	{"eol", C_SH(C_EOL), MD_CHAR},
383#endif /* VEOL */
384#if defined(VEOL2)
385	{"eol2", C_SH(C_EOL2), MD_CHAR},
386#endif /* VEOL2 */
387#if defined(VSWTCH)
388	{"swtch", C_SH(C_SWTCH), MD_CHAR},
389#endif /* VSWTCH */
390#if defined(VDSWTCH)
391	{"dswtch", C_SH(C_DSWTCH), MD_CHAR},
392#endif /* VDSWTCH */
393#if defined(VERASE2)
394	{"erase2", C_SH(C_ERASE2), MD_CHAR},
395#endif /* VERASE2 */
396#if defined(VSTART)
397	{"start", C_SH(C_START), MD_CHAR},
398#endif /* VSTART */
399#if defined(VSTOP)
400	{"stop", C_SH(C_STOP), MD_CHAR},
401#endif /* VSTOP */
402#if defined(VWERASE)
403	{"werase", C_SH(C_WERASE), MD_CHAR},
404#endif /* VWERASE */
405#if defined(VSUSP)
406	{"susp", C_SH(C_SUSP), MD_CHAR},
407#endif /* VSUSP */
408#if defined(VDSUSP)
409	{"dsusp", C_SH(C_DSUSP), MD_CHAR},
410#endif /* VDSUSP */
411#if defined(VREPRINT)
412	{"reprint", C_SH(C_REPRINT), MD_CHAR},
413#endif /* VREPRINT */
414#if defined(VDISCARD)
415	{"discard", C_SH(C_DISCARD), MD_CHAR},
416#endif /* VDISCARD */
417#if defined(VLNEXT)
418	{"lnext", C_SH(C_LNEXT), MD_CHAR},
419#endif /* VLNEXT */
420#if defined(VSTATUS)
421	{"status", C_SH(C_STATUS), MD_CHAR},
422#endif /* VSTATUS */
423#if defined(VPAGE)
424	{"page", C_SH(C_PAGE), MD_CHAR},
425#endif /* VPAGE */
426#if defined(VPGOFF)
427	{"pgoff", C_SH(C_PGOFF), MD_CHAR},
428#endif /* VPGOFF */
429#if defined(VKILL2)
430	{"kill2", C_SH(C_KILL2), MD_CHAR},
431#endif /* VKILL2 */
432#if defined(VBRK)
433	{"brk", C_SH(C_BRK), MD_CHAR},
434#endif /* VBRK */
435#if defined(VMIN)
436	{"min", C_SH(C_MIN), MD_CHAR},
437#endif /* VMIN */
438#if defined(VTIME)
439	{"time", C_SH(C_TIME), MD_CHAR},
440#endif /* VTIME */
441	{NULL, 0, -1},
442};
443
444
445
446#define	tty__gettabs(td)	((((td)->c_oflag & TAB3) == TAB3) ? 0 : 1)
447#define	tty__geteightbit(td)	(((td)->c_cflag & CSIZE) == CS8)
448#define	tty__cooked_mode(td)	((td)->c_lflag & ICANON)
449
450private int	tty_getty(EditLine *, struct termios *);
451private int	tty_setty(EditLine *, int, const struct termios *);
452private int	tty__getcharindex(int);
453private void	tty__getchar(struct termios *, unsigned char *);
454private void	tty__setchar(struct termios *, unsigned char *);
455private speed_t	tty__getspeed(struct termios *);
456private int	tty_setup(EditLine *);
457
458#define	t_qu	t_ts
459
460/* tty_getty():
461 *	Wrapper for tcgetattr to handle EINTR
462 */
463private int
464tty_getty(EditLine *el, struct termios *t)
465{
466	int rv;
467	while ((rv = tcgetattr(el->el_infd, t)) == -1 && errno == EINTR)
468		continue;
469	return rv;
470}
471
472/* tty_setty():
473 *	Wrapper for tcsetattr to handle EINTR
474 */
475private int
476tty_setty(EditLine *el, int action, const struct termios *t)
477{
478	int rv;
479	while ((rv = tcsetattr(el->el_infd, action, t)) == -1 && errno == EINTR)
480		continue;
481	return rv;
482}
483
484/* tty_setup():
485 *	Get the tty parameters and initialize the editing state
486 */
487private int
488tty_setup(EditLine *el)
489{
490	int rst = 1;
491
492	if (el->el_flags & EDIT_DISABLED)
493		return (0);
494
495	if (tty_getty(el, &el->el_tty.t_ed) == -1) {
496#ifdef DEBUG_TTY
497		(void) fprintf(el->el_errfile,
498		    "tty_setup: tty_getty: %s\n", strerror(errno));
499#endif /* DEBUG_TTY */
500		return (-1);
501	}
502	el->el_tty.t_ts = el->el_tty.t_ex = el->el_tty.t_ed;
503
504	el->el_tty.t_speed = tty__getspeed(&el->el_tty.t_ex);
505	el->el_tty.t_tabs = tty__gettabs(&el->el_tty.t_ex);
506	el->el_tty.t_eight = tty__geteightbit(&el->el_tty.t_ex);
507
508	/*
509         * Reset the tty chars to reasonable defaults
510         * If they are disabled, then enable them.
511         */
512	if (rst) {
513		if (tty__cooked_mode(&el->el_tty.t_ts)) {
514			tty__getchar(&el->el_tty.t_ts, el->el_tty.t_c[TS_IO]);
515			/*
516	                 * Don't affect CMIN and CTIME for the editor mode
517	                 */
518			for (rst = 0; rst < C_NCC - 2; rst++)
519				if (el->el_tty.t_c[TS_IO][rst] !=
520				      el->el_tty.t_vdisable
521				    && el->el_tty.t_c[ED_IO][rst] !=
522				      el->el_tty.t_vdisable)
523					el->el_tty.t_c[ED_IO][rst] =
524					    el->el_tty.t_c[TS_IO][rst];
525			for (rst = 0; rst < C_NCC; rst++)
526				if (el->el_tty.t_c[TS_IO][rst] !=
527				    el->el_tty.t_vdisable)
528					el->el_tty.t_c[EX_IO][rst] =
529					    el->el_tty.t_c[TS_IO][rst];
530		}
531	}
532
533	el->el_tty.t_ed.c_iflag &= ~el->el_tty.t_t[ED_IO][MD_INP].t_clrmask;
534	el->el_tty.t_ed.c_iflag |= el->el_tty.t_t[ED_IO][MD_INP].t_setmask;
535
536	el->el_tty.t_ed.c_oflag &= ~el->el_tty.t_t[ED_IO][MD_OUT].t_clrmask;
537	el->el_tty.t_ed.c_oflag |= el->el_tty.t_t[ED_IO][MD_OUT].t_setmask;
538
539	el->el_tty.t_ed.c_cflag &= ~el->el_tty.t_t[ED_IO][MD_CTL].t_clrmask;
540	el->el_tty.t_ed.c_cflag |= el->el_tty.t_t[ED_IO][MD_CTL].t_setmask;
541
542	el->el_tty.t_ed.c_lflag &= ~el->el_tty.t_t[ED_IO][MD_LIN].t_clrmask;
543	el->el_tty.t_ed.c_lflag |= el->el_tty.t_t[ED_IO][MD_LIN].t_setmask;
544
545	tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]);
546	tty_bind_char(el, 1);
547	return (0);
548}
549
550protected int
551tty_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 */
565protected void
566/*ARGSUSED*/
567tty_end(EditLine *el __unused)
568{
569
570	/* XXX: Maybe reset to an initial state? */
571}
572
573
574/* tty__getspeed():
575 *	Get the tty speed
576 */
577private speed_t
578tty__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 */
590private int
591tty__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 */
698private void
699tty__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 */
780private void
781tty__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 */
862protected void
863tty_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 */
908protected int
909tty_rawmode(EditLine *el)
910{
911
912	if (el->el_tty.t_mode == ED_IO || el->el_tty.t_mode == QU_IO)
913		return (0);
914
915	if (el->el_flags & EDIT_DISABLED)
916		return (0);
917
918	if (tty_getty(el, &el->el_tty.t_ts) == -1) {
919#ifdef DEBUG_TTY
920		(void) fprintf(el->el_errfile, "tty_rawmode: tty_getty: %s\n",
921		    strerror(errno));
922#endif /* DEBUG_TTY */
923		return (-1);
924	}
925	/*
926         * We always keep up with the eight bit setting and the speed of the
927         * tty. But only we only believe changes that are made to cooked mode!
928         */
929	el->el_tty.t_eight = tty__geteightbit(&el->el_tty.t_ts);
930	el->el_tty.t_speed = tty__getspeed(&el->el_tty.t_ts);
931
932	if (tty__getspeed(&el->el_tty.t_ed) != el->el_tty.t_speed) {
933		(void) cfsetispeed(&el->el_tty.t_ed, el->el_tty.t_speed);
934		(void) cfsetospeed(&el->el_tty.t_ed, el->el_tty.t_speed);
935	}
936	if (tty__cooked_mode(&el->el_tty.t_ts)) {
937		if ((el->el_tty.t_ts.c_cflag != el->el_tty.t_ex.c_cflag) &&
938		    (el->el_tty.t_ts.c_cflag != el->el_tty.t_ed.c_cflag)) {
939			el->el_tty.t_ed.c_cflag =
940			    el->el_tty.t_ts.c_cflag;
941			el->el_tty.t_ed.c_cflag &=
942			    ~el->el_tty.t_t[ED_IO][MD_CTL].t_clrmask;
943			el->el_tty.t_ed.c_cflag |=
944			    el->el_tty.t_t[ED_IO][MD_CTL].t_setmask;
945		}
946		if ((el->el_tty.t_ts.c_lflag != el->el_tty.t_ex.c_lflag) &&
947		    (el->el_tty.t_ts.c_lflag != el->el_tty.t_ed.c_lflag)) {
948			el->el_tty.t_ed.c_lflag =
949			    el->el_tty.t_ts.c_lflag;
950			el->el_tty.t_ed.c_lflag &=
951			    ~el->el_tty.t_t[ED_IO][MD_LIN].t_clrmask;
952			el->el_tty.t_ed.c_lflag |=
953			    el->el_tty.t_t[ED_IO][MD_LIN].t_setmask;
954		}
955		if ((el->el_tty.t_ts.c_iflag != el->el_tty.t_ex.c_iflag) &&
956		    (el->el_tty.t_ts.c_iflag != el->el_tty.t_ed.c_iflag)) {
957			el->el_tty.t_ed.c_iflag =
958			    el->el_tty.t_ts.c_iflag;
959			el->el_tty.t_ed.c_iflag &=
960			    ~el->el_tty.t_t[ED_IO][MD_INP].t_clrmask;
961			el->el_tty.t_ed.c_iflag |=
962			    el->el_tty.t_t[ED_IO][MD_INP].t_setmask;
963		}
964		if ((el->el_tty.t_ts.c_oflag != el->el_tty.t_ex.c_oflag) &&
965		    (el->el_tty.t_ts.c_oflag != el->el_tty.t_ed.c_oflag)) {
966			el->el_tty.t_ed.c_oflag =
967			    el->el_tty.t_ts.c_oflag;
968			el->el_tty.t_ed.c_oflag &=
969			    ~el->el_tty.t_t[ED_IO][MD_OUT].t_clrmask;
970			el->el_tty.t_ed.c_oflag |=
971			    el->el_tty.t_t[ED_IO][MD_OUT].t_setmask;
972		}
973		if (tty__gettabs(&el->el_tty.t_ex) == 0)
974			el->el_tty.t_tabs = 0;
975		else
976			el->el_tty.t_tabs = EL_CAN_TAB ? 1 : 0;
977
978		{
979			int i;
980
981			tty__getchar(&el->el_tty.t_ts, el->el_tty.t_c[TS_IO]);
982			/*
983		         * Check if the user made any changes.
984		         * If he did, then propagate the changes to the
985		         * edit and execute data structures.
986		         */
987			for (i = 0; i < C_NCC; i++)
988				if (el->el_tty.t_c[TS_IO][i] !=
989				    el->el_tty.t_c[EX_IO][i])
990					break;
991
992			if (i != C_NCC) {
993				/*
994				 * Propagate changes only to the unprotected
995				 * chars that have been modified just now.
996				 */
997				for (i = 0; i < C_NCC; i++) {
998					if (!((el->el_tty.t_t[ED_IO][MD_CHAR].t_setmask & C_SH(i)))
999					    && (el->el_tty.t_c[TS_IO][i] != el->el_tty.t_c[EX_IO][i]))
1000						el->el_tty.t_c[ED_IO][i] = el->el_tty.t_c[TS_IO][i];
1001					if (el->el_tty.t_t[ED_IO][MD_CHAR].t_clrmask & C_SH(i))
1002						el->el_tty.t_c[ED_IO][i] = el->el_tty.t_vdisable;
1003				}
1004				tty_bind_char(el, 0);
1005				tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]);
1006
1007				for (i = 0; i < C_NCC; i++) {
1008					if (!((el->el_tty.t_t[EX_IO][MD_CHAR].t_setmask & C_SH(i)))
1009					    && (el->el_tty.t_c[TS_IO][i] != el->el_tty.t_c[EX_IO][i]))
1010						el->el_tty.t_c[EX_IO][i] = el->el_tty.t_c[TS_IO][i];
1011					if (el->el_tty.t_t[EX_IO][MD_CHAR].t_clrmask & C_SH(i))
1012						el->el_tty.t_c[EX_IO][i] = el->el_tty.t_vdisable;
1013				}
1014			}
1015		}
1016	}
1017
1018	if (el->el_tty.t_mode == EX_IO)
1019		el->el_tty.t_ex = el->el_tty.t_ts;
1020
1021	if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ed) == -1) {
1022#ifdef DEBUG_TTY
1023		(void) fprintf(el->el_errfile, "tty_rawmode: tty_setty: %s\n",
1024		    strerror(errno));
1025#endif /* DEBUG_TTY */
1026		return (-1);
1027	}
1028	el->el_tty.t_mode = ED_IO;
1029	return (0);
1030}
1031
1032
1033/* tty_cookedmode():
1034 *	Set the tty back to normal mode
1035 */
1036protected int
1037tty_cookedmode(EditLine *el)
1038{				/* set tty in normal setup */
1039
1040	if (el->el_tty.t_mode == EX_IO)
1041		return (0);
1042
1043	if (el->el_flags & EDIT_DISABLED)
1044		return (0);
1045
1046	if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ex) == -1) {
1047#ifdef DEBUG_TTY
1048		(void) fprintf(el->el_errfile,
1049		    "tty_cookedmode: tty_setty: %s\n",
1050		    strerror(errno));
1051#endif /* DEBUG_TTY */
1052		return (-1);
1053	}
1054	el->el_tty.t_mode = EX_IO;
1055	return (0);
1056}
1057
1058
1059/* tty_quotemode():
1060 *	Turn on quote mode
1061 */
1062protected int
1063tty_quotemode(EditLine *el)
1064{
1065	if (el->el_tty.t_mode == QU_IO)
1066		return (0);
1067
1068	el->el_tty.t_qu = el->el_tty.t_ed;
1069
1070	el->el_tty.t_qu.c_iflag &= ~el->el_tty.t_t[QU_IO][MD_INP].t_clrmask;
1071	el->el_tty.t_qu.c_iflag |= el->el_tty.t_t[QU_IO][MD_INP].t_setmask;
1072
1073	el->el_tty.t_qu.c_oflag &= ~el->el_tty.t_t[QU_IO][MD_OUT].t_clrmask;
1074	el->el_tty.t_qu.c_oflag |= el->el_tty.t_t[QU_IO][MD_OUT].t_setmask;
1075
1076	el->el_tty.t_qu.c_cflag &= ~el->el_tty.t_t[QU_IO][MD_CTL].t_clrmask;
1077	el->el_tty.t_qu.c_cflag |= el->el_tty.t_t[QU_IO][MD_CTL].t_setmask;
1078
1079	el->el_tty.t_qu.c_lflag &= ~el->el_tty.t_t[QU_IO][MD_LIN].t_clrmask;
1080	el->el_tty.t_qu.c_lflag |= el->el_tty.t_t[QU_IO][MD_LIN].t_setmask;
1081
1082	if (tty_setty(el, TCSADRAIN, &el->el_tty.t_qu) == -1) {
1083#ifdef DEBUG_TTY
1084		(void) fprintf(el->el_errfile, "QuoteModeOn: tty_setty: %s\n",
1085		    strerror(errno));
1086#endif /* DEBUG_TTY */
1087		return (-1);
1088	}
1089	el->el_tty.t_mode = QU_IO;
1090	return (0);
1091}
1092
1093
1094/* tty_noquotemode():
1095 *	Turn off quote mode
1096 */
1097protected int
1098tty_noquotemode(EditLine *el)
1099{
1100
1101	if (el->el_tty.t_mode != QU_IO)
1102		return (0);
1103	if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ed) == -1) {
1104#ifdef DEBUG_TTY
1105		(void) fprintf(el->el_errfile, "QuoteModeOff: tty_setty: %s\n",
1106		    strerror(errno));
1107#endif /* DEBUG_TTY */
1108		return (-1);
1109	}
1110	el->el_tty.t_mode = ED_IO;
1111	return (0);
1112}
1113
1114
1115/* tty_stty():
1116 *	Stty builtin
1117 */
1118protected int
1119/*ARGSUSED*/
1120tty_stty(EditLine *el, int argc __unused, const char **argv)
1121{
1122	const ttymodes_t *m;
1123	char x;
1124	int aflag = 0;
1125	const char *s, *d;
1126	const char *name;
1127	struct termios *tios = &el->el_tty.t_ex;
1128	int z = EX_IO;
1129
1130	if (argv == NULL)
1131		return (-1);
1132	name = *argv++;
1133
1134	while (argv && *argv && argv[0][0] == '-' && argv[0][2] == '\0')
1135		switch (argv[0][1]) {
1136		case 'a':
1137			aflag++;
1138			argv++;
1139			break;
1140		case 'd':
1141			argv++;
1142			tios = &el->el_tty.t_ed;
1143			z = ED_IO;
1144			break;
1145		case 'x':
1146			argv++;
1147			tios = &el->el_tty.t_ex;
1148			z = EX_IO;
1149			break;
1150		case 'q':
1151			argv++;
1152			tios = &el->el_tty.t_ts;
1153			z = QU_IO;
1154			break;
1155		default:
1156			(void) fprintf(el->el_errfile,
1157			    "%s: Unknown switch `%c'.\n",
1158			    name, argv[0][1]);
1159			return (-1);
1160		}
1161
1162	if (!argv || !*argv) {
1163		int i = -1;
1164		size_t len = 0, st = 0, cu;
1165		for (m = ttymodes; m->m_name; m++) {
1166			if (m->m_type != i) {
1167				(void) fprintf(el->el_outfile, "%s%s",
1168				    i != -1 ? "\n" : "",
1169				    el->el_tty.t_t[z][m->m_type].t_name);
1170				i = m->m_type;
1171				st = len =
1172				    strlen(el->el_tty.t_t[z][m->m_type].t_name);
1173			}
1174			if (i != -1) {
1175			    x = (el->el_tty.t_t[z][i].t_setmask & m->m_value)
1176				?  '+' : '\0';
1177			    x = (el->el_tty.t_t[z][i].t_clrmask & m->m_value)
1178				? '-' : x;
1179			} else {
1180			    x = '\0';
1181			}
1182
1183			if (x != '\0' || aflag) {
1184
1185				cu = strlen(m->m_name) + (x != '\0') + 1;
1186
1187				if (len + cu >= (size_t)el->el_term.t_size.h) {
1188					(void) fprintf(el->el_outfile, "\n%*s",
1189					    (int)st, "");
1190					len = st + cu;
1191				} else
1192					len += cu;
1193
1194				if (x != '\0')
1195					(void) fprintf(el->el_outfile, "%c%s ",
1196					    x, m->m_name);
1197				else
1198					(void) fprintf(el->el_outfile, "%s ",
1199					    m->m_name);
1200			}
1201		}
1202		(void) fprintf(el->el_outfile, "\n");
1203		return (0);
1204	}
1205	while (argv && (s = *argv++)) {
1206		const char *p;
1207		switch (*s) {
1208		case '+':
1209		case '-':
1210			x = *s++;
1211			break;
1212		default:
1213			x = '\0';
1214			break;
1215		}
1216		d = s;
1217		p = strchr(s, '=');
1218		for (m = ttymodes; m->m_name; m++)
1219			if ((p ? strncmp(m->m_name, d, (size_t)(p - d)) :
1220			    strcmp(m->m_name, d)) == 0 &&
1221			    (p == NULL || m->m_type == MD_CHAR))
1222				break;
1223
1224		if (!m->m_name) {
1225			(void) fprintf(el->el_errfile,
1226			    "%s: Invalid argument `%s'.\n", name, d);
1227			return (-1);
1228		}
1229		if (p) {
1230			int c = ffs((int)m->m_value);
1231			int v = *++p ? parse__escape((const char **) &p) :
1232			    el->el_tty.t_vdisable;
1233			assert(c != 0);
1234			c--;
1235			c = tty__getcharindex(c);
1236			assert(c != -1);
1237			tios->c_cc[c] = v;
1238			continue;
1239		}
1240		switch (x) {
1241		case '+':
1242			el->el_tty.t_t[z][m->m_type].t_setmask |= m->m_value;
1243			el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value;
1244			break;
1245		case '-':
1246			el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value;
1247			el->el_tty.t_t[z][m->m_type].t_clrmask |= m->m_value;
1248			break;
1249		default:
1250			el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value;
1251			el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value;
1252			break;
1253		}
1254	}
1255
1256	if (el->el_tty.t_mode == z) {
1257		if (tty_setty(el, TCSADRAIN, tios) == -1) {
1258#ifdef DEBUG_TTY
1259			(void) fprintf(el->el_errfile,
1260			    "tty_stty: tty_setty: %s\n", strerror(errno));
1261#endif /* DEBUG_TTY */
1262			return (-1);
1263		}
1264	}
1265
1266	return (0);
1267}
1268
1269
1270#ifdef notyet
1271/* tty_printchar():
1272 *	DEbugging routine to print the tty characters
1273 */
1274private void
1275tty_printchar(EditLine *el, unsigned char *s)
1276{
1277	ttyperm_t *m;
1278	int i;
1279
1280	for (i = 0; i < C_NCC; i++) {
1281		for (m = el->el_tty.t_t; m->m_name; m++)
1282			if (m->m_type == MD_CHAR && C_SH(i) == m->m_value)
1283				break;
1284		if (m->m_name)
1285			(void) fprintf(el->el_errfile, "%s ^%c ",
1286			    m->m_name, s[i] + 'A' - 1);
1287		if (i % 5 == 0)
1288			(void) fprintf(el->el_errfile, "\n");
1289	}
1290	(void) fprintf(el->el_errfile, "\n");
1291}
1292#endif /* notyet */
1293