1 /* $NetBSD: tty.c,v 1.68 2018/12/02 16:58:13 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";
40 __RCSID("$NetBSD: tty.c,v 1.68 2018/12/02 16:58:13 christos Exp $");
42 #endif /* not lint && not SCCSID */
45 * tty.c: tty interface stuff
49 #include <stdlib.h> /* for abort */
51 #include <strings.h> /* for ffs */
52 #include <unistd.h> /* for isatty */
58 typedef struct ttymodes_t {
64 typedef struct ttymap_t {
65 wint_t nch, och; /* Internal and termio rep of chars */
66 el_action_t bind[3]; /* emacs, vi, and vi-cmd */
70 static const ttyperm_t ttyperm = {
72 {"iflag:", ICRNL, (INLCR | IGNCR)},
73 {"oflag:", (OPOST | ONLCR), ONLRET},
75 {"lflag:", (ISIG | ICANON | ECHO | ECHOE | ECHOCTL | IEXTEN),
76 (NOFLSH | ECHONL | EXTPROC | FLUSHO)},
80 {"iflag:", (INLCR | ICRNL), IGNCR},
81 {"oflag:", (OPOST | ONLCR), ONLRET},
84 (NOFLSH | ICANON | ECHO | ECHOK | ECHONL | EXTPROC | IEXTEN | FLUSHO)},
85 {"chars:", (C_SH(C_MIN) | C_SH(C_TIME) | C_SH(C_SWTCH) | C_SH(C_DSWTCH) |
86 C_SH(C_SUSP) | C_SH(C_DSUSP) | C_SH(C_EOL) | C_SH(C_DISCARD) |
87 C_SH(C_PGOFF) | C_SH(C_PAGE) | C_SH(C_STATUS)), 0}
90 {"iflag:", 0, IXON | IXOFF | INLCR | ICRNL},
93 {"lflag:", 0, ISIG | IEXTEN},
98 static const ttychar_t ttychar = {
100 CINTR, CQUIT, CERASE, CKILL,
101 CEOF, CEOL, CEOL2, CSWTCH,
102 CDSWTCH, CERASE2, CSTART, CSTOP,
103 CWERASE, CSUSP, CDSUSP, CREPRINT,
104 CDISCARD, CLNEXT, CSTATUS, CPAGE,
105 CPGOFF, CKILL2, CBRK, CMIN,
109 CINTR, CQUIT, CERASE, CKILL,
110 _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE,
111 _POSIX_VDISABLE, CERASE2, CSTART, CSTOP,
112 _POSIX_VDISABLE, CSUSP, _POSIX_VDISABLE, _POSIX_VDISABLE,
113 CDISCARD, _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE,
114 _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE, 1,
128 static const ttymap_t tty_map[] = {
131 {EM_DELETE_PREV_CHAR, VI_DELETE_PREV_CHAR, ED_PREV_CHAR}},
135 {EM_DELETE_PREV_CHAR, VI_DELETE_PREV_CHAR, ED_PREV_CHAR}},
139 {EM_KILL_LINE, VI_KILL_LINE_PREV, ED_UNASSIGNED}},
143 {EM_KILL_LINE, VI_KILL_LINE_PREV, ED_UNASSIGNED}},
147 {EM_DELETE_OR_LIST, VI_LIST_OR_EOF, ED_UNASSIGNED}},
151 {ED_DELETE_PREV_WORD, ED_DELETE_PREV_WORD, ED_PREV_WORD}},
154 {C_REPRINT, VREPRINT,
155 {ED_REDISPLAY, ED_INSERT, ED_REDISPLAY}},
156 #endif /* VREPRINT */
159 {ED_QUOTED_INSERT, ED_QUOTED_INSERT, ED_UNASSIGNED}},
161 {(wint_t)-1, (wint_t)-1,
162 {ED_UNASSIGNED, ED_UNASSIGNED, ED_UNASSIGNED}}
165 static const ttymodes_t ttymodes[] = {
167 {"ignbrk", IGNBRK, MD_INP},
170 {"brkint", BRKINT, MD_INP},
173 {"ignpar", IGNPAR, MD_INP},
176 {"parmrk", PARMRK, MD_INP},
179 {"inpck", INPCK, MD_INP},
182 {"istrip", ISTRIP, MD_INP},
185 {"inlcr", INLCR, MD_INP},
188 {"igncr", IGNCR, MD_INP},
191 {"icrnl", ICRNL, MD_INP},
194 {"iuclc", IUCLC, MD_INP},
197 {"ixon", IXON, MD_INP},
200 {"ixany", IXANY, MD_INP},
203 {"ixoff", IXOFF, MD_INP},
206 {"imaxbel", IMAXBEL, MD_INP},
210 {"opost", OPOST, MD_OUT},
213 {"olcuc", OLCUC, MD_OUT},
216 {"onlcr", ONLCR, MD_OUT},
219 {"ocrnl", OCRNL, MD_OUT},
222 {"onocr", ONOCR, MD_OUT},
225 {"onoeot", ONOEOT, MD_OUT},
228 {"onlret", ONLRET, MD_OUT},
231 {"ofill", OFILL, MD_OUT},
234 {"ofdel", OFDEL, MD_OUT},
237 {"nldly", NLDLY, MD_OUT},
240 {"crdly", CRDLY, MD_OUT},
243 {"tabdly", TABDLY, MD_OUT},
246 {"xtabs", XTABS, MD_OUT},
249 {"bsdly", BSDLY, MD_OUT},
252 {"vtdly", VTDLY, MD_OUT},
255 {"ffdly", FFDLY, MD_OUT},
258 {"pageout", PAGEOUT, MD_OUT},
261 {"wrap", WRAP, MD_OUT},
265 {"cignore", CIGNORE, MD_CTL},
268 {"cbaud", CBAUD, MD_CTL},
271 {"cstopb", CSTOPB, MD_CTL},
274 {"cread", CREAD, MD_CTL},
277 {"parenb", PARENB, MD_CTL},
280 {"parodd", PARODD, MD_CTL},
283 {"hupcl", HUPCL, MD_CTL},
286 {"clocal", CLOCAL, MD_CTL},
289 {"loblk", LOBLK, MD_CTL},
292 {"cibaud", CIBAUD, MD_CTL},
296 {"ccts_oflow", CCTS_OFLOW, MD_CTL},
298 {"crtscts", CRTSCTS, MD_CTL},
299 #endif /* CCTS_OFLOW */
302 {"crts_iflow", CRTS_IFLOW, MD_CTL},
303 #endif /* CRTS_IFLOW */
305 {"cdtrcts", CDTRCTS, MD_CTL},
308 {"mdmbuf", MDMBUF, MD_CTL},
311 {"rcv1en", RCV1EN, MD_CTL},
314 {"xmt1en", XMT1EN, MD_CTL},
318 {"isig", ISIG, MD_LIN},
321 {"icanon", ICANON, MD_LIN},
324 {"xcase", XCASE, MD_LIN},
327 {"echo", ECHO, MD_LIN},
330 {"echoe", ECHOE, MD_LIN},
333 {"echok", ECHOK, MD_LIN},
336 {"echonl", ECHONL, MD_LIN},
339 {"noflsh", NOFLSH, MD_LIN},
342 {"tostop", TOSTOP, MD_LIN},
345 {"echoctl", ECHOCTL, MD_LIN},
348 {"echoprt", ECHOPRT, MD_LIN},
351 {"echoke", ECHOKE, MD_LIN},
354 {"defecho", DEFECHO, MD_LIN},
357 {"flusho", FLUSHO, MD_LIN},
360 {"pendin", PENDIN, MD_LIN},
363 {"iexten", IEXTEN, MD_LIN},
366 {"nokerninfo", NOKERNINFO, MD_LIN},
367 #endif /* NOKERNINFO */
369 {"altwerase", ALTWERASE, MD_LIN},
370 #endif /* ALTWERASE */
372 {"extproc", EXTPROC, MD_LIN},
376 {"intr", C_SH(C_INTR), MD_CHAR},
379 {"quit", C_SH(C_QUIT), MD_CHAR},
382 {"erase", C_SH(C_ERASE), MD_CHAR},
385 {"kill", C_SH(C_KILL), MD_CHAR},
388 {"eof", C_SH(C_EOF), MD_CHAR},
391 {"eol", C_SH(C_EOL), MD_CHAR},
394 {"eol2", C_SH(C_EOL2), MD_CHAR},
397 {"swtch", C_SH(C_SWTCH), MD_CHAR},
400 {"dswtch", C_SH(C_DSWTCH), MD_CHAR},
403 {"erase2", C_SH(C_ERASE2), MD_CHAR},
406 {"start", C_SH(C_START), MD_CHAR},
409 {"stop", C_SH(C_STOP), MD_CHAR},
412 {"werase", C_SH(C_WERASE), MD_CHAR},
415 {"susp", C_SH(C_SUSP), MD_CHAR},
418 {"dsusp", C_SH(C_DSUSP), MD_CHAR},
420 #if defined(VREPRINT)
421 {"reprint", C_SH(C_REPRINT), MD_CHAR},
422 #endif /* VREPRINT */
423 #if defined(VDISCARD)
424 {"discard", C_SH(C_DISCARD), MD_CHAR},
425 #endif /* VDISCARD */
427 {"lnext", C_SH(C_LNEXT), MD_CHAR},
430 {"status", C_SH(C_STATUS), MD_CHAR},
433 {"page", C_SH(C_PAGE), MD_CHAR},
436 {"pgoff", C_SH(C_PGOFF), MD_CHAR},
439 {"kill2", C_SH(C_KILL2), MD_CHAR},
442 {"brk", C_SH(C_BRK), MD_CHAR},
445 {"min", C_SH(C_MIN), MD_CHAR},
448 {"time", C_SH(C_TIME), MD_CHAR},
455 #define tty__gettabs(td) ((((td)->c_oflag & TAB3) == TAB3) ? 0 : 1)
456 #define tty__geteightbit(td) (((td)->c_cflag & CSIZE) == CS8)
457 #define tty__cooked_mode(td) ((td)->c_lflag & ICANON)
459 static int tty_getty(EditLine *, struct termios *);
460 static int tty_setty(EditLine *, int, const struct termios *);
461 static int tty__getcharindex(int);
462 static void tty__getchar(struct termios *, unsigned char *);
463 static void tty__setchar(struct termios *, unsigned char *);
464 static speed_t tty__getspeed(struct termios *);
465 static int tty_setup(EditLine *);
466 static void tty_setup_flags(EditLine *, struct termios *, int);
471 * Wrapper for tcgetattr to handle EINTR
474 tty_getty(EditLine *el, struct termios *t)
477 while ((rv = tcgetattr(el->el_infd, t)) == -1 && errno == EINTR)
483 * Wrapper for tcsetattr to handle EINTR
486 tty_setty(EditLine *el, int action, const struct termios *t)
489 while ((rv = tcsetattr(el->el_infd, action, t)) == -1 && errno == EINTR)
495 * Get the tty parameters and initialize the editing state
498 tty_setup(EditLine *el)
500 int rst = (el->el_flags & NO_RESET) == 0;
502 if (el->el_flags & EDIT_DISABLED)
505 if (el->el_tty.t_initialized)
508 if (!isatty(el->el_outfd)) {
510 (void) fprintf(el->el_errfile, "%s: isatty: %s\n", __func__,
512 #endif /* DEBUG_TTY */
515 if (tty_getty(el, &el->el_tty.t_or) == -1) {
517 (void) fprintf(el->el_errfile, "%s: tty_getty: %s\n", __func__,
519 #endif /* DEBUG_TTY */
522 el->el_tty.t_ts = el->el_tty.t_ex = el->el_tty.t_ed = el->el_tty.t_or;
524 el->el_tty.t_speed = tty__getspeed(&el->el_tty.t_ex);
525 el->el_tty.t_tabs = tty__gettabs(&el->el_tty.t_ex);
526 el->el_tty.t_eight = tty__geteightbit(&el->el_tty.t_ex);
528 tty_setup_flags(el, &el->el_tty.t_ex, EX_IO);
531 * Reset the tty chars to reasonable defaults
532 * If they are disabled, then enable them.
535 if (tty__cooked_mode(&el->el_tty.t_ts)) {
536 tty__getchar(&el->el_tty.t_ts, el->el_tty.t_c[TS_IO]);
538 * Don't affect CMIN and CTIME for the editor mode
540 for (rst = 0; rst < C_NCC - 2; rst++)
541 if (el->el_tty.t_c[TS_IO][rst] !=
542 el->el_tty.t_vdisable
543 && el->el_tty.t_c[ED_IO][rst] !=
544 el->el_tty.t_vdisable)
545 el->el_tty.t_c[ED_IO][rst] =
546 el->el_tty.t_c[TS_IO][rst];
547 for (rst = 0; rst < C_NCC; rst++)
548 if (el->el_tty.t_c[TS_IO][rst] !=
549 el->el_tty.t_vdisable)
550 el->el_tty.t_c[EX_IO][rst] =
551 el->el_tty.t_c[TS_IO][rst];
553 tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]);
554 if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ex) == -1) {
556 (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n",
557 __func__, strerror(errno));
558 #endif /* DEBUG_TTY */
563 tty_setup_flags(el, &el->el_tty.t_ed, ED_IO);
565 tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]);
566 tty_bind_char(el, 1);
567 el->el_tty.t_initialized = 1;
572 tty_init(EditLine *el)
575 el->el_tty.t_mode = EX_IO;
576 el->el_tty.t_vdisable = _POSIX_VDISABLE;
577 el->el_tty.t_initialized = 0;
578 (void) memcpy(el->el_tty.t_t, ttyperm, sizeof(ttyperm_t));
579 (void) memcpy(el->el_tty.t_c, ttychar, sizeof(ttychar_t));
580 return tty_setup(el);
585 * Restore the tty to its original settings
589 tty_end(EditLine *el, int how)
591 if (el->el_flags & EDIT_DISABLED)
594 if (!el->el_tty.t_initialized)
597 if (tty_setty(el, how, &el->el_tty.t_or) == -1)
600 (void) fprintf(el->el_errfile,
601 "%s: tty_setty: %s\n", __func__, strerror(errno));
602 #endif /* DEBUG_TTY */
611 tty__getspeed(struct termios *td)
615 if ((spd = cfgetispeed(td)) == 0)
616 spd = cfgetospeed(td);
621 * Return the index of the asked char in the c_cc array
624 tty__getcharindex(int i)
690 #endif /* VREPRINT */
694 #endif /* VDISCARD */
729 * Get the tty characters
732 tty__getchar(struct termios *td, unsigned char *s)
736 s[C_INTR] = td->c_cc[VINTR];
739 s[C_QUIT] = td->c_cc[VQUIT];
742 s[C_ERASE] = td->c_cc[VERASE];
745 s[C_KILL] = td->c_cc[VKILL];
748 s[C_EOF] = td->c_cc[VEOF];
751 s[C_EOL] = td->c_cc[VEOL];
754 s[C_EOL2] = td->c_cc[VEOL2];
757 s[C_SWTCH] = td->c_cc[VSWTCH];
760 s[C_DSWTCH] = td->c_cc[VDSWTCH];
763 s[C_ERASE2] = td->c_cc[VERASE2];
766 s[C_START] = td->c_cc[VSTART];
769 s[C_STOP] = td->c_cc[VSTOP];
772 s[C_WERASE] = td->c_cc[VWERASE];
775 s[C_SUSP] = td->c_cc[VSUSP];
778 s[C_DSUSP] = td->c_cc[VDSUSP];
781 s[C_REPRINT] = td->c_cc[VREPRINT];
782 #endif /* VREPRINT */
784 s[C_DISCARD] = td->c_cc[VDISCARD];
785 #endif /* VDISCARD */
787 s[C_LNEXT] = td->c_cc[VLNEXT];
790 s[C_STATUS] = td->c_cc[VSTATUS];
793 s[C_PAGE] = td->c_cc[VPAGE];
796 s[C_PGOFF] = td->c_cc[VPGOFF];
799 s[C_KILL2] = td->c_cc[VKILL2];
802 s[C_MIN] = td->c_cc[VMIN];
805 s[C_TIME] = td->c_cc[VTIME];
811 * Set the tty characters
814 tty__setchar(struct termios *td, unsigned char *s)
818 td->c_cc[VINTR] = s[C_INTR];
821 td->c_cc[VQUIT] = s[C_QUIT];
824 td->c_cc[VERASE] = s[C_ERASE];
827 td->c_cc[VKILL] = s[C_KILL];
830 td->c_cc[VEOF] = s[C_EOF];
833 td->c_cc[VEOL] = s[C_EOL];
836 td->c_cc[VEOL2] = s[C_EOL2];
839 td->c_cc[VSWTCH] = s[C_SWTCH];
842 td->c_cc[VDSWTCH] = s[C_DSWTCH];
845 td->c_cc[VERASE2] = s[C_ERASE2];
848 td->c_cc[VSTART] = s[C_START];
851 td->c_cc[VSTOP] = s[C_STOP];
854 td->c_cc[VWERASE] = s[C_WERASE];
857 td->c_cc[VSUSP] = s[C_SUSP];
860 td->c_cc[VDSUSP] = s[C_DSUSP];
863 td->c_cc[VREPRINT] = s[C_REPRINT];
864 #endif /* VREPRINT */
866 td->c_cc[VDISCARD] = s[C_DISCARD];
867 #endif /* VDISCARD */
869 td->c_cc[VLNEXT] = s[C_LNEXT];
872 td->c_cc[VSTATUS] = s[C_STATUS];
875 td->c_cc[VPAGE] = s[C_PAGE];
878 td->c_cc[VPGOFF] = s[C_PGOFF];
881 td->c_cc[VKILL2] = s[C_KILL2];
884 td->c_cc[VMIN] = s[C_MIN];
887 td->c_cc[VTIME] = s[C_TIME];
893 * Rebind the editline functions
896 tty_bind_char(EditLine *el, int force)
899 unsigned char *t_n = el->el_tty.t_c[ED_IO];
900 unsigned char *t_o = el->el_tty.t_ed.c_cc;
901 wchar_t new[2], old[2];
903 el_action_t *map, *alt;
904 const el_action_t *dmap, *dalt;
905 new[1] = old[1] = '\0';
907 map = el->el_map.key;
908 alt = el->el_map.alt;
909 if (el->el_map.type == MAP_VI) {
910 dmap = el->el_map.vii;
911 dalt = el->el_map.vic;
913 dmap = el->el_map.emacs;
917 for (tp = tty_map; tp->nch != (wint_t)-1; tp++) {
918 new[0] = (wchar_t)t_n[tp->nch];
919 old[0] = (wchar_t)t_o[tp->och];
920 if (new[0] == old[0] && !force)
922 /* Put the old default binding back, and set the new binding */
923 keymacro_clear(el, map, old);
924 map[(unsigned char)old[0]] = dmap[(unsigned char)old[0]];
925 keymacro_clear(el, map, new);
926 /* MAP_VI == 1, MAP_EMACS == 0... */
927 map[(unsigned char)new[0]] = tp->bind[el->el_map.type];
929 keymacro_clear(el, alt, old);
930 alt[(unsigned char)old[0]] =
931 dalt[(unsigned char)old[0]];
932 keymacro_clear(el, alt, new);
933 alt[(unsigned char)new[0]] =
934 tp->bind[el->el_map.type + 1];
941 tty__get_flag(struct termios *t, int kind) {
959 tty_update_flag(EditLine *el, tcflag_t f, int mode, int kind)
961 f &= ~el->el_tty.t_t[mode][kind].t_clrmask;
962 f |= el->el_tty.t_t[mode][kind].t_setmask;
968 tty_update_flags(EditLine *el, int kind)
970 tcflag_t *tt, *ed, *ex;
971 tt = tty__get_flag(&el->el_tty.t_ts, kind);
972 ed = tty__get_flag(&el->el_tty.t_ed, kind);
973 ex = tty__get_flag(&el->el_tty.t_ex, kind);
975 if (*tt != *ex && (kind != MD_CTL || *tt != *ed)) {
976 *ed = tty_update_flag(el, *tt, ED_IO, kind);
977 *ex = tty_update_flag(el, *tt, EX_IO, kind);
983 tty_update_char(EditLine *el, int mode, int c) {
984 if (!((el->el_tty.t_t[mode][MD_CHAR].t_setmask & C_SH(c)))
985 && (el->el_tty.t_c[TS_IO][c] != el->el_tty.t_c[EX_IO][c]))
986 el->el_tty.t_c[mode][c] = el->el_tty.t_c[TS_IO][c];
987 if (el->el_tty.t_t[mode][MD_CHAR].t_clrmask & C_SH(c))
988 el->el_tty.t_c[mode][c] = el->el_tty.t_vdisable;
993 * Set terminal into 1 character at a time mode.
996 tty_rawmode(EditLine *el)
999 if (el->el_tty.t_mode == ED_IO || el->el_tty.t_mode == QU_IO)
1002 if (el->el_flags & EDIT_DISABLED)
1005 if (tty_getty(el, &el->el_tty.t_ts) == -1) {
1007 (void) fprintf(el->el_errfile, "%s: tty_getty: %s\n", __func__,
1009 #endif /* DEBUG_TTY */
1013 * We always keep up with the eight bit setting and the speed of the
1014 * tty. But we only believe changes that are made to cooked mode!
1016 el->el_tty.t_eight = tty__geteightbit(&el->el_tty.t_ts);
1017 el->el_tty.t_speed = tty__getspeed(&el->el_tty.t_ts);
1019 if (tty__getspeed(&el->el_tty.t_ex) != el->el_tty.t_speed ||
1020 tty__getspeed(&el->el_tty.t_ed) != el->el_tty.t_speed) {
1021 (void) cfsetispeed(&el->el_tty.t_ex, el->el_tty.t_speed);
1022 (void) cfsetospeed(&el->el_tty.t_ex, el->el_tty.t_speed);
1023 (void) cfsetispeed(&el->el_tty.t_ed, el->el_tty.t_speed);
1024 (void) cfsetospeed(&el->el_tty.t_ed, el->el_tty.t_speed);
1026 if (tty__cooked_mode(&el->el_tty.t_ts)) {
1029 for (i = MD_INP; i <= MD_LIN; i++)
1030 tty_update_flags(el, i);
1032 if (tty__gettabs(&el->el_tty.t_ex) == 0)
1033 el->el_tty.t_tabs = 0;
1035 el->el_tty.t_tabs = EL_CAN_TAB ? 1 : 0;
1037 tty__getchar(&el->el_tty.t_ts, el->el_tty.t_c[TS_IO]);
1039 * Check if the user made any changes.
1040 * If he did, then propagate the changes to the
1041 * edit and execute data structures.
1043 for (i = 0; i < C_NCC; i++)
1044 if (el->el_tty.t_c[TS_IO][i] !=
1045 el->el_tty.t_c[EX_IO][i])
1050 * Propagate changes only to the unlibedit_private
1051 * chars that have been modified just now.
1053 for (i = 0; i < C_NCC; i++)
1054 tty_update_char(el, ED_IO, i);
1056 tty_bind_char(el, 0);
1057 tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]);
1059 for (i = 0; i < C_NCC; i++)
1060 tty_update_char(el, EX_IO, i);
1062 tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]);
1065 if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ed) == -1) {
1067 (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", __func__,
1069 #endif /* DEBUG_TTY */
1072 el->el_tty.t_mode = ED_IO;
1077 /* tty_cookedmode():
1078 * Set the tty back to normal mode
1081 tty_cookedmode(EditLine *el)
1082 { /* set tty in normal setup */
1084 if (el->el_tty.t_mode == EX_IO)
1087 if (el->el_flags & EDIT_DISABLED)
1090 if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ex) == -1) {
1092 (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", __func__,
1094 #endif /* DEBUG_TTY */
1097 el->el_tty.t_mode = EX_IO;
1103 * Turn on quote mode
1106 tty_quotemode(EditLine *el)
1108 if (el->el_tty.t_mode == QU_IO)
1111 el->el_tty.t_qu = el->el_tty.t_ed;
1113 tty_setup_flags(el, &el->el_tty.t_qu, QU_IO);
1115 if (tty_setty(el, TCSADRAIN, &el->el_tty.t_qu) == -1) {
1117 (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", __func__,
1119 #endif /* DEBUG_TTY */
1122 el->el_tty.t_mode = QU_IO;
1127 /* tty_noquotemode():
1128 * Turn off quote mode
1131 tty_noquotemode(EditLine *el)
1134 if (el->el_tty.t_mode != QU_IO)
1136 if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ed) == -1) {
1138 (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", __func__,
1140 #endif /* DEBUG_TTY */
1143 el->el_tty.t_mode = ED_IO;
1153 tty_stty(EditLine *el, int argc __attribute__((__unused__)),
1154 const wchar_t **argv)
1156 const ttymodes_t *m;
1159 const wchar_t *s, *d;
1160 char name[EL_BUFSIZ];
1161 struct termios *tios = &el->el_tty.t_ex;
1166 strncpy(name, ct_encode_string(*argv++, &el->el_scratch), sizeof(name));
1167 name[sizeof(name) - 1] = '\0';
1169 while (argv && *argv && argv[0][0] == '-' && argv[0][2] == '\0')
1170 switch (argv[0][1]) {
1177 tios = &el->el_tty.t_ed;
1182 tios = &el->el_tty.t_ex;
1187 tios = &el->el_tty.t_ts;
1191 (void) fprintf(el->el_errfile,
1192 "%s: Unknown switch `%lc'.\n",
1193 name, (wint_t)argv[0][1]);
1197 if (!argv || !*argv) {
1199 size_t len = 0, st = 0, cu;
1200 for (m = ttymodes; m->m_name; m++) {
1201 if (m->m_type != i) {
1202 (void) fprintf(el->el_outfile, "%s%s",
1203 i != -1 ? "\n" : "",
1204 el->el_tty.t_t[z][m->m_type].t_name);
1207 strlen(el->el_tty.t_t[z][m->m_type].t_name);
1210 x = (el->el_tty.t_t[z][i].t_setmask & m->m_value)
1213 if (el->el_tty.t_t[z][i].t_clrmask & m->m_value)
1219 if (x != '\0' || aflag) {
1221 cu = strlen(m->m_name) + (x != '\0') + 1;
1224 (size_t)el->el_terminal.t_size.h) {
1225 (void) fprintf(el->el_outfile, "\n%*s",
1232 (void) fprintf(el->el_outfile, "%c%s ",
1235 (void) fprintf(el->el_outfile, "%s ",
1239 (void) fprintf(el->el_outfile, "\n");
1242 while (argv && (s = *argv++)) {
1254 p = wcschr(s, L'=');
1255 for (m = ttymodes; m->m_name; m++)
1256 if ((p ? strncmp(m->m_name, ct_encode_string(d,
1257 &el->el_scratch), (size_t)(p - d)) :
1258 strcmp(m->m_name, ct_encode_string(d,
1259 &el->el_scratch))) == 0 &&
1260 (p == NULL || m->m_type == MD_CHAR))
1264 (void) fprintf(el->el_errfile,
1265 "%s: Invalid argument `%ls'.\n", name, d);
1269 int c = ffs((int)m->m_value);
1270 int v = *++p ? parse__escape(&p) :
1271 el->el_tty.t_vdisable;
1274 c = tty__getcharindex(c);
1276 tios->c_cc[c] = (cc_t)v;
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;
1285 el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value;
1286 el->el_tty.t_t[z][m->m_type].t_clrmask |= m->m_value;
1289 el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value;
1290 el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value;
1295 tty_setup_flags(el, tios, z);
1296 if (el->el_tty.t_mode == z) {
1297 if (tty_setty(el, TCSADRAIN, tios) == -1) {
1299 (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n",
1300 __func__, strerror(errno));
1301 #endif /* DEBUG_TTY */
1312 * DEbugging routine to print the tty characters
1315 tty_printchar(EditLine *el, unsigned char *s)
1320 for (i = 0; i < C_NCC; i++) {
1321 for (m = el->el_tty.t_t; m->m_name; m++)
1322 if (m->m_type == MD_CHAR && C_SH(i) == m->m_value)
1325 (void) fprintf(el->el_errfile, "%s ^%c ",
1326 m->m_name, s[i] + 'A' - 1);
1328 (void) fprintf(el->el_errfile, "\n");
1330 (void) fprintf(el->el_errfile, "\n");
1336 tty_setup_flags(EditLine *el, struct termios *tios, int mode)
1339 for (kind = MD_INP; kind <= MD_LIN; kind++) {
1340 tcflag_t *f = tty__get_flag(tios, kind);
1341 *f = tty_update_flag(el, *f, mode, kind);
1346 tty_get_signal_character(EditLine *el, int sig)
1349 tcflag_t *ed = tty__get_flag(&el->el_tty.t_ed, MD_INP);
1350 if ((*ed & ECHOCTL) == 0)
1356 return el->el_tty.t_c[ED_IO][VINTR];
1360 return el->el_tty.t_c[ED_IO][VQUIT];
1364 return el->el_tty.t_c[ED_IO][VSTATUS];
1368 return el->el_tty.t_c[ED_IO][VSUSP];