hare

The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

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:
Mrt/+linux/types.ha | 156+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mscripts/gen-stdlib | 1+
Mstdlib.mk | 2++
Aunix/tty/+linux/termios.ha | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
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)?; +};