GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libedit/tty.c Lines: 121 306 39.5 %
Date: 2017-11-13 Branches: 34 196 17.3 %

Line Branch Exec Source
1
/*	$OpenBSD: tty.c,v 1.27 2016/05/06 13:12:52 schwarze 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
468
tty_getty(EditLine *el, struct termios *t)
469
{
470
	int rv;
471

6
	while ((rv = tcgetattr(el->el_infd, t)) == -1 && errno == EINTR)
472
		continue;
473
2
	return rv;
474
}
475
476
/* tty_setty():
477
 *	Wrapper for tcsetattr to handle EINTR
478
 */
479
static int
480
tty_setty(EditLine *el, int action, const struct termios *t)
481
{
482
	int rv;
483

6
	while ((rv = tcsetattr(el->el_infd, action, t)) == -1 && errno == EINTR)
484
		continue;
485
2
	return rv;
486
}
487
488
/* tty_setup():
489
 *	Get the tty parameters and initialize the editing state
490
 */
491
static int
492
tty_setup(EditLine *el)
493
{
494
	int rst = 1;
495
496
6
	if (el->el_flags & EDIT_DISABLED)
497
		return 0;
498
499
3
	if (el->el_tty.t_initialized)
500
		return -1;
501
502
3
	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
1
		return -1;
508
	}
509
2
	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
2
	el->el_tty.t_ts = el->el_tty.t_ex = el->el_tty.t_ed = el->el_tty.t_or;
517
518
2
	el->el_tty.t_speed = tty__getspeed(&el->el_tty.t_ex);
519
2
	el->el_tty.t_tabs = tty__gettabs(&el->el_tty.t_ex);
520
2
	el->el_tty.t_eight = tty__geteightbit(&el->el_tty.t_ex);
521
522
2
	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
2
	if (rst) {
529
2
		if (tty__cooked_mode(&el->el_tty.t_ts)) {
530
2
			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
96
			for (rst = 0; rst < C_NCC - 2; rst++)
535
136
				if (el->el_tty.t_c[TS_IO][rst] !=
536
46
				      el->el_tty.t_vdisable
537
90
				    && el->el_tty.t_c[ED_IO][rst] !=
538
				      el->el_tty.t_vdisable)
539
16
					el->el_tty.t_c[ED_IO][rst] =
540
					    el->el_tty.t_c[TS_IO][rst];
541
104
			for (rst = 0; rst < C_NCC; rst++)
542
100
				if (el->el_tty.t_c[TS_IO][rst] !=
543
50
				    el->el_tty.t_vdisable)
544
48
					el->el_tty.t_c[EX_IO][rst] =
545
					    el->el_tty.t_c[TS_IO][rst];
546
		}
547
2
		tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]);
548
2
		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
2
	tty_setup_flags(el, &el->el_tty.t_ed, ED_IO);
559
560
2
	tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]);
561
2
	tty_bind_char(el, 1);
562
2
	el->el_tty.t_initialized = 1;
563
2
	return 0;
564
3
}
565
566
protected int
567
tty_init(EditLine *el)
568
{
569
570
6
	el->el_tty.t_mode = EX_IO;
571
3
	el->el_tty.t_vdisable = _POSIX_VDISABLE;
572
3
	el->el_tty.t_initialized = 0;
573
3
	(void) memcpy(el->el_tty.t_t, ttyperm, sizeof(ttyperm_t));
574
3
	(void) memcpy(el->el_tty.t_c, ttychar, sizeof(ttychar_t));
575
3
	return tty_setup(el);
576
}
577
578
579
/* tty_end():
580
 *	Restore the tty to its original settings
581
 */
582
protected void
583
/*ARGSUSED*/
584
tty_end(EditLine *el)
585
{
586
	if (el->el_flags & EDIT_DISABLED)
587
		return;
588
589
	if (!el->el_tty.t_initialized)
590
		return;
591
592
	if (tty_setty(el, TCSAFLUSH, &el->el_tty.t_or) == -1) {
593
#ifdef DEBUG_TTY
594
		(void) fprintf(el->el_errfile,
595
		    "%s: tty_setty: %s\n", __func__, strerror(errno));
596
#endif /* DEBUG_TTY */
597
	}
598
}
599
600
601
/* tty__getspeed():
602
 *	Get the tty speed
603
 */
