1
/* $NetBSD: tty.c,v 1.41 2011/10/04 15:27:04 christos Exp $ */
4
* Copyright (c) 1992, 1993
5
* The Regents of the University of California. All rights reserved.
7
* This code is derived from software contributed to Berkeley by
8
* Christos Zoulas of Cornell University.
10
* Redistribution and use in source and binary forms, with or without
11
* modification, are permitted provided that the following conditions
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.
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
36
#if !defined(lint) && !defined(SCCSID)
38
static char sccsid[] = "@(#)tty.c 8.1 (Berkeley) 6/4/93";
41
#endif /* not lint && not SCCSID */
44
* tty.c: tty interface stuff
48
#include <unistd.h> /* for isatty */
49
#include <strings.h> /* for ffs */
53
typedef struct ttymodes_t {
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 */
65
private const ttyperm_t ttyperm = {
67
{"iflag:", ICRNL, (INLCR | IGNCR)},
68
{"oflag:", (OPOST | ONLCR), ONLRET},
70
{"lflag:", (ISIG | ICANON | ECHO | ECHOE | ECHOCTL | IEXTEN),
71
(NOFLSH | ECHONL | EXTPROC | FLUSHO)},
75
{"iflag:", (INLCR | ICRNL), IGNCR},
76
{"oflag:", (OPOST | ONLCR), ONLRET},
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}
85
{"iflag:", 0, IXON | IXOFF | INLCR | ICRNL},
88
{"lflag:", 0, ISIG | IEXTEN},
93
private const ttychar_t ttychar = {
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,
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,
123
private const ttymap_t tty_map[] = {
126
{EM_DELETE_PREV_CHAR, VI_DELETE_PREV_CHAR, ED_PREV_CHAR}},
130
{EM_DELETE_PREV_CHAR, VI_DELETE_PREV_CHAR, ED_PREV_CHAR}},
134
{EM_KILL_LINE, VI_KILL_LINE_PREV, ED_UNASSIGNED}},
138
{EM_KILL_LINE, VI_KILL_LINE_PREV, ED_UNASSIGNED}},
142
{EM_DELETE_OR_LIST, VI_LIST_OR_EOF, ED_UNASSIGNED}},
146
{ED_DELETE_PREV_WORD, ED_DELETE_PREV_WORD, ED_PREV_WORD}},
149
{C_REPRINT, VREPRINT,
150
{ED_REDISPLAY, ED_INSERT, ED_REDISPLAY}},
151
#endif /* VREPRINT */
154
{ED_QUOTED_INSERT, ED_QUOTED_INSERT, ED_UNASSIGNED}},
157
{ED_UNASSIGNED, ED_UNASSIGNED, ED_UNASSIGNED}}
160
private const ttymodes_t ttymodes[] = {
162
{"ignbrk", IGNBRK, MD_INP},
165
{"brkint", BRKINT, MD_INP},
168
{"ignpar", IGNPAR, MD_INP},
171
{"parmrk", PARMRK, MD_INP},
174
{"inpck", INPCK, MD_INP},
177
{"istrip", ISTRIP, MD_INP},
180
{"inlcr", INLCR, MD_INP},
183
{"igncr", IGNCR, MD_INP},
186
{"icrnl", ICRNL, MD_INP},
189
{"iuclc", IUCLC, MD_INP},
192
{"ixon", IXON, MD_INP},
195
{"ixany", IXANY, MD_INP},
198
{"ixoff", IXOFF, MD_INP},
201
{"imaxbel", IMAXBEL, MD_INP},
205
{"opost", OPOST, MD_OUT},
208
{"olcuc", OLCUC, MD_OUT},
211
{"onlcr", ONLCR, MD_OUT},
214
{"ocrnl", OCRNL, MD_OUT},
217
{"onocr", ONOCR, MD_OUT},
220
{"onoeot", ONOEOT, MD_OUT},
223
{"onlret", ONLRET, MD_OUT},
226
{"ofill", OFILL, MD_OUT},
229
{"ofdel", OFDEL, MD_OUT},
232
{"nldly", NLDLY, MD_OUT},
235
{"crdly", CRDLY, MD_OUT},
238
{"tabdly", TABDLY, MD_OUT},
241
{"xtabs", XTABS, MD_OUT},
244
{"bsdly", BSDLY, MD_OUT},
247
{"vtdly", VTDLY, MD_OUT},
250
{"ffdly", FFDLY, MD_OUT},
253
{"pageout", PAGEOUT, MD_OUT},
256
{"wrap", WRAP, MD_OUT},
260
{"cignore", CIGNORE, MD_CTL},
263
{"cbaud", CBAUD, MD_CTL},
266
{"cstopb", CSTOPB, MD_CTL},
269
{"cread", CREAD, MD_CTL},
272
{"parenb", PARENB, MD_CTL},
275
{"parodd", PARODD, MD_CTL},
278
{"hupcl", HUPCL, MD_CTL},
281
{"clocal", CLOCAL, MD_CTL},
284
{"loblk", LOBLK, MD_CTL},
287
{"cibaud", CIBAUD, MD_CTL},
291
{"ccts_oflow", CCTS_OFLOW, MD_CTL},
293
{"crtscts", CRTSCTS, MD_CTL},
294
#endif /* CCTS_OFLOW */
297
{"crts_iflow", CRTS_IFLOW, MD_CTL},
298
#endif /* CRTS_IFLOW */
300
{"cdtrcts", CDTRCTS, MD_CTL},
303
{"mdmbuf", MDMBUF, MD_CTL},
306
{"rcv1en", RCV1EN, MD_CTL},
309
{"xmt1en", XMT1EN, MD_CTL},
313
{"isig", ISIG, MD_LIN},
316
{"icanon", ICANON, MD_LIN},
319
{"xcase", XCASE, MD_LIN},
322
{"echo", ECHO, MD_LIN},
325
{"echoe", ECHOE, MD_LIN},
328
{"echok", ECHOK, MD_LIN},
331
{"echonl", ECHONL, MD_LIN},
334
{"noflsh", NOFLSH, MD_LIN},
337
{"tostop", TOSTOP, MD_LIN},
340
{"echoctl", ECHOCTL, MD_LIN},
343
{"echoprt", ECHOPRT, MD_LIN},
346
{"echoke", ECHOKE, MD_LIN},
349
{"defecho", DEFECHO, MD_LIN},
352
{"flusho", FLUSHO, MD_LIN},
355
{"pendin", PENDIN, MD_LIN},
358
{"iexten", IEXTEN, MD_LIN},
361
{"nokerninfo", NOKERNINFO, MD_LIN},
362
#endif /* NOKERNINFO */
364
{"altwerase", ALTWERASE, MD_LIN},
365
#endif /* ALTWERASE */
367
{"extproc", EXTPROC, MD_LIN},
371
{"intr", C_SH(C_INTR), MD_CHAR},
374
{"quit", C_SH(C_QUIT), MD_CHAR},
377
{"erase", C_SH(C_ERASE), MD_CHAR},
380
{"kill", C_SH(C_KILL), MD_CHAR},
383
{"eof", C_SH(C_EOF), MD_CHAR},
386
{"eol", C_SH(C_EOL), MD_CHAR},
389
{"eol2", C_SH(C_EOL2), MD_CHAR},
392
{"swtch", C_SH(C_SWTCH), MD_CHAR},
395
{"dswtch", C_SH(C_DSWTCH), MD_CHAR},
398
{"erase2", C_SH(C_ERASE2), MD_CHAR},
401
{"start", C_SH(C_START), MD_CHAR},
404
{"stop", C_SH(C_STOP), MD_CHAR},
407
{"werase", C_SH(C_WERASE), MD_CHAR},
410
{"susp", C_SH(C_SUSP), MD_CHAR},
413
{"dsusp", C_SH(C_DSUSP), MD_CHAR},
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 */
422
{"lnext", C_SH(C_LNEXT), MD_CHAR},
425
{"status", C_SH(C_STATUS), MD_CHAR},
428
{"page", C_SH(C_PAGE), MD_CHAR},
431
{"pgoff", C_SH(C_PGOFF), MD_CHAR},
434
{"kill2", C_SH(C_KILL2), MD_CHAR},
437
{"brk", C_SH(C_BRK), MD_CHAR},
440
{"min", C_SH(C_MIN), MD_CHAR},
443
{"time", C_SH(C_TIME), MD_CHAR},
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)
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 *);
465
* Wrapper for tcgetattr to handle EINTR
468
tty_getty(EditLine *el, struct termios *t)
471
while ((rv = tcgetattr(el->el_infd, t)) == -1 && errno == EINTR)
477
* Wrapper for tcsetattr to handle EINTR
480
tty_setty(EditLine *el, int action, const struct termios *t)
483
while ((rv = tcsetattr(el->el_infd, action, t)) == -1 && errno == EINTR)
489
* Get the tty parameters and initialize the editing state
492
tty_setup(EditLine *el)
496
if (el->el_flags & EDIT_DISABLED)
499
if (!isatty(el->el_outfd)) {
501
(void) fprintf(el->el_errfile,
502
"tty_setup: isatty: %s\n", strerror(errno));
503
#endif /* DEBUG_TTY */
506
if (tty_getty(el, &el->el_tty.t_ed) == -1) {
508
(void) fprintf(el->el_errfile,
509
"tty_setup: tty_getty: %s\n", strerror(errno));
510
#endif /* DEBUG_TTY */
513
el->el_tty.t_ts = el->el_tty.t_ex = el->el_tty.t_ed;
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);
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;
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;
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;
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;
532
* Reset the tty chars to reasonable defaults
533
* If they are disabled, then enable them.
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]);
539
* Don't affect CMIN and CTIME for the editor mode
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];
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) {
557
(void) fprintf(el->el_errfile,
558
"tty_setup: tty_setty: %s\n",
560
#endif /* DEBUG_TTY */
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;
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;
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;
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;
577
tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]);
578
tty_bind_char(el, 1);
583
tty_init(EditLine *el)
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);
595
* Restore the tty to its original settings
599
tty_end(EditLine *el __attribute__((__unused__)))
602
/* XXX: Maybe reset to an initial state? */
610
tty__getspeed(struct termios *td)
614
if ((spd = cfgetispeed(td)) == 0)
615
spd = cfgetospeed(td);
620
* Return the index of the asked char in the c_cc array
623
tty__getcharindex(int i)
689
#endif /* VREPRINT */
693
#endif /* VDISCARD */
728
* Get the tty characters
731
tty__getchar(struct termios *td, unsigned char *s)
735
s[C_INTR] = td->c_cc[VINTR];
738
s[C_QUIT] = td->c_cc[VQUIT];
741
s[C_ERASE] = td->c_cc[VERASE];
744
s[C_KILL] = td->c_cc[VKILL];
747
s[C_EOF] = td->c_cc[VEOF];
750
s[C_EOL] = td->c_cc[VEOL];
753
s[C_EOL2] = td->c_cc[VEOL2];
756
s[C_SWTCH] = td->c_cc[VSWTCH];
759
s[C_DSWTCH] = td->c_cc[VDSWTCH];
762
s[C_ERASE2] = td->c_cc[VERASE2];
765
s[C_START] = td->c_cc[VSTART];
768
s[C_STOP] = td->c_cc[VSTOP];
771
s[C_WERASE] = td->c_cc[VWERASE];
774
s[C_SUSP] = td->c_cc[VSUSP];
777
s[C_DSUSP] = td->c_cc[VDSUSP];
780
s[C_REPRINT] = td->c_cc[VREPRINT];
781
#endif /* VREPRINT */
783
s[C_DISCARD] = td->c_cc[VDISCARD];
784
#endif /* VDISCARD */
786
s[C_LNEXT] = td->c_cc[VLNEXT];
789
s[C_STATUS] = td->c_cc[VSTATUS];
792
s[C_PAGE] = td->c_cc[VPAGE];
795
s[C_PGOFF] = td->c_cc[VPGOFF];
798
s[C_KILL2] = td->c_cc[VKILL2];
801
s[C_MIN] = td->c_cc[VMIN];
804
s[C_TIME] = td->c_cc[VTIME];
810
* Set the tty characters
813
tty__setchar(struct termios *td, unsigned char *s)
817
td->c_cc[VINTR] = s[C_INTR];
820
td->c_cc[VQUIT] = s[C_QUIT];
823
td->c_cc[VERASE] = s[C_ERASE];
826
td->c_cc[VKILL] = s[C_KILL];
829
td->c_cc[VEOF] = s[C_EOF];
832
td->c_cc[VEOL] = s[C_EOL];
835
td->c_cc[VEOL2] = s[C_EOL2];
838
td->c_cc[VSWTCH] = s[C_SWTCH];
841
td->c_cc[VDSWTCH] = s[C_DSWTCH];
844
td->c_cc[VERASE2] = s[C_ERASE2];
847
td->c_cc[VSTART] = s[C_START];
850
td->c_cc[VSTOP] = s[C_STOP];
853
td->c_cc[VWERASE] = s[C_WERASE];
856
td->c_cc[VSUSP] = s[C_SUSP];
859
td->c_cc[VDSUSP] = s[C_DSUSP];
862
td->c_cc[VREPRINT] = s[C_REPRINT];
863
#endif /* VREPRINT */
865
td->c_cc[VDISCARD] = s[C_DISCARD];
866
#endif /* VDISCARD */
868
td->c_cc[VLNEXT] = s[C_LNEXT];
871
td->c_cc[VSTATUS] = s[C_STATUS];
874
td->c_cc[VPAGE] = s[C_PAGE];
877
td->c_cc[VPGOFF] = s[C_PGOFF];
880
td->c_cc[VKILL2] = s[C_KILL2];
883
td->c_cc[VMIN] = s[C_MIN];
886
td->c_cc[VTIME] = s[C_TIME];
892
* Rebind the editline functions
895
tty_bind_char(EditLine *el, int force)
898
unsigned char *t_n = el->el_tty.t_c[ED_IO];
899
unsigned char *t_o = el->el_tty.t_ed.c_cc;
902
el_action_t *map, *alt;
903
const el_action_t *dmap, *dalt;
904
new[1] = old[1] = '\0';
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;
912
dmap = el->el_map.emacs;
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)
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];
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];
938
* Set terminal into 1 character at a time mode.
941
tty_rawmode(EditLine *el)
944
if (el->el_tty.t_mode == ED_IO || el->el_tty.t_mode == QU_IO)
947
if (el->el_flags & EDIT_DISABLED)
950
if (tty_getty(el, &el->el_tty.t_ts) == -1) {
952
(void) fprintf(el->el_errfile, "tty_rawmode: tty_getty: %s\n",
954
#endif /* DEBUG_TTY */
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!
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);
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);
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;
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;
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;
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;
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;
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;
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;
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;
1035
if (tty__gettabs(&el->el_tty.t_ex) == 0)
1036
el->el_tty.t_tabs = 0;
1038
el->el_tty.t_tabs = EL_CAN_TAB ? 1 : 0;
1043
tty__getchar(&el->el_tty.t_ts, el->el_tty.t_c[TS_IO]);
1045
* Check if the user made any changes.
1046
* If he did, then propagate the changes to the
1047
* edit and execute data structures.
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])
1056
* Propagate changes only to the unprotected
1057
* chars that have been modified just now.
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;
1066
tty_bind_char(el, 0);
1067
tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]);
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;
1076
tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]);
1080
if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ed) == -1) {
1082
(void) fprintf(el->el_errfile, "tty_rawmode: tty_setty: %s\n",
1084
#endif /* DEBUG_TTY */
1087
el->el_tty.t_mode = ED_IO;
1092
/* tty_cookedmode():
1093
* Set the tty back to normal mode
1096
tty_cookedmode(EditLine *el)
1097
{ /* set tty in normal setup */
1099
if (el->el_tty.t_mode == EX_IO)
1102
if (el->el_flags & EDIT_DISABLED)
1105
if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ex) == -1) {
1107
(void) fprintf(el->el_errfile,
1108
"tty_cookedmode: tty_setty: %s\n",
1110
#endif /* DEBUG_TTY */
1113
el->el_tty.t_mode = EX_IO;
1119
* Turn on quote mode
1122
tty_quotemode(EditLine *el)
1124
if (el->el_tty.t_mode == QU_IO)
1127
el->el_tty.t_qu = el->el_tty.t_ed;
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;
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;
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;
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;
1141
if (tty_setty(el, TCSADRAIN, &el->el_tty.t_qu) == -1) {
1143
(void) fprintf(el->el_errfile, "QuoteModeOn: tty_setty: %s\n",
1145
#endif /* DEBUG_TTY */
1148
el->el_tty.t_mode = QU_IO;
1153
/* tty_noquotemode():
1154
* Turn off quote mode
1157
tty_noquotemode(EditLine *el)
1160
if (el->el_tty.t_mode != QU_IO)
1162
if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ed) == -1) {
1164
(void) fprintf(el->el_errfile, "QuoteModeOff: tty_setty: %s\n",
1166
#endif /* DEBUG_TTY */
1169
el->el_tty.t_mode = ED_IO;
1179
tty_stty(EditLine *el, int argc __attribute__((__unused__)), const Char **argv)
1181
const ttymodes_t *m;
1185
char name[EL_BUFSIZ];
1186
struct termios *tios = &el->el_tty.t_ex;
1191
strncpy(name, ct_encode_string(*argv++, &el->el_scratch), sizeof(name));
1192
name[sizeof(name) - 1] = '\0';
1194
while (argv && *argv && argv[0][0] == '-' && argv[0][2] == '\0')
1195
switch (argv[0][1]) {
1202
tios = &el->el_tty.t_ed;
1207
tios = &el->el_tty.t_ex;
1212
tios = &el->el_tty.t_ts;
1216
(void) fprintf(el->el_errfile,
1217
"%s: Unknown switch `%c'.\n",
1222
if (!argv || !*argv) {
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);
1232
strlen(el->el_tty.t_t[z][m->m_type].t_name);
1235
x = (el->el_tty.t_t[z][i].t_setmask & m->m_value)
1238
if (el->el_tty.t_t[z][i].t_clrmask & m->m_value)
1244
if (x != '\0' || aflag) {
1246
cu = strlen(m->m_name) + (x != '\0') + 1;
1248
if (len + cu >= (size_t)el->el_terminal.t_size.h) {
1249
(void) fprintf(el->el_outfile, "\n%*s",
1256
(void) fprintf(el->el_outfile, "%c%s ",
1259
(void) fprintf(el->el_outfile, "%s ",
1263
(void) fprintf(el->el_outfile, "\n");
1266
while (argv && (s = *argv++)) {
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))
1286
(void) fprintf(el->el_errfile,
1287
"%s: Invalid argument `" FSTR "'.\n", name, d);
1291
int c = ffs((int)m->m_value);
1292
int v = *++p ? parse__escape(&p) :
1293
el->el_tty.t_vdisable;
1296
c = tty__getcharindex(c);
1298
tios->c_cc[c] = (cc_t)v;
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;
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;
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;
1317
if (el->el_tty.t_mode == z) {
1318
if (tty_setty(el, TCSADRAIN, tios) == -1) {
1320
(void) fprintf(el->el_errfile,
1321
"tty_stty: tty_setty: %s\n", strerror(errno));
1322
#endif /* DEBUG_TTY */
1333
* DEbugging routine to print the tty characters
1336
tty_printchar(EditLine *el, unsigned char *s)
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)
1346
(void) fprintf(el->el_errfile, "%s ^%c ",
1347
m->m_name, s[i] + 'A' - 1);
1349
(void) fprintf(el->el_errfile, "\n");
1351
(void) fprintf(el->el_errfile, "\n");