summaryrefslogtreecommitdiffstats
path: root/contrib/tcsh/mi.termios.c
diff options
context:
space:
mode:
authorobrien <obrien@FreeBSD.org>2000-04-15 04:41:27 +0000
committerobrien <obrien@FreeBSD.org>2000-04-15 04:41:27 +0000
commit4ad28cefef28ce6bdb44a0532cfe20a2076bc694 (patch)
tree7679c440a91912ee9586cee3ebab24596c0fe1c4 /contrib/tcsh/mi.termios.c
downloadFreeBSD-src-4ad28cefef28ce6bdb44a0532cfe20a2076bc694.zip
FreeBSD-src-4ad28cefef28ce6bdb44a0532cfe20a2076bc694.tar.gz
Import the latest version of the 44BSD C-shell -- tcsh-6.09.
Diffstat (limited to 'contrib/tcsh/mi.termios.c')
-rw-r--r--contrib/tcsh/mi.termios.c393
1 files changed, 393 insertions, 0 deletions
diff --git a/contrib/tcsh/mi.termios.c b/contrib/tcsh/mi.termios.c
new file mode 100644
index 0000000..b4834b6
--- /dev/null
+++ b/contrib/tcsh/mi.termios.c
@@ -0,0 +1,393 @@
+/* $Header: /src/pub/tcsh/mi.termios.c,v 1.3 1996/04/26 19:18:38 christos Exp $ */
+/* termios.c - fake termios interface using sgtty interface
+ * by Magnus Doell and Bruce Evans.
+ *
+ */
+#include "sh.h"
+RCSID("$Id: mi.termios.c,v 1.3 1996/04/26 19:18:38 christos Exp $")
+
+#ifdef _MINIX
+
+
+/* Undefine everything that clashes with sgtty.h. */
+#undef B0
+#undef B50
+#undef B75
+#undef B110
+#undef B134
+#undef B150
+#undef B200
+#undef B300
+#undef B600
+#undef B1200
+#undef B1800
+#undef B2400
+#undef B4800
+#undef B9600
+#undef B19200
+#undef B28800
+#undef B38400
+#undef B57600
+#undef B115200
+/* Do not #undef CRMOD. We want a warning when they differ! */
+#undef ECHO
+/* Do not #undef XTABS. We want a warning when they differ! */
+
+/* Redefine some of the termios.h names just undefined with 'T_' prefixed
+ * to the name. Don't bother with the low speeds - Minix does not support
+ * them. Add support for higher speeds (speeds are now easy and don't need
+ * defines because they are not encoded).
+ */
+#define T_ECHO 000001
+
+#include <errno.h>
+#include <sgtty.h>
+
+static _PROTOTYPE( int tc_to_sg_speed, (speed_t speed) );
+static _PROTOTYPE( speed_t sg_to_tc_speed, (int speed) );
+#define B19200 192
+
+/* The speed get/set functions could be macros in the Minix implementation
+ * because there are speed fields in the structure with no fancy packing
+ * and it is not practical to check the values outside the driver.
+ * Where tests are necessary because the driver acts different from what
+ * POSIX requires, they are done in tcsetattr.
+ */
+
+speed_t cfgetispeed(termios_p)
+struct termios *termios_p;
+{
+ return termios_p->c_ispeed;
+}
+
+speed_t cfgetospeed(termios_p)
+struct termios *termios_p;
+{
+ return termios_p->c_ospeed;
+}
+
+speed_t cfsetispeed(termios_p, speed)
+struct termios *termios_p;
+speed_t speed;
+{
+ termios_p->c_ispeed = speed;
+ return 0;
+}
+
+speed_t cfsetospeed(termios_p, speed)
+struct termios *termios_p;
+speed_t speed;
+{
+ termios_p->c_ospeed = speed;
+ return 0;
+}
+
+static speed_t sg_to_tc_speed(speed)
+int speed;
+{
+ /* The speed encodings in sgtty.h and termios.h are different. Both are
+ * inflexible. Minix doesn't really support B0 but we map it through
+ * anyway. It doesn't support B50, B75 or B134.
+ */
+ switch (speed) {
+ case B0: return 0;
+ case B110: return 110;
+ case B200: return 200;
+ case B300: return 300;
+ case B600: return 600;
+ case B1200: return 1200;
+ case B1800: return 1800;
+ case B2400: return 2400;
+ case B4800: return 4800;
+ case B9600: return 9600;
+ case B19200: return 19200;
+#ifdef B28800
+ case B28800: return 28800;
+#endif
+#ifdef B38400
+ case B38400: return 38400;
+#endif
+#ifdef B57600
+ case B57600: return 57600;
+#endif
+#ifdef B115200
+ case B115200: return 115200;
+#endif
+ default: return (speed_t)-1;
+ }
+}
+
+static int tc_to_sg_speed(speed)
+speed_t speed;
+{
+ /* Don't use a switch here in case the compiler is 16-bit and doesn't
+ * properly support longs (speed_t's) in switches. It turns out the
+ * switch is larger and slower for most compilers anyway!
+ */
+ if (speed == 0) return 0;
+ if (speed == 110) return B110;
+ if (speed == 200) return B200;
+ if (speed == 300) return B300;
+ if (speed == 600) return B600;
+ if (speed == 1200) return B1200;
+ if (speed == 1800) return B1800;
+ if (speed == 2400) return B2400;
+ if (speed == 4800) return B4800;
+ if (speed == 9600) return B9600;
+ if (speed == 19200) return B19200;
+#ifdef B28800
+ if (speed == 28800) return B28800;
+#endif
+#ifdef B38400
+ if (speed == 38400) return B38400;
+#endif
+#ifdef B57600
+ if (speed == 57600) return B57600;
+#endif
+#ifdef B115200
+ if (speed == 115200) return B115200;
+#endif
+ return -1;
+}
+
+int tcgetattr(filedes, termios_p)
+int filedes;
+struct termios *termios_p;
+{
+ struct sgttyb sgbuf;
+ struct tchars tcbuf;
+
+ if (ioctl(filedes, TIOCGETP, &sgbuf) < 0
+ || ioctl(filedes, TIOCGETC, (struct sgttyb *) &tcbuf) < 0)
+ {
+ return -1;
+ }
+
+ /* Minix input flags:
+ * BRKINT: forced off (break is not recognized)
+ * IGNBRK: forced on (break is not recognized)
+ * ICRNL: set if CRMOD is set and not RAW (CRMOD also controls output)
+ * IGNCR: forced off (ignoring cr's is not supported)
+ * INLCR: forced off (mapping nl's to cr's is not supported)
+ * ISTRIP: forced off (should be off for consoles, on for rs232 no RAW)
+ * IXOFF: forced off (rs232 uses CTS instead of XON/XOFF)
+ * IXON: forced on if not RAW
+ * PARMRK: forced off (no '\377', '\0', X sequence on errors)
+ * ? IGNPAR: forced off (input with parity/framing errors is kept)
+ * ? INPCK: forced off (input parity checking is not supported)
+ */
+ termios_p->c_iflag = IGNBRK;
+ if (!(sgbuf.sg_flags & RAW))
+ {
+ termios_p->c_iflag |= IXON;
+ if (sgbuf.sg_flags & CRMOD)
+ {
+ termios_p->c_iflag |= ICRNL;
+ }
+ }
+
+ /* Minix output flags:
+ * OPOST: set if CRMOD or XTABS is set
+ * XTABS: copied from sg_flags
+ * CRMOD: copied from sg_flags
+ */
+ termios_p->c_oflag = sgbuf.sg_flags & (CRMOD | XTABS);
+ if (termios_p->c_oflag)
+ {
+ termios_p->c_oflag |= OPOST;
+ }
+
+ /* Minix local flags:
+ * ECHO: set if ECHO is set
+ * ECHOE: set if ECHO is set (ERASE echoed as error-corecting backspace)
+ * ECHOK: set if ECHO is set ('\n' echoed after KILL char)
+ * ECHONL: forced off ('\n' not echoed when ECHO isn't set)
+ * ICANON: set if neither CBREAK nor RAW
+ * IEXTEN: forced off
+ * ISIG: set if not RAW
+ * NOFLSH: forced off (input/output queues are always flushed)
+ * TOSTOP: forced off (no job control)
+ */
+ termios_p->c_lflag = 0;
+ if (sgbuf.sg_flags & ECHO)
+ {
+ termios_p->c_lflag |= T_ECHO | ECHOE | ECHOK;
+ }
+ if (!(sgbuf.sg_flags & RAW))
+ {
+ termios_p->c_lflag |= ISIG;
+ if (!(sgbuf.sg_flags & CBREAK))
+ {
+ termios_p->c_lflag |= ICANON;
+ }
+ }
+
+ /* Minix control flags:
+ * CLOCAL: forced on (ignore modem status lines - not quite right)
+ * CREAD: forced on (receiver is always enabled)
+ * CSIZE: CS5-CS8 correspond directly to BITS5-BITS8
+ * CSTOPB: set for B110 (driver will generate 2 stop-bits than)
+ * HUPCL: forced off
+ * PARENB: set if EVENP or ODDP is set
+ * PARODD: set if ODDP is set
+ */
+ termios_p->c_cflag = CLOCAL | CREAD;
+ switch (sgbuf.sg_flags & BITS8)
+ {
+ case BITS5: termios_p->c_cflag |= CS5; break;
+ case BITS6: termios_p->c_cflag |= CS6; break;
+ case BITS7: termios_p->c_cflag |= CS7; break;
+ case BITS8: termios_p->c_cflag |= CS8; break;
+ }
+ if (sgbuf.sg_flags & ODDP)
+ {
+ termios_p->c_cflag |= PARENB | PARODD;
+ }
+ if (sgbuf.sg_flags & EVENP)
+ {
+ termios_p->c_cflag |= PARENB;
+ }
+ if (sgbuf.sg_ispeed == B110)
+ {
+ termios_p->c_cflag |= CSTOPB;
+ }
+
+ /* Minix may give back different input and output baudrates,
+ * but only the input baudrate is valid for both.
+ * As our termios emulation will fail, if input baudrate differs
+ * from output baudrate, force them to be equal.
+ * Otherwise it would be very suprisingly not to be able to set
+ * the terminal back to the state returned by tcgetattr :).
+ */
+ termios_p->c_ospeed =
+ termios_p->c_ispeed =
+ sg_to_tc_speed((unsigned char) sgbuf.sg_ispeed);
+
+ /* Minix control characters correspond directly except VSUSP and the
+ * important VMIN and VTIME are not really supported.
+ */
+ termios_p->c_cc[VEOF] = tcbuf.t_eofc;
+ termios_p->c_cc[VEOL] = tcbuf.t_brkc;
+ termios_p->c_cc[VERASE] = sgbuf.sg_erase;
+ termios_p->c_cc[VINTR] = tcbuf.t_intrc;
+ termios_p->c_cc[VKILL] = sgbuf.sg_kill;
+ termios_p->c_cc[VQUIT] = tcbuf.t_quitc;
+ termios_p->c_cc[VSTART] = tcbuf.t_startc;
+ termios_p->c_cc[VSTOP] = tcbuf.t_stopc;
+ termios_p->c_cc[VMIN] = 1;
+ termios_p->c_cc[VTIME] = 0;
+ termios_p->c_cc[VSUSP] = 0;
+
+ return 0;
+}
+
+int tcsetattr(filedes, opt_actions, termios_p)
+int filedes;
+int opt_actions;
+struct termios *termios_p;
+{
+ struct sgttyb sgbuf;
+ struct tchars tcbuf;
+ int sgspeed;
+
+ /* Posix 1003.1-1988 page 135 says:
+ * Attempts to set unsupported baud rates shall be ignored, and it is
+ * implementation-defined whether an error is returned by any or all of
+ * cfsetispeed(), cfsetospeed(), or tcsetattr(). This refers both to
+ * changes to baud rates not supported by the hardware, and to changes
+ * setting the input and output baud rates to different values if the
+ * hardware does not support it.
+ * Ignoring means not to change the existing settings, doesn't it?
+ */
+ if ((termios_p->c_ispeed != 0 && termios_p->c_ispeed != termios_p->c_ospeed)
+ || (sgspeed = tc_to_sg_speed(termios_p->c_ospeed)) < 0)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ sgbuf.sg_ispeed = sgbuf.sg_ospeed = sgspeed;
+ sgbuf.sg_flags = 0;
+
+ /* I don't know what should happen with requests that are not supported by
+ * old Minix drivers and therefore cannot be emulated.
+ * Returning an error may confuse the application (the values aren't really
+ * invalid or unsupported by the hardware, they just couldn't be satisfied
+ * by the driver). Not returning an error might be even worse because the
+ * driver will act different to what the application requires it to act
+ * after sucessfully setting the attributes as specified.
+ * Settings that cannot be emulated fully include:
+ * c_ospeed != 110 && c_cflag & CSTOPB
+ * c_ospeed == 110 && ! c_cflag & CSTOPB
+ * (c_cc[VMIN] != 1 || c_cc[VTIME] != 0) && ! c_lflag & ICANON
+ * c_lflag & ICANON && ! c_lflag & ISIG
+ * For the moment I just ignore these conflicts.
+ */
+
+ if (termios_p->c_oflag & OPOST)
+ {
+ /* CRMOD isn't Posix and may conflict with ICRNL, which is Posix,
+ * so we just ignore it.
+ */
+ if (termios_p->c_oflag & XTABS)
+ {
+ sgbuf.sg_flags |= XTABS;
+ }
+ }
+
+ if (termios_p->c_iflag & ICRNL)
+ {
+ /* We couldn't do it better :-(. */
+ sgbuf.sg_flags |= CRMOD;
+ }
+
+ if (termios_p->c_lflag & T_ECHO)
+ {
+ sgbuf.sg_flags |= ECHO;
+ }
+ if (!(termios_p->c_lflag & ICANON))
+ {
+ if (termios_p->c_lflag & ISIG)
+ {
+ sgbuf.sg_flags |= CBREAK;
+ }
+ else
+ {
+ sgbuf.sg_flags |= RAW;
+ }
+ }
+
+ switch (termios_p->c_cflag & CSIZE)
+ {
+ case CS5: sgbuf.sg_flags |= BITS5; break;
+ case CS6: sgbuf.sg_flags |= BITS6; break;
+ case CS7: sgbuf.sg_flags |= BITS7; break;
+ case CS8: sgbuf.sg_flags |= BITS8; break;
+ }
+ if (termios_p->c_cflag & PARENB)
+ {
+ if (termios_p->c_cflag & PARODD)
+ {
+ sgbuf.sg_flags |= ODDP;
+ }
+ else
+ {
+ sgbuf.sg_flags |= EVENP;
+ }
+ }
+
+ sgbuf.sg_erase = termios_p->c_cc[VERASE];
+ sgbuf.sg_kill = termios_p->c_cc[VKILL];
+
+ tcbuf.t_intrc = termios_p->c_cc[VINTR];
+ tcbuf.t_quitc = termios_p->c_cc[VQUIT];
+ tcbuf.t_startc = termios_p->c_cc[VSTART];
+ tcbuf.t_stopc = termios_p->c_cc[VSTOP];
+ tcbuf.t_eofc = termios_p->c_cc[VEOF];
+ tcbuf.t_brkc = termios_p->c_cc[VEOL];
+
+ return ioctl(filedes, TIOCSETP, &sgbuf) < 0 &&
+ ioctl(filedes, TIOCSETC, (struct sgttyb *) &tcbuf) < 0 ?
+ -1 : 0;
+}
+#endif /* _MINIX */
OpenPOWER on IntegriCloud