604
static speed_t
605
tty__getspeed(struct termios *td)
606
{
607
	speed_t spd;
608
609
4
	if ((spd = cfgetispeed(td)) == 0)
610
		spd = cfgetospeed(td);
611
2
	return spd;
612
}
613
614
/* tty__getspeed():
615
 *	Return the index of the asked char in the c_cc array
616
 */
617
static int
618
tty__getcharindex(int i)
619
{
620
	switch (i) {
621
#ifdef VINTR
622
	case C_INTR:
623
		return VINTR;
624
#endif /* VINTR */
625
#ifdef VQUIT
626
	case C_QUIT:
627
		return VQUIT;
628
#endif /* VQUIT */
629
#ifdef VERASE
630
	case C_ERASE:
631
		return VERASE;
632
#endif /* VERASE */
633
#ifdef VKILL
634
	case C_KILL:
635
		return VKILL;
636
#endif /* VKILL */
637
#ifdef VEOF
638
	case C_EOF:
639
		return VEOF;
640
#endif /* VEOF */
641
#ifdef VEOL
642
	case C_EOL:
643
		return VEOL;
644
#endif /* VEOL */
645
#ifdef VEOL2
646
	case C_EOL2:
647
		return VEOL2;
648
#endif /* VEOL2 */
649
#ifdef VSWTCH
650
	case C_SWTCH:
651
		return VSWTCH;
652
#endif /* VSWTCH */
653
#ifdef VDSWTCH
654
	case C_DSWTCH:
655
		return VDSWTCH;
656
#endif /* VDSWTCH */
657
#ifdef VERASE2
658
	case C_ERASE2:
659
		return VERASE2;
660
#endif /* VERASE2 */
661
#ifdef VSTART
662
	case C_START:
663
		return VSTART;
664
#endif /* VSTART */
665
#ifdef VSTOP
666
	case C_STOP:
667
		return VSTOP;
668
#endif /* VSTOP */
669
#ifdef VWERASE
670
	case C_WERASE:
671
		return VWERASE;
672
#endif /* VWERASE */
673
#ifdef VSUSP
674
	case C_SUSP:
675
		return VSUSP;
676
#endif /* VSUSP */
677
#ifdef VDSUSP
678
	case C_DSUSP:
679
		return VDSUSP;
680
#endif /* VDSUSP */
681
#ifdef VREPRINT
682
	case C_REPRINT:
683
		return VREPRINT;
684
#endif /* VREPRINT */
685
#ifdef VDISCARD
686
	case C_DISCARD:
687
		return VDISCARD;
688
#endif /* VDISCARD */
689
#ifdef VLNEXT
690
	case C_LNEXT:
691
		return VLNEXT;
692
#endif /* VLNEXT */
693
#ifdef VSTATUS
694
	case C_STATUS:
695
		return VSTATUS;
696
#endif /* VSTATUS */
697
#ifdef VPAGE
698
	case C_PAGE:
699
		return VPAGE;
700
#endif /* VPAGE */
701
#ifdef VPGOFF
702
	case C_PGOFF:
703
		return VPGOFF;
704
#endif /* VPGOFF */
705
#ifdef VKILL2
706
	case C_KILL2:
707
		return VKILL2;
708
#endif /* KILL2 */
709
#ifdef VMIN
710
	case C_MIN:
711
		return VMIN;
712
#endif /* VMIN */
713
#ifdef VTIME
714
	case C_TIME:
715
		return VTIME;
716
#endif /* VTIME */
717
	default:
718
		return -1;
719
	}
720
}
721
722
/* tty__getchar():
723
 *	Get the tty characters
724
 */
