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