commit e76aa414d7f0cbdda05099fb115add36d4c88cc1
parent 62eaaea9e212f077edc212047a3d5743f96dd1d3
Author: Alexey Yerin <yyp@disroot.org>
Date: Mon, 1 Nov 2021 12:29:09 +0300
unix::tty: add initial termios support
Signed-off-by: Alexey Yerin <yyp@disroot.org>
Diffstat:
4 files changed, 219 insertions(+), 0 deletions(-)
diff --git a/rt/+linux/types.ha b/rt/+linux/types.ha
@@ -576,7 +576,163 @@ export type winsize = struct {
ws_ypixel: u16,
};
+export type termios = struct {
+ c_iflag: tcflag,
+ c_oflag: tcflag,
+ c_cflag: tcflag,
+ c_lflag: tcflag,
+ c_line: cc,
+ c_cc: [NCCS]cc,
+};
+
+export def NCCS: size = 19;
+
+export type cc = enum char {
+ VINTR = 0,
+ VQUIT = 1,
+ VERASE = 2,
+ VKILL = 3,
+ VEOF = 4,
+ VTIME = 5,
+ VMIN = 6,
+ VSWTC = 7,
+ VSTART = 8,
+ VSTOP = 9,
+ VSUSP = 10,
+ VEOL = 11,
+ VREPRINT = 12,
+ VDISCARD = 13,
+ VWERASE = 14,
+ VLNEXT = 15,
+ VEOL2 = 16,
+};
+
+export type tcflag = enum uint {
+ // c_iflag bit meaning
+ IGNBRK = 0o00001,
+ BRKINT = 0o00002,
+ IGNPAR = 0o00004,
+ PARMRK = 0o00010,
+ INPCK = 0o00020,
+ ISTRIP = 0o00040,
+ INLCR = 0o00100,
+ IGNCR = 0o00200,
+ ICRNL = 0o00400,
+ IUCLC = 0o01000,
+ IXON = 0o02000,
+ IXANY = 0o04000,
+ IXOFF = 0o10000,
+ IMAXBEL = 0o20000,
+ IUTF8 = 0o40000,
+
+ // c_oflag bit meaning
+ OPOST = 0o000001,
+ OLCUC = 0o000002,
+ ONLCR = 0o000004,
+ OCRNL = 0o000010,
+ ONOCR = 0o000020,
+ ONLRET = 0o000040,
+ OFILL = 0o000100,
+ OFDEL = 0o000200,
+ NLDLY = 0o000400,
+ NL0 = 0o000000,
+ NL1 = 0o000400,
+ CRDLY = 0o003000,
+ CR0 = 0o000000,
+ CR1 = 0o001000,
+ CR2 = 0o002000,
+ CR3 = 0o003000,
+ TABDLY = 0o014000,
+ TAB0 = 0o000000,
+ TAB1 = 0o004000,
+ TAB2 = 0o010000,
+ TAB3 = 0o014000,
+ XTABS = 0o014000,
+ BSDLY = 0o020000,
+ BS0 = 0o000000,
+ BS1 = 0o020000,
+ VTDLY = 0o040000,
+ VT0 = 0o000000,
+ VT1 = 0o040000,
+ FFDLY = 0o100000,
+ FF0 = 0o000000,
+ FF1 = 0o100000,
+
+ // c_cflag bit meaning
+ CBAUD = 0o010017,
+ B0 = 0o000000,
+ B50 = 0o000001,
+ B75 = 0o000002,
+ B110 = 0o000003,
+ B134 = 0o000004,
+ B150 = 0o000005,
+ B200 = 0o000006,
+ B300 = 0o000007,
+ B600 = 0o000010,
+ B1200 = 0o000011,
+ B1800 = 0o000012,
+ B2400 = 0o000013,
+ B4800 = 0o000014,
+ B9600 = 0o000015,
+ B19200 = 0o000016,
+ B38400 = 0o000017,
+ EXTA = B19200,
+ EXTB = B38400,
+ CSIZE = 0o000060,
+ CS5 = 0o000000,
+ CS6 = 0o000020,
+ CS7 = 0o000040,
+ CS8 = 0o000060,
+ CSTOPB = 0o000100,
+ CREAD = 0o000200,
+ PARENB = 0o000400,
+ PARODD = 0o001000,
+ HUPCL = 0o002000,
+ CLOCAL = 0o004000,
+ CBAUDEX = 0o010000,
+ BOTHER = 0o010000,
+ B57600 = 0o010001,
+ B115200 = 0o010002,
+ B230400 = 0o010003,
+ B460800 = 0o010004,
+ B500000 = 0o010005,
+ B576000 = 0o010006,
+ B921600 = 0o010007,
+ B1000000 = 0o010010,
+ B1152000 = 0o010011,
+ B1500000 = 0o010012,
+ B2000000 = 0o010013,
+ B2500000 = 0o010014,
+ B3000000 = 0o010015,
+ B3500000 = 0o010016,
+ B4000000 = 0o010017,
+ CIBAUD = 0o02003600000,
+ CMSPAR = 0o10000000000,
+ CRTSCTS = 0o20000000000,
+
+ // c_lflag bit meaning
+ ISIG = 0o000001,
+ ICANON = 0o000002,
+ XCASE = 0o000004,
+ ECHO = 0o000010,
+ ECHOE = 0o000020,
+ ECHOK = 0o000040,
+ ECHONL = 0o000100,
+ NOFLSH = 0o000200,
+ TOSTOP = 0o000400,
+ ECHOCTL = 0o001000,
+ ECHOPRT = 0o002000,
+ ECHOKE = 0o004000,
+ FLUSHO = 0o010000,
+ PENDIN = 0o040000,
+ IEXTEN = 0o100000,
+ EXTPROC = 0o200000,
+};
+
+
export def TIOCGWINSZ: u64 = 0x5413;
+export def TCGETS: u64 = 0x5401;
+export def TCSETS: u64 = 0x5402;
export def MLOCK_ONFAULT: uint = 0x01;
diff --git a/scripts/gen-stdlib b/scripts/gen-stdlib
@@ -1005,6 +1005,7 @@ unix_tty() {
types.ha \
+linux/isatty.ha \
+linux/open.ha \
+ +linux/termios.ha \
+linux/winsize.ha
gen_ssa -plinux unix::tty rt fs io os
diff --git a/stdlib.mk b/stdlib.mk
@@ -1590,6 +1590,7 @@ stdlib_unix_tty_linux_srcs= \
$(STDLIB)/unix/tty/types.ha \
$(STDLIB)/unix/tty/+linux/isatty.ha \
$(STDLIB)/unix/tty/+linux/open.ha \
+ $(STDLIB)/unix/tty/+linux/termios.ha \
$(STDLIB)/unix/tty/+linux/winsize.ha
$(HARECACHE)/unix/tty/unix_tty-linux.ssa: $(stdlib_unix_tty_linux_srcs) $(stdlib_rt) $(stdlib_rt_$(PLATFORM)) $(stdlib_fs_$(PLATFORM)) $(stdlib_io_$(PLATFORM)) $(stdlib_os_$(PLATFORM))
@@ -3251,6 +3252,7 @@ testlib_unix_tty_linux_srcs= \
$(STDLIB)/unix/tty/types.ha \
$(STDLIB)/unix/tty/+linux/isatty.ha \
$(STDLIB)/unix/tty/+linux/open.ha \
+ $(STDLIB)/unix/tty/+linux/termios.ha \
$(STDLIB)/unix/tty/+linux/winsize.ha
$(TESTCACHE)/unix/tty/unix_tty-linux.ssa: $(testlib_unix_tty_linux_srcs) $(testlib_rt) $(testlib_rt_$(PLATFORM)) $(testlib_fs_$(PLATFORM)) $(testlib_io_$(PLATFORM)) $(testlib_os_$(PLATFORM))
diff --git a/unix/tty/+linux/termios.ha b/unix/tty/+linux/termios.ha
@@ -0,0 +1,60 @@
+use io;
+use rt;
+use errors;
+
+export type termios = struct {
+ file: io::file,
+ saved: rt::termios,
+ current: rt::termios,
+};
+
+// Retrieves serial port settings of the given terminal.
+export fn termios_query(file: io::file) (termios | errors::error) = {
+ let settings = rt::termios { ... };
+
+ match (rt::ioctl(file, rt::TCGETS, &settings)) {
+ case int => void;
+ case err: rt::errno =>
+ return errors::errno(err);
+ };
+
+ return termios {
+ file = file,
+ saved = settings,
+ current = settings,
+ };
+};
+
+// Restores original serial port settings.
+export fn termios_restore(termios: *const termios) void = {
+ rt::ioctl(termios.file, rt::TCSETS, &termios.saved): void;
+};
+
+// Sets serial port settings.
+export fn termios_set(termios: *const termios) (void | errors::error) = {
+ match (rt::ioctl(termios.file, rt::TCSETS, &termios.current)) {
+ case int => void;
+ case err: rt::errno =>
+ return errors::errno(err);
+ };
+};
+
+// Enables "raw" mode for this terminal, disabling echoing, line
+// editing, and signal handling. Users should call [[termios_query]]
+// prior to this to save the previous terminal settings, and
+// [[termios_restore]] to restore them before exiting.
+export fn makeraw(termios: *termios) (void | errors::error) = {
+ // Disable break signal and CR<->LF processing
+ termios.current.c_iflag &= ~(rt::tcflag::IGNBRK | rt::tcflag::BRKINT
+ | rt::tcflag::INLCR | rt::tcflag::IGNCR
+ | rt::tcflag::ICRNL);
+ // Disable output post-processing
+ termios.current.c_oflag &= ~rt::tcflag::OPOST;
+ // Disable character echo, canonical mode, implementation defined
+ // extensions and INTR/QUIT/SUSP characters
+ termios.current.c_lflag &= ~(rt::tcflag::ECHO | rt::tcflag::ECHONL
+ | rt::tcflag::ICANON | rt::tcflag::IEXTEN
+ | rt::tcflag::ISIG);
+
+ termios_set(termios)?;
+};