725
static void
726
tty__getchar(struct termios *td, unsigned char *s)
727
{
728
729
#ifdef VINTR
730
4
	s[C_INTR] = td->c_cc[VINTR];
731
#endif /* VINTR */
732
#ifdef VQUIT
733
2
	s[C_QUIT] = td->c_cc[VQUIT];
734
#endif /* VQUIT */
735
#ifdef VERASE
736
2
	s[C_ERASE] = td->c_cc[VERASE];
737
#endif /* VERASE */
738
#ifdef VKILL
739
2
	s[C_KILL] = td->c_cc[VKILL];
740
#endif /* VKILL */
741
#ifdef VEOF
742
2
	s[C_EOF] = td->c_cc[VEOF];
743
#endif /* VEOF */
744
#ifdef VEOL
745
2
	s[C_EOL] = td->c_cc[VEOL];
746
#endif /* VEOL */
747
#ifdef VEOL2
748
2
	s[C_EOL2] = td->c_cc[VEOL2];
749
#endif /* VEOL2 */
750
#ifdef VSWTCH
751
	s[C_SWTCH] = td->c_cc[VSWTCH];
752
#endif /* VSWTCH */
753
#ifdef VDSWTCH
754
	s[C_DSWTCH] = td->c_cc[VDSWTCH];
755
#endif /* VDSWTCH */
756
#ifdef VERASE2
757
	s[C_ERASE2] = td->c_cc[VERASE2];
758
#endif /* VERASE2 */
759
#ifdef VSTART
760
2
	s[C_START] = td->c_cc[VSTART];
761
#endif /* VSTART */
762
#ifdef VSTOP
763
2
	s[C_STOP] = td->c_cc[VSTOP];
764
#endif /* VSTOP */
765
#ifdef VWERASE
766
2
	s[C_WERASE] = td->c_cc[VWERASE];
767
#endif /* VWERASE */
768
#ifdef VSUSP
769
2
	s[C_SUSP] = td->c_cc[VSUSP];
770
#endif /* VSUSP */
771
#ifdef VDSUSP
772
2
	s[C_DSUSP] = td->c_cc[VDSUSP];
773
#endif /* VDSUSP */
774
#ifdef VREPRINT
775
2
	s[C_REPRINT] = td->c_cc[VREPRINT];
776
#endif /* VREPRINT */
777
#ifdef VDISCARD
778
2
	s[C_DISCARD] = td->c_cc[VDISCARD];
779
#endif /* VDISCARD */
780
#ifdef VLNEXT
781
2
	s[C_LNEXT] = td->c_cc[VLNEXT];
782
#endif /* VLNEXT */
783
#ifdef VSTATUS
784
2
	s[C_STATUS] = td->c_cc[VSTATUS];
785
#endif /* VSTATUS */
786
#ifdef VPAGE
787
	s[C_PAGE] = td->c_cc[VPAGE];
788
#endif /* VPAGE */
789
#ifdef VPGOFF
790
	s[C_PGOFF] = td->c_cc[VPGOFF];
791
#endif /* VPGOFF */
792
#ifdef VKILL2
793
	s[C_KILL2] = td->c_cc[VKILL2];
794
#endif /* KILL2 */
795
#ifdef VMIN
796
2
	s[C_MIN] = td->c_cc[VMIN];
797
#endif /* VMIN */
798
#ifdef VTIME
799
2
	s[C_TIME] = td->c_cc[VTIME];
800
#endif /* VTIME */
801
2
}				/* tty__getchar */
802
803
804
/* tty__setchar():
805
 *	Set the tty characters
806
 */
