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