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