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