807
static void
808
tty__setchar(struct termios *td, unsigned char *s)
809
{
810
811
#ifdef VINTR
812
8
	td->c_cc[VINTR] = s[C_INTR];
813
#endif /* VINTR */
814
#ifdef VQUIT
815
4
	td->c_cc[VQUIT] = s[C_QUIT];
816
#endif /* VQUIT */
817
#ifdef VERASE
818
4
	td->c_cc[VERASE] = s[C_ERASE];
819
#endif /* VERASE */
820
#ifdef VKILL
821
4
	td->c_cc[VKILL] = s[C_KILL];
822
#endif /* VKILL */
823
#ifdef VEOF
824
4
	td->c_cc[VEOF] = s[C_EOF];
825
#endif /* VEOF */
826
#ifdef VEOL
827
4
	td->c_cc[VEOL] = s[C_EOL];
828
#endif /* VEOL */
829
#ifdef VEOL2
830
4
	td->c_cc[VEOL2] = s[C_EOL2];
831
#endif /* VEOL2 */
832
#ifdef VSWTCH
833
	td->c_cc[VSWTCH] = s[C_SWTCH];
834
#endif /* VSWTCH */
835
#ifdef VDSWTCH
836
	td->c_cc[VDSWTCH] = s[C_DSWTCH];
837
#endif /* VDSWTCH */
838
#ifdef VERASE2
839
	td->c_cc[VERASE2] = s[C_ERASE2];
840
#endif /* VERASE2 */
841
#ifdef VSTART
842
4
	td->c_cc[VSTART] = s[C_START];
843
#endif /* VSTART */
844
#ifdef VSTOP
845
4
	td->c_cc[VSTOP] = s[C_STOP];
846
#endif /* VSTOP */
847
#ifdef VWERASE
848
4
	td->c_cc[VWERASE] = s[C_WERASE];
849
#endif /* VWERASE */
850
#ifdef VSUSP
851
4
	td->c_cc[VSUSP] = s[C_SUSP];
852
#endif /* VSUSP */
853
#ifdef VDSUSP
854
4
	td->c_cc[VDSUSP] = s[C_DSUSP];
855
#endif /* VDSUSP */
856
#ifdef VREPRINT
857
4
	td->c_cc[VREPRINT] = s[C_REPRINT];
858
#endif /* VREPRINT */
859
#ifdef VDISCARD
860
4
	td->c_cc[VDISCARD] = s[C_DISCARD];
861
#endif /* VDISCARD */
862
#ifdef VLNEXT
863
4
	td->c_cc[VLNEXT] = s[C_LNEXT];
864
#endif /* VLNEXT */
865
#ifdef VSTATUS
866
4
	td->c_cc[VSTATUS] = s[C_STATUS];
867
#endif /* VSTATUS */
868
#ifdef VPAGE
869
	td->c_cc[VPAGE] = s[C_PAGE];
870
#endif /* VPAGE */
871
#ifdef VPGOFF
872
	td->c_cc[VPGOFF] = s[C_PGOFF];
873
#endif /* VPGOFF */
874
#ifdef VKILL2
875
	td->c_cc[VKILL2] = s[C_KILL2];
876
#endif /* VKILL2 */
877
#ifdef VMIN
878
4
	td->c_cc[VMIN] = s[C_MIN];
879
#endif /* VMIN */
880
#ifdef VTIME
881
4
	td->c_cc[VTIME] = s[C_TIME];
882
#endif /* VTIME */
883
4
}				/* tty__setchar */
884
885
886
/* tty_bind_char():
887
 *	Rebind the editline functions
888
 */
