Use termios via CGO

Signed-off-by: Yohei Ueda <yohei@jp.ibm.com>
This commit is contained in:
Yohei Ueda 2014-11-21 22:12:03 +09:00
parent bfe8d7af74
commit 92251ceb7b
6 changed files with 75 additions and 6 deletions

View file

@ -47,8 +47,7 @@ func SetWinsize(fd uintptr, ws *Winsize) error {
// IsTerminal returns true if the given file descriptor is a terminal. // IsTerminal returns true if the given file descriptor is a terminal.
func IsTerminal(fd uintptr) bool { func IsTerminal(fd uintptr) bool {
var termios Termios var termios Termios
_, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(getTermios), uintptr(unsafe.Pointer(&termios))) return tcget(fd, &termios) == 0
return err == 0
} }
// Restore restores the terminal connected to the given file descriptor to a // 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 { if state == nil {
return ErrInvalidState return ErrInvalidState
} }
_, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(setTermios), uintptr(unsafe.Pointer(&state.termios))) if err := tcset(fd, &state.termios); err != 0 {
if err != 0 {
return err return err
} }
return nil return nil
@ -66,7 +64,7 @@ func RestoreTerminal(fd uintptr, state *State) error {
func SaveState(fd uintptr) (*State, error) { func SaveState(fd uintptr) (*State, error) {
var oldState State 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 return nil, err
} }
@ -77,7 +75,7 @@ func DisableEcho(fd uintptr, state *State) error {
newState := state.termios newState := state.termios
newState.Lflag &^= syscall.ECHO 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 return err
} }
handleInterrupt(fd, state) handleInterrupt(fd, state)

47
term/term_cgo.go Normal file
View file

@ -0,0 +1,47 @@
// +build !windows,cgo
package term
import (
"syscall"
"unsafe"
)
// #include <termios.h>
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
}

18
term/term_nocgo.go Normal file
View file

@ -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
}

View file

@ -1,3 +1,5 @@
// +build !cgo
package term package term
import ( import (

View file

@ -1,3 +1,5 @@
// +build !cgo
package term package term
import ( import (

View file

@ -1,3 +1,5 @@
// +build !cgo
package term package term
import ( import (