tinybox
testing posix compliant
138cea346f3e238ce43c41add3ce104a7c735d65
SM <seb.michalk@gmail.com>
2025-09-24 08:29:33 +0000
tinybox/fdset_posix.go | 32 ++++++++++++++++++++++++++++++++ tinybox/select_bsd.go | 16 ++++++++++++++++ tinybox/select_linux.go | 9 +++++++++ tinybox/tb.go | 48 ++++++++++++++++-------------------------------- tinybox/termios_bsd.go | 27 +++++++++++++++++++++++++++ tinybox/termios_linux.go | 27 +++++++++++++++++++++++++++ 6 files changed, 127 insertions(+), 32 deletions(-) diff --git a/tinybox/fdset_posix.go b/tinybox/fdset_posix.go new file mode 100644 index 0000000..b9e50e0 --- /dev/null +++ b/tinybox/fdset_posix.go @@ -0,0 +1,32 @@ +//go:build linux || darwin || freebsd || netbsd || openbsd || dragonfly + +package tb + +import ( + "syscall" + "unsafe" +) + +func setFd(set *syscall.FdSet, fd int) { + if fd < 0 { + return + } + bytes := unsafe.Slice((*byte)(unsafe.Pointer(set)), int(unsafe.Sizeof(*set))) + idx := fd / 8 + if idx >= len(bytes) { + return + } + bytes[idx] |= 1 << (uint(fd) % 8) +} + +func fdIsSet(set *syscall.FdSet, fd int) bool { + if fd < 0 { + return false + } + bytes := unsafe.Slice((*byte)(unsafe.Pointer(set)), int(unsafe.Sizeof(*set))) + idx := fd / 8 + if idx >= len(bytes) { + return false + } + return bytes[idx]&(1<<(uint(fd)%8)) != 0 +} diff --git a/tinybox/select_bsd.go b/tinybox/select_bsd.go new file mode 100644 index 0000000..f8decbc --- /dev/null +++ b/tinybox/select_bsd.go @@ -0,0 +1,16 @@ +//go:build darwin || freebsd || netbsd || openbsd || dragonfly + +package tb + +import "syscall" + +func selectRead(fd int, set *syscall.FdSet, tv *syscall.Timeval) (int, error) { + err := syscall.Select(fd+1, set, nil, nil, tv) + if err != nil { + return 0, err + } + if fdIsSet(set, fd) { + return 1, nil + } + return 0, nil +} diff --git a/tinybox/select_linux.go b/tinybox/select_linux.go new file mode 100644 index 0000000..37f92d9 --- /dev/null +++ b/tinybox/select_linux.go @@ -0,0 +1,9 @@ +//go:build linux + +package tb + +import "syscall" + +func selectRead(fd int, set *syscall.FdSet, tv *syscall.Timeval) (int, error) { + return syscall.Select(fd+1, set, nil, nil, tv) +} diff --git a/tinybox/tb.go b/tinybox/tb.go index 22535c2..70f9a39 100644 --- a/tinybox/tb.go +++ b/tinybox/tb.go @@ -36,26 +36,6 @@ import ( ) const ( - TCGETS = 0x5401 - TCSETS = 0x5402 - TIOCGWINSZ = 0x5413 - ICANON = 0x2 - ECHO = 0x8 - ISIG = 0x1 - IEXTEN = 0x8000 - BRKINT = 0x2 - ICRNL = 0x100 - INPCK = 0x10 - ISTRIP = 0x20 - IXON = 0x400 - OPOST = 0x1 - CS8 = 0x30 - VMIN = 6 - VTIME = 5 - F_GETFL = 3 - F_SETFL = 4 - O_NONBLOCK = 0x800 - ESC = "\033" BEL = "\x07" @@ -112,12 +92,7 @@ var ( resetColorSeq = []byte(ResetColor) ) -type termios struct { - Iflag, Oflag, Cflag, Lflag uint32 - Line uint8 - Cc [32]uint8 - Ispeed, Ospeed uint32 -} +type termios = syscall.Termios type winsize struct { Row, Col, Xpixel, Ypixel uint16 @@ -288,10 +263,13 @@ func queryTermSize() (int, int, error) { fd := int(syscall.Stdin) fdSet := &syscall.FdSet{} - fdSet.Bits[fd/64] |= 1 << (uint(fd) % 64) + setFd(fdSet, fd) tv := syscall.Timeval{Sec: 1, Usec: 0} - n := syscall.Select(fd+1, fdSet, nil, nil, &tv) + n, err := selectRead(fd, fdSet, &tv) + if err != nil { + return 80, 24, err + } if n <= 0 { return 80, 24, fmt.Errorf("timeout") } @@ -672,14 +650,17 @@ func PollEventTimeout(timeout time.Duration) (Event, error) { fd := int(syscall.Stdin) fdSet := &syscall.FdSet{} - fdSet.Bits[fd/64] |= 1 << (uint(fd) % 64) + setFd(fdSet, fd) tv := syscall.Timeval{ Sec: int64(timeout / time.Second), Usec: int64((timeout % time.Second) / time.Microsecond), } - n := syscall.Select(fd+1, fdSet, nil, nil, &tv) + n, err := selectRead(fd, fdSet, &tv) + if err != nil { + return Event{}, err + } if n <= 0 { return Event{}, fmt.Errorf("timeout") } @@ -1071,10 +1052,13 @@ func GetCursorPos() (x, y int) { fd := int(syscall.Stdin) fdSet := &syscall.FdSet{} - fdSet.Bits[fd/64] |= 1 << (uint(fd) % 64) + setFd(fdSet, fd) tv := syscall.Timeval{Sec: 1, Usec: 0} // 1 second timeout - n := syscall.Select(fd+1, fdSet, nil, nil, &tv) + n, err := selectRead(fd, fdSet, &tv) + if err != nil { + return 0, 0 + } if n <= 0 { return 0, 0 } diff --git a/tinybox/termios_bsd.go b/tinybox/termios_bsd.go new file mode 100644 index 0000000..59ccf0d --- /dev/null +++ b/tinybox/termios_bsd.go @@ -0,0 +1,27 @@ +//go:build darwin || freebsd || netbsd || openbsd || dragonfly + +package tb + +import "syscall" + +const ( + TCGETS = syscall.TIOCGETA + TCSETS = syscall.TIOCSETA + TIOCGWINSZ = syscall.TIOCGWINSZ + ICANON = syscall.ICANON + ECHO = syscall.ECHO + ISIG = syscall.ISIG + IEXTEN = syscall.IEXTEN + BRKINT = syscall.BRKINT + ICRNL = syscall.ICRNL + INPCK = syscall.INPCK + ISTRIP = syscall.ISTRIP + IXON = syscall.IXON + OPOST = syscall.OPOST + CS8 = syscall.CS8 + VMIN = syscall.VMIN + VTIME = syscall.VTIME + F_GETFL = syscall.F_GETFL + F_SETFL = syscall.F_SETFL + O_NONBLOCK = syscall.O_NONBLOCK +) diff --git a/tinybox/termios_linux.go b/tinybox/termios_linux.go new file mode 100644 index 0000000..3b56cb3 --- /dev/null +++ b/tinybox/termios_linux.go @@ -0,0 +1,27 @@ +//go:build linux + +package tb + +import "syscall" + +const ( + TCGETS = syscall.TCGETS + TCSETS = syscall.TCSETS + TIOCGWINSZ = syscall.TIOCGWINSZ + ICANON = syscall.ICANON + ECHO = syscall.ECHO + ISIG = syscall.ISIG + IEXTEN = syscall.IEXTEN + BRKINT = syscall.BRKINT + ICRNL = syscall.ICRNL + INPCK = syscall.INPCK + ISTRIP = syscall.ISTRIP + IXON = syscall.IXON + OPOST = syscall.OPOST + CS8 = syscall.CS8 + VMIN = syscall.VMIN + VTIME = syscall.VTIME + F_GETFL = syscall.F_GETFL + F_SETFL = syscall.F_SETFL + O_NONBLOCK = syscall.O_NONBLOCK +)