889
protected void
890
tty_bind_char(EditLine *el, int force)
891
{
892
893
16
	unsigned char *t_n = el->el_tty.t_c[ED_IO];
894
8
	unsigned char *t_o = el->el_tty.t_ed.c_cc;
895
8
	wchar_t new[2], old[2];
896
	const ttymap_t *tp;
897
	el_action_t *map, *alt;
898
	const el_action_t *dmap, *dalt;
899
8
	new[1] = old[1] = '\0';
900
901
8
	map = el->el_map.key;
902
8
	alt = el->el_map.alt;
903
8
	if (el->el_map.type == MAP_VI) {
904
5
		dmap = el->el_map.vii;
905
5
		dalt = el->el_map.vic;
906
5
	} else {
907
3
		dmap = el->el_map.emacs;
908
		dalt = NULL;
909
	}
910
911
112
	for (tp = tty_map; tp->nch != (wint_t)-1; tp++) {
912
48
		new[0] = (wchar_t)t_n[tp->nch];
913
48
		old[0] = (wchar_t)t_o[tp->och];
914
48
		if (new[0] == old[0] && !force)
915
			continue;
916
		/* Put the old default binding back, and set the new binding */
917
48
		keymacro_clear(el, map, old);
918
48
		map[(unsigned char)old[0]] = dmap[(unsigned char)old[0]];
919
48
		keymacro_clear(el, map, new);
920
		/* MAP_VI == 1, MAP_EMACS == 0... */
921
48
		map[(unsigned char)new[0]] = tp->bind[el->el_map.type];
922
48
		if (dalt) {
923
30
			keymacro_clear(el, alt, old);
924
30
			alt[(unsigned char)old[0]] =
925
30
			    dalt[(unsigned char)old[0]];
926
30
			keymacro_clear(el, alt, new);
927
30
			alt[(unsigned char)new[0]] =
928
30
			    tp->bind[el->el_map.type + 1];
929
30
		}
930
	}
931
8
}
932
933
934
static tcflag_t *
935
tty__get_flag(struct termios *t, int kind) {
936

32
	switch (kind) {
937
	case MD_INP:
938
4
		return &t->c_iflag;
939
	case MD_OUT:
940
4
		return &t->c_oflag;
941
	case MD_CTL:
942
4
		return &t->c_cflag;
943
	case MD_LIN:
944
4
		return &t->c_lflag;
945
	default:
946
		abort();
947
		/*NOTREACHED*/
948
	}
949
16
}
950
951
952
static tcflag_t
953
tty_update_flag(EditLine *el, tcflag_t f, int mode, int kind)
954
{
955
32
	f &= ~el->el_tty.t_t[mode][kind].t_clrmask;
956
16
	f |= el->el_tty.t_t[mode][kind].t_setmask;
957
16
	return f;
958
}
959
960
961
static void
962
tty_update_flags(EditLine *el, int kind)
963
{
964
	tcflag_t *tt, *ed, *ex;
965
	tt = tty__get_flag(&el->el_tty.t_ts, kind);
966
	ed = tty__get_flag(&el->el_tty.t_ed, kind);
967
	ex = tty__get_flag(&el->el_tty.t_ex, kind);
968
969
	if (*tt != *ex && (kind != MD_CTL || *tt != *ed)) {
970
		*ed = tty_update_flag(el, *tt, ED_IO, kind);
971
		*ex = tty_update_flag(el, *tt, EX_IO, kind);
972
	}
973
}
974
975
976
static void
977
tty_update_char(EditLine *el, int mode, int c) {
978
	if (!((el->el_tty.t_t[mode][MD_CHAR].t_setmask & C_SH(c)))
979
	    && (el->el_tty.t_c[TS_IO][c] != el->el_tty.t_c[EX_IO][c]))
980
		el->el_tty.t_c[mode][c] = el->el_tty.t_c[TS_IO][c];
981
	if (el->el_tty.t_t[mode][MD_CHAR].t_clrmask & C_SH(c))
982
		el->el_tty.t_c[mode][c] = el->el_tty.t_vdisable;
983
}
984
985
986
/* tty_rawmode():
987
 *	Set terminal into 1 character at a time mode.
988
 */
