Sfoglia il codice sorgente

Use termios via CGO

Signed-off-by: Yohei Ueda <yohei@jp.ibm.com>
Yohei Ueda 10 anni fa
parent
commit
244af451e9

+ 4 - 6
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)

+ 47 - 0
pkg/term/term_cgo.go

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

+ 2 - 0
pkg/term/termios_darwin.go

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

+ 2 - 0
pkg/term/termios_freebsd.go

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

+ 2 - 0
pkg/term/termios_linux.go

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