LEFT | RIGHT |
1 // Copyright 2011 The Go Authors. All rights reserved. | 1 // Copyright 2011 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 // +build linux,!appengine darwin | 5 // +build linux,!appengine darwin |
6 | 6 |
7 // Package terminal provides support functions for dealing with terminals, as | 7 // Package terminal provides support functions for dealing with terminals, as |
8 // commonly found on UNIX systems. | 8 // commonly found on UNIX systems. |
9 // | 9 // |
10 // Putting a terminal into raw mode is the most common requirement: | 10 // Putting a terminal into raw mode is the most common requirement: |
(...skipping 11 matching lines...) Expand all Loading... |
22 "unsafe" | 22 "unsafe" |
23 ) | 23 ) |
24 | 24 |
25 // State contains the state of a terminal. | 25 // State contains the state of a terminal. |
26 type State struct { | 26 type State struct { |
27 termios syscall.Termios | 27 termios syscall.Termios |
28 } | 28 } |
29 | 29 |
30 // IsTerminal returns true if the given file descriptor is a terminal. | 30 // IsTerminal returns true if the given file descriptor is a terminal. |
31 func IsTerminal(fd int) bool { | 31 func IsTerminal(fd int) bool { |
32 » _, err := tcgetattr(fd) | 32 » var termios syscall.Termios |
33 » return err == nil | 33 » _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadT
ermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0) |
| 34 » return err == 0 |
34 } | 35 } |
35 | 36 |
36 // MakeRaw put the terminal connected to the given file descriptor into raw | 37 // MakeRaw put the terminal connected to the given file descriptor into raw |
37 // mode and returns the previous state of the terminal so that it can be | 38 // mode and returns the previous state of the terminal so that it can be |
38 // restored. | 39 // restored. |
39 func MakeRaw(fd int) (*State, error) { | 40 func MakeRaw(fd int) (*State, error) { |
40 var oldState State | 41 var oldState State |
41 » termios, err := tcgetattr(fd) | 42 » if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlRe
adTermios, uintptr(unsafe.Pointer(&oldState.termios)), 0, 0, 0); err != 0 { |
42 » if err != nil { | |
43 return nil, err | 43 return nil, err |
44 } | 44 } |
45 oldState.termios = *termios | |
46 | 45 |
47 » termios.Iflag &^= syscall.ISTRIP | syscall.INLCR | syscall.ICRNL | sysca
ll.IGNCR | syscall.IXON | syscall.IXOFF | 46 » newState := oldState.termios |
48 » termios.Lflag &^= syscall.ECHO | syscall.ICANON | syscall.ISIG | 47 » newState.Iflag &^= syscall.ISTRIP | syscall.INLCR | syscall.ICRNL | sysc
all.IGNCR | syscall.IXON | syscall.IXOFF |
49 » if err := tcsetattr(fd, termios); err != nil { | 48 » newState.Lflag &^= syscall.ECHO | syscall.ICANON | syscall.ISIG |
| 49 » if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWr
iteTermios, uintptr(unsafe.Pointer(&newState)), 0, 0, 0); err != 0 { |
50 return nil, err | 50 return nil, err |
51 } | 51 } |
| 52 |
52 return &oldState, nil | 53 return &oldState, nil |
53 } | 54 } |
54 | 55 |
55 // GetState returns the current state of a terminal which may be useful to | 56 // GetState returns the current state of a terminal which may be useful to |
56 // restore the terminal after a signal. | 57 // restore the terminal after a signal. |
57 func GetState(fd int) (*State, error) { | 58 func GetState(fd int) (*State, error) { |
58 var oldState State | 59 var oldState State |
59 » termios, err := tcgetattr(fd) | 60 » if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlRe
adTermios, uintptr(unsafe.Pointer(&oldState.termios)), 0, 0, 0); err != 0 { |
60 » if err != nil { | |
61 return nil, err | 61 return nil, err |
62 } | 62 } |
63 » oldState.termios = *termios | 63 |
64 return &oldState, nil | 64 return &oldState, nil |
65 } | 65 } |
66 | 66 |
67 // Restore restores the terminal connected to the given file descriptor to a | 67 // Restore restores the terminal connected to the given file descriptor to a |
68 // previous state. | 68 // previous state. |
69 func Restore(fd int, state *State) error { | 69 func Restore(fd int, state *State) error { |
70 » return tcsetattr(fd, &state.termios) | 70 » _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWrite
Termios, uintptr(unsafe.Pointer(&state.termios)), 0, 0, 0) |
| 71 » return err |
71 } | 72 } |
72 | 73 |
73 // GetSize returns the dimensions of the given terminal. | 74 // GetSize returns the dimensions of the given terminal. |
74 func GetSize(fd int) (width, height int, err error) { | 75 func GetSize(fd int) (width, height int, err error) { |
75 var dimensions [4]uint16 | 76 var dimensions [4]uint16 |
76 | 77 |
77 if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr
(syscall.TIOCGWINSZ), uintptr(unsafe.Pointer(&dimensions)), 0, 0, 0); err != 0 { | 78 if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr
(syscall.TIOCGWINSZ), uintptr(unsafe.Pointer(&dimensions)), 0, 0, 0); err != 0 { |
78 return -1, -1, err | 79 return -1, -1, err |
79 } | 80 } |
80 return int(dimensions[1]), int(dimensions[0]), nil | 81 return int(dimensions[1]), int(dimensions[0]), nil |
81 } | 82 } |
82 | 83 |
83 // ReadPassword reads a line of input from a terminal without local echo. This | 84 // ReadPassword reads a line of input from a terminal without local echo. This |
84 // is commonly used for inputting passwords and other sensitive data. The slice | 85 // is commonly used for inputting passwords and other sensitive data. The slice |
85 // returned does not include the \n. | 86 // returned does not include the \n. |
86 func ReadPassword(fd int) ([]byte, error) { | 87 func ReadPassword(fd int) ([]byte, error) { |
87 » oldState, err := tcgetattr(fd) | 88 » var oldState syscall.Termios |
88 » if err != nil { | 89 » if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlRe
adTermios, uintptr(unsafe.Pointer(&oldState)), 0, 0, 0); err != 0 { |
89 return nil, err | 90 return nil, err |
90 } | 91 } |
91 | 92 |
92 » newState := *oldState | 93 » newState := oldState |
93 newState.Lflag &^= syscall.ECHO | 94 newState.Lflag &^= syscall.ECHO |
94 newState.Lflag |= syscall.ICANON | syscall.ISIG | 95 newState.Lflag |= syscall.ICANON | syscall.ISIG |
95 newState.Iflag |= syscall.ICRNL | 96 newState.Iflag |= syscall.ICRNL |
96 » if err := tcsetattr(fd, &newState); err != nil { | 97 » if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWr
iteTermios, uintptr(unsafe.Pointer(&newState)), 0, 0, 0); err != 0 { |
97 return nil, err | 98 return nil, err |
98 } | 99 } |
99 | 100 |
100 defer func() { | 101 defer func() { |
101 » » tcsetattr(fd, oldState) | 102 » » syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermi
os, uintptr(unsafe.Pointer(&oldState)), 0, 0, 0) |
102 }() | 103 }() |
103 | 104 |
104 var buf [16]byte | 105 var buf [16]byte |
105 var ret []byte | 106 var ret []byte |
106 for { | 107 for { |
107 n, err := syscall.Read(fd, buf[:]) | 108 n, err := syscall.Read(fd, buf[:]) |
108 if err != nil { | 109 if err != nil { |
109 return nil, err | 110 return nil, err |
110 } | 111 } |
111 if n == 0 { | 112 if n == 0 { |
112 if len(ret) == 0 { | 113 if len(ret) == 0 { |
113 return nil, io.EOF | 114 return nil, io.EOF |
114 } | 115 } |
115 break | 116 break |
116 } | 117 } |
117 if buf[n-1] == '\n' { | 118 if buf[n-1] == '\n' { |
118 n-- | 119 n-- |
119 } | 120 } |
120 ret = append(ret, buf[:n]...) | 121 ret = append(ret, buf[:n]...) |
121 if n < len(buf) { | 122 if n < len(buf) { |
122 break | 123 break |
123 } | 124 } |
124 } | 125 } |
125 | 126 |
126 return ret, nil | 127 return ret, nil |
127 } | 128 } |
LEFT | RIGHT |