...
1
2
3
4
5
6
7
8
9 package term
10
11 import (
12 "encoding/binary"
13 "io"
14 "regexp"
15 "syscall"
16 "unsafe"
17 )
18
19 var kernel32 = syscall.NewLazyDLL("kernel32.dll")
20
21 var (
22 procGetFileInformationByHandleEx = kernel32.NewProc("GetFileInformationByHandleEx")
23 msysPipeNameRegex = regexp.MustCompile(`\\(cygwin|msys)-\w+-pty\d?-(to|from)-master`)
24 )
25
26 const (
27 fileNameInfo = 0x02
28 )
29
30
31 func IsTerminal(w io.Writer) bool {
32 return IsConsole(w) || IsMSYSTerminal(w)
33 }
34
35
36 func IsConsole(w io.Writer) bool {
37 var handle syscall.Handle
38
39 if fw, ok := w.(fder); ok {
40 handle = syscall.Handle(fw.Fd())
41 } else {
42
43 return false
44 }
45
46 var st uint32
47 err := syscall.GetConsoleMode(handle, &st)
48
49
50
51
52 return (err == nil && st != 0)
53 }
54
55
56 func IsMSYSTerminal(w io.Writer) bool {
57 var handle syscall.Handle
58
59 if fw, ok := w.(fder); ok {
60 handle = syscall.Handle(fw.Fd())
61 } else {
62
63 return false
64 }
65
66
67
68 filetype, err := syscall.GetFileType(handle)
69
70 if filetype != syscall.FILE_TYPE_PIPE || err != nil {
71 return false
72 }
73
74
75 data := make([]byte, 256)
76
77 r, _, e := syscall.Syscall6(
78 procGetFileInformationByHandleEx.Addr(),
79 4,
80 uintptr(handle),
81 uintptr(fileNameInfo),
82 uintptr(unsafe.Pointer(&data[0])),
83 uintptr(len(data)),
84 0,
85 0,
86 )
87
88 if r != 0 && e == 0 {
89
90 unameLen := binary.LittleEndian.Uint32(data[:4]) / 2
91 uname := make([]uint16, unameLen)
92
93 for i := uint32(0); i < unameLen; i++ {
94 uname[i] = binary.LittleEndian.Uint16(data[i*2+4 : i*2+2+4])
95 }
96
97 name := syscall.UTF16ToString(uname)
98
99 return msysPipeNameRegex.MatchString(name)
100 }
101
102 return false
103 }
104
View as plain text