1/*	$NetBSD: tty.c,v 1.70 2021/07/14 07:47:23 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.70 2021/07/14 07:47:23 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 <stdlib.h>	/* for abort */
50#include <string.h>
51#include <strings.h>	/* for ffs */
52#include <unistd.h>	/* for isatty */
53
54#include "el.h"
55#include "fcns.h"
56#include "parse.h"
57
58typedef struct ttymodes_t {
59	const char *m_name;
60	unsigned int m_value;
61	int m_type;
62}          ttymodes_t;
63
64typedef struct ttymap_t {
65	wint_t nch, och;	/* Internal and termio rep of chars */
66	el_action_t bind[3];	/* emacs, vi, and vi-cmd */
67} ttymap_t;
68
69
70static const ttyperm_t ttyperm = {
71	{
72		{"iflag:", ICRNL, (INLCR | IGNCR)},
73		{"oflag:", (OPOST | ONLCR), ONLRET},
74		{"cflag:", 0, 0},
75		{"lflag:", (ISIG | ICANON | ECHO | ECHOE | ECHOCTL | IEXTEN),
76		(NOFLSH | ECHONL | EXTPROC | FLUSHO)},
77		{"chars:", 0, 0},
78	},
79	{
80		{"iflag:", (INLCR | ICRNL), IGNCR},
81		{"oflag:", (OPOST | ONLCR), ONLRET},
82		{"cflag:", 0, 0},
83		{"lflag:", ISIG,
84		(NOFLSH | ICANON | ECHO | ECHOK | ECHONL | EXTPROC | IEXTEN | FLUSHO)},
85		{"chars:", (C_SH(C_MIN) | C_SH(C_TIME) | C_SH(C_SWTCH) | C_SH(C_DSWTCH) |
86			    C_SH(C_SUSP) | C_SH(C_DSUSP) | C_SH(C_EOL) | C_SH(C_DISCARD) |
87		    C_SH(C_PGOFF) | C_SH(C_PAGE) | C_SH(C_STATUS)), 0}
88	},
89	{
90		{"iflag:", 0, IXON | IXOFF | INLCR | ICRNL},
91		{"oflag:", 0, 0},
92		{"cflag:", 0, 0},
93		{"lflag:", 0, ISIG | IEXTEN},
94		{"chars:", 0, 0},
95	}
96};
97
98static const ttychar_t ttychar = {
99	{
100		CINTR, CQUIT, CERASE, CKILL,
101		CEOF, CEOL, CEOL2, CSWTCH,
102		CDSWTCH, CERASE2, CSTART, CSTOP,
103		CWERASE, CSUSP, CDSUSP, CREPRINT,
104		CDISCARD, CLNEXT, CSTATUS, CPAGE,
105		CPGOFF, CKILL2, CBRK, CMIN,
106		CTIME
107	},
108	{
109		CINTR, CQUIT, CERASE, CKILL,
110		_POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE,
111		_POSIX_VDISABLE, CERASE2, CSTART, CSTOP,
112		_POSIX_VDISABLE, CSUSP, _POSIX_VDISABLE, _POSIX_VDISABLE,
113		CDISCARD, _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE,
114		_POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE, 1,
115		0
116	},
117	{
118		0, 0, 0, 0,
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
125	}
126};
127
128static const ttymap_t tty_map[] = {
129#ifdef VERASE
130	{C_ERASE, VERASE,
131	{EM_DELETE_PREV_CHAR, VI_DELETE_PREV_CHAR, ED_PREV_CHAR}},
132#endif /* VERASE */
133#ifdef VERASE2
134	{C_ERASE2, VERASE2,
135	{EM_DELETE_PREV_CHAR, VI_DELETE_PREV_CHAR, ED_PREV_CHAR}},
136#endif /* VERASE2 */
137#ifdef VKILL
138	{C_KILL, VKILL,
139	{EM_KILL_LINE, VI_KILL_LINE_PREV, ED_UNASSIGNED}},
140#endif /* VKILL */
141#ifdef VKILL2
142	{C_KILL2, VKILL2,
143	{EM_KILL_LINE, VI_KILL_LINE_PREV, ED_UNASSIGNED}},
144#endif /* VKILL2 */
145#ifdef VEOF
146	{C_EOF, VEOF,
147	{EM_DELETE_OR_LIST, VI_LIST_OR_EOF, ED_UNASSIGNED}},
148#endif /* VEOF */
149#ifdef VWERASE
150	{C_WERASE, VWERASE,
151	{ED_DELETE_PREV_WORD, ED_DELETE_PREV_WORD, ED_PREV_WORD}},
152#endif /* VWERASE */
153#ifdef VREPRINT
154	{C_REPRINT, VREPRINT,
155	{ED_REDISPLAY, ED_INSERT, ED_REDISPLAY}},
156#endif /* VREPRINT */
157#ifdef VLNEXT
158	{C_LNEXT, VLNEXT,
159	{ED_QUOTED_INSERT, ED_QUOTED_INSERT, ED_UNASSIGNED}},
160#endif /* VLNEXT */
161	{(wint_t)-1, (wint_t)-1,
162	{ED_UNASSIGNED, ED_UNASSIGNED, ED_UNASSIGNED}}
163};
164
165static const ttymodes_t ttymodes[] = {
166#ifdef	IGNBRK
167	{"ignbrk", IGNBRK, MD_INP},
168#endif /* IGNBRK */
169#ifdef	BRKINT
170	{"brkint", BRKINT, MD_INP},
171#endif /* BRKINT */
172#ifdef	IGNPAR
173	{"ignpar", IGNPAR, MD_INP},
174#endif /* IGNPAR */
175#ifdef	PARMRK
176	{"parmrk", PARMRK, MD_INP},
177#endif /* PARMRK */
178#ifdef	INPCK
179	{"inpck", INPCK, MD_INP},
180#endif /* INPCK */
181#ifdef	ISTRIP
182	{"istrip", ISTRIP, MD_INP},
183#endif /* ISTRIP */
184#ifdef	INLCR
185	{"inlcr", INLCR, MD_INP},
186#endif /* INLCR */
187#ifdef	IGNCR
188	{"igncr", IGNCR, MD_INP},
189#endif /* IGNCR */
190#ifdef	ICRNL
191	{"icrnl", ICRNL, MD_INP},
192#endif /* ICRNL */
193#ifdef	IUCLC
194	{"iuclc", IUCLC, MD_INP},
195#endif /* IUCLC */
196#ifdef	IXON
197	{"ixon", IXON, MD_INP},
198#endif /* IXON */
199#ifdef	IXANY
200	{"ixany", IXANY, MD_INP},
201#endif /* IXANY */
202#ifdef	IXOFF
203	{"ixoff", IXOFF, MD_INP},
204#endif /* IXOFF */
205#ifdef  IMAXBEL
206	{"imaxbel", IMAXBEL, MD_INP},
207#endif /* IMAXBEL */
208
209#ifdef	OPOST
210	{"opost", OPOST, MD_OUT},
211#endif /* OPOST */
212#ifdef	OLCUC
213	{"olcuc", OLCUC, MD_OUT},
214#endif /* OLCUC */
215#ifdef	ONLCR
216	{"onlcr", ONLCR, MD_OUT},
217#endif /* ONLCR */
218#ifdef	OCRNL
219	{"ocrnl", OCRNL, MD_OUT},
220#endif /* OCRNL */
221#ifdef	ONOCR
222	{"onocr", ONOCR, MD_OUT},
223#endif /* ONOCR */
224#ifdef ONOEOT
225	{"onoeot", ONOEOT, MD_OUT},
226#endif /* ONOEOT */
227#ifdef	ONLRET
228	{"onlret", ONLRET, MD_OUT},
229#endif /* ONLRET */
230#ifdef	OFILL
231	{"ofill", OFILL, MD_OUT},
232#endif /* OFILL */
233#ifdef	OFDEL
234	{"ofdel", OFDEL, MD_OUT},
235#endif /* OFDEL */
236#ifdef	NLDLY
237	{"nldly", NLDLY, MD_OUT},
238#endif /* NLDLY */
239#ifdef	CRDLY
240	{"crdly", CRDLY, MD_OUT},
241#endif /* CRDLY */
242#ifdef	TABDLY
243	{"tabdly", TABDLY, MD_OUT},
244#endif /* TABDLY */
245#ifdef	XTABS
246	{"xtabs", XTABS, MD_OUT},
247#endif /* XTABS */
248#ifdef	BSDLY
249	{"bsdly", BSDLY, MD_OUT},
250#endif /* BSDLY */
251#ifdef	VTDLY
252	{"vtdly", VTDLY, MD_OUT},
253#endif /* VTDLY */
254#ifdef	FFDLY
255	{"ffdly", FFDLY, MD_OUT},
256#endif /* FFDLY */
257#ifdef	PAGEOUT
258	{"pageout", PAGEOUT, MD_OUT},
259#endif /* PAGEOUT */
260#ifdef	WRAP
261	{"wrap", WRAP, MD_OUT},
262#endif /* WRAP */
263
264#ifdef	CIGNORE
265	{"cignore", CIGNORE, MD_CTL},
266#endif /* CBAUD */
267#ifdef	CBAUD
268	{"cbaud", CBAUD, MD_CTL},
269#endif /* CBAUD */
270#ifdef	CSTOPB
271	{"cstopb", CSTOPB, MD_CTL},
272#endif /* CSTOPB */
273#ifdef	CREAD
274	{"cread", CREAD, MD_CTL},
275#endif /* CREAD */
276#ifdef	PARENB
277	{"parenb", PARENB, MD_CTL},
278#endif /* PARENB */
279#ifdef	PARODD
280	{"parodd", PARODD, MD_CTL},
281#endif /* PARODD */
282#ifdef	HUPCL
283	{"hupcl", HUPCL, MD_CTL},
284#endif /* HUPCL */
285#ifdef	CLOCAL
286	{"clocal", CLOCAL, MD_CTL},
287#endif /* CLOCAL */
288#ifdef	LOBLK
289	{"loblk", LOBLK, MD_CTL},
290#endif /* LOBLK */
291#ifdef	CIBAUD
292	{"cibaud", CIBAUD, MD_CTL},
293#endif /* CIBAUD */
294#ifdef CRTSCTS
295#ifdef CCTS_OFLOW
296	{"ccts_oflow", CCTS_OFLOW, MD_CTL},
297#else
298	{"crtscts", CRTSCTS, MD_CTL},
299#endif /* CCTS_OFLOW */
300#endif /* CRTSCTS */
301#ifdef CRTS_IFLOW
302	{"crts_iflow", CRTS_IFLOW, MD_CTL},
303#endif /* CRTS_IFLOW */
304#ifdef CDTRCTS
305	{"cdtrcts", CDTRCTS, MD_CTL},
306#endif /* CDTRCTS */
307#ifdef MDMBUF
308	{"mdmbuf", MDMBUF, MD_CTL},
309#endif /* MDMBUF */
310#ifdef RCV1EN
311	{"rcv1en", RCV1EN, MD_CTL},
312#endif /* RCV1EN */
313#ifdef XMT1EN
314	{"xmt1en", XMT1EN, MD_CTL},
315#endif /* XMT1EN */
316
317#ifdef	ISIG
318	{"isig", ISIG, MD_LIN},
319#endif /* ISIG */
320#ifdef	ICANON
321	{"icanon", ICANON, MD_LIN},
322#endif /* ICANON */
323#ifdef	XCASE
324	{"xcase", XCASE, MD_LIN},
325#endif /* XCASE */
326#ifdef	ECHO
327	{"echo", ECHO, MD_LIN},
328#endif /* ECHO */
329#ifdef	ECHOE
330	{"echoe", ECHOE, MD_LIN},
331#endif /* ECHOE */
332#ifdef	ECHOK
333	{"echok", ECHOK, MD_LIN},
334#endif /* ECHOK */
335#ifdef	ECHONL
336	{"echonl", ECHONL, MD_LIN},
337#endif /* ECHONL */
338#ifdef	NOFLSH
339	{"noflsh", NOFLSH, MD_LIN},
340#endif /* NOFLSH */
341#ifdef	TOSTOP
342	{"tostop", TOSTOP, MD_LIN},
343#endif /* TOSTOP */
344#ifdef	ECHOCTL
345	{"echoctl", ECHOCTL, MD_LIN},
346#endif /* ECHOCTL */
347#ifdef	ECHOPRT
348	{"echoprt", ECHOPRT, MD_LIN},
349#endif /* ECHOPRT */
350#ifdef	ECHOKE
351	{"echoke", ECHOKE, MD_LIN},
352#endif /* ECHOKE */
353#ifdef	DEFECHO
354	{"defecho", DEFECHO, MD_LIN},
355#endif /* DEFECHO */
356#ifdef	FLUSHO
357	{"flusho", FLUSHO, MD_LIN},
358#endif /* FLUSHO */
359#ifdef	PENDIN
360	{"pendin", PENDIN, MD_LIN},
361#endif /* PENDIN */
362#ifdef	IEXTEN
363	{"iexten", IEXTEN, MD_LIN},
364#endif /* IEXTEN */
365#ifdef	NOKERNINFO
366	{"nokerninfo", NOKERNINFO, MD_LIN},
367#endif /* NOKERNINFO */
368#ifdef	ALTWERASE
369	{"altwerase", ALTWERASE, MD_LIN},
370#endif /* ALTWERASE */
371#ifdef	EXTPROC
372	{"extproc", EXTPROC, MD_LIN},
373#endif /* EXTPROC */
374
375#if defined(VINTR)
376	{"intr", C_SH(C_INTR), MD_CHAR},
377#endif /* VINTR */
378#if defined(VQUIT)
379	{"quit", C_SH(C_QUIT), MD_CHAR},
380#endif /* VQUIT */
381#if defined(VERASE)
382	{"erase", C_SH(C_ERASE), MD_CHAR},
383#endif /* VERASE */
384#if defined(VKILL)
385	{"kill", C_SH(C_KILL), MD_CHAR},
386#endif /* VKILL */
387#if defined(VEOF)
388	{"eof", C_SH(C_EOF), MD_CHAR},
389#endif /* VEOF */
390#if defined(VEOL)
391	{"eol", C_SH(C_EOL), MD_CHAR},
392#endif /* VEOL */
393#if defined(VEOL2)
394	{"eol2", C_SH(C_EOL2), MD_CHAR},
395#endif /* VEOL2 */
396#if defined(VSWTCH)
397	{"swtch", C_SH(C_SWTCH), MD_CHAR},
398#endif /* VSWTCH */
399#if defined(VDSWTCH)
400	{"dswtch", C_SH(C_DSWTCH), MD_CHAR},
401#endif /* VDSWTCH */
402#if defined(VERASE2)
403	{"erase2", C_SH(C_ERASE2), MD_CHAR},
404#endif /* VERASE2 */
405#if defined(VSTART)
406	{"start", C_SH(C_START), MD_CHAR},
407#endif /* VSTART */
408#if defined(VSTOP)
409	{"stop", C_SH(C_STOP), MD_CHAR},
410#endif /* VSTOP */
411#if defined(VWERASE)
412	{"werase", C_SH(C_WERASE), MD_CHAR},
413#endif /* VWERASE */
414#if defined(VSUSP)
415	{"susp", C_SH(C_SUSP), MD_CHAR},
416#endif /* VSUSP */
417#if defined(VDSUSP)
418	{"dsusp", C_SH(C_DSUSP), MD_CHAR},
419#endif /* VDSUSP */
420#if defined(VREPRINT)
421	{"reprint", C_SH(C_REPRINT), MD_CHAR},
422#endif /* VREPRINT */
423#if defined(VDISCARD)
424	{"discard", C_SH(C_DISCARD), MD_CHAR},
425#endif /* VDISCARD */
426#if defined(VLNEXT)
427	{"lnext", C_SH(C_LNEXT), MD_CHAR},
428#endif /* VLNEXT */
429#if defined(VSTATUS)
430	{"status", C_SH(C_STATUS), MD_CHAR},
431#endif /* VSTATUS */
432#if defined(VPAGE)
433	{"page", C_SH(C_PAGE), MD_CHAR},
434#endif /* VPAGE */
435#if defined(VPGOFF)
436	{"pgoff", C_SH(C_PGOFF), MD_CHAR},
437#endif /* VPGOFF */
438#if defined(VKILL2)
439	{"kill2", C_SH(C_KILL2), MD_CHAR},
440#endif /* VKILL2 */
441#if defined(VBRK)
442	{"brk", C_SH(C_BRK), MD_CHAR},
443#endif /* VBRK */
444#if defined(VMIN)
445	{"min", C_SH(C_MIN), MD_CHAR},
446#endif /* VMIN */
447#if defined(VTIME)
448	{"time", C_SH(C_TIME), MD_CHAR},
449#endif /* VTIME */
450	{NULL, 0, -1},
451};
452
453
454
455#define	tty__gettabs(td)	((((td)->c_oflag & TAB3) == TAB3) ? 0 : 1)
456#define	tty__geteightbit(td)	(((td)->c_cflag & CSIZE) == CS8)
457#define	tty__cooked_mode(td)	((td)->c_lflag & ICANON)
458
459static int	tty_getty(EditLine *, struct termios *);
460static int	tty_setty(EditLine *, int, const struct termios *);
461static int	tty__getcharindex(int);
462static void	tty__getchar(struct termios *, unsigned char *);
463static void	tty__setchar(struct termios *, unsigned char *);
464static speed_t	tty__getspeed(struct termios *);
465static int	tty_setup(EditLine *);
466static void	tty_setup_flags(EditLine *, struct termios *, int);
467
468#define	t_qu	t_ts
469
470/* tty_getty():
471 *	Wrapper for tcgetattr to handle EINTR
472 */
473static int
474tty_getty(EditLine *el, struct termios *t)
475{
476	int rv;
477	while ((rv = tcgetattr(el->el_infd, t)) == -1 && errno == EINTR)
478		continue;
479	return rv;
480}
481
482/* tty_setty():
483 *	Wrapper for tcsetattr to handle EINTR
484 */
485static int
486tty_setty(EditLine *el, int action, const struct termios *t)
487{
488	int rv;
489	while ((rv = tcsetattr(el->el_infd, action, t)) == -1 && errno == EINTR)
490		continue;
491	return rv;
492}
493
494/* tty_setup():
495 *	Get the tty parameters and initialize the editing state
496 */
497static int
498tty_setup(EditLine *el)
499{
500	int rst = (el->el_flags & NO_RESET) == 0;
501
502	if (el->el_flags & EDIT_DISABLED)
503		return 0;
504
505	if (el->el_tty.t_initialized)
506		return -1;
507
508	if (!isatty(el->el_outfd)) {
509#ifdef DEBUG_TTY
510		(void) fprintf(el->el_errfile, "%s: isatty: %s\n", __func__,
511		    strerror(errno));
512#endif /* DEBUG_TTY */
513		return -1;
514	}
515	if (tty_getty(el, &el->el_tty.t_or) == -1) {
516#ifdef DEBUG_TTY
517		(void) fprintf(el->el_errfile, "%s: tty_getty: %s\n", __func__,
518		    strerror(errno));
519#endif /* DEBUG_TTY */
520		return -1;
521	}
522	el->el_tty.t_ts = el->el_tty.t_ex = el->el_tty.t_ed = el->el_tty.t_or;
523
524	el->el_tty.t_speed = tty__getspeed(&el->el_tty.t_ex);
525	el->el_tty.t_tabs = tty__gettabs(&el->el_tty.t_ex);
526	el->el_tty.t_eight = tty__geteightbit(&el->el_tty.t_ex);
527
528	tty_setup_flags(el, &el->el_tty.t_ex, EX_IO);
529
530	/*
531         * Reset the tty chars to reasonable defaults
532         * If they are disabled, then enable them.
533         */
534	if (rst) {
535		if (tty__cooked_mode(&el->el_tty.t_ts)) {
536			tty__getchar(&el->el_tty.t_ts, el->el_tty.t_c[TS_IO]);
537			/*
538	                 * Don't affect CMIN and CTIME for the editor mode
539	                 */
540			for (rst = 0; rst < C_NCC - 2; rst++)
541				if (el->el_tty.t_c[TS_IO][rst] !=
542				      el->el_tty.t_vdisable
543				    && el->el_tty.t_c[ED_IO][rst] !=
544				      el->el_tty.t_vdisable)
545					el->el_tty.t_c[ED_IO][rst] =
546					    el->el_tty.t_c[TS_IO][rst];
547			for (rst = 0; rst < C_NCC; rst++)
548				if (el->el_tty.t_c[TS_IO][rst] !=
549				    el->el_tty.t_vdisable)
550					el->el_tty.t_c[EX_IO][rst] =
551					    el->el_tty.t_c[TS_IO][rst];
552		}
553		tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]);
554		if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ex) == -1) {
555#ifdef DEBUG_TTY
556			(void) fprintf(el->el_errfile, "%s: tty_setty: %s\n",
557			    __func__, strerror(errno));
558#endif /* DEBUG_TTY */
559			return -1;
560		}
561	}
562
563	tty_setup_flags(el, &el->el_tty.t_ed, ED_IO);
564
565	tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]);
566	tty_bind_char(el, 1);
567	el->el_tty.t_initialized = 1;
568	return 0;
569}
570
571libedit_private int
572tty_init(EditLine *el)
573{
574
575	el->el_tty.t_mode = EX_IO;
576	el->el_tty.t_vdisable = _POSIX_VDISABLE;
577	el->el_tty.t_initialized = 0;
578	(void) memcpy(el->el_tty.t_t, ttyperm, sizeof(ttyperm_t));
579	(void) memcpy(el->el_tty.t_c, ttychar, sizeof(ttychar_t));
580	return tty_setup(el);
581}
582
583
584/* tty_end():
585 *	Restore the tty to its original settings
586 */
587libedit_private void
588/*ARGSUSED*/
589tty_end(EditLine *el, int how)
590{
591	if (el->el_flags & EDIT_DISABLED)
592		return;
593
594	if (!el->el_tty.t_initialized)
595		return;
596
597	if (tty_setty(el, how, &el->el_tty.t_or) == -1)
598	{
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 */
610static 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 */
623static 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 */
731static 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 */
813static 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 */
895libedit_private 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	wchar_t 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] = (wchar_t)t_n[tp->nch];
919		old[0] = (wchar_t)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[(unsigned char)old[0]] = dmap[(unsigned char)old[0]];
925		keymacro_clear(el, map, new);
926		/* MAP_VI == 1, MAP_EMACS == 0... */
927		map[(unsigned char)new[0]] = tp->bind[el->el_map.type];
928		if (dalt) {
929			keymacro_clear(el, alt, old);
930			alt[(unsigned char)old[0]] =
931			    dalt[(unsigned char)old[0]];
932			keymacro_clear(el, alt, new);
933			alt[(unsigned char)new[0]] =
934			    tp->bind[el->el_map.type + 1];
935		}
936	}
937}
938
939
940static tcflag_t *
941tty__get_flag(struct termios *t, int kind) {
942	switch (kind) {
943	case MD_INP:
944		return &t->c_iflag;
945	case MD_OUT:
946		return &t->c_oflag;
947	case MD_CTL:
948		return &t->c_cflag;
949	case MD_LIN:
950		return &t->c_lflag;
951	default:
952		abort();
953		/*NOTREACHED*/
954	}
955}
956
957
958static tcflag_t
959tty_update_flag(EditLine *el, tcflag_t f, int mode, int kind)
960{
961	f &= ~el->el_tty.t_t[mode][kind].t_clrmask;
962	f |= el->el_tty.t_t[mode][kind].t_setmask;
963	return f;
964}
965
966
967static void
968tty_update_flags(EditLine *el, int kind)
969{
970	tcflag_t *tt, *ed, *ex;
971	tt = tty__get_flag(&el->el_tty.t_ts, kind);
972	ed = tty__get_flag(&el->el_tty.t_ed, kind);
973	ex = tty__get_flag(&el->el_tty.t_ex, kind);
974
975	if (*tt != *ex && (kind != MD_CTL || *tt != *ed)) {
976		*ed = tty_update_flag(el, *tt, ED_IO, kind);
977		*ex = tty_update_flag(el, *tt, EX_IO, kind);
978	}
979}
980
981
982static void
983tty_update_char(EditLine *el, int mode, int c) {
984	if (!((el->el_tty.t_t[mode][MD_CHAR].t_setmask & C_SH(c)))
985	    && (el->el_tty.t_c[TS_IO][c] != el->el_tty.t_c[EX_IO][c]))
986		el->el_tty.t_c[mode][c] = el->el_tty.t_c[TS_IO][c];
987	if (el->el_tty.t_t[mode][MD_CHAR].t_clrmask & C_SH(c))
988		el->el_tty.t_c[mode][c] = el->el_tty.t_vdisable;
989}
990
991
992/* tty_rawmode():
993 *	Set terminal into 1 character at a time mode.
994 */
995libedit_private int
996tty_rawmode(EditLine *el)
997{
998
999	if (el->el_tty.t_mode == ED_IO || el->el_tty.t_mode == QU_IO)
1000		return 0;
1001
1002	if (el->el_flags & EDIT_DISABLED)
1003		return 0;
1004
1005	if (tty_getty(el, &el->el_tty.t_ts) == -1) {
1006#ifdef DEBUG_TTY
1007		(void) fprintf(el->el_errfile, "%s: tty_getty: %s\n", __func__,
1008		    strerror(errno));
1009#endif /* DEBUG_TTY */
1010		return -1;
1011	}
1012	/*
1013         * We always keep up with the eight bit setting and the speed of the
1014         * tty. But we only believe changes that are made to cooked mode!
1015         */
1016	el->el_tty.t_eight = tty__geteightbit(&el->el_tty.t_ts);
1017	el->el_tty.t_speed = tty__getspeed(&el->el_tty.t_ts);
1018
1019	if (tty__getspeed(&el->el_tty.t_ex) != el->el_tty.t_speed ||
1020	    tty__getspeed(&el->el_tty.t_ed) != el->el_tty.t_speed) {
1021		(void) cfsetispeed(&el->el_tty.t_ex, el->el_tty.t_speed);
1022		(void) cfsetospeed(&el->el_tty.t_ex, el->el_tty.t_speed);
1023		(void) cfsetispeed(&el->el_tty.t_ed, el->el_tty.t_speed);
1024		(void) cfsetospeed(&el->el_tty.t_ed, el->el_tty.t_speed);
1025	}
1026	if (tty__cooked_mode(&el->el_tty.t_ts)) {
1027		int i;
1028
1029		for (i = MD_INP; i <= MD_LIN; i++)
1030			tty_update_flags(el, i);
1031
1032		if (tty__gettabs(&el->el_tty.t_ex) == 0)
1033			el->el_tty.t_tabs = 0;
1034		else
1035			el->el_tty.t_tabs = EL_CAN_TAB ? 1 : 0;
1036
1037		tty__getchar(&el->el_tty.t_ts, el->el_tty.t_c[TS_IO]);
1038		/*
1039		 * Check if the user made any changes.
1040		 * If he did, then propagate the changes to the
1041		 * edit and execute data structures.
1042		 */
1043		for (i = 0; i < C_NCC; i++)
1044			if (el->el_tty.t_c[TS_IO][i] !=
1045			    el->el_tty.t_c[EX_IO][i])
1046				break;
1047
1048		if (i != C_NCC) {
1049			/*
1050			 * Propagate changes only to the unlibedit_private
1051			 * chars that have been modified just now.
1052			 */
1053			for (i = 0; i < C_NCC; i++)
1054				tty_update_char(el, ED_IO, i);
1055
1056			tty_bind_char(el, 0);
1057			tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]);
1058
1059			for (i = 0; i < C_NCC; i++)
1060				tty_update_char(el, EX_IO, i);
1061
1062			tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]);
1063		}
1064	}
1065	if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ed) == -1) {
1066#ifdef DEBUG_TTY
1067		(void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", __func__,
1068		    strerror(errno));
1069#endif /* DEBUG_TTY */
1070		return -1;
1071	}
1072	el->el_tty.t_mode = ED_IO;
1073	return 0;
1074}
1075
1076
1077/* tty_cookedmode():
1078 *	Set the tty back to normal mode
1079 */
1080libedit_private int
1081tty_cookedmode(EditLine *el)
1082{				/* set tty in normal setup */
1083
1084	if (el->el_tty.t_mode == EX_IO)
1085		return 0;
1086
1087	if (el->el_flags & EDIT_DISABLED)
1088		return 0;
1089
1090	if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ex) == -1) {
1091#ifdef DEBUG_TTY
1092		(void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", __func__,
1093		    strerror(errno));
1094#endif /* DEBUG_TTY */
1095		return -1;
1096	}
1097	el->el_tty.t_mode = EX_IO;
1098	return 0;
1099}
1100
1101
1102/* tty_quotemode():
1103 *	Turn on quote mode
1104 */
1105libedit_private int
1106tty_quotemode(EditLine *el)
1107{
1108	if (el->el_tty.t_mode == QU_IO)
1109		return 0;
1110
1111	el->el_tty.t_qu = el->el_tty.t_ed;
1112
1113	tty_setup_flags(el, &el->el_tty.t_qu, QU_IO);
1114
1115	if (tty_setty(el, TCSADRAIN, &el->el_tty.t_qu) == -1) {
1116#ifdef DEBUG_TTY
1117		(void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", __func__,
1118		    strerror(errno));
1119#endif /* DEBUG_TTY */
1120		return -1;
1121	}
1122	el->el_tty.t_mode = QU_IO;
1123	return 0;
1124}
1125
1126
1127/* tty_noquotemode():
1128 *	Turn off quote mode
1129 */
1130libedit_private int
1131tty_noquotemode(EditLine *el)
1132{
1133
1134	if (el->el_tty.t_mode != QU_IO)
1135		return 0;
1136	if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ed) == -1) {
1137#ifdef DEBUG_TTY
1138		(void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", __func__,
1139		    strerror(errno));
1140#endif /* DEBUG_TTY */
1141		return -1;
1142	}
1143	el->el_tty.t_mode = ED_IO;
1144	return 0;
1145}
1146
1147
1148/* tty_stty():
1149 *	Stty builtin
1150 */
1151libedit_private int
1152/*ARGSUSED*/
1153tty_stty(EditLine *el, int argc __attribute__((__unused__)),
1154    const wchar_t **argv)
1155{
1156	const ttymodes_t *m;
1157	char x;
1158	int aflag = 0;
1159	const wchar_t *s, *d;
1160        char name[EL_BUFSIZ];
1161	struct termios *tios = &el->el_tty.t_ex;
1162	int z = EX_IO;
1163
1164	if (argv == NULL)
1165		return -1;
1166	strlcpy(name, ct_encode_string(*argv++, &el->el_scratch), sizeof(name));
1167
1168	while (argv && *argv && argv[0][0] == '-' && argv[0][2] == '\0')
1169		switch (argv[0][1]) {
1170		case 'a':
1171			aflag++;
1172			argv++;
1173			break;
1174		case 'd':
1175			argv++;
1176			tios = &el->el_tty.t_ed;
1177			z = ED_IO;
1178			break;
1179		case 'x':
1180			argv++;
1181			tios = &el->el_tty.t_ex;
1182			z = EX_IO;
1183			break;
1184		case 'q':
1185			argv++;
1186			tios = &el->el_tty.t_ts;
1187			z = QU_IO;
1188			break;
1189		default:
1190			(void) fprintf(el->el_errfile,
1191			    "%s: Unknown switch `%lc'.\n",
1192			    name, (wint_t)argv[0][1]);
1193			return -1;
1194		}
1195
1196	if (!argv || !*argv) {
1197		int i = -1;
1198		size_t len = 0, st = 0, cu;
1199		for (m = ttymodes; m->m_name; m++) {
1200			if (m->m_type != i) {
1201				(void) fprintf(el->el_outfile, "%s%s",
1202				    i != -1 ? "\n" : "",
1203				    el->el_tty.t_t[z][m->m_type].t_name);
1204				i = m->m_type;
1205				st = len =
1206				    strlen(el->el_tty.t_t[z][m->m_type].t_name);
1207			}
1208			if (i != -1) {
1209			    x = (el->el_tty.t_t[z][i].t_setmask & m->m_value)
1210				?  '+' : '\0';
1211
1212			    if (el->el_tty.t_t[z][i].t_clrmask & m->m_value)
1213				x = '-';
1214			} else {
1215			    x = '\0';
1216			}
1217
1218			if (x != '\0' || aflag) {
1219
1220				cu = strlen(m->m_name) + (x != '\0') + 1;
1221
1222				if (len + cu >=
1223				    (size_t)el->el_terminal.t_size.h) {
1224					(void) fprintf(el->el_outfile, "\n%*s",
1225					    (int)st, "");
1226					len = st + cu;
1227				} else
1228					len += cu;
1229
1230				if (x != '\0')
1231					(void) fprintf(el->el_outfile, "%c%s ",
1232					    x, m->m_name);
1233				else
1234					(void) fprintf(el->el_outfile, "%s ",
1235					    m->m_name);
1236			}
1237		}
1238		(void) fprintf(el->el_outfile, "\n");
1239		return 0;
1240	}
1241	while (argv && (s = *argv++)) {
1242		const wchar_t *p;
1243		switch (*s) {
1244		case '+':
1245		case '-':
1246			x = (char)*s++;
1247			break;
1248		default:
1249			x = '\0';
1250			break;
1251		}
1252		d = s;
1253		p = wcschr(s, L'=');
1254		for (m = ttymodes; m->m_name; m++)
1255			if ((p ? strncmp(m->m_name, ct_encode_string(d,
1256			    &el->el_scratch), (size_t)(p - d)) :
1257			    strcmp(m->m_name, ct_encode_string(d,
1258			    &el->el_scratch))) == 0 &&
1259			    (p == NULL || m->m_type == MD_CHAR))
1260				break;
1261
1262		if (!m->m_name) {
1263			(void) fprintf(el->el_errfile,
1264			    "%s: Invalid argument `%ls'.\n", name, d);
1265			return -1;
1266		}
1267		if (p) {
1268			int c = ffs((int)m->m_value);
1269			int v = *++p ? parse__escape(&p) :
1270			    el->el_tty.t_vdisable;
1271			assert(c != 0);
1272			c--;
1273			c = tty__getcharindex(c);
1274			assert(c != -1);
1275			tios->c_cc[c] = (cc_t)v;
1276			continue;
1277		}
1278		switch (x) {
1279		case '+':
1280			el->el_tty.t_t[z][m->m_type].t_setmask |= m->m_value;
1281			el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value;
1282			break;
1283		case '-':
1284			el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value;
1285			el->el_tty.t_t[z][m->m_type].t_clrmask |= m->m_value;
1286			break;
1287		default:
1288			el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value;
1289			el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value;
1290			break;
1291		}
1292	}
1293
1294	tty_setup_flags(el, tios, z);
1295	if (el->el_tty.t_mode == z) {
1296		if (tty_setty(el, TCSADRAIN, tios) == -1) {
1297#ifdef DEBUG_TTY
1298			(void) fprintf(el->el_errfile, "%s: tty_setty: %s\n",
1299			    __func__, strerror(errno));
1300#endif /* DEBUG_TTY */
1301			return -1;
1302		}
1303	}
1304
1305	return 0;
1306}
1307
1308
1309#ifdef notyet
1310/* tty_printchar():
1311 *	DEbugging routine to print the tty characters
1312 */
1313static void
1314tty_printchar(EditLine *el, unsigned char *s)
1315{
1316	ttyperm_t *m;
1317	int i;
1318
1319	for (i = 0; i < C_NCC; i++) {
1320		for (m = el->el_tty.t_t; m->m_name; m++)
1321			if (m->m_type == MD_CHAR && C_SH(i) == m->m_value)
1322				break;
1323		if (m->m_name)
1324			(void) fprintf(el->el_errfile, "%s ^%c ",
1325			    m->m_name, s[i] + 'A' - 1);
1326		if (i % 5 == 0)
1327			(void) fprintf(el->el_errfile, "\n");
1328	}
1329	(void) fprintf(el->el_errfile, "\n");
1330}
1331#endif /* notyet */
1332
1333
1334static void
1335tty_setup_flags(EditLine *el, struct termios *tios, int mode)
1336{
1337	int kind;
1338	for (kind = MD_INP; kind <= MD_LIN; kind++) {
1339		tcflag_t *f = tty__get_flag(tios, kind);
1340		*f = tty_update_flag(el, *f, mode, kind);
1341	}
1342}
1343
1344libedit_private int
1345tty_get_signal_character(EditLine *el, int sig)
1346{
1347#ifdef ECHOCTL
1348	tcflag_t *ed = tty__get_flag(&el->el_tty.t_ed, MD_INP);
1349	if ((*ed & ECHOCTL) == 0)
1350		return -1;
1351#endif
1352	switch (sig) {
1353#if defined(SIGINT) && defined(VINTR)
1354	case SIGINT:
1355		return el->el_tty.t_c[ED_IO][VINTR];
1356#endif
1357#if defined(SIGQUIT) && defined(VQUIT)
1358	case SIGQUIT:
1359		return el->el_tty.t_c[ED_IO][VQUIT];
1360#endif
1361#if defined(SIGINFO) && defined(VSTATUS)
1362	case SIGINFO:
1363		return el->el_tty.t_c[ED_IO][VSTATUS];
1364#endif
1365#if defined(SIGTSTP) && defined(VSUSP)
1366	case SIGTSTP:
1367		return el->el_tty.t_c[ED_IO][VSUSP];
1368#endif
1369	default:
1370		return -1;
1371	}
1372}
1373