989
protected int
990
tty_rawmode(EditLine *el)
991
{
992
993
	if (el->el_tty.t_mode == ED_IO || el->el_tty.t_mode == QU_IO)
994
		return 0;
995
996
	if (el->el_flags & EDIT_DISABLED)
997
		return 0;
998
999
	if (tty_getty(el, &el->el_tty.t_ts) == -1) {
1000
#ifdef DEBUG_TTY
1001
		(void) fprintf(el->el_errfile, "tty_rawmode: tty_getty: %s\n",
1002
		    strerror(errno));
1003
#endif /* DEBUG_TTY */
1004
		return -1;
1005
	}
1006
	/*
1007
         * We always keep up with the eight bit setting and the speed of the
1008
         * tty. But we only believe changes that are made to cooked mode!
1009
         */
1010
	el->el_tty.t_eight = tty__geteightbit(&el->el_tty.t_ts);
1011
	el->el_tty.t_speed = tty__getspeed(&el->el_tty.t_ts);
1012
1013
	if (tty__getspeed(&el->el_tty.t_ex) != el->el_tty.t_speed ||
1014
	    tty__getspeed(&el->el_tty.t_ed) != el->el_tty.t_speed) {
1015
		(void) cfsetispeed(&el->el_tty.t_ex, el->el_tty.t_speed);
1016
		(void) cfsetospeed(&el->el_tty.t_ex, el->el_tty.t_speed);
1017
		(void) cfsetispeed(&el->el_tty.t_ed, el->el_tty.t_speed);
1018
		(void) cfsetospeed(&el->el_tty.t_ed, el->el_tty.t_speed);
1019
	}
1020
	if (tty__cooked_mode(&el->el_tty.t_ts)) {
1021
		int i;
1022
1023
		for (i = MD_INP; i <= MD_LIN; i++)
1024
			tty_update_flags(el, i);
1025
1026
		if (tty__gettabs(&el->el_tty.t_ex) == 0)
1027
			el->el_tty.t_tabs = 0;
1028
		else
1029
			el->el_tty.t_tabs = EL_CAN_TAB ? 1 : 0;
1030
1031
		tty__getchar(&el->el_tty.t_ts, el->el_tty.t_c[TS_IO]);
1032
		/*
1033
		 * Check if the user made any changes.
1034
		 * If he did, then propagate the changes to the
1035
		 * edit and execute data structures.
1036
		 */
1037
		for (i = 0; i < C_NCC; i++)
1038
			if (el->el_tty.t_c[TS_IO][i] !=
1039
			    el->el_tty.t_c[EX_IO][i])
1040
				break;
1041
1042
		if (i != C_NCC) {
1043
			/*
1044
			 * Propagate changes only to the unprotected
1045
			 * chars that have been modified just now.
1046
			 */
1047
			for (i = 0; i < C_NCC; i++)
1048
				tty_update_char(el, ED_IO, i);
1049
1050
			tty_bind_char(el, 0);
1051
			tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]);
1052
1053
			for (i = 0; i < C_NCC; i++)
1054
				tty_update_char(el, EX_IO, i);
1055
1056
			tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]);
1057
		}
1058
	}
1059
	if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ed) == -1) {
1060
#ifdef DEBUG_TTY
1061
		(void) fprintf(el->el_errfile, "tty_rawmode: tty_setty: %s\n",
1062
		    strerror(errno));
1063
#endif /* DEBUG_TTY */
1064
		return -1;
1065
	}
1066
	el->el_tty.t_mode = ED_IO;
1067
	return 0;
1068
}
1069
1070
1071
/* tty_cookedmode():
1072
 *	Set the tty back to normal mode
1073
 */
1074
protected int
1075
tty_cookedmode(EditLine *el)
1076
{				/* set tty in normal setup */
1077
1078
	if (el->el_tty.t_mode == EX_IO)
1079
		return 0;
1080
1081
	if (el->el_flags & EDIT_DISABLED)
1082
		return 0;
1083
1084
	if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ex) == -1) {
1085
#ifdef DEBUG_TTY
1086
		(void) fprintf(el->el_errfile,
1087
		    "tty_cookedmode: tty_setty: %s\n",
1088
		    strerror(errno));
1089
#endif /* DEBUG_TTY */
1090
		return -1;
1091
	}
1092
	el->el_tty.t_mode = EX_IO;
1093
	return 0;
1094
}
1095
1096
1097
/* tty_quotemode():
1098
 *	Turn on quote mode
1099
 */
1100
protected int
1101
tty_quotemode(EditLine *el)
1102
{
1103
	if (el->el_tty.t_mode == QU_IO)
1104
		return 0;
1105
1106
	el->el_tty.t_qu = el->el_tty.t_ed;
1107
1108
	tty_setup_flags(el, &el->el_tty.t_qu, QU_IO);
1109
1110
	if (tty_setty(el, TCSADRAIN, &el->el_tty.t_qu) == -1) {
1111
#ifdef DEBUG_TTY
1112
		(void) fprintf(el->el_errfile, "QuoteModeOn: tty_setty: %s\n",
1113
		    strerror(errno));
1114
#endif /* DEBUG_TTY */
1115
		return -1;
1116
	}
1117
	el->el_tty.t_mode = QU_IO;
1118
	return 0;
1119
}
1120
1121
1122
/* tty_noquotemode():
1123
 *	Turn off quote mode
1124
 */
1125
protected int
1126
tty_noquotemode(EditLine *el)
1127
{
1128
1129
	if (el->el_tty.t_mode != QU_IO)
1130
		return 0;
1131
	if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ed) == -1) {
1132
#ifdef DEBUG_TTY
1133
		(void) fprintf(el->el_errfile, "QuoteModeOff: tty_setty: %s\n",
1134
		    strerror(errno));
1135
#endif /* DEBUG_TTY */
1136
		return -1;
1137
	}
1138
	el->el_tty.t_mode = ED_IO;
1139
	return 0;
1140
}
1141
1142
1143
/* tty_stty():
1144
 *	Stty builtin
1145
 */
1146
protected int
1147
/*ARGSUSED*/
1148
tty_stty(EditLine *el, int argc __attribute__((__unused__)),
1149
    const wchar_t **argv)
1150
{
1151
	const ttymodes_t *m;
1152
	char x;
1153
	int aflag = 0;
1154
	const wchar_t *s, *d;
1155
        char name[EL_BUFSIZ];
1156
	struct termios *tios = &el->el_tty.t_ex;
1157
	int z = EX_IO;
1158
1159
	if (argv == NULL)
1160
		return -1;
1161
	strncpy(name, ct_encode_string(*argv++, &el->el_scratch), sizeof(name));
1162
        name[sizeof(name) - 1] = '\0';
1163
1164
	while (argv && *argv && argv[0][0] == '-' && argv[0][2] == '\0')
1165
		switch (argv[0][1]) {
1166
		case 'a':
1167
			aflag++;
1168
			argv++;
1169
			break;
1170
		case 'd':
1171
			argv++;
1172
			tios = &el->el_tty.t_ed;
1173
			z = ED_IO;
1174
			break;
1175
		case 'x':
1176
			argv++;
1177
			tios = &el->el_tty.t_ex;
1178
			z = EX_IO;
1179
			break;
1180
		case 'q':
1181
			argv++;
1182
			tios = &el->el_tty.t_ts;
1183
			z = QU_IO;
1184
			break;
1185
		default:
1186
			(void) fprintf(el->el_errfile,
1187
			    "%s: Unknown switch `%lc'.\n",
1188
			    name, argv[0][1]);
1189
			return -1;
1190
		}
1191
1192
	if (!argv || !*argv) {
1193
		int i = -1;
1194
		size_t len = 0, st = 0, cu;
1195
		for (m = ttymodes; m->m_name; m++) {
1196
			if (m->m_type != i) {
1197
				(void) fprintf(el->el_outfile, "%s%s",
1198
				    i != -1 ? "\n" : "",
1199
				    el->el_tty.t_t[z][m->m_type].t_name);
1200
				i = m->m_type;
1201
				st = len =
1202
				    strlen(el->el_tty.t_t[z][m->m_type].t_name);
1203
			}
1204
			if (i != -1) {
1205
			    x = (el->el_tty.t_t[z][i].t_setmask & m->m_value)
1206
				?  '+' : '\0';
1207
			    x = (el->el_tty.t_t[z][i].t_clrmask & m->m_value)
1208
				? '-' : x;
1209
			} else {
1210
			    x = '\0';
1211
			}
1212
1213
			if (x != '\0' || aflag) {
1214
1215
				cu = strlen(m->m_name) + (x != '\0') + 1;
1216
1217
				if (len + cu >=
1218
				    (size_t)el->el_terminal.t_size.h) {
1219
					(void) fprintf(el->el_outfile, "\n%*s",
1220
					    (int)st, "");
1221
					len = st + cu;
1222
				} else
1223
					len += cu;
1224
1225
				if (x != '\0')
1226
					(void) fprintf(el->el_outfile, "%c%s ",
1227
					    x, m->m_name);
1228
				else
1229
					(void) fprintf(el->el_outfile, "%s ",
1230
					    m->m_name);
1231
			}
1232
		}
1233
		(void) fprintf(el->el_outfile, "\n");
1234
		return 0;
1235
	}
1236
	while (argv && (s = *argv++)) {
1237
		const wchar_t *p;
1238
		switch (*s) {
1239
		case '+':
1240
		case '-':
1241
			x = *s++;
1242
			break;
1243
		default:
1244
			x = '\0';
1245
			break;
1246
		}
1247
		d = s;
1248
		p = wcschr(s, L'=');
1249
		for (m = ttymodes; m->m_name; m++)
1250
			if ((p ? strncmp(m->m_name, ct_encode_string(d, &el->el_scratch), (size_t)(p - d)) :
1251
			    strcmp(m->m_name, ct_encode_string(d, &el->el_scratch))) == 0 &&
1252
			    (p == NULL || m->m_type == MD_CHAR))
1253
				break;
1254
1255
		if (!m->m_name) {
1256
			(void) fprintf(el->el_errfile,
1257
			    "%s: Invalid argument `%ls'.\n", name, d);
1258
			return -1;
1259
		}
1260
		if (p) {
1261
			int c = ffs((int)m->m_value);
1262
			int v = *++p ? parse__escape(&p) :
1263
			    el->el_tty.t_vdisable;
1264
			assert(c != 0);
1265
			c--;
1266
			c = tty__getcharindex(c);
1267
			assert(c != -1);
1268
			tios->c_cc[c] = v;
1269
			continue;
1270
		}
1271
		switch (x) {
1272
		case '+':
1273
			el->el_tty.t_t[z][m->m_type].t_setmask |= m->m_value;
1274
			el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value;
1275
			break;
1276
		case '-':
1277
			el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value;
1278
			el->el_tty.t_t[z][m->m_type].t_clrmask |= m->m_value;
1279
			break;
1280
		default:
1281
			el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value;
1282
			el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value;
1283
			break;
1284
		}
1285
	}
1286
1287
	tty_setup_flags(el, tios, z);
1288
	if (el->el_tty.t_mode == z) {
1289
		if (tty_setty(el, TCSADRAIN, tios) == -1) {
1290
#ifdef DEBUG_TTY
1291
			(void) fprintf(el->el_errfile,
1292
			    "tty_stty: tty_setty: %s\n", strerror(errno));
1293
#endif /* DEBUG_TTY */
1294
			return -1;
1295
		}
1296
	}
1297
1298
	return 0;
1299
}
1300
1301
1302
#ifdef notyet
1303
/* tty_printchar():
1304
 *	DEbugging routine to print the tty characters
1305
 */
1306
static void
1307
tty_printchar(EditLine *el, unsigned char *s)
1308
{
1309
	ttyperm_t *m;
1310
	int i;
1311
1312
	for (i = 0; i < C_NCC; i++) {
1313
		for (m = el->el_tty.t_t; m->m_name; m++)
1314
			if (m->m_type == MD_CHAR && C_SH(i) == m->m_value)
1315
				break;
1316
		if (m->m_name)
1317
			(void) fprintf(el->el_errfile, "%s ^%c ",
1318
			    m->m_name, s[i] + 'A' - 1);
1319
		if (i % 5 == 0)
1320
			(void) fprintf(el->el_errfile, "\n");
1321
	}
1322
	(void) fprintf(el->el_errfile, "\n");
1323
}
1324
#endif /* notyet */
1325
1326
1327
static void
1328
tty_setup_flags(EditLine *el, struct termios *tios, int mode)
1329
{
1330
	int kind;
1331
44
	for (kind = MD_INP; kind <= MD_LIN; kind++) {
1332
16
		tcflag_t *f = tty__get_flag(tios, kind);
1333
16
		*f = tty_update_flag(el, *f, mode, kind);
1334
	}
1335
4
}