Browse code

Use termios via CGO

Signed-off-by: Yohei Ueda <yohei@jp.ibm.com>

Yohei Ueda authored on 2014/11/21 22:12:03
Showing 6 changed files
... ...
@@ -47,8 +47,7 @@ func SetWinsize(fd uintptr, ws *Winsize) error {
47 47
 // IsTerminal returns true if the given file descriptor is a terminal.
48 48
 func IsTerminal(fd uintptr) bool {
49 49
 	var termios Termios
50
-	_, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(getTermios), uintptr(unsafe.Pointer(&termios)))
51
-	return err == 0
50
+	return tcget(fd, &termios) == 0
52 51
 }
53 52
 
54 53
 // Restore restores the terminal connected to the given file descriptor to a
... ...
@@ -57,8 +56,7 @@ func RestoreTerminal(fd uintptr, state *State) error {
57 57
 	if state == nil {
58 58
 		return ErrInvalidState
59 59
 	}
60
-	_, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(setTermios), uintptr(unsafe.Pointer(&state.termios)))
61
-	if err != 0 {
60
+	if err := tcset(fd, &state.termios); err != 0 {
62 61
 		return err
63 62
 	}
64 63
 	return nil
... ...
@@ -66,7 +64,7 @@ func RestoreTerminal(fd uintptr, state *State) error {
66 66
 
67 67
 func SaveState(fd uintptr) (*State, error) {
68 68
 	var oldState State
69
-	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, getTermios, uintptr(unsafe.Pointer(&oldState.termios))); err != 0 {
69
+	if err := tcget(fd, &oldState.termios); err != 0 {
70 70
 		return nil, err
71 71
 	}
72 72
 
... ...
@@ -77,7 +75,7 @@ func DisableEcho(fd uintptr, state *State) error {
77 77
 	newState := state.termios
78 78
 	newState.Lflag &^= syscall.ECHO
79 79
 
80
-	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, setTermios, uintptr(unsafe.Pointer(&newState))); err != 0 {
80
+	if err := tcset(fd, &newState); err != 0 {
81 81
 		return err
82 82
 	}
83 83
 	handleInterrupt(fd, state)
84 84
new file mode 100644
... ...
@@ -0,0 +1,47 @@
0
+// +build !windows,cgo
1
+
2
+package term
3
+
4
+import (
5
+	"syscall"
6
+	"unsafe"
7
+)
8
+
9
+// #include <termios.h>
10
+import "C"
11
+
12
+type Termios syscall.Termios
13
+
14
+// MakeRaw put the terminal connected to the given file descriptor into raw
15
+// mode and returns the previous state of the terminal so that it can be
16
+// restored.
17
+func MakeRaw(fd uintptr) (*State, error) {
18
+	var oldState State
19
+	if err := tcget(fd, &oldState.termios); err != 0 {
20
+		return nil, err
21
+	}
22
+
23
+	newState := oldState.termios
24
+
25
+	C.cfmakeraw((*C.struct_termios)(unsafe.Pointer(&newState)))
26
+	if err := tcset(fd, &newState); err != 0 {
27
+		return nil, err
28
+	}
29
+	return &oldState, nil
30
+}
31
+
32
+func tcget(fd uintptr, p *Termios) syscall.Errno {
33
+	ret, err := C.tcgetattr(C.int(fd), (*C.struct_termios)(unsafe.Pointer(p)))
34
+	if ret != 0 {
35
+		return err.(syscall.Errno)
36
+	}
37
+	return 0
38
+}
39
+
40
+func tcset(fd uintptr, p *Termios) syscall.Errno {
41
+	ret, err := C.tcsetattr(C.int(fd), C.TCSANOW, (*C.struct_termios)(unsafe.Pointer(p)))
42
+	if ret != 0 {
43
+		return err.(syscall.Errno)
44
+	}
45
+	return 0
46
+}
0 47
new file mode 100644
... ...
@@ -0,0 +1,18 @@
0
+// +build !windows,!cgo
1
+
2
+package term
3
+
4
+import (
5
+	"syscall"
6
+	"unsafe"
7
+)
8
+
9
+func tcget(fd uintptr, p *Termios) syscall.Errno {
10
+	_, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(getTermios), uintptr(unsafe.Pointer(p)))
11
+	return err
12
+}
13
+
14
+func tcset(fd uintptr, p *Termios) syscall.Errno {
15
+	_, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, setTermios, uintptr(unsafe.Pointer(p)))
16
+	return err
17
+}
... ...
@@ -1,3 +1,5 @@
1
+// +build !cgo
2
+
1 3
 package term
2 4
 
3 5
 import (
... ...
@@ -1,3 +1,5 @@
1
+// +build !cgo
2
+
1 3
 package term
2 4
 
3 5
 import (
... ...
@@ -1,3 +1,5 @@
1
+// +build !cgo
2
+
1 3
 package term
2 4
 
3 5
 import (