/* $OpenBSD: tty.c,v 1.8 2003/06/02 20:18:40 millert Exp $ */ /* $NetBSD: tty.c,v 1.3 1997/04/11 17:52:49 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. */ #if !defined(lint) && !defined(SCCSID) #if 0 static char sccsid[] = "@(#)tty.c 8.1 (Berkeley) 6/4/93"; #else static const char rcsid[] = "$OpenBSD: tty.c,v 1.8 2003/06/02 20:18:40 millert Exp $"; #endif #endif /* not lint && not SCCSID */ /* * tty.c: tty interface stuff */ #include "sys.h" #include "tty.h" #include "el.h" typedef struct ttymodes_t { char *m_name; u_int m_value; int m_type; } ttymodes_t; typedef struct ttymap_t { int nch, och; /* Internal and termio rep of chars */ el_action_t bind[3]; /* emacs, vi, and vi-cmd */ } ttymap_t; private 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 }, { "oflag:", 0, 0 }, { "cflag:", 0, 0 }, { "lflag:", 0, ISIG | IEXTEN }, { "chars:", 0, 0 }, } }; private 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 } }; private ttymap_t tty_map[] = { #ifdef VERASE { C_ERASE, VERASE, { ED_DELETE_PREV_CHAR, VI_DELETE_PREV_CHAR, ED_PREV_CHAR } }, #endif /* VERASE */ #ifdef VERASE2 { C_ERASE2, VERASE2, { ED_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 */ { -1, -1, { ED_UNASSIGNED, ED_UNASSIGNED, ED_UNASSIGNED } } }; private ttymodes_t ttymodes[] = { # ifdef IGNBRK { "ignbrk", IGNBRK, M_INP }, # endif /* IGNBRK */ # ifdef BRKINT { "brkint", BRKINT, M_INP }, # endif /* BRKINT */ # ifdef IGNPAR { "ignpar", IGNPAR, M_INP }, # endif /* IGNPAR */ # ifdef PARMRK { "parmrk", PARMRK, M_INP }, # endif /* PARMRK */ # ifdef INPCK { "inpck", INPCK, M_INP }, # endif /* INPCK */ # ifdef ISTRIP { "istrip", ISTRIP, M_INP }, # endif /* ISTRIP */ # ifdef INLCR { "inlcr", INLCR, M_INP }, # endif /* INLCR */ # ifdef IGNCR { "igncr", IGNCR, M_INP }, # endif /* IGNCR */ # ifdef ICRNL { "icrnl", ICRNL, M_INP }, # endif /* ICRNL */ # ifdef IUCLC { "iuclc", IUCLC, M_INP }, # endif /* IUCLC */ # ifdef IXON { "ixon", IXON, M_INP }, # endif /* IXON */ # ifdef IXANY { "ixany", IXANY, M_INP }, # endif /* IXANY */ # ifdef IXOFF { "ixoff", IXOFF, M_INP }, # endif /* IXOFF */ # ifdef IMAXBEL { "imaxbel",IMAXBEL,M_INP }, # endif /* IMAXBEL */ # ifdef OPOST { "opost", OPOST, M_OUT }, # endif /* OPOST */ # ifdef OLCUC { "olcuc", OLCUC, M_OUT }, # endif /* OLCUC */ # ifdef ONLCR { "onlcr", ONLCR, M_OUT }, # endif /* ONLCR */ # ifdef OCRNL { "ocrnl", OCRNL, M_OUT }, # endif /* OCRNL */ # ifdef ONOCR { "onocr", ONOCR, M_OUT }, # endif /* ONOCR */ # ifdef ONOEOT { "onoeot", ONOEOT, M_OUT }, # endif /* ONOEOT */ # ifdef ONLRET { "onlret", ONLRET, M_OUT }, # endif /* ONLRET */ # ifdef OFILL { "ofill", OFILL, M_OUT }, # endif /* OFILL */ # ifdef OFDEL { "ofdel", OFDEL, M_OUT }, # endif /* OFDEL */ # ifdef NLDLY { "nldly", NLDLY, M_OUT }, # endif /* NLDLY */ # ifdef CRDLY { "crdly", CRDLY, M_OUT }, # endif /* CRDLY */ # ifdef TABDLY { "tabdly", TABDLY, M_OUT }, # endif /* TABDLY */ # ifdef XTABS { "xtabs", XTABS, M_OUT }, # endif /* XTABS */ # ifdef BSDLY { "bsdly", BSDLY, M_OUT }, # endif /* BSDLY */ # ifdef VTDLY { "vtdly", VTDLY, M_OUT }, # endif /* VTDLY */ # ifdef FFDLY { "ffdly", FFDLY, M_OUT }, # endif /* FFDLY */ # ifdef PAGEOUT { "pageout",PAGEOUT,M_OUT }, # endif /* PAGEOUT */ # ifdef WRAP { "wrap", WRAP, M_OUT }, # endif /* WRAP */ # ifdef CIGNORE { "cignore",CIGNORE,M_CTL }, # endif /* CBAUD */ # ifdef CBAUD { "cbaud", CBAUD, M_CTL }, # endif /* CBAUD */ # ifdef CSTOPB { "cstopb", CSTOPB, M_CTL }, # endif /* CSTOPB */ # ifdef CREAD { "cread", CREAD, M_CTL }, # endif /* CREAD */ # ifdef PARENB { "parenb", PARENB, M_CTL }, # endif /* PARENB */ # ifdef PARODD { "parodd", PARODD, M_CTL }, # endif /* PARODD */ # ifdef HUPCL { "hupcl", HUPCL, M_CTL }, # endif /* HUPCL */ # ifdef CLOCAL { "clocal", CLOCAL, M_CTL }, # endif /* CLOCAL */ # ifdef LOBLK { "loblk", LOBLK, M_CTL }, # endif /* LOBLK */ # ifdef CIBAUD { "cibaud", CIBAUD, M_CTL }, # endif /* CIBAUD */ # ifdef CRTSCTS # ifdef CCTS_OFLOW { "ccts_oflow",CCTS_OFLOW,M_CTL }, # else { "crtscts",CRTSCTS,M_CTL }, # endif /* CCTS_OFLOW */ # endif /* CRTSCTS */ # ifdef CRTS_IFLOW { "crts_iflow",CRTS_IFLOW,M_CTL }, # endif /* CRTS_IFLOW */ # ifdef MDMBUF { "mdmbuf", MDMBUF, M_CTL }, # endif /* MDMBUF */ # ifdef RCV1EN { "rcv1en", RCV1EN, M_CTL }, # endif /* RCV1EN */ # ifdef XMT1EN { "xmt1en", XMT1EN, M_CTL }, # endif /* XMT1EN */ # ifdef ISIG { "isig", ISIG, M_LIN }, # endif /* ISIG */ # ifdef ICANON { "icanon", ICANON, M_LIN }, # endif /* ICANON */ # ifdef XCASE { "xcase", XCASE, M_LIN }, # endif /* XCASE */ # ifdef ECHO { "echo", ECHO, M_LIN }, # endif /* ECHO */ # ifdef ECHOE { "echoe", ECHOE, M_LIN }, # endif /* ECHOE */ # ifdef ECHOK { "echok", ECHOK, M_LIN }, # endif /* ECHOK */ # ifdef ECHONL { "echonl", ECHONL, M_LIN }, # endif /* ECHONL */ # ifdef NOFLSH { "noflsh", NOFLSH, M_LIN }, # endif /* NOFLSH */ # ifdef TOSTOP { "tostop", TOSTOP, M_LIN }, # endif /* TOSTOP */ # ifdef ECHOCTL { "echoctl",ECHOCTL,M_LIN }, # endif /* ECHOCTL */ # ifdef ECHOPRT { "echoprt",ECHOPRT,M_LIN }, # endif /* ECHOPRT */ # ifdef ECHOKE { "echoke", ECHOKE, M_LIN }, # endif /* ECHOKE */ # ifdef DEFECHO { "defecho",DEFECHO,M_LIN }, # endif /* DEFECHO */ # ifdef FLUSHO { "flusho", FLUSHO, M_LIN }, # endif /* FLUSHO */ # ifdef PENDIN { "pendin", PENDIN, M_LIN }, # endif /* PENDIN */ # ifdef IEXTEN { "iexten", IEXTEN, M_LIN }, # endif /* IEXTEN */ # ifdef NOKERNINFO { "nokerninfo",NOKERNINFO,M_LIN }, # endif /* NOKERNINFO */ # ifdef ALTWERASE { "altwerase",ALTWERASE,M_LIN }, # endif /* ALTWERASE */ # ifdef EXTPROC { "extproc",EXTPROC, M_LIN }, # endif /* EXTPROC */ # if defined(VINTR) { "intr", C_SH(C_INTR), M_CHAR }, # endif /* VINTR */ # if defined(VQUIT) { "quit", C_SH(C_QUIT), M_CHAR }, # endif /* VQUIT */ # if defined(VERASE) { "erase", C_SH(C_ERASE), M_CHAR }, # endif /* VERASE */ # if defined(VKILL) { "kill", C_SH(C_KILL), M_CHAR }, # endif /* VKILL */ # if defined(VEOF) { "eof", C_SH(C_EOF), M_CHAR }, # endif /* VEOF */ # if defined(VEOL) { "eol", C_SH(C_EOL), M_CHAR }, # endif /* VEOL */ # if defined(VEOL2) { "eol2", C_SH(C_EOL2), M_CHAR }, # endif /* VEOL2 */ # if defined(VSWTCH) { "swtch", C_SH(C_SWTCH), M_CHAR }, # endif /* VSWTCH */ # if defined(VDSWTCH) { "dswtch", C_SH(C_DSWTCH), M_CHAR }, # endif /* VDSWTCH */ # if defined(VERASE2) { "erase2", C_SH(C_ERASE2), M_CHAR }, # endif /* VERASE2 */ # if defined(VSTART) { "start", C_SH(C_START), M_CHAR }, # endif /* VSTART */ # if defined(VSTOP) { "stop", C_SH(C_STOP), M_CHAR }, # endif /* VSTOP */ # if defined(VWERASE) { "werase", C_SH(C_WERASE), M_CHAR }, # endif /* VWERASE */ # if defined(VSUSP) { "susp", C_SH(C_SUSP), M_CHAR }, # endif /* VSUSP */ # if defined(VDSUSP) { "dsusp", C_SH(C_DSUSP), M_CHAR }, # endif /* VDSUSP */ # if defined(VREPRINT) { "reprint", C_SH(C_REPRINT),M_CHAR }, # endif /* VREPRINT */ # if defined(VDISCARD) { "discard", C_SH(C_DISCARD),M_CHAR }, # endif /* VDISCARD */ # if defined(VLNEXT) { "lnext", C_SH(C_LNEXT), M_CHAR }, # endif /* VLNEXT */ # if defined(VSTATUS) { "status", C_SH(C_STATUS), M_CHAR }, # endif /* VSTATUS */ # if defined(VPAGE) { "page", C_SH(C_PAGE), M_CHAR }, # endif /* VPAGE */ # if defined(VPGOFF) { "pgoff", C_SH(C_PGOFF), M_CHAR }, # endif /* VPGOFF */ # if defined(VKILL2) { "kill2", C_SH(C_KILL2), M_CHAR }, # endif /* VKILL2 */ # if defined(VBRK) { "brk", C_SH(C_BRK), M_CHAR }, # endif /* VBRK */ # if defined(VMIN) { "min", C_SH(C_MIN), M_CHAR }, # endif /* VMIN */ # if defined(VTIME) { "time", C_SH(C_TIME), M_CHAR }, # endif /* VTIME */ { NULL, 0, -1 }, }; #define tty_getty(el, td) tcgetattr((el)->el_infd, (td)) #define tty_setty(el, td) tcsetattr((el)->el_infd, TCSADRAIN, (td)) #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) private void tty__getchar(struct termios *, unsigned char *); private void tty__setchar(struct termios *, unsigned char *); private speed_t tty__getspeed(struct termios *); private int tty_setup(EditLine *); #define t_qu t_ts /* tty_setup(): * Get the tty parameters and initialize the editing state */ private int tty_setup(el) EditLine *el; { int rst = 1; if (tty_getty(el, &el->el_tty.t_ed) == -1) { #ifdef DEBUG_TTY (void)fprintf(el->el_errfile, "tty_setup: tty_getty: %s\n", 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_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); el->el_tty.t_ex.c_iflag &= ~el->el_tty.t_t[EX_IO][M_INP].t_clrmask; el->el_tty.t_ex.c_iflag |= el->el_tty.t_t[EX_IO][M_INP].t_setmask; el->el_tty.t_ex.c_oflag &= ~el->el_tty.t_t[EX_IO][M_OUT].t_clrmask; el->el_tty.t_ex.c_oflag |= el->el_tty.t_t[EX_IO][M_OUT].t_setmask; el->el_tty.t_ex.c_cflag &= ~el->el_tty.t_t[EX_IO][M_CTL].t_clrmask; el->el_tty.t_ex.c_cflag |= el->el_tty.t_t[EX_IO][M_CTL].t_setmask; el->el_tty.t_ex.c_lflag &= ~el->el_tty.t_t[EX_IO][M_LIN].t_clrmask; el->el_tty.t_ex.c_lflag |= el->el_tty.t_t[EX_IO][M_LIN].t_setmask; /* * 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_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, &el->el_tty.t_ex) == -1) { #ifdef DEBUG_TTY (void)fprintf(el->el_errfile, "tty_setup: tty_setty: %s\n", strerror(errno)); #endif /* DEBUG_TTY */ return(-1); } } else tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]); el->el_tty.t_ed.c_iflag &= ~el->el_tty.t_t[ED_IO][M_INP].t_clrmask; el->el_tty.t_ed.c_iflag |= el->el_tty.t_t[ED_IO][M_INP].t_setmask; el->el_tty.t_ed.c_oflag &= ~el->el_tty.t_t[ED_IO][M_OUT].t_clrmask; el->el_tty.t_ed.c_oflag |= el->el_tty.t_t[ED_IO][M_OUT].t_setmask; el->el_tty.t_ed.c_cflag &= ~el->el_tty.t_t[ED_IO][M_CTL].t_clrmask; el->el_tty.t_ed.c_cflag |= el->el_tty.t_t[ED_IO][M_CTL].t_setmask; el->el_tty.t_ed.c_lflag &= ~el->el_tty.t_t[ED_IO][M_LIN].t_clrmask; el->el_tty.t_ed.c_lflag |= el->el_tty.t_t[ED_IO][M_LIN].t_setmask; tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]); return 0; } protected int tty_init(el) EditLine *el; { el->el_tty.t_mode = EX_IO; el->el_tty.t_vdisable = _POSIX_VDISABLE; (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); } /* end tty_init */ /* tty_end(): * Restore the tty to its original settings */ protected void /*ARGSUSED*/ tty_end(el) EditLine *el; { /* XXX: Maybe reset to an initial state? */ } /* tty__getspeed(): * Get the tty speed */ private speed_t tty__getspeed(td) struct termios *td; { speed_t spd; if ((spd = cfgetispeed(td)) == 0) spd = cfgetospeed(td); return spd; } /* end tty__getspeed */ /* tty__getchar(): * Get the tty characters */ private void tty__getchar(td, s) 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 */ private void tty__setchar(td, s) 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 */ protected void tty_bind_char(el, force) 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; unsigned char new[2], old[2]; ttymap_t *tp; el_action_t *dmap, *dalt, *map, *alt; 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 != -1; tp++) { new[0] = t_n[tp->nch]; old[0] = t_o[tp->och]; if (new[0] == old[0] && !force) continue; /* Put the old default binding back, and set the new binding */ key_clear(el, map, old); map[old[0]] = dmap[old[0]]; key_clear(el, map, new); /* MAP_VI == 1, MAP_EMACS == 0... */ map[new[0]] = tp->bind[el->el_map.type]; if (dalt) { key_clear(el, alt, old); alt[old[0]] = dalt[old[0]]; key_clear(el, alt, new); alt[new[0]] = tp->bind[el->el_map.type+1]; } } } /* tty_rawmode(): * Set terminal into 1 character at a time mode. */ protected int tty_rawmode(el) EditLine *el; { if (el->el_tty.t_mode == ED_IO) return (0); if (tty_getty(el, &el->el_tty.t_ts) == -1) { #ifdef DEBUG_TTY (void)fprintf(el->el_errfile, "tty_rawmode: tty_getty: %s\n", strerror(errno)); #endif /* DEBUG_TTY */ return(-1); } /* * We always keep up with the eight bit setting and the speed of the * tty. But only 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)) { if (el->el_tty.t_ts.c_cflag != el->el_tty.t_ex.c_cflag) { el->el_tty.t_ex.c_cflag = el->el_tty.t_ts.c_cflag; el->el_tty.t_ex.c_cflag &= ~el->el_tty.t_t[EX_IO][M_CTL].t_clrmask; el->el_tty.t_ex.c_cflag |= el->el_tty.t_t[EX_IO][M_CTL].t_setmask; el->el_tty.t_ed.c_cflag = el->el_tty.t_ts.c_cflag; el->el_tty.t_ed.c_cflag &= ~el->el_tty.t_t[ED_IO][M_CTL].t_clrmask; el->el_tty.t_ed.c_cflag |= el->el_tty.t_t[ED_IO][M_CTL].t_setmask; } if ((el->el_tty.t_ts.c_lflag != el->el_tty.t_ex.c_lflag) && (el->el_tty.t_ts.c_lflag != el->el_tty.t_ed.c_lflag)) { el->el_tty.t_ex.c_lflag = el->el_tty.t_ts.c_lflag; el->el_tty.t_ex.c_lflag &= ~el->el_tty.t_t[EX_IO][M_LIN].t_clrmask; el->el_tty.t_ex.c_lflag |= el->el_tty.t_t[EX_IO][M_LIN].t_setmask; el->el_tty.t_ed.c_lflag = el->el_tty.t_ts.c_lflag; el->el_tty.t_ed.c_lflag &= ~el->el_tty.t_t[ED_IO][M_LIN].t_clrmask; el->el_tty.t_ed.c_lflag |= el->el_tty.t_t[ED_IO][M_LIN].t_setmask; } if ((el->el_tty.t_ts.c_iflag != el->el_tty.t_ex.c_iflag) && (el->el_tty.t_ts.c_iflag != el->el_tty.t_ed.c_iflag)) { el->el_tty.t_ex.c_iflag = el->el_tty.t_ts.c_iflag; el->el_tty.t_ex.c_iflag &= ~el->el_tty.t_t[EX_IO][M_INP].t_clrmask; el->el_tty.t_ex.c_iflag |= el->el_tty.t_t[EX_IO][M_INP].t_setmask; el->el_tty.t_ed.c_iflag = el->el_tty.t_ts.c_iflag; el->el_tty.t_ed.c_iflag &= ~el->el_tty.t_t[ED_IO][M_INP].t_clrmask; el->el_tty.t_ed.c_iflag |= el->el_tty.t_t[ED_IO][M_INP].t_setmask; } if ((el->el_tty.t_ts.c_oflag != el->el_tty.t_ex.c_oflag) && (el->el_tty.t_ts.c_oflag != el->el_tty.t_ed.c_oflag)) { el->el_tty.t_ex.c_oflag = el->el_tty.t_ts.c_oflag; el->el_tty.t_ex.c_oflag &= ~el->el_tty.t_t[EX_IO][M_OUT].t_clrmask; el->el_tty.t_ex.c_oflag |= el->el_tty.t_t[EX_IO][M_OUT].t_setmask; el->el_tty.t_ed.c_oflag = el->el_tty.t_ts.c_oflag; el->el_tty.t_ed.c_oflag &= ~el->el_tty.t_t[ED_IO][M_OUT].t_clrmask; el->el_tty.t_ed.c_oflag |= el->el_tty.t_t[ED_IO][M_OUT].t_setmask; } 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; { int i; 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 unprotected chars * that have been modified just now. */ for (i = 0; i < C_NCC; i++) { if (!((el->el_tty.t_t[ED_IO][M_CHAR].t_setmask & C_SH(i))) && (el->el_tty.t_c[TS_IO][i] != el->el_tty.t_c[EX_IO][i])) el->el_tty.t_c[ED_IO][i] = el->el_tty.t_c[TS_IO][i]; if (el->el_tty.t_t[ED_IO][M_CHAR].t_clrmask & C_SH(i)) el->el_tty.t_c[ED_IO][i] = el->el_tty.t_vdisable; } 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++) { if (!((el->el_tty.t_t[EX_IO][M_CHAR].t_setmask & C_SH(i))) && (el->el_tty.t_c[TS_IO][i] != el->el_tty.t_c[EX_IO][i])) el->el_tty.t_c[EX_IO][i] = el->el_tty.t_c[TS_IO][i]; if (el->el_tty.t_t[EX_IO][M_CHAR].t_clrmask & C_SH(i)) el->el_tty.t_c[EX_IO][i] = el->el_tty.t_vdisable; } tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]); } } } if (tty_setty(el, &el->el_tty.t_ed) == -1) { #ifdef DEBUG_TTY (void)fprintf(el->el_errfile, "tty_rawmode: tty_setty: %s\n", strerror(errno)); #endif /* DEBUG_TTY */ return -1; } el->el_tty.t_mode = ED_IO; return (0); } /* end tty_rawmode */ /* tty_cookedmode(): * Set the tty back to normal mode */ protected int tty_cookedmode(el) EditLine *el; { /* set tty in normal setup */ if (el->el_tty.t_mode == EX_IO) return (0); if (tty_setty(el, &el->el_tty.t_ex) == -1) { #ifdef DEBUG_TTY (void)fprintf(el->el_errfile, "tty_cookedmode: tty_setty: %s\n", strerror(errno)); #endif /* DEBUG_TTY */ return -1; } el->el_tty.t_mode = EX_IO; return (0); } /* end tty_cookedmode */ /* tty_quotemode(): * Turn on quote mode */ protected int tty_quotemode(el) EditLine *el; { if (el->el_tty.t_mode == QU_IO) return 0; el->el_tty.t_qu = el->el_tty.t_ed; el->el_tty.t_qu.c_iflag &= ~el->el_tty.t_t[QU_IO][M_INP].t_clrmask; el->el_tty.t_qu.c_iflag |= el->el_tty.t_t[QU_IO][M_INP].t_setmask; el->el_tty.t_qu.c_oflag &= ~el->el_tty.t_t[QU_IO][M_OUT].t_clrmask; el->el_tty.t_qu.c_oflag |= el->el_tty.t_t[QU_IO][M_OUT].t_setmask; el->el_tty.t_qu.c_cflag &= ~el->el_tty.t_t[QU_IO][M_CTL].t_clrmask; el->el_tty.t_qu.c_cflag |= el->el_tty.t_t[QU_IO][M_CTL].t_setmask; el->el_tty.t_qu.c_lflag &= ~el->el_tty.t_t[QU_IO][M_LIN].t_clrmask; el->el_tty.t_qu.c_lflag |= el->el_tty.t_t[QU_IO][M_LIN].t_setmask; if (tty_setty(el, &el->el_tty.t_qu) == -1) { #ifdef DEBUG_TTY (void)fprintf(el->el_errfile, "QuoteModeOn: tty_setty: %s\n", strerror(errno)); #endif /* DEBUG_TTY */ return -1; } el->el_tty.t_mode = QU_IO; return 0; } /* end tty_quotemode */ /* tty_noquotemode(): * Turn off quote mode */ protected int tty_noquotemode(el) EditLine *el; { if (el->el_tty.t_mode != QU_IO) return 0; if (tty_setty(el, &el->el_tty.t_ed) == -1) { #ifdef DEBUG_TTY (void)fprintf(el->el_errfile, "QuoteModeOff: tty_setty: %s\n", strerror(errno)); #endif /* DEBUG_TTY */ return -1; } el->el_tty.t_mode = ED_IO; return 0; } /* tty_stty(): * Stty builtin */ protected int /*ARGSUSED*/ tty_stty(el, argc, argv) EditLine *el; int argc; char **argv; { ttymodes_t *m; char x, *d; int aflag = 0; char *s; char *name; int z = EX_IO; if (argv == NULL) return -1; name = *argv++; while (argv && *argv && argv[0][0] == '-' && argv[0][2] == '\0') switch (argv[0][1]) { case 'a': aflag++; argv++; break; case 'd': argv++; z = ED_IO; break; case 'x': argv++; z = EX_IO; break; case 'q': argv++; z = QU_IO; break; default: (void)fprintf(el->el_errfile, "%s: Unknown switch `%c'.\n", name, argv[0][1]); return -1; } if (!argv || !*argv) { int i = -1; int 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); } x = (el->el_tty.t_t[z][i].t_setmask & m->m_value) ? '+' : '\0'; x = (el->el_tty.t_t[z][i].t_clrmask & m->m_value) ? '-' : x; if (x != '\0' || aflag) { cu = strlen(m->m_name) + (x != '\0') + 1; if (len + cu >= el->el_term.t_size.h) { (void)fprintf(el->el_outfile, "\n%*s", 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++)) { switch (*s) { case '+': case '-': x = *s++; break; default: x = '\0'; break; } d = s; for (m = ttymodes; m->m_name; m++) if (strcmp(m->m_name, d) == 0) break; if (!m->m_name) { (void)fprintf(el->el_errfile, "%s: Invalid argument `%s'.\n", name, d); return -1; } 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; } } return 0; } /* end tty_stty */ #ifdef notyet /* tty_printchar(): * DEbugging routine to print the tty characters */ private void tty_printchar(el, s) 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 == M_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 */