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