From 244af451e9bdff5c87bca84e4c15193fc9eebc64 Mon Sep 17 00:00:00 2001 From: Yohei Ueda Date: Fri, 21 Nov 2014 22:12:03 +0900 Subject: [PATCH] Use termios via CGO Signed-off-by: Yohei Ueda --- pkg/term/term.go | 10 ++++---- pkg/term/term_cgo.go | 47 +++++++++++++++++++++++++++++++++++++ pkg/term/term_nocgo.go | 18 ++++++++++++++ pkg/term/termios_darwin.go | 2 ++ pkg/term/termios_freebsd.go | 2 ++ pkg/term/termios_linux.go | 2 ++ 6 files changed, 75 insertions(+), 6 deletions(-) create mode 100644 pkg/term/term_cgo.go create mode 100644 pkg/term/term_nocgo.go diff --git a/pkg/term/term.go b/pkg/term/term.go index 553747a7a0..8d807d8d44 100644 --- a/pkg/term/term.go +++ b/pkg/term/term.go @@ -47,8 +47,7 @@ func SetWinsize(fd uintptr, ws *Winsize) error { // IsTerminal returns true if the given file descriptor is a terminal. func IsTerminal(fd uintptr) bool { var termios Termios - _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(getTermios), uintptr(unsafe.Pointer(&termios))) - return err == 0 + return tcget(fd, &termios) == 0 } // Restore restores the terminal connected to the given file descriptor to a @@ -57,8 +56,7 @@ func RestoreTerminal(fd uintptr, state *State) error { if state == nil { return ErrInvalidState } - _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(setTermios), uintptr(unsafe.Pointer(&state.termios))) - if err != 0 { + if err := tcset(fd, &state.termios); err != 0 { return err } return nil @@ -66,7 +64,7 @@ func RestoreTerminal(fd uintptr, state *State) error { func SaveState(fd uintptr) (*State, error) { var oldState State - if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, getTermios, uintptr(unsafe.Pointer(&oldState.termios))); err != 0 { + if err := tcget(fd, &oldState.termios); err != 0 { return nil, err } @@ -77,7 +75,7 @@ func DisableEcho(fd uintptr, state *State) error { newState := state.termios newState.Lflag &^= syscall.ECHO - if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, setTermios, uintptr(unsafe.Pointer(&newState))); err != 0 { + if err := tcset(fd, &newState); err != 0 { return err } handleInterrupt(fd, state) diff --git a/pkg/term/term_cgo.go b/pkg/term/term_cgo.go new file mode 100644 index 0000000000..ddf080cf93 --- /dev/null +++ b/pkg/term/term_cgo.go @@ -0,0 +1,47 @@ +// +build !windows,cgo + +package term + +import ( + "syscall" + "unsafe" +) + +// #include +import "C" + +type Termios syscall.Termios + +// MakeRaw put the terminal connected to the given file descriptor into raw +// mode and returns the previous state of the terminal so that it can be +// restored. +func MakeRaw(fd uintptr) (*State, error) { + var oldState State + if err := tcget(fd, &oldState.termios); err != 0 { + return nil, err + } + + newState := oldState.termios + + C.cfmakeraw((*C.struct_termios)(unsafe.Pointer(&newState))) + if err := tcset(fd, &newState); err != 0 { + return nil, err + } + return &oldState, nil +} + +func tcget(fd uintptr, p *Termios) syscall.Errno { + ret, err := C.tcgetattr(C.int(fd), (*C.struct_termios)(unsafe.Pointer(p))) + if ret != 0 { + return err.(syscall.Errno) + } + return 0 +} + +func tcset(fd uintptr, p *Termios) syscall.Errno { + ret, err := C.tcsetattr(C.int(fd), C.TCSANOW, (*C.struct_termios)(unsafe.Pointer(p))) + if ret != 0 { + return err.(syscall.Errno) + } + return 0 +} diff --git a/pkg/term/term_nocgo.go b/pkg/term/term_nocgo.go new file mode 100644 index 0000000000..c211c3992d --- /dev/null +++ b/pkg/term/term_nocgo.go @@ -0,0 +1,18 @@ +// +build !windows,!cgo + +package term + +import ( + "syscall" + "unsafe" +) + +func tcget(fd uintptr, p *Termios) syscall.Errno { + _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(getTermios), uintptr(unsafe.Pointer(p))) + return err +} + +func tcset(fd uintptr, p *Termios) syscall.Errno { + _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, setTermios, uintptr(unsafe.Pointer(p))) + return err +} diff --git a/pkg/term/termios_darwin.go b/pkg/term/termios_darwin.go index 11cd70d10b..2640e8b935 100644 --- a/pkg/term/termios_darwin.go +++ b/pkg/term/termios_darwin.go @@ -1,3 +1,5 @@ +// +build !cgo + package term import ( diff --git a/pkg/term/termios_freebsd.go b/pkg/term/termios_freebsd.go index ed3659572c..969beda239 100644 --- a/pkg/term/termios_freebsd.go +++ b/pkg/term/termios_freebsd.go @@ -1,3 +1,5 @@ +// +build !cgo + package term import ( diff --git a/pkg/term/termios_linux.go b/pkg/term/termios_linux.go index 4a717c84a7..024187ff06 100644 --- a/pkg/term/termios_linux.go +++ b/pkg/term/termios_linux.go @@ -1,3 +1,5 @@ +// +build !cgo + package term import (