1 /* $NetBSD: tty.c,v 1.65 2016/05/09 21:46:56 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.65 2016/05/09 21:46:56 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)
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)
591 if (el->el_flags & EDIT_DISABLED)
594 if (!el->el_tty.t_initialized)
597 if (tty_setty(el, TCSAFLUSH, &el->el_tty.t_or) == -1) {
599 (void) fprintf(el->el_errfile,
600 "%s: tty_setty: %s\n", __func__, strerror(errno));
601 #endif /* DEBUG_TTY */
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;
900 wchar_t new[2], old[2];
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 != (wint_t)-1; tp++) {
917 new[0] = (wchar_t)t_n[tp->nch];
918 old[0] = (wchar_t)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[(unsigned char)old[0]] = dmap[(unsigned char)old[0]];
924 keymacro_clear(el, map, new);
925 /* MAP_VI == 1, MAP_EMACS == 0... */
926 map[(unsigned char)new[0]] = tp->bind[el->el_map.type];
928 keymacro_clear(el, alt, old);
929 alt[(unsigned char)old[0]] =
930 dalt[(unsigned char)old[0]];
931 keymacro_clear(el, alt, new);
932 alt[(unsigned char)new[0]] =
933 tp->bind[el->el_map.type + 1];
940 tty__get_flag(struct termios *t, int kind) {
958 tty_update_flag(EditLine *el, tcflag_t f, int mode, int kind)
960 f &= ~el->el_tty.t_t[mode][kind].t_clrmask;
961 f |= el->el_tty.t_t[mode][kind].t_setmask;
967 tty_update_flags(EditLine *el, int kind)
969 tcflag_t *tt, *ed, *ex;
970 tt = tty__get_flag(&el->el_tty.t_ts, kind);
971 ed = tty__get_flag(&el->el_tty.t_ed, kind);
972 ex = tty__get_flag(&el->el_tty.t_ex, kind);
974 if (*tt != *ex && (kind != MD_CTL || *tt != *ed)) {
975 *ed = tty_update_flag(el, *tt, ED_IO, kind);
976 *ex = tty_update_flag(el, *tt, EX_IO, kind);
982 tty_update_char(EditLine *el, int mode, int c) {
983 if (!((el->el_tty.t_t[mode][MD_CHAR].t_setmask & C_SH(c)))
984 && (el->el_tty.t_c[TS_IO][c] != el->el_tty.t_c[EX_IO][c]))
985 el->el_tty.t_c[mode][c] = el->el_tty.t_c[TS_IO][c];
986 if (el->el_tty.t_t[mode][MD_CHAR].t_clrmask & C_SH(c))
987 el->el_tty.t_c[mode][c] = el->el_tty.t_vdisable;
992 * Set terminal into 1 character at a time mode.
995 tty_rawmode(EditLine *el)
998 if (el->el_tty.t_mode == ED_IO || el->el_tty.t_mode == QU_IO)
1001 if (el->el_flags & EDIT_DISABLED)
1004 if (tty_getty(el, &el->el_tty.t_ts) == -1) {
1006 (void) fprintf(el->el_errfile, "%s: tty_getty: %s\n", __func__,
1008 #endif /* DEBUG_TTY */
1012 * We always keep up with the eight bit setting and the speed of the
1013 * tty. But we only believe changes that are made to cooked mode!
1015 el->el_tty.t_eight = tty__geteightbit(&el->el_tty.t_ts);
1016 el->el_tty.t_speed = tty__getspeed(&el->el_tty.t_ts);
1018 if (tty__getspeed(&el->el_tty.t_ex) != el->el_tty.t_speed ||
1019 tty__getspeed(&el->el_tty.t_ed) != el->el_tty.t_speed) {
1020 (void) cfsetispeed(&el->el_tty.t_ex, el->el_tty.t_speed);
1021 (void) cfsetospeed(&el->el_tty.t_ex, el->el_tty.t_speed);
1022 (void) cfsetispeed(&el->el_tty.t_ed, el->el_tty.t_speed);
1023 (void) cfsetospeed(&el->el_tty.t_ed, el->el_tty.t_speed);
1025 if (tty__cooked_mode(&el->el_tty.t_ts)) {
1028 for (i = MD_INP; i <= MD_LIN; i++)
1029 tty_update_flags(el, i);
1031 if (tty__gettabs(&el->el_tty.t_ex) == 0)
1032 el->el_tty.t_tabs = 0;
1034 el->el_tty.t_tabs = EL_CAN_TAB ? 1 : 0;
1036 tty__getchar(&el->el_tty.t_ts, el->el_tty.t_c[TS_IO]);
1038 * Check if the user made any changes.
1039 * If he did, then propagate the changes to the
1040 * edit and execute data structures.
1042 for (i = 0; i < C_NCC; i++)
1043 if (el->el_tty.t_c[TS_IO][i] !=
1044 el->el_tty.t_c[EX_IO][i])
1049 * Propagate changes only to the unlibedit_private
1050 * chars that have been modified just now.
1052 for (i = 0; i < C_NCC; i++)
1053 tty_update_char(el, ED_IO, i);
1055 tty_bind_char(el, 0);
1056 tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]);
1058 for (i = 0; i < C_NCC; i++)
1059 tty_update_char(el, EX_IO, i);
1061 tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]);
1064 if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ed) == -1) {
1066 (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", __func__,
1068 #endif /* DEBUG_TTY */
1071 el->el_tty.t_mode = ED_IO;
1076 /* tty_cookedmode():
1077 * Set the tty back to normal mode
1080 tty_cookedmode(EditLine *el)
1081 { /* set tty in normal setup */
1083 if (el->el_tty.t_mode == EX_IO)
1086 if (el->el_flags & EDIT_DISABLED)
1089 if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ex) == -1) {
1091 (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", __func__,
1093 #endif /* DEBUG_TTY */
1096 el->el_tty.t_mode = EX_IO;
1102 * Turn on quote mode
1105 tty_quotemode(EditLine *el)
1107 if (el->el_tty.t_mode == QU_IO)
1110 el->el_tty.t_qu = el->el_tty.t_ed;
1112 tty_setup_flags(el, &el->el_tty.t_qu, QU_IO);
1114 if (tty_setty(el, TCSADRAIN, &el->el_tty.t_qu) == -1) {
1116 (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", __func__,
1118 #endif /* DEBUG_TTY */
1121 el->el_tty.t_mode = QU_IO;
1126 /* tty_noquotemode():
1127 * Turn off quote mode
1130 tty_noquotemode(EditLine *el)
1133 if (el->el_tty.t_mode != QU_IO)
1135 if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ed) == -1) {
1137 (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", __func__,
1139 #endif /* DEBUG_TTY */
1142 el->el_tty.t_mode = ED_IO;
1152 tty_stty(EditLine *el, int argc __attribute__((__unused__)),
1153 const wchar_t **argv)
1155 const ttymodes_t *m;
1158 const wchar_t *s, *d;
1159 char name[EL_BUFSIZ];
1160 struct termios *tios = &el->el_tty.t_ex;
1165 strncpy(name, ct_encode_string(*argv++, &el->el_scratch), sizeof(name));
1166 name[sizeof(name) - 1] = '\0';
1168 while (argv && *argv && argv[0][0] == '-' && argv[0][2] == '\0')
1169 switch (argv[0][1]) {
1176 tios = &el->el_tty.t_ed;
1181 tios = &el->el_tty.t_ex;
1186 tios = &el->el_tty.t_ts;
1190 (void) fprintf(el->el_errfile,
1191 "%s: Unknown switch `%lc'.\n",
1192 name, (wint_t)argv[0][1]);
1196 if (!argv || !*argv) {
1198 size_t len = 0, st = 0, cu;
1199 for (m = ttymodes; m->m_name; m++) {
1200 if (m->m_type != i) {
1201 (void) fprintf(el->el_outfile, "%s%s",
1202 i != -1 ? "\n" : "",
1203 el->el_tty.t_t[z][m->m_type].t_name);
1206 strlen(el->el_tty.t_t[z][m->m_type].t_name);
1209 x = (el->el_tty.t_t[z][i].t_setmask & m->m_value)
1212 if (el->el_tty.t_t[z][i].t_clrmask & m->m_value)
1218 if (x != '\0' || aflag) {
1220 cu = strlen(m->m_name) + (x != '\0') + 1;
1223 (size_t)el->el_terminal.t_size.h) {
1224 (void) fprintf(el->el_outfile, "\n%*s",
1231 (void) fprintf(el->el_outfile, "%c%s ",
1234 (void) fprintf(el->el_outfile, "%s ",
1238 (void) fprintf(el->el_outfile, "\n");
1241 while (argv && (s = *argv++)) {
1253 p = wcschr(s, L'=');
1254 for (m = ttymodes; m->m_name; m++)
1255 if ((p ? strncmp(m->m_name, ct_encode_string(d,
1256 &el->el_scratch), (size_t)(p - d)) :
1257 strcmp(m->m_name, ct_encode_string(d,
1258 &el->el_scratch))) == 0 &&
1259 (p == NULL || m->m_type == MD_CHAR))
1263 (void) fprintf(el->el_errfile,
1264 "%s: Invalid argument `%ls'.\n", name, d);
1268 int c = ffs((int)m->m_value);
1269 int v = *++p ? parse__escape(&p) :
1270 el->el_tty.t_vdisable;
1273 c = tty__getcharindex(c);
1275 tios->c_cc[c] = (cc_t)v;
1280 el->el_tty.t_t[z][m->m_type].t_setmask |= m->m_value;
1281 el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value;
1284 el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value;
1285 el->el_tty.t_t[z][m->m_type].t_clrmask |= m->m_value;
1288 el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value;
1289 el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value;
1294 tty_setup_flags(el, tios, z);
1295 if (el->el_tty.t_mode == z) {
1296 if (tty_setty(el, TCSADRAIN, tios) == -1) {
1298 (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n",
1299 __func__, strerror(errno));
1300 #endif /* DEBUG_TTY */
1311 * DEbugging routine to print the tty characters
1314 tty_printchar(EditLine *el, unsigned char *s)
1319 for (i = 0; i < C_NCC; i++) {
1320 for (m = el->el_tty.t_t; m->m_name; m++)
1321 if (m->m_type == MD_CHAR && C_SH(i) == m->m_value)
1324 (void) fprintf(el->el_errfile, "%s ^%c ",
1325 m->m_name, s[i] + 'A' - 1);
1327 (void) fprintf(el->el_errfile, "\n");
1329 (void) fprintf(el->el_errfile, "\n");
1335 tty_setup_flags(EditLine *el, struct termios *tios, int mode)
1338 for (kind = MD_INP; kind <= MD_LIN; kind++) {
1339 tcflag_t *f = tty__get_flag(tios, kind);
1340 *f = tty_update_flag(el, *f, mode, kind);