| /* $NetBSD: tty.c,v 1.68 2018/12/02 16:58:13 christos Exp $ */ |
| |
| /*- |
| * Copyright (c) 1992, 1993 |
| * The Regents of the University of California. All rights reserved. |
| * |
| * This code is derived from software contributed to Berkeley by |
| * Christos Zoulas of Cornell University. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * 3. Neither the name of the University nor the names of its contributors |
| * may be used to endorse or promote products derived from this software |
| * without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
| * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
| * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| * SUCH DAMAGE. |
| */ |
| |
| #include "config.h" |
| #if !defined(lint) && !defined(SCCSID) |
| #if 0 |
| static char sccsid[] = "@(#)tty.c 8.1 (Berkeley) 6/4/93"; |
| #else |
| __RCSID("$NetBSD: tty.c,v 1.68 2018/12/02 16:58:13 christos Exp $"); |
| #endif |
| #endif /* not lint && not SCCSID */ |
| |
| /* |
| * tty.c: tty interface stuff |
| */ |
| #include <assert.h> |
| #include <errno.h> |
| #include <stdlib.h> /* for abort */ |
| #include <string.h> |
| #include <strings.h> /* for ffs */ |
| #include <unistd.h> /* for isatty */ |
| |
| #include "el.h" |
| #include "fcns.h" |
| #include "parse.h" |
| |
| typedef struct ttymodes_t { |
| const char *m_name; |
| unsigned int m_value; |
| int m_type; |
| } ttymodes_t; |
| |
| typedef struct ttymap_t { |
| wint_t nch, och; /* Internal and termio rep of chars */ |
| el_action_t bind[3]; /* emacs, vi, and vi-cmd */ |
| } ttymap_t; |
| |
| |
| static const ttyperm_t ttyperm = { |
| { |
| {"iflag:", ICRNL, (INLCR | IGNCR)}, |
| {"oflag:", (OPOST | ONLCR), ONLRET}, |
| {"cflag:", 0, 0}, |
| {"lflag:", (ISIG | ICANON | ECHO | ECHOE | ECHOCTL | IEXTEN), |
| (NOFLSH | ECHONL | EXTPROC | FLUSHO)}, |
| {"chars:", 0, 0}, |
| }, |
| { |
| {"iflag:", (INLCR | ICRNL), IGNCR}, |
| {"oflag:", (OPOST | ONLCR), ONLRET}, |
| {"cflag:", 0, 0}, |
| {"lflag:", ISIG, |
| (NOFLSH | ICANON | ECHO | ECHOK | ECHONL | EXTPROC | IEXTEN | FLUSHO)}, |
| {"chars:", (C_SH(C_MIN) | C_SH(C_TIME) | C_SH(C_SWTCH) | C_SH(C_DSWTCH) | |
| C_SH(C_SUSP) | C_SH(C_DSUSP) | C_SH(C_EOL) | C_SH(C_DISCARD) | |
| C_SH(C_PGOFF) | C_SH(C_PAGE) | C_SH(C_STATUS)), 0} |
| }, |
| { |
| {"iflag:", 0, IXON | IXOFF | INLCR | ICRNL}, |
| {"oflag:", 0, 0}, |
| {"cflag:", 0, 0}, |
| {"lflag:", 0, ISIG | IEXTEN}, |
| {"chars:", 0, 0}, |
| } |
| }; |
| |
| static const ttychar_t ttychar = { |
| { |
| CINTR, CQUIT, CERASE, CKILL, |
| CEOF, CEOL, CEOL2, CSWTCH, |
| CDSWTCH, CERASE2, CSTART, CSTOP, |
| CWERASE, CSUSP, CDSUSP, CREPRINT, |
| CDISCARD, CLNEXT, CSTATUS, CPAGE, |
| CPGOFF, CKILL2, CBRK, CMIN, |
| CTIME |
| }, |
| { |
| CINTR, CQUIT, CERASE, CKILL, |
| _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE, |
| _POSIX_VDISABLE, CERASE2, CSTART, CSTOP, |
| _POSIX_VDISABLE, CSUSP, _POSIX_VDISABLE, _POSIX_VDISABLE, |
| CDISCARD, _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE, |
| _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE, 1, |
| 0 |
| }, |
| { |
| 0, 0, 0, 0, |
| 0, 0, 0, 0, |
| 0, 0, 0, 0, |
| 0, 0, 0, 0, |
| 0, 0, 0, 0, |
| 0, 0, 0, 0, |
| 0 |
| } |
| }; |
| |
| static const ttymap_t tty_map[] = { |
| #ifdef VERASE |
| {C_ERASE, VERASE, |
| {EM_DELETE_PREV_CHAR, VI_DELETE_PREV_CHAR, ED_PREV_CHAR}}, |
| #endif /* VERASE */ |
| #ifdef VERASE2 |
| {C_ERASE2, VERASE2, |
| {EM_DELETE_PREV_CHAR, VI_DELETE_PREV_CHAR, ED_PREV_CHAR}}, |
| #endif /* VERASE2 */ |
| #ifdef VKILL |
| {C_KILL, VKILL, |
| {EM_KILL_LINE, VI_KILL_LINE_PREV, ED_UNASSIGNED}}, |
| #endif /* VKILL */ |
| #ifdef VKILL2 |
| {C_KILL2, VKILL2, |
| {EM_KILL_LINE, VI_KILL_LINE_PREV, ED_UNASSIGNED}}, |
| #endif /* VKILL2 */ |
| #ifdef VEOF |
| {C_EOF, VEOF, |
| {EM_DELETE_OR_LIST, VI_LIST_OR_EOF, ED_UNASSIGNED}}, |
| #endif /* VEOF */ |
| #ifdef VWERASE |
| {C_WERASE, VWERASE, |
| {ED_DELETE_PREV_WORD, ED_DELETE_PREV_WORD, ED_PREV_WORD}}, |
| #endif /* VWERASE */ |
| #ifdef VREPRINT |
| {C_REPRINT, VREPRINT, |
| {ED_REDISPLAY, ED_INSERT, ED_REDISPLAY}}, |
| #endif /* VREPRINT */ |
| #ifdef VLNEXT |
| {C_LNEXT, VLNEXT, |
| {ED_QUOTED_INSERT, ED_QUOTED_INSERT, ED_UNASSIGNED}}, |
| #endif /* VLNEXT */ |
| {(wint_t)-1, (wint_t)-1, |
| {ED_UNASSIGNED, ED_UNASSIGNED, ED_UNASSIGNED}} |
| }; |
| |
| static const ttymodes_t ttymodes[] = { |
| #ifdef IGNBRK |
| {"ignbrk", IGNBRK, MD_INP}, |
| #endif /* IGNBRK */ |
| #ifdef BRKINT |
| {"brkint", BRKINT, MD_INP}, |
| #endif /* BRKINT */ |
| #ifdef IGNPAR |
| {"ignpar", IGNPAR, MD_INP}, |
| #endif /* IGNPAR */ |
| #ifdef PARMRK |
| {"parmrk", PARMRK, MD_INP}, |
| #endif /* PARMRK */ |
| #ifdef INPCK |
| {"inpck", INPCK, MD_INP}, |
| #endif /* INPCK */ |
| #ifdef ISTRIP |
| {"istrip", ISTRIP, MD_INP}, |
| #endif /* ISTRIP */ |
| #ifdef INLCR |
| {"inlcr", INLCR, MD_INP}, |
| #endif /* INLCR */ |
| #ifdef IGNCR |
| {"igncr", IGNCR, MD_INP}, |
| #endif /* IGNCR */ |
| #ifdef ICRNL |
| {"icrnl", ICRNL, MD_INP}, |
| #endif /* ICRNL */ |
| #ifdef IUCLC |
| {"iuclc", IUCLC, MD_INP}, |
| #endif /* IUCLC */ |
| #ifdef IXON |
| {"ixon", IXON, MD_INP}, |
| #endif /* IXON */ |
| #ifdef IXANY |
| {"ixany", IXANY, MD_INP}, |
| #endif /* IXANY */ |
| #ifdef IXOFF |
| {"ixoff", IXOFF, MD_INP}, |
| #endif /* IXOFF */ |
| #ifdef IMAXBEL |
| {"imaxbel", IMAXBEL, MD_INP}, |
| #endif /* IMAXBEL */ |
| |
| #ifdef OPOST |
| {"opost", OPOST, MD_OUT}, |
| #endif /* OPOST */ |
| #ifdef OLCUC |
| {"olcuc", OLCUC, MD_OUT}, |
| #endif /* OLCUC */ |
| #ifdef ONLCR |
| {"onlcr", ONLCR, MD_OUT}, |
| #endif /* ONLCR */ |
| #ifdef OCRNL |
| {"ocrnl", OCRNL, MD_OUT}, |
| #endif /* OCRNL */ |
| #ifdef ONOCR |
| {"onocr", ONOCR, MD_OUT}, |
| #endif /* ONOCR */ |
| #ifdef ONOEOT |
| {"onoeot", ONOEOT, MD_OUT}, |
| #endif /* ONOEOT */ |
| #ifdef ONLRET |
| {"onlret", ONLRET, MD_OUT}, |
| #endif /* ONLRET */ |
| #ifdef OFILL |
| {"ofill", OFILL, MD_OUT}, |
| #endif /* OFILL */ |
| #ifdef OFDEL |
| {"ofdel", OFDEL, MD_OUT}, |
| #endif /* OFDEL */ |
| #ifdef NLDLY |
| {"nldly", NLDLY, MD_OUT}, |
| #endif /* NLDLY */ |
| #ifdef CRDLY |
| {"crdly", CRDLY, MD_OUT}, |
| #endif /* CRDLY */ |
| #ifdef TABDLY |
| {"tabdly", TABDLY, MD_OUT}, |
| #endif /* TABDLY */ |
| #ifdef XTABS |
| {"xtabs", XTABS, MD_OUT}, |
| #endif /* XTABS */ |
| #ifdef BSDLY |
| {"bsdly", BSDLY, MD_OUT}, |
| #endif /* BSDLY */ |
| #ifdef VTDLY |
| {"vtdly", VTDLY, MD_OUT}, |
| #endif /* VTDLY */ |
| #ifdef FFDLY |
| {"ffdly", FFDLY, MD_OUT}, |
| #endif /* FFDLY */ |
| #ifdef PAGEOUT |
| {"pageout", PAGEOUT, MD_OUT}, |
| #endif /* PAGEOUT */ |
| #ifdef WRAP |
| {"wrap", WRAP, MD_OUT}, |
| #endif /* WRAP */ |
| |
| #ifdef CIGNORE |
| {"cignore", CIGNORE, MD_CTL}, |
| #endif /* CBAUD */ |
| #ifdef CBAUD |
| {"cbaud", CBAUD, MD_CTL}, |
| #endif /* CBAUD */ |
| #ifdef CSTOPB |
| {"cstopb", CSTOPB, MD_CTL}, |
| #endif /* CSTOPB */ |
| #ifdef CREAD |
| {"cread", CREAD, MD_CTL}, |
| #endif /* CREAD */ |
| #ifdef PARENB |
| {"parenb", PARENB, MD_CTL}, |
| #endif /* PARENB */ |
| #ifdef PARODD |
| {"parodd", PARODD, MD_CTL}, |
| #endif /* PARODD */ |
| #ifdef HUPCL |
| {"hupcl", HUPCL, MD_CTL}, |
| #endif /* HUPCL */ |
| #ifdef CLOCAL |
| {"clocal", CLOCAL, MD_CTL}, |
| #endif /* CLOCAL */ |
| #ifdef LOBLK |
| {"loblk", LOBLK, MD_CTL}, |
| #endif /* LOBLK */ |
| #ifdef CIBAUD |
| {"cibaud", CIBAUD, MD_CTL}, |
| #endif /* CIBAUD */ |
| #ifdef CRTSCTS |
| #ifdef CCTS_OFLOW |
| {"ccts_oflow", CCTS_OFLOW, MD_CTL}, |
| #else |
| {"crtscts", CRTSCTS, MD_CTL}, |
| #endif /* CCTS_OFLOW */ |
| #endif /* CRTSCTS */ |
| #ifdef CRTS_IFLOW |
| {"crts_iflow", CRTS_IFLOW, MD_CTL}, |
| #endif /* CRTS_IFLOW */ |
| #ifdef CDTRCTS |
| {"cdtrcts", CDTRCTS, MD_CTL}, |
| #endif /* CDTRCTS */ |
| #ifdef MDMBUF |
| {"mdmbuf", MDMBUF, MD_CTL}, |
| #endif /* MDMBUF */ |
| #ifdef RCV1EN |
| {"rcv1en", RCV1EN, MD_CTL}, |
| #endif /* RCV1EN */ |
| #ifdef XMT1EN |
| {"xmt1en", XMT1EN, MD_CTL}, |
| #endif /* XMT1EN */ |
| |
| #ifdef ISIG |
| {"isig", ISIG, MD_LIN}, |
| #endif /* ISIG */ |
| #ifdef ICANON |
| {"icanon", ICANON, MD_LIN}, |
| #endif /* ICANON */ |
| #ifdef XCASE |
| {"xcase", XCASE, MD_LIN}, |
| #endif /* XCASE */ |
| #ifdef ECHO |
| {"echo", ECHO, MD_LIN}, |
| #endif /* ECHO */ |
| #ifdef ECHOE |
| {"echoe", ECHOE, MD_LIN}, |
| #endif /* ECHOE */ |
| #ifdef ECHOK |
| {"echok", ECHOK, MD_LIN}, |
| #endif /* ECHOK */ |
| #ifdef ECHONL |
| {"echonl", ECHONL, MD_LIN}, |
| #endif /* ECHONL */ |
| #ifdef NOFLSH |
| {"noflsh", NOFLSH, MD_LIN}, |
| #endif /* NOFLSH */ |
| #ifdef TOSTOP |
| {"tostop", TOSTOP, MD_LIN}, |
| #endif /* TOSTOP */ |
| #ifdef ECHOCTL |
| {"echoctl", ECHOCTL, MD_LIN}, |
| #endif /* ECHOCTL */ |
| #ifdef ECHOPRT |
| {"echoprt", ECHOPRT, MD_LIN}, |
| #endif /* ECHOPRT */ |
| #ifdef ECHOKE |
| {"echoke", ECHOKE, MD_LIN}, |
| #endif /* ECHOKE */ |
| #ifdef DEFECHO |
| {"defecho", DEFECHO, MD_LIN}, |
| #endif /* DEFECHO */ |
| #ifdef FLUSHO |
| {"flusho", FLUSHO, MD_LIN}, |
| #endif /* FLUSHO */ |
| #ifdef PENDIN |
| {"pendin", PENDIN, MD_LIN}, |
| #endif /* PENDIN */ |
| #ifdef IEXTEN |
| {"iexten", IEXTEN, MD_LIN}, |
| #endif /* IEXTEN */ |
| #ifdef NOKERNINFO |
| {"nokerninfo", NOKERNINFO, MD_LIN}, |
| #endif /* NOKERNINFO */ |
| #ifdef ALTWERASE |
| {"altwerase", ALTWERASE, MD_LIN}, |
| #endif /* ALTWERASE */ |
| #ifdef EXTPROC |
| {"extproc", EXTPROC, MD_LIN}, |
| #endif /* EXTPROC */ |
| |
| #if defined(VINTR) |
| {"intr", C_SH(C_INTR), MD_CHAR}, |
| #endif /* VINTR */ |
| #if defined(VQUIT) |
| {"quit", C_SH(C_QUIT), MD_CHAR}, |
| #endif /* VQUIT */ |
| #if defined(VERASE) |
| {"erase", C_SH(C_ERASE), MD_CHAR}, |
| #endif /* VERASE */ |
| #if defined(VKILL) |
| {"kill", C_SH(C_KILL), MD_CHAR}, |
| #endif /* VKILL */ |
| #if defined(VEOF) |
| {"eof", C_SH(C_EOF), MD_CHAR}, |
| #endif /* VEOF */ |
| #if defined(VEOL) |
| {"eol", C_SH(C_EOL), MD_CHAR}, |
| #endif /* VEOL */ |
| #if defined(VEOL2) |
| {"eol2", C_SH(C_EOL2), MD_CHAR}, |
| #endif /* VEOL2 */ |
| #if defined(VSWTCH) |
| {"swtch", C_SH(C_SWTCH), MD_CHAR}, |
| #endif /* VSWTCH */ |
| #if defined(VDSWTCH) |
| {"dswtch", C_SH(C_DSWTCH), MD_CHAR}, |
| #endif /* VDSWTCH */ |
| #if defined(VERASE2) |
| {"erase2", C_SH(C_ERASE2), MD_CHAR}, |
| #endif /* VERASE2 */ |
| #if defined(VSTART) |
| {"start", C_SH(C_START), MD_CHAR}, |
| #endif /* VSTART */ |
| #if defined(VSTOP) |
| {"stop", C_SH(C_STOP), MD_CHAR}, |
| #endif /* VSTOP */ |
| #if defined(VWERASE) |
| {"werase", C_SH(C_WERASE), MD_CHAR}, |
| #endif /* VWERASE */ |
| #if defined(VSUSP) |
| {"susp", C_SH(C_SUSP), MD_CHAR}, |
| #endif /* VSUSP */ |
| #if defined(VDSUSP) |
| {"dsusp", C_SH(C_DSUSP), MD_CHAR}, |
| #endif /* VDSUSP */ |
| #if defined(VREPRINT) |
| {"reprint", C_SH(C_REPRINT), MD_CHAR}, |
| #endif /* VREPRINT */ |
| #if defined(VDISCARD) |
| {"discard", C_SH(C_DISCARD), MD_CHAR}, |
| #endif /* VDISCARD */ |
| #if defined(VLNEXT) |
| {"lnext", C_SH(C_LNEXT), MD_CHAR}, |
| #endif /* VLNEXT */ |
| #if defined(VSTATUS) |
| {"status", C_SH(C_STATUS), MD_CHAR}, |
| #endif /* VSTATUS */ |
| #if defined(VPAGE) |
| {"page", C_SH(C_PAGE), MD_CHAR}, |
| #endif /* VPAGE */ |
| #if defined(VPGOFF) |
| {"pgoff", C_SH(C_PGOFF), MD_CHAR}, |
| #endif /* VPGOFF */ |
| #if defined(VKILL2) |
| {"kill2", C_SH(C_KILL2), MD_CHAR}, |
| #endif /* VKILL2 */ |
| #if defined(VBRK) |
| {"brk", C_SH(C_BRK), MD_CHAR}, |
| #endif /* VBRK */ |
| #if defined(VMIN) |
| {"min", C_SH(C_MIN), MD_CHAR}, |
| #endif /* VMIN */ |
| #if defined(VTIME) |
| {"time", C_SH(C_TIME), MD_CHAR}, |
| #endif /* VTIME */ |
| {NULL, 0, -1}, |
| }; |
| |
| |
| |
| #define tty__gettabs(td) ((((td)->c_oflag & TAB3) == TAB3) ? 0 : 1) |
| #define tty__geteightbit(td) (((td)->c_cflag & CSIZE) == CS8) |
| #define tty__cooked_mode(td) ((td)->c_lflag & ICANON) |
| |
| static int tty_getty(EditLine *, struct termios *); |
| static int tty_setty(EditLine *, int, const struct termios *); |
| static int tty__getcharindex(int); |
| static void tty__getchar(struct termios *, unsigned char *); |
| static void tty__setchar(struct termios *, unsigned char *); |
| static speed_t tty__getspeed(struct termios *); |
| static int tty_setup(EditLine *); |
| static void tty_setup_flags(EditLine *, struct termios *, int); |
| |
| #define t_qu t_ts |
| |
| /* tty_getty(): |
| * Wrapper for tcgetattr to handle EINTR |
| */ |
| static int |
| tty_getty(EditLine *el, struct termios *t) |
| { |
| int rv; |
| while ((rv = tcgetattr(el->el_infd, t)) == -1 && errno == EINTR) |
| continue; |
| return rv; |
| } |
| |
| /* tty_setty(): |
| * Wrapper for tcsetattr to handle EINTR |
| */ |
| static int |
| tty_setty(EditLine *el, int action, const struct termios *t) |
| { |
| int rv; |
| while ((rv = tcsetattr(el->el_infd, action, t)) == -1 && errno == EINTR) |
| continue; |
| return rv; |
| } |
| |
| /* tty_setup(): |
| * Get the tty parameters and initialize the editing state |
| */ |
| static int |
| tty_setup(EditLine *el) |
| { |
| int rst = (el->el_flags & NO_RESET) == 0; |
| |
| if (el->el_flags & EDIT_DISABLED) |
| return 0; |
| |
| if (el->el_tty.t_initialized) |
| return -1; |
| |
| if (!isatty(el->el_outfd)) { |
| #ifdef DEBUG_TTY |
| (void) fprintf(el->el_errfile, "%s: isatty: %s\n", __func__, |
| strerror(errno)); |
| #endif /* DEBUG_TTY */ |
| return -1; |
| } |
| if (tty_getty(el, &el->el_tty.t_or) == -1) { |
| #ifdef DEBUG_TTY |
| (void) fprintf(el->el_errfile, "%s: tty_getty: %s\n", __func__, |
| strerror(errno)); |
| #endif /* DEBUG_TTY */ |
| return -1; |
| } |
| el->el_tty.t_ts = el->el_tty.t_ex = el->el_tty.t_ed = el->el_tty.t_or; |
| |
| el->el_tty.t_speed = tty__getspeed(&el->el_tty.t_ex); |
| el->el_tty.t_tabs = tty__gettabs(&el->el_tty.t_ex); |
| el->el_tty.t_eight = tty__geteightbit(&el->el_tty.t_ex); |
| |
| tty_setup_flags(el, &el->el_tty.t_ex, EX_IO); |
| |
| /* |
| * Reset the tty chars to reasonable defaults |
| * If they are disabled, then enable them. |
| */ |
| if (rst) { |
| if (tty__cooked_mode(&el->el_tty.t_ts)) { |
| tty__getchar(&el->el_tty.t_ts, el->el_tty.t_c[TS_IO]); |
| /* |
| * Don't affect CMIN and CTIME for the editor mode |
| */ |
| for (rst = 0; rst < C_NCC - 2; rst++) |
| if (el->el_tty.t_c[TS_IO][rst] != |
| el->el_tty.t_vdisable |
| && el->el_tty.t_c[ED_IO][rst] != |
| el->el_tty.t_vdisable) |
| el->el_tty.t_c[ED_IO][rst] = |
| el->el_tty.t_c[TS_IO][rst]; |
| for (rst = 0; rst < C_NCC; rst++) |
| if (el->el_tty.t_c[TS_IO][rst] != |
| el->el_tty.t_vdisable) |
| el->el_tty.t_c[EX_IO][rst] = |
| el->el_tty.t_c[TS_IO][rst]; |
| } |
| tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]); |
| if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ex) == -1) { |
| #ifdef DEBUG_TTY |
| (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", |
| __func__, strerror(errno)); |
| #endif /* DEBUG_TTY */ |
| return -1; |
| } |
| } |
| |
| tty_setup_flags(el, &el->el_tty.t_ed, ED_IO); |
| |
| tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]); |
| tty_bind_char(el, 1); |
| el->el_tty.t_initialized = 1; |
| return 0; |
| } |
| |
| libedit_private int |
| tty_init(EditLine *el) |
| { |
| |
| el->el_tty.t_mode = EX_IO; |
| el->el_tty.t_vdisable = _POSIX_VDISABLE; |
| el->el_tty.t_initialized = 0; |
| (void) memcpy(el->el_tty.t_t, ttyperm, sizeof(ttyperm_t)); |
| (void) memcpy(el->el_tty.t_c, ttychar, sizeof(ttychar_t)); |
| return tty_setup(el); |
| } |
| |
| |
| /* tty_end(): |
| * Restore the tty to its original settings |
| */ |
| libedit_private void |
| /*ARGSUSED*/ |
| tty_end(EditLine *el, int how) |
| { |
| if (el->el_flags & EDIT_DISABLED) |
| return; |
| |
| if (!el->el_tty.t_initialized) |
| return; |
| |
| if (tty_setty(el, how, &el->el_tty.t_or) == -1) |
| { |
| #ifdef DEBUG_TTY |
| (void) fprintf(el->el_errfile, |
| "%s: tty_setty: %s\n", __func__, strerror(errno)); |
| #endif /* DEBUG_TTY */ |
| } |
| } |
| |
| |
| /* tty__getspeed(): |
| * Get the tty speed |
| */ |
| static speed_t |
| tty__getspeed(struct termios *td) |
| { |
| speed_t spd; |
| |
| if ((spd = cfgetispeed(td)) == 0) |
| spd = cfgetospeed(td); |
| return spd; |
| } |
| |
| /* tty__getspeed(): |
| * Return the index of the asked char in the c_cc array |
| */ |
| static int |
| tty__getcharindex(int i) |
| { |
| switch (i) { |
| #ifdef VINTR |
| case C_INTR: |
| return VINTR; |
| #endif /* VINTR */ |
| #ifdef VQUIT |
| case C_QUIT: |
| return VQUIT; |
| #endif /* VQUIT */ |
| #ifdef VERASE |
| case C_ERASE: |
| return VERASE; |
| #endif /* VERASE */ |
| #ifdef VKILL |
| case C_KILL: |
| return VKILL; |
| #endif /* VKILL */ |
| #ifdef VEOF |
| case C_EOF: |
| return VEOF; |
| #endif /* VEOF */ |
| #ifdef VEOL |
| case C_EOL: |
| return VEOL; |
| #endif /* VEOL */ |
| #ifdef VEOL2 |
| case C_EOL2: |
| return VEOL2; |
| #endif /* VEOL2 */ |
| #ifdef VSWTCH |
| case C_SWTCH: |
| return VSWTCH; |
| #endif /* VSWTCH */ |
| #ifdef VDSWTCH |
| case C_DSWTCH: |
| return VDSWTCH; |
| #endif /* VDSWTCH */ |
| #ifdef VERASE2 |
| case C_ERASE2: |
| return VERASE2; |
| #endif /* VERASE2 */ |
| #ifdef VSTART |
| case C_START: |
| return VSTART; |
| #endif /* VSTART */ |
| #ifdef VSTOP |
| case C_STOP: |
| return VSTOP; |
| #endif /* VSTOP */ |
| #ifdef VWERASE |
| case C_WERASE: |
| return VWERASE; |
| #endif /* VWERASE */ |
| #ifdef VSUSP |
| case C_SUSP: |
| return VSUSP; |
| #endif /* VSUSP */ |
| #ifdef VDSUSP |
| case C_DSUSP: |
| return VDSUSP; |
| #endif /* VDSUSP */ |
| #ifdef VREPRINT |
| case C_REPRINT: |
| return VREPRINT; |
| #endif /* VREPRINT */ |
| #ifdef VDISCARD |
| case C_DISCARD: |
| return VDISCARD; |
| #endif /* VDISCARD */ |
| #ifdef VLNEXT |
| case C_LNEXT: |
| return VLNEXT; |
| #endif /* VLNEXT */ |
| #ifdef VSTATUS |
| case C_STATUS: |
| return VSTATUS; |
| #endif /* VSTATUS */ |
| #ifdef VPAGE |
| case C_PAGE: |
| return VPAGE; |
| #endif /* VPAGE */ |
| #ifdef VPGOFF |
| case C_PGOFF: |
| return VPGOFF; |
| #endif /* VPGOFF */ |
| #ifdef VKILL2 |
| case C_KILL2: |
| return VKILL2; |
| #endif /* KILL2 */ |
| #ifdef VMIN |
| case C_MIN: |
| return VMIN; |
| #endif /* VMIN */ |
| #ifdef VTIME |
| case C_TIME: |
| return VTIME; |
| #endif /* VTIME */ |
| default: |
| return -1; |
| } |
| } |
| |
| /* tty__getchar(): |
| * Get the tty characters |
| */ |
| static void |
| tty__getchar(struct termios *td, unsigned char *s) |
| { |
| |
| #ifdef VINTR |
| s[C_INTR] = td->c_cc[VINTR]; |
| #endif /* VINTR */ |
| #ifdef VQUIT |
| s[C_QUIT] = td->c_cc[VQUIT]; |
| #endif /* VQUIT */ |
| #ifdef VERASE |
| s[C_ERASE] = td->c_cc[VERASE]; |
| #endif /* VERASE */ |
| #ifdef VKILL |
| s[C_KILL] = td->c_cc[VKILL]; |
| #endif /* VKILL */ |
| #ifdef VEOF |
| s[C_EOF] = td->c_cc[VEOF]; |
| #endif /* VEOF */ |
| #ifdef VEOL |
| s[C_EOL] = td->c_cc[VEOL]; |
| #endif /* VEOL */ |
| #ifdef VEOL2 |
| s[C_EOL2] = td->c_cc[VEOL2]; |
| #endif /* VEOL2 */ |
| #ifdef VSWTCH |
| s[C_SWTCH] = td->c_cc[VSWTCH]; |
| #endif /* VSWTCH */ |
| #ifdef VDSWTCH |
| s[C_DSWTCH] = td->c_cc[VDSWTCH]; |
| #endif /* VDSWTCH */ |
| #ifdef VERASE2 |
| s[C_ERASE2] = td->c_cc[VERASE2]; |
| #endif /* VERASE2 */ |
| #ifdef VSTART |
| s[C_START] = td->c_cc[VSTART]; |
| #endif /* VSTART */ |
| #ifdef VSTOP |
| s[C_STOP] = td->c_cc[VSTOP]; |
| #endif /* VSTOP */ |
| #ifdef VWERASE |
| s[C_WERASE] = td->c_cc[VWERASE]; |
| #endif /* VWERASE */ |
| #ifdef VSUSP |
| s[C_SUSP] = td->c_cc[VSUSP]; |
| #endif /* VSUSP */ |
| #ifdef VDSUSP |
| s[C_DSUSP] = td->c_cc[VDSUSP]; |
| #endif /* VDSUSP */ |
| #ifdef VREPRINT |
| s[C_REPRINT] = td->c_cc[VREPRINT]; |
| #endif /* VREPRINT */ |
| #ifdef VDISCARD |
| s[C_DISCARD] = td->c_cc[VDISCARD]; |
| #endif /* VDISCARD */ |
| #ifdef VLNEXT |
| s[C_LNEXT] = td->c_cc[VLNEXT]; |
| #endif /* VLNEXT */ |
| #ifdef VSTATUS |
| s[C_STATUS] = td->c_cc[VSTATUS]; |
| #endif /* VSTATUS */ |
| #ifdef VPAGE |
| s[C_PAGE] = td->c_cc[VPAGE]; |
| #endif /* VPAGE */ |
| #ifdef VPGOFF |
| s[C_PGOFF] = td->c_cc[VPGOFF]; |
| #endif /* VPGOFF */ |
| #ifdef VKILL2 |
| s[C_KILL2] = td->c_cc[VKILL2]; |
| #endif /* KILL2 */ |
| #ifdef VMIN |
| s[C_MIN] = td->c_cc[VMIN]; |
| #endif /* VMIN */ |
| #ifdef VTIME |
| s[C_TIME] = td->c_cc[VTIME]; |
| #endif /* VTIME */ |
| } /* tty__getchar */ |
| |
| |
| /* tty__setchar(): |
| * Set the tty characters |
| */ |
| static void |
| tty__setchar(struct termios *td, unsigned char *s) |
| { |
| |
| #ifdef VINTR |
| td->c_cc[VINTR] = s[C_INTR]; |
| #endif /* VINTR */ |
| #ifdef VQUIT |
| td->c_cc[VQUIT] = s[C_QUIT]; |
| #endif /* VQUIT */ |
| #ifdef VERASE |
| td->c_cc[VERASE] = s[C_ERASE]; |
| #endif /* VERASE */ |
| #ifdef VKILL |
| td->c_cc[VKILL] = s[C_KILL]; |
| #endif /* VKILL */ |
| #ifdef VEOF |
| td->c_cc[VEOF] = s[C_EOF]; |
| #endif /* VEOF */ |
| #ifdef VEOL |
| td->c_cc[VEOL] = s[C_EOL]; |
| #endif /* VEOL */ |
| #ifdef VEOL2 |
| td->c_cc[VEOL2] = s[C_EOL2]; |
| #endif /* VEOL2 */ |
| #ifdef VSWTCH |
| td->c_cc[VSWTCH] = s[C_SWTCH]; |
| #endif /* VSWTCH */ |
| #ifdef VDSWTCH |
| td->c_cc[VDSWTCH] = s[C_DSWTCH]; |
| #endif /* VDSWTCH */ |
| #ifdef VERASE2 |
| td->c_cc[VERASE2] = s[C_ERASE2]; |
| #endif /* VERASE2 */ |
| #ifdef VSTART |
| td->c_cc[VSTART] = s[C_START]; |
| #endif /* VSTART */ |
| #ifdef VSTOP |
| td->c_cc[VSTOP] = s[C_STOP]; |
| #endif /* VSTOP */ |
| #ifdef VWERASE |
| td->c_cc[VWERASE] = s[C_WERASE]; |
| #endif /* VWERASE */ |
| #ifdef VSUSP |
| td->c_cc[VSUSP] = s[C_SUSP]; |
| #endif /* VSUSP */ |
| #ifdef VDSUSP |
| td->c_cc[VDSUSP] = s[C_DSUSP]; |
| #endif /* VDSUSP */ |
| #ifdef VREPRINT |
| td->c_cc[VREPRINT] = s[C_REPRINT]; |
| #endif /* VREPRINT */ |
| #ifdef VDISCARD |
| td->c_cc[VDISCARD] = s[C_DISCARD]; |
| #endif /* VDISCARD */ |
| #ifdef VLNEXT |
| td->c_cc[VLNEXT] = s[C_LNEXT]; |
| #endif /* VLNEXT */ |
| #ifdef VSTATUS |
| td->c_cc[VSTATUS] = s[C_STATUS]; |
| #endif /* VSTATUS */ |
| #ifdef VPAGE |
| td->c_cc[VPAGE] = s[C_PAGE]; |
| #endif /* VPAGE */ |
| #ifdef VPGOFF |
| td->c_cc[VPGOFF] = s[C_PGOFF]; |
| #endif /* VPGOFF */ |
| #ifdef VKILL2 |
| td->c_cc[VKILL2] = s[C_KILL2]; |
| #endif /* VKILL2 */ |
| #ifdef VMIN |
| td->c_cc[VMIN] = s[C_MIN]; |
| #endif /* VMIN */ |
| #ifdef VTIME |
| td->c_cc[VTIME] = s[C_TIME]; |
| #endif /* VTIME */ |
| } /* tty__setchar */ |
| |
| |
| /* tty_bind_char(): |
| * Rebind the editline functions |
| */ |
| libedit_private void |
| tty_bind_char(EditLine *el, int force) |
| { |
| |
| unsigned char *t_n = el->el_tty.t_c[ED_IO]; |
| unsigned char *t_o = el->el_tty.t_ed.c_cc; |
| wchar_t new[2], old[2]; |
| const ttymap_t *tp; |
| el_action_t *map, *alt; |
| const el_action_t *dmap, *dalt; |
| new[1] = old[1] = '\0'; |
| |
| map = el->el_map.key; |
| alt = el->el_map.alt; |
| if (el->el_map.type == MAP_VI) { |
| dmap = el->el_map.vii; |
| dalt = el->el_map.vic; |
| } else { |
| dmap = el->el_map.emacs; |
| dalt = NULL; |
| } |
| |
| for (tp = tty_map; tp->nch != (wint_t)-1; tp++) { |
| new[0] = (wchar_t)t_n[tp->nch]; |
| old[0] = (wchar_t)t_o[tp->och]; |
| if (new[0] == old[0] && !force) |
| continue; |
| /* Put the old default binding back, and set the new binding */ |
| keymacro_clear(el, map, old); |
| map[(unsigned char)old[0]] = dmap[(unsigned char)old[0]]; |
| keymacro_clear(el, map, new); |
| /* MAP_VI == 1, MAP_EMACS == 0... */ |
| map[(unsigned char)new[0]] = tp->bind[el->el_map.type]; |
| if (dalt) { |
| keymacro_clear(el, alt, old); |
| alt[(unsigned char)old[0]] = |
| dalt[(unsigned char)old[0]]; |
| keymacro_clear(el, alt, new); |
| alt[(unsigned char)new[0]] = |
| tp->bind[el->el_map.type + 1]; |
| } |
| } |
| } |
| |
| |
| static tcflag_t * |
| tty__get_flag(struct termios *t, int kind) { |
| switch (kind) { |
| case MD_INP: |
| return &t->c_iflag; |
| case MD_OUT: |
| return &t->c_oflag; |
| case MD_CTL: |
| return &t->c_cflag; |
| case MD_LIN: |
| return &t->c_lflag; |
| default: |
| abort(); |
| /*NOTREACHED*/ |
| } |
| } |
| |
| |
| static tcflag_t |
| tty_update_flag(EditLine *el, tcflag_t f, int mode, int kind) |
| { |
| f &= ~el->el_tty.t_t[mode][kind].t_clrmask; |
| f |= el->el_tty.t_t[mode][kind].t_setmask; |
| return f; |
| } |
| |
| |
| static void |
| tty_update_flags(EditLine *el, int kind) |
| { |
| tcflag_t *tt, *ed, *ex; |
| tt = tty__get_flag(&el->el_tty.t_ts, kind); |
| ed = tty__get_flag(&el->el_tty.t_ed, kind); |
| ex = tty__get_flag(&el->el_tty.t_ex, kind); |
| |
| if (*tt != *ex && (kind != MD_CTL || *tt != *ed)) { |
| *ed = tty_update_flag(el, *tt, ED_IO, kind); |
| *ex = tty_update_flag(el, *tt, EX_IO, kind); |
| } |
| } |
| |
| |
| static void |
| tty_update_char(EditLine *el, int mode, int c) { |
| if (!((el->el_tty.t_t[mode][MD_CHAR].t_setmask & C_SH(c))) |
| && (el->el_tty.t_c[TS_IO][c] != el->el_tty.t_c[EX_IO][c])) |
| el->el_tty.t_c[mode][c] = el->el_tty.t_c[TS_IO][c]; |
| if (el->el_tty.t_t[mode][MD_CHAR].t_clrmask & C_SH(c)) |
| el->el_tty.t_c[mode][c] = el->el_tty.t_vdisable; |
| } |
| |
| |
| /* tty_rawmode(): |
| * Set terminal into 1 character at a time mode. |
| */ |
| libedit_private int |
| tty_rawmode(EditLine *el) |
| { |
| |
| if (el->el_tty.t_mode == ED_IO || el->el_tty.t_mode == QU_IO) |
| return 0; |
| |
| if (el->el_flags & EDIT_DISABLED) |
| return 0; |
| |
| if (tty_getty(el, &el->el_tty.t_ts) == -1) { |
| #ifdef DEBUG_TTY |
| (void) fprintf(el->el_errfile, "%s: tty_getty: %s\n", __func__, |
| strerror(errno)); |
| #endif /* DEBUG_TTY */ |
| return -1; |
| } |
| /* |
| * We always keep up with the eight bit setting and the speed of the |
| * tty. But we only believe changes that are made to cooked mode! |
| */ |
| el->el_tty.t_eight = tty__geteightbit(&el->el_tty.t_ts); |
| el->el_tty.t_speed = tty__getspeed(&el->el_tty.t_ts); |
| |
| if (tty__getspeed(&el->el_tty.t_ex) != el->el_tty.t_speed || |
| tty__getspeed(&el->el_tty.t_ed) != el->el_tty.t_speed) { |
| (void) cfsetispeed(&el->el_tty.t_ex, el->el_tty.t_speed); |
| (void) cfsetospeed(&el->el_tty.t_ex, el->el_tty.t_speed); |
| (void) cfsetispeed(&el->el_tty.t_ed, el->el_tty.t_speed); |
| (void) cfsetospeed(&el->el_tty.t_ed, el->el_tty.t_speed); |
| } |
| if (tty__cooked_mode(&el->el_tty.t_ts)) { |
| int i; |
| |
| for (i = MD_INP; i <= MD_LIN; i++) |
| tty_update_flags(el, i); |
| |
| if (tty__gettabs(&el->el_tty.t_ex) == 0) |
| el->el_tty.t_tabs = 0; |
| else |
| el->el_tty.t_tabs = EL_CAN_TAB ? 1 : 0; |
| |
| tty__getchar(&el->el_tty.t_ts, el->el_tty.t_c[TS_IO]); |
| /* |
| * Check if the user made any changes. |
| * If he did, then propagate the changes to the |
| * edit and execute data structures. |
| */ |
| for (i = 0; i < C_NCC; i++) |
| if (el->el_tty.t_c[TS_IO][i] != |
| el->el_tty.t_c[EX_IO][i]) |
| break; |
| |
| if (i != C_NCC) { |
| /* |
| * Propagate changes only to the unlibedit_private |
| * chars that have been modified just now. |
| */ |
| for (i = 0; i < C_NCC; i++) |
| tty_update_char(el, ED_IO, i); |
| |
| tty_bind_char(el, 0); |
| tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]); |
| |
| for (i = 0; i < C_NCC; i++) |
| tty_update_char(el, EX_IO, i); |
| |
| tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]); |
| } |
| } |
| if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ed) == -1) { |
| #ifdef DEBUG_TTY |
| (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", __func__, |
| strerror(errno)); |
| #endif /* DEBUG_TTY */ |
| return -1; |
| } |
| el->el_tty.t_mode = ED_IO; |
| return 0; |
| } |
| |
| |
| /* tty_cookedmode(): |
| * Set the tty back to normal mode |
| */ |
| libedit_private int |
| tty_cookedmode(EditLine *el) |
| { /* set tty in normal setup */ |
| |
| if (el->el_tty.t_mode == EX_IO) |
| return 0; |
| |
| if (el->el_flags & EDIT_DISABLED) |
| return 0; |
| |
| if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ex) == -1) { |
| #ifdef DEBUG_TTY |
| (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", __func__, |
| strerror(errno)); |
| #endif /* DEBUG_TTY */ |
| return -1; |
| } |
| el->el_tty.t_mode = EX_IO; |
| return 0; |
| } |
| |
| |
| /* tty_quotemode(): |
| * Turn on quote mode |
| */ |
| libedit_private int |
| tty_quotemode(EditLine *el) |
| { |
| if (el->el_tty.t_mode == QU_IO) |
| return 0; |
| |
| el->el_tty.t_qu = el->el_tty.t_ed; |
| |
| tty_setup_flags(el, &el->el_tty.t_qu, QU_IO); |
| |
| if (tty_setty(el, TCSADRAIN, &el->el_tty.t_qu) == -1) { |
| #ifdef DEBUG_TTY |
| (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", __func__, |
| strerror(errno)); |
| #endif /* DEBUG_TTY */ |
| return -1; |
| } |
| el->el_tty.t_mode = QU_IO; |
| return 0; |
| } |
| |
| |
| /* tty_noquotemode(): |
| * Turn off quote mode |
| */ |
| libedit_private int |
| tty_noquotemode(EditLine *el) |
| { |
| |
| if (el->el_tty.t_mode != QU_IO) |
| return 0; |
| if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ed) == -1) { |
| #ifdef DEBUG_TTY |
| (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", __func__, |
| strerror(errno)); |
| #endif /* DEBUG_TTY */ |
| return -1; |
| } |
| el->el_tty.t_mode = ED_IO; |
| return 0; |
| } |
| |
| |
| /* tty_stty(): |
| * Stty builtin |
| */ |
| libedit_private int |
| /*ARGSUSED*/ |
| tty_stty(EditLine *el, int argc __attribute__((__unused__)), |
| const wchar_t **argv) |
| { |
| const ttymodes_t *m; |
| char x; |
| int aflag = 0; |
| const wchar_t *s, *d; |
| char name[EL_BUFSIZ]; |
| struct termios *tios = &el->el_tty.t_ex; |
| int z = EX_IO; |
| |
| if (argv == NULL) |
| return -1; |
| strncpy(name, ct_encode_string(*argv++, &el->el_scratch), sizeof(name)); |
| name[sizeof(name) - 1] = '\0'; |
| |
| while (argv && *argv && argv[0][0] == '-' && argv[0][2] == '\0') |
| switch (argv[0][1]) { |
| case 'a': |
| aflag++; |
| argv++; |
| break; |
| case 'd': |
| argv++; |
| tios = &el->el_tty.t_ed; |
| z = ED_IO; |
| break; |
| case 'x': |
| argv++; |
| tios = &el->el_tty.t_ex; |
| z = EX_IO; |
| break; |
| case 'q': |
| argv++; |
| tios = &el->el_tty.t_ts; |
| z = QU_IO; |
| break; |
| default: |
| (void) fprintf(el->el_errfile, |
| "%s: Unknown switch `%lc'.\n", |
| name, (wint_t)argv[0][1]); |
| return -1; |
| } |
| |
| if (!argv || !*argv) { |
| int i = -1; |
| size_t len = 0, st = 0, cu; |
| for (m = ttymodes; m->m_name; m++) { |
| if (m->m_type != i) { |
| (void) fprintf(el->el_outfile, "%s%s", |
| i != -1 ? "\n" : "", |
| el->el_tty.t_t[z][m->m_type].t_name); |
| i = m->m_type; |
| st = len = |
| strlen(el->el_tty.t_t[z][m->m_type].t_name); |
| } |
| if (i != -1) { |
| x = (el->el_tty.t_t[z][i].t_setmask & m->m_value) |
| ? '+' : '\0'; |
| |
| if (el->el_tty.t_t[z][i].t_clrmask & m->m_value) |
| x = '-'; |
| } else { |
| x = '\0'; |
| } |
| |
| if (x != '\0' || aflag) { |
| |
| cu = strlen(m->m_name) + (x != '\0') + 1; |
| |
| if (len + cu >= |
| (size_t)el->el_terminal.t_size.h) { |
| (void) fprintf(el->el_outfile, "\n%*s", |
| (int)st, ""); |
| len = st + cu; |
| } else |
| len += cu; |
| |
| if (x != '\0') |
| (void) fprintf(el->el_outfile, "%c%s ", |
| x, m->m_name); |
| else |
| (void) fprintf(el->el_outfile, "%s ", |
| m->m_name); |
| } |
| } |
| (void) fprintf(el->el_outfile, "\n"); |
| return 0; |
| } |
| while (argv && (s = *argv++)) { |
| const wchar_t *p; |
| switch (*s) { |
| case '+': |
| case '-': |
| x = (char)*s++; |
| break; |
| default: |
| x = '\0'; |
| break; |
| } |
| d = s; |
| p = wcschr(s, L'='); |
| for (m = ttymodes; m->m_name; m++) |
| if ((p ? strncmp(m->m_name, ct_encode_string(d, |
| &el->el_scratch), (size_t)(p - d)) : |
| strcmp(m->m_name, ct_encode_string(d, |
| &el->el_scratch))) == 0 && |
| (p == NULL || m->m_type == MD_CHAR)) |
| break; |
| |
| if (!m->m_name) { |
| (void) fprintf(el->el_errfile, |
| "%s: Invalid argument `%ls'.\n", name, d); |
| return -1; |
| } |
| if (p) { |
| int c = ffs((int)m->m_value); |
| int v = *++p ? parse__escape(&p) : |
| el->el_tty.t_vdisable; |
| assert(c != 0); |
| c--; |
| c = tty__getcharindex(c); |
| assert(c != -1); |
| tios->c_cc[c] = (cc_t)v; |
| continue; |
| } |
| switch (x) { |
| case '+': |
| el->el_tty.t_t[z][m->m_type].t_setmask |= m->m_value; |
| el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value; |
| break; |
| case '-': |
| el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value; |
| el->el_tty.t_t[z][m->m_type].t_clrmask |= m->m_value; |
| break; |
| default: |
| el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value; |
| el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value; |
| break; |
| } |
| } |
| |
| tty_setup_flags(el, tios, z); |
| if (el->el_tty.t_mode == z) { |
| if (tty_setty(el, TCSADRAIN, tios) == -1) { |
| #ifdef DEBUG_TTY |
| (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", |
| __func__, strerror(errno)); |
| #endif /* DEBUG_TTY */ |
| return -1; |
| } |
| } |
| |
| return 0; |
| } |
| |
| |
| #ifdef notyet |
| /* tty_printchar(): |
| * DEbugging routine to print the tty characters |
| */ |
| static void |
| tty_printchar(EditLine *el, unsigned char *s) |
| { |
| ttyperm_t *m; |
| int i; |
| |
| for (i = 0; i < C_NCC; i++) { |
| for (m = el->el_tty.t_t; m->m_name; m++) |
| if (m->m_type == MD_CHAR && C_SH(i) == m->m_value) |
| break; |
| if (m->m_name) |
| (void) fprintf(el->el_errfile, "%s ^%c ", |
| m->m_name, s[i] + 'A' - 1); |
| if (i % 5 == 0) |
| (void) fprintf(el->el_errfile, "\n"); |
| } |
| (void) fprintf(el->el_errfile, "\n"); |
| } |
| #endif /* notyet */ |
| |
| |
| static void |
| tty_setup_flags(EditLine *el, struct termios *tios, int mode) |
| { |
| int kind; |
| for (kind = MD_INP; kind <= MD_LIN; kind++) { |
| tcflag_t *f = tty__get_flag(tios, kind); |
| *f = tty_update_flag(el, *f, mode, kind); |
| } |
| } |
| |
| libedit_private int |
| tty_get_signal_character(EditLine *el, int sig) |
| { |
| #ifdef ECHOCTL |
| tcflag_t *ed = tty__get_flag(&el->el_tty.t_ed, MD_INP); |
| if ((*ed & ECHOCTL) == 0) |
| return -1; |
| #endif |
| switch (sig) { |
| #ifdef SIGINT |
| case SIGINT: |
| return el->el_tty.t_c[ED_IO][VINTR]; |
| #endif |
| #ifdef SIGQUIT |
| case SIGQUIT: |
| return el->el_tty.t_c[ED_IO][VQUIT]; |
| #endif |
| #ifdef SIGINFO |
| case SIGINFO: |
| return el->el_tty.t_c[ED_IO][VSTATUS]; |
| #endif |
| #ifdef SIGTSTP |
| case SIGTSTP: |
| return el->el_tty.t_c[ED_IO][VSUSP]; |
| #endif |
| default: |
| return -1; |
| } |
| } |