1 /* $NetBSD: tty.c,v 1.42 2012/05/15 15:59:01 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.42 2012/05/15 15:59:01 christos Exp $");
42 #endif /* not lint && not SCCSID */
45 * tty.c: tty interface stuff
49 #include <unistd.h> /* for isatty */
50 #include <strings.h> /* for ffs */
54 typedef struct ttymodes_t {
60 typedef struct ttymap_t {
61 Int nch, och; /* Internal and termio rep of chars */
62 el_action_t bind[3]; /* emacs, vi, and vi-cmd */
66 private const ttyperm_t ttyperm = {
68 {"iflag:", ICRNL, (INLCR | IGNCR)},
69 {"oflag:", (OPOST | ONLCR), ONLRET},
71 {"lflag:", (ISIG | ICANON | ECHO | ECHOE | ECHOCTL | IEXTEN),
72 (NOFLSH | ECHONL | EXTPROC | FLUSHO)},
76 {"iflag:", (INLCR | ICRNL), IGNCR},
77 {"oflag:", (OPOST | ONLCR), ONLRET},
80 (NOFLSH | ICANON | ECHO | ECHOK | ECHONL | EXTPROC | IEXTEN | FLUSHO)},
81 {"chars:", (C_SH(C_MIN) | C_SH(C_TIME) | C_SH(C_SWTCH) | C_SH(C_DSWTCH) |
82 C_SH(C_SUSP) | C_SH(C_DSUSP) | C_SH(C_EOL) | C_SH(C_DISCARD) |
83 C_SH(C_PGOFF) | C_SH(C_PAGE) | C_SH(C_STATUS)), 0}
86 {"iflag:", 0, IXON | IXOFF | INLCR | ICRNL},
89 {"lflag:", 0, ISIG | IEXTEN},
94 private const ttychar_t ttychar = {
96 CINTR, CQUIT, CERASE, CKILL,
97 CEOF, CEOL, CEOL2, CSWTCH,
98 CDSWTCH, CERASE2, CSTART, CSTOP,
99 CWERASE, CSUSP, CDSUSP, CREPRINT,
100 CDISCARD, CLNEXT, CSTATUS, CPAGE,
101 CPGOFF, CKILL2, CBRK, CMIN,
105 CINTR, CQUIT, CERASE, CKILL,
106 _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE,
107 _POSIX_VDISABLE, CERASE2, CSTART, CSTOP,
108 _POSIX_VDISABLE, CSUSP, _POSIX_VDISABLE, _POSIX_VDISABLE,
109 CDISCARD, _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE,
110 _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE, 1,
124 private const ttymap_t tty_map[] = {
127 {EM_DELETE_PREV_CHAR, VI_DELETE_PREV_CHAR, ED_PREV_CHAR}},
131 {EM_DELETE_PREV_CHAR, VI_DELETE_PREV_CHAR, ED_PREV_CHAR}},
135 {EM_KILL_LINE, VI_KILL_LINE_PREV, ED_UNASSIGNED}},
139 {EM_KILL_LINE, VI_KILL_LINE_PREV, ED_UNASSIGNED}},
143 {EM_DELETE_OR_LIST, VI_LIST_OR_EOF, ED_UNASSIGNED}},
147 {ED_DELETE_PREV_WORD, ED_DELETE_PREV_WORD, ED_PREV_WORD}},
150 {C_REPRINT, VREPRINT,
151 {ED_REDISPLAY, ED_INSERT, ED_REDISPLAY}},
152 #endif /* VREPRINT */
155 {ED_QUOTED_INSERT, ED_QUOTED_INSERT, ED_UNASSIGNED}},
158 {ED_UNASSIGNED, ED_UNASSIGNED, ED_UNASSIGNED}}
161 private const ttymodes_t ttymodes[] = {
163 {"ignbrk", IGNBRK, MD_INP},
166 {"brkint", BRKINT, MD_INP},
169 {"ignpar", IGNPAR, MD_INP},
172 {"parmrk", PARMRK, MD_INP},
175 {"inpck", INPCK, MD_INP},
178 {"istrip", ISTRIP, MD_INP},
181 {"inlcr", INLCR, MD_INP},
184 {"igncr", IGNCR, MD_INP},
187 {"icrnl", ICRNL, MD_INP},
190 {"iuclc", IUCLC, MD_INP},
193 {"ixon", IXON, MD_INP},
196 {"ixany", IXANY, MD_INP},
199 {"ixoff", IXOFF, MD_INP},
202 {"imaxbel", IMAXBEL, MD_INP},
206 {"opost", OPOST, MD_OUT},
209 {"olcuc", OLCUC, MD_OUT},
212 {"onlcr", ONLCR, MD_OUT},
215 {"ocrnl", OCRNL, MD_OUT},
218 {"onocr", ONOCR, MD_OUT},
221 {"onoeot", ONOEOT, MD_OUT},
224 {"onlret", ONLRET, MD_OUT},
227 {"ofill", OFILL, MD_OUT},
230 {"ofdel", OFDEL, MD_OUT},
233 {"nldly", NLDLY, MD_OUT},
236 {"crdly", CRDLY, MD_OUT},
239 {"tabdly", TABDLY, MD_OUT},
242 {"xtabs", XTABS, MD_OUT},
245 {"bsdly", BSDLY, MD_OUT},
248 {"vtdly", VTDLY, MD_OUT},
251 {"ffdly", FFDLY, MD_OUT},
254 {"pageout", PAGEOUT, MD_OUT},
257 {"wrap", WRAP, MD_OUT},
261 {"cignore", CIGNORE, MD_CTL},
264 {"cbaud", CBAUD, MD_CTL},
267 {"cstopb", CSTOPB, MD_CTL},
270 {"cread", CREAD, MD_CTL},
273 {"parenb", PARENB, MD_CTL},
276 {"parodd", PARODD, MD_CTL},
279 {"hupcl", HUPCL, MD_CTL},
282 {"clocal", CLOCAL, MD_CTL},
285 {"loblk", LOBLK, MD_CTL},
288 {"cibaud", CIBAUD, MD_CTL},
292 {"ccts_oflow", CCTS_OFLOW, MD_CTL},
294 {"crtscts", CRTSCTS, MD_CTL},
295 #endif /* CCTS_OFLOW */
298 {"crts_iflow", CRTS_IFLOW, MD_CTL},
299 #endif /* CRTS_IFLOW */
301 {"cdtrcts", CDTRCTS, MD_CTL},
304 {"mdmbuf", MDMBUF, MD_CTL},
307 {"rcv1en", RCV1EN, MD_CTL},
310 {"xmt1en", XMT1EN, MD_CTL},
314 {"isig", ISIG, MD_LIN},
317 {"icanon", ICANON, MD_LIN},
320 {"xcase", XCASE, MD_LIN},
323 {"echo", ECHO, MD_LIN},
326 {"echoe", ECHOE, MD_LIN},
329 {"echok", ECHOK, MD_LIN},
332 {"echonl", ECHONL, MD_LIN},
335 {"noflsh", NOFLSH, MD_LIN},
338 {"tostop", TOSTOP, MD_LIN},
341 {"echoctl", ECHOCTL, MD_LIN},
344 {"echoprt", ECHOPRT, MD_LIN},
347 {"echoke", ECHOKE, MD_LIN},
350 {"defecho", DEFECHO, MD_LIN},
353 {"flusho", FLUSHO, MD_LIN},
356 {"pendin", PENDIN, MD_LIN},
359 {"iexten", IEXTEN, MD_LIN},
362 {"nokerninfo", NOKERNINFO, MD_LIN},
363 #endif /* NOKERNINFO */
365 {"altwerase", ALTWERASE, MD_LIN},
366 #endif /* ALTWERASE */
368 {"extproc", EXTPROC, MD_LIN},
372 {"intr", C_SH(C_INTR), MD_CHAR},
375 {"quit", C_SH(C_QUIT), MD_CHAR},
378 {"erase", C_SH(C_ERASE), MD_CHAR},
381 {"kill", C_SH(C_KILL), MD_CHAR},
384 {"eof", C_SH(C_EOF), MD_CHAR},
387 {"eol", C_SH(C_EOL), MD_CHAR},
390 {"eol2", C_SH(C_EOL2), MD_CHAR},
393 {"swtch", C_SH(C_SWTCH), MD_CHAR},
396 {"dswtch", C_SH(C_DSWTCH), MD_CHAR},
399 {"erase2", C_SH(C_ERASE2), MD_CHAR},
402 {"start", C_SH(C_START), MD_CHAR},
405 {"stop", C_SH(C_STOP), MD_CHAR},
408 {"werase", C_SH(C_WERASE), MD_CHAR},
411 {"susp", C_SH(C_SUSP), MD_CHAR},
414 {"dsusp", C_SH(C_DSUSP), MD_CHAR},
416 #if defined(VREPRINT)
417 {"reprint", C_SH(C_REPRINT), MD_CHAR},
418 #endif /* VREPRINT */
419 #if defined(VDISCARD)
420 {"discard", C_SH(C_DISCARD), MD_CHAR},
421 #endif /* VDISCARD */
423 {"lnext", C_SH(C_LNEXT), MD_CHAR},
426 {"status", C_SH(C_STATUS), MD_CHAR},
429 {"page", C_SH(C_PAGE), MD_CHAR},
432 {"pgoff", C_SH(C_PGOFF), MD_CHAR},
435 {"kill2", C_SH(C_KILL2), MD_CHAR},
438 {"brk", C_SH(C_BRK), MD_CHAR},
441 {"min", C_SH(C_MIN), MD_CHAR},
444 {"time", C_SH(C_TIME), MD_CHAR},
451 #define tty__gettabs(td) ((((td)->c_oflag & TAB3) == TAB3) ? 0 : 1)
452 #define tty__geteightbit(td) (((td)->c_cflag & CSIZE) == CS8)
453 #define tty__cooked_mode(td) ((td)->c_lflag & ICANON)
455 private int tty_getty(EditLine *, struct termios *);
456 private int tty_setty(EditLine *, int, const struct termios *);
457 private int tty__getcharindex(int);
458 private void tty__getchar(struct termios *, unsigned char *);
459 private void tty__setchar(struct termios *, unsigned char *);
460 private speed_t tty__getspeed(struct termios *);
461 private int tty_setup(EditLine *);
466 * Wrapper for tcgetattr to handle EINTR
469 tty_getty(EditLine *el, struct termios *t)
472 while ((rv = tcgetattr(el->el_infd, t)) == -1 && errno == EINTR)
478 * Wrapper for tcsetattr to handle EINTR
481 tty_setty(EditLine *el, int action, const struct termios *t)
484 while ((rv = tcsetattr(el->el_infd, action, t)) == -1 && errno == EINTR)
490 * Get the tty parameters and initialize the editing state
493 tty_setup(EditLine *el)
497 if (el->el_flags & EDIT_DISABLED)
500 if (!isatty(el->el_outfd)) {
502 (void) fprintf(el->el_errfile, "%s: isatty: %s\n", __func__,
504 #endif /* DEBUG_TTY */
507 if (tty_getty(el, &el->el_tty.t_or) == -1) {
509 (void) fprintf(el->el_errfile, "%s: tty_getty: %s\n", __func__,
511 #endif /* DEBUG_TTY */
514 el->el_tty.t_ts = el->el_tty.t_ex = el->el_tty.t_ed = el->el_tty.t_or;
516 el->el_tty.t_speed = tty__getspeed(&el->el_tty.t_ex);
517 el->el_tty.t_tabs = tty__gettabs(&el->el_tty.t_ex);
518 el->el_tty.t_eight = tty__geteightbit(&el->el_tty.t_ex);
520 el->el_tty.t_ex.c_iflag &= ~el->el_tty.t_t[EX_IO][MD_INP].t_clrmask;
521 el->el_tty.t_ex.c_iflag |= el->el_tty.t_t[EX_IO][MD_INP].t_setmask;
523 el->el_tty.t_ex.c_oflag &= ~el->el_tty.t_t[EX_IO][MD_OUT].t_clrmask;
524 el->el_tty.t_ex.c_oflag |= el->el_tty.t_t[EX_IO][MD_OUT].t_setmask;
526 el->el_tty.t_ex.c_cflag &= ~el->el_tty.t_t[EX_IO][MD_CTL].t_clrmask;
527 el->el_tty.t_ex.c_cflag |= el->el_tty.t_t[EX_IO][MD_CTL].t_setmask;
529 el->el_tty.t_ex.c_lflag &= ~el->el_tty.t_t[EX_IO][MD_LIN].t_clrmask;
530 el->el_tty.t_ex.c_lflag |= el->el_tty.t_t[EX_IO][MD_LIN].t_setmask;
533 * Reset the tty chars to reasonable defaults
534 * If they are disabled, then enable them.
537 if (tty__cooked_mode(&el->el_tty.t_ts)) {
538 tty__getchar(&el->el_tty.t_ts, el->el_tty.t_c[TS_IO]);
540 * Don't affect CMIN and CTIME for the editor mode
542 for (rst = 0; rst < C_NCC - 2; rst++)
543 if (el->el_tty.t_c[TS_IO][rst] !=
544 el->el_tty.t_vdisable
545 && el->el_tty.t_c[ED_IO][rst] !=
546 el->el_tty.t_vdisable)
547 el->el_tty.t_c[ED_IO][rst] =
548 el->el_tty.t_c[TS_IO][rst];
549 for (rst = 0; rst < C_NCC; rst++)
550 if (el->el_tty.t_c[TS_IO][rst] !=
551 el->el_tty.t_vdisable)
552 el->el_tty.t_c[EX_IO][rst] =
553 el->el_tty.t_c[TS_IO][rst];
555 tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]);
556 if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ex) == -1) {
558 (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n",
559 __func__, strerror(errno));
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)
601 if (tty_setty(el, TCSAFLUSH, &el->el_tty.t_or) == -1) {
603 (void) fprintf(el->el_errfile,
604 "%s: tty_setty: %s\n", __func__, strerror(errno));
605 #endif /* DEBUG_TTY */
614 tty__getspeed(struct termios *td)
618 if ((spd = cfgetispeed(td)) == 0)
619 spd = cfgetospeed(td);
624 * Return the index of the asked char in the c_cc array
627 tty__getcharindex(int i)
693 #endif /* VREPRINT */
697 #endif /* VDISCARD */
732 * Get the tty characters
735 tty__getchar(struct termios *td, unsigned char *s)
739 s[C_INTR] = td->c_cc[VINTR];
742 s[C_QUIT] = td->c_cc[VQUIT];
745 s[C_ERASE] = td->c_cc[VERASE];
748 s[C_KILL] = td->c_cc[VKILL];
751 s[C_EOF] = td->c_cc[VEOF];
754 s[C_EOL] = td->c_cc[VEOL];
757 s[C_EOL2] = td->c_cc[VEOL2];
760 s[C_SWTCH] = td->c_cc[VSWTCH];
763 s[C_DSWTCH] = td->c_cc[VDSWTCH];
766 s[C_ERASE2] = td->c_cc[VERASE2];
769 s[C_START] = td->c_cc[VSTART];
772 s[C_STOP] = td->c_cc[VSTOP];
775 s[C_WERASE] = td->c_cc[VWERASE];
778 s[C_SUSP] = td->c_cc[VSUSP];
781 s[C_DSUSP] = td->c_cc[VDSUSP];
784 s[C_REPRINT] = td->c_cc[VREPRINT];
785 #endif /* VREPRINT */
787 s[C_DISCARD] = td->c_cc[VDISCARD];
788 #endif /* VDISCARD */
790 s[C_LNEXT] = td->c_cc[VLNEXT];
793 s[C_STATUS] = td->c_cc[VSTATUS];
796 s[C_PAGE] = td->c_cc[VPAGE];
799 s[C_PGOFF] = td->c_cc[VPGOFF];
802 s[C_KILL2] = td->c_cc[VKILL2];
805 s[C_MIN] = td->c_cc[VMIN];
808 s[C_TIME] = td->c_cc[VTIME];
814 * Set the tty characters
817 tty__setchar(struct termios *td, unsigned char *s)
821 td->c_cc[VINTR] = s[C_INTR];
824 td->c_cc[VQUIT] = s[C_QUIT];
827 td->c_cc[VERASE] = s[C_ERASE];
830 td->c_cc[VKILL] = s[C_KILL];
833 td->c_cc[VEOF] = s[C_EOF];
836 td->c_cc[VEOL] = s[C_EOL];
839 td->c_cc[VEOL2] = s[C_EOL2];
842 td->c_cc[VSWTCH] = s[C_SWTCH];
845 td->c_cc[VDSWTCH] = s[C_DSWTCH];
848 td->c_cc[VERASE2] = s[C_ERASE2];
851 td->c_cc[VSTART] = s[C_START];
854 td->c_cc[VSTOP] = s[C_STOP];
857 td->c_cc[VWERASE] = s[C_WERASE];
860 td->c_cc[VSUSP] = s[C_SUSP];
863 td->c_cc[VDSUSP] = s[C_DSUSP];
866 td->c_cc[VREPRINT] = s[C_REPRINT];
867 #endif /* VREPRINT */
869 td->c_cc[VDISCARD] = s[C_DISCARD];
870 #endif /* VDISCARD */
872 td->c_cc[VLNEXT] = s[C_LNEXT];
875 td->c_cc[VSTATUS] = s[C_STATUS];
878 td->c_cc[VPAGE] = s[C_PAGE];
881 td->c_cc[VPGOFF] = s[C_PGOFF];
884 td->c_cc[VKILL2] = s[C_KILL2];
887 td->c_cc[VMIN] = s[C_MIN];
890 td->c_cc[VTIME] = s[C_TIME];
896 * Rebind the editline functions
899 tty_bind_char(EditLine *el, int force)
902 unsigned char *t_n = el->el_tty.t_c[ED_IO];
903 unsigned char *t_o = el->el_tty.t_ed.c_cc;
906 el_action_t *map, *alt;
907 const el_action_t *dmap, *dalt;
908 new[1] = old[1] = '\0';
910 map = el->el_map.key;
911 alt = el->el_map.alt;
912 if (el->el_map.type == MAP_VI) {
913 dmap = el->el_map.vii;
914 dalt = el->el_map.vic;
916 dmap = el->el_map.emacs;
920 for (tp = tty_map; tp->nch != (Int)-1; tp++) {
921 new[0] = t_n[tp->nch];
922 old[0] = t_o[tp->och];
923 if (new[0] == old[0] && !force)
925 /* Put the old default binding back, and set the new binding */
926 keymacro_clear(el, map, old);
927 map[UC(old[0])] = dmap[UC(old[0])];
928 keymacro_clear(el, map, new);
929 /* MAP_VI == 1, MAP_EMACS == 0... */
930 map[UC(new[0])] = tp->bind[el->el_map.type];
932 keymacro_clear(el, alt, old);
933 alt[UC(old[0])] = dalt[UC(old[0])];
934 keymacro_clear(el, alt, new);
935 alt[UC(new[0])] = tp->bind[el->el_map.type + 1];
942 * Set terminal into 1 character at a time mode.
945 tty_rawmode(EditLine *el)
948 if (el->el_tty.t_mode == ED_IO || el->el_tty.t_mode == QU_IO)
951 if (el->el_flags & EDIT_DISABLED)
954 if (tty_getty(el, &el->el_tty.t_ts) == -1) {
956 (void) fprintf(el->el_errfile, "%s: tty_getty: %s\n", __func__,
958 #endif /* DEBUG_TTY */
962 * We always keep up with the eight bit setting and the speed of the
963 * tty. But we only believe changes that are made to cooked mode!
965 el->el_tty.t_eight = tty__geteightbit(&el->el_tty.t_ts);
966 el->el_tty.t_speed = tty__getspeed(&el->el_tty.t_ts);
968 if (tty__getspeed(&el->el_tty.t_ex) != el->el_tty.t_speed ||
969 tty__getspeed(&el->el_tty.t_ed) != el->el_tty.t_speed) {
970 (void) cfsetispeed(&el->el_tty.t_ex, el->el_tty.t_speed);
971 (void) cfsetospeed(&el->el_tty.t_ex, el->el_tty.t_speed);
972 (void) cfsetispeed(&el->el_tty.t_ed, el->el_tty.t_speed);
973 (void) cfsetospeed(&el->el_tty.t_ed, el->el_tty.t_speed);
975 if (tty__cooked_mode(&el->el_tty.t_ts)) {
976 if (el->el_tty.t_ts.c_cflag != el->el_tty.t_ex.c_cflag) {
977 el->el_tty.t_ex.c_cflag =
978 el->el_tty.t_ts.c_cflag;
979 el->el_tty.t_ex.c_cflag &=
980 ~el->el_tty.t_t[EX_IO][MD_CTL].t_clrmask;
981 el->el_tty.t_ex.c_cflag |=
982 el->el_tty.t_t[EX_IO][MD_CTL].t_setmask;
984 el->el_tty.t_ed.c_cflag =
985 el->el_tty.t_ts.c_cflag;
986 el->el_tty.t_ed.c_cflag &=
987 ~el->el_tty.t_t[ED_IO][MD_CTL].t_clrmask;
988 el->el_tty.t_ed.c_cflag |=
989 el->el_tty.t_t[ED_IO][MD_CTL].t_setmask;
991 if ((el->el_tty.t_ts.c_lflag != el->el_tty.t_ex.c_lflag) &&
992 (el->el_tty.t_ts.c_lflag != el->el_tty.t_ed.c_lflag)) {
993 el->el_tty.t_ex.c_lflag =
994 el->el_tty.t_ts.c_lflag;
995 el->el_tty.t_ex.c_lflag &=
996 ~el->el_tty.t_t[EX_IO][MD_LIN].t_clrmask;
997 el->el_tty.t_ex.c_lflag |=
998 el->el_tty.t_t[EX_IO][MD_LIN].t_setmask;
1000 el->el_tty.t_ed.c_lflag =
1001 el->el_tty.t_ts.c_lflag;
1002 el->el_tty.t_ed.c_lflag &=
1003 ~el->el_tty.t_t[ED_IO][MD_LIN].t_clrmask;
1004 el->el_tty.t_ed.c_lflag |=
1005 el->el_tty.t_t[ED_IO][MD_LIN].t_setmask;
1007 if ((el->el_tty.t_ts.c_iflag != el->el_tty.t_ex.c_iflag) &&
1008 (el->el_tty.t_ts.c_iflag != el->el_tty.t_ed.c_iflag)) {
1009 el->el_tty.t_ex.c_iflag =
1010 el->el_tty.t_ts.c_iflag;
1011 el->el_tty.t_ex.c_iflag &=
1012 ~el->el_tty.t_t[EX_IO][MD_INP].t_clrmask;
1013 el->el_tty.t_ex.c_iflag |=
1014 el->el_tty.t_t[EX_IO][MD_INP].t_setmask;
1016 el->el_tty.t_ed.c_iflag =
1017 el->el_tty.t_ts.c_iflag;
1018 el->el_tty.t_ed.c_iflag &=
1019 ~el->el_tty.t_t[ED_IO][MD_INP].t_clrmask;
1020 el->el_tty.t_ed.c_iflag |=
1021 el->el_tty.t_t[ED_IO][MD_INP].t_setmask;
1023 if ((el->el_tty.t_ts.c_oflag != el->el_tty.t_ex.c_oflag) &&
1024 (el->el_tty.t_ts.c_oflag != el->el_tty.t_ed.c_oflag)) {
1025 el->el_tty.t_ex.c_oflag =
1026 el->el_tty.t_ts.c_oflag;
1027 el->el_tty.t_ex.c_oflag &=
1028 ~el->el_tty.t_t[EX_IO][MD_OUT].t_clrmask;
1029 el->el_tty.t_ex.c_oflag |=
1030 el->el_tty.t_t[EX_IO][MD_OUT].t_setmask;
1032 el->el_tty.t_ed.c_oflag =
1033 el->el_tty.t_ts.c_oflag;
1034 el->el_tty.t_ed.c_oflag &=
1035 ~el->el_tty.t_t[ED_IO][MD_OUT].t_clrmask;
1036 el->el_tty.t_ed.c_oflag |=
1037 el->el_tty.t_t[ED_IO][MD_OUT].t_setmask;
1039 if (tty__gettabs(&el->el_tty.t_ex) == 0)
1040 el->el_tty.t_tabs = 0;
1042 el->el_tty.t_tabs = EL_CAN_TAB ? 1 : 0;
1047 tty__getchar(&el->el_tty.t_ts, el->el_tty.t_c[TS_IO]);
1049 * Check if the user made any changes.
1050 * If he did, then propagate the changes to the
1051 * edit and execute data structures.
1053 for (i = 0; i < C_NCC; i++)
1054 if (el->el_tty.t_c[TS_IO][i] !=
1055 el->el_tty.t_c[EX_IO][i])
1060 * Propagate changes only to the unprotected
1061 * chars that have been modified just now.
1063 for (i = 0; i < C_NCC; i++) {
1064 if (!((el->el_tty.t_t[ED_IO][MD_CHAR].t_setmask & C_SH(i)))
1065 && (el->el_tty.t_c[TS_IO][i] != el->el_tty.t_c[EX_IO][i]))
1066 el->el_tty.t_c[ED_IO][i] = el->el_tty.t_c[TS_IO][i];
1067 if (el->el_tty.t_t[ED_IO][MD_CHAR].t_clrmask & C_SH(i))
1068 el->el_tty.t_c[ED_IO][i] = el->el_tty.t_vdisable;
1070 tty_bind_char(el, 0);
1071 tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]);
1073 for (i = 0; i < C_NCC; i++) {
1074 if (!((el->el_tty.t_t[EX_IO][MD_CHAR].t_setmask & C_SH(i)))
1075 && (el->el_tty.t_c[TS_IO][i] != el->el_tty.t_c[EX_IO][i]))
1076 el->el_tty.t_c[EX_IO][i] = el->el_tty.t_c[TS_IO][i];
1077 if (el->el_tty.t_t[EX_IO][MD_CHAR].t_clrmask & C_SH(i))
1078 el->el_tty.t_c[EX_IO][i] = el->el_tty.t_vdisable;
1080 tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]);
1084 if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ed) == -1) {
1086 (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", __func__,
1088 #endif /* DEBUG_TTY */
1091 el->el_tty.t_mode = ED_IO;
1096 /* tty_cookedmode():
1097 * Set the tty back to normal mode
1100 tty_cookedmode(EditLine *el)
1101 { /* set tty in normal setup */
1103 if (el->el_tty.t_mode == EX_IO)
1106 if (el->el_flags & EDIT_DISABLED)
1109 if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ex) == -1) {
1111 (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", __func__,
1113 #endif /* DEBUG_TTY */
1116 el->el_tty.t_mode = EX_IO;
1122 * Turn on quote mode
1125 tty_quotemode(EditLine *el)
1127 if (el->el_tty.t_mode == QU_IO)
1130 el->el_tty.t_qu = el->el_tty.t_ed;
1132 el->el_tty.t_qu.c_iflag &= ~el->el_tty.t_t[QU_IO][MD_INP].t_clrmask;
1133 el->el_tty.t_qu.c_iflag |= el->el_tty.t_t[QU_IO][MD_INP].t_setmask;
1135 el->el_tty.t_qu.c_oflag &= ~el->el_tty.t_t[QU_IO][MD_OUT].t_clrmask;
1136 el->el_tty.t_qu.c_oflag |= el->el_tty.t_t[QU_IO][MD_OUT].t_setmask;
1138 el->el_tty.t_qu.c_cflag &= ~el->el_tty.t_t[QU_IO][MD_CTL].t_clrmask;
1139 el->el_tty.t_qu.c_cflag |= el->el_tty.t_t[QU_IO][MD_CTL].t_setmask;
1141 el->el_tty.t_qu.c_lflag &= ~el->el_tty.t_t[QU_IO][MD_LIN].t_clrmask;
1142 el->el_tty.t_qu.c_lflag |= el->el_tty.t_t[QU_IO][MD_LIN].t_setmask;
1144 if (tty_setty(el, TCSADRAIN, &el->el_tty.t_qu) == -1) {
1146 (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", __func__,
1148 #endif /* DEBUG_TTY */
1151 el->el_tty.t_mode = QU_IO;
1156 /* tty_noquotemode():
1157 * Turn off quote mode
1160 tty_noquotemode(EditLine *el)
1163 if (el->el_tty.t_mode != QU_IO)
1165 if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ed) == -1) {
1167 (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", __func__,
1169 #endif /* DEBUG_TTY */
1172 el->el_tty.t_mode = ED_IO;
1182 tty_stty(EditLine *el, int argc __attribute__((__unused__)), const Char **argv)
1184 const ttymodes_t *m;
1188 char name[EL_BUFSIZ];
1189 struct termios *tios = &el->el_tty.t_ex;
1194 strncpy(name, ct_encode_string(*argv++, &el->el_scratch), sizeof(name));
1195 name[sizeof(name) - 1] = '\0';
1197 while (argv && *argv && argv[0][0] == '-' && argv[0][2] == '\0')
1198 switch (argv[0][1]) {
1205 tios = &el->el_tty.t_ed;
1210 tios = &el->el_tty.t_ex;
1215 tios = &el->el_tty.t_ts;
1219 (void) fprintf(el->el_errfile,
1220 "%s: Unknown switch `%c'.\n",
1225 if (!argv || !*argv) {
1227 size_t len = 0, st = 0, cu;
1228 for (m = ttymodes; m->m_name; m++) {
1229 if (m->m_type != i) {
1230 (void) fprintf(el->el_outfile, "%s%s",
1231 i != -1 ? "\n" : "",
1232 el->el_tty.t_t[z][m->m_type].t_name);
1235 strlen(el->el_tty.t_t[z][m->m_type].t_name);
1238 x = (el->el_tty.t_t[z][i].t_setmask & m->m_value)
1241 if (el->el_tty.t_t[z][i].t_clrmask & m->m_value)
1247 if (x != '\0' || aflag) {
1249 cu = strlen(m->m_name) + (x != '\0') + 1;
1252 (size_t)el->el_terminal.t_size.h) {
1253 (void) fprintf(el->el_outfile, "\n%*s",
1260 (void) fprintf(el->el_outfile, "%c%s ",
1263 (void) fprintf(el->el_outfile, "%s ",
1267 (void) fprintf(el->el_outfile, "\n");
1270 while (argv && (s = *argv++)) {
1283 for (m = ttymodes; m->m_name; m++)
1284 if ((p ? strncmp(m->m_name, ct_encode_string(d,
1285 &el->el_scratch), (size_t)(p - d)) :
1286 strcmp(m->m_name, ct_encode_string(d,
1287 &el->el_scratch))) == 0 &&
1288 (p == NULL || m->m_type == MD_CHAR))
1292 (void) fprintf(el->el_errfile,
1293 "%s: Invalid argument `" FSTR "'.\n", name, d);
1297 int c = ffs((int)m->m_value);
1298 int v = *++p ? parse__escape(&p) :
1299 el->el_tty.t_vdisable;
1302 c = tty__getcharindex(c);
1304 tios->c_cc[c] = (cc_t)v;
1309 el->el_tty.t_t[z][m->m_type].t_setmask |= m->m_value;
1310 el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value;
1313 el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value;
1314 el->el_tty.t_t[z][m->m_type].t_clrmask |= m->m_value;
1317 el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value;
1318 el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value;
1323 if (el->el_tty.t_mode == z) {
1324 if (tty_setty(el, TCSADRAIN, tios) == -1) {
1326 (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n",
1327 __func__, strerror(errno));
1328 #endif /* DEBUG_TTY */
1339 * DEbugging routine to print the tty characters
1342 tty_printchar(EditLine *el, unsigned char *s)
1347 for (i = 0; i < C_NCC; i++) {
1348 for (m = el->el_tty.t_t; m->m_name; m++)
1349 if (m->m_type == MD_CHAR && C_SH(i) == m->m_value)
1352 (void) fprintf(el->el_errfile, "%s ^%c ",
1353 m->m_name, s[i] + 'A' - 1);
1355 (void) fprintf(el->el_errfile, "\n");
1357 (void) fprintf(el->el_errfile, "\n");