OSDN Git Service

delete miner
[bytom/vapor.git] / vendor / github.com / go-kit / kit / log / term / terminal_windows.go
1 // Based on ssh/terminal:
2 // Copyright 2011 The Go Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style
4 // license that can be found in the LICENSE file.
5
6 // +build windows
7
8 package term
9
10 import (
11         "encoding/binary"
12         "io"
13         "regexp"
14         "syscall"
15         "unsafe"
16 )
17
18 var kernel32 = syscall.NewLazyDLL("kernel32.dll")
19
20 var (
21         procGetFileInformationByHandleEx = kernel32.NewProc("GetFileInformationByHandleEx")
22         msysPipeNameRegex                = regexp.MustCompile(`\\(cygwin|msys)-\w+-pty\d?-(to|from)-master`)
23 )
24
25 const (
26         fileNameInfo = 0x02
27 )
28
29 // IsTerminal returns true if w writes to a terminal.
30 func IsTerminal(w io.Writer) bool {
31         return IsConsole(w) || IsMSYSTerminal(w)
32 }
33
34 // IsConsole returns true if w writes to a Windows console.
35 func IsConsole(w io.Writer) bool {
36         var handle syscall.Handle
37
38         if fw, ok := w.(fder); ok {
39                 handle = syscall.Handle(fw.Fd())
40         } else {
41                 // The writer has no file-descriptor and so can't be a terminal.
42                 return false
43         }
44
45         var st uint32
46         err := syscall.GetConsoleMode(handle, &st)
47
48         // If the handle is attached to a terminal, GetConsoleMode returns a
49         // non-zero value containing the console mode flags. We don't care about
50         // the specifics of flags, just that it is not zero.
51         return (err == nil && st != 0)
52 }
53
54 // IsMSYSTerminal returns true if w writes to a MSYS/MSYS2 terminal.
55 func IsMSYSTerminal(w io.Writer) bool {
56         var handle syscall.Handle
57
58         if fw, ok := w.(fder); ok {
59                 handle = syscall.Handle(fw.Fd())
60         } else {
61                 // The writer has no file-descriptor and so can't be a terminal.
62                 return false
63         }
64
65         // MSYS(2) terminal reports as a pipe for STDIN/STDOUT/STDERR. If it isn't
66         // a pipe, it can't be a MSYS(2) terminal.
67         filetype, err := syscall.GetFileType(handle)
68
69         if filetype != syscall.FILE_TYPE_PIPE || err != nil {
70                 return false
71         }
72
73         // MSYS2/Cygwin terminal's name looks like: \msys-dd50a72ab4668b33-pty2-to-master
74         data := make([]byte, 256, 256)
75
76         r, _, e := syscall.Syscall6(
77                 procGetFileInformationByHandleEx.Addr(),
78                 4,
79                 uintptr(handle),
80                 uintptr(fileNameInfo),
81                 uintptr(unsafe.Pointer(&data[0])),
82                 uintptr(len(data)),
83                 0,
84                 0,
85         )
86
87         if r != 0 && e == 0 {
88                 // The first 4 bytes of the buffer are the size of the UTF16 name, in bytes.
89                 unameLen := binary.LittleEndian.Uint32(data[:4]) / 2
90                 uname := make([]uint16, unameLen, unameLen)
91
92                 for i := uint32(0); i < unameLen; i++ {
93                         uname[i] = binary.LittleEndian.Uint16(data[i*2+4 : i*2+2+4])
94                 }
95
96                 name := syscall.UTF16ToString(uname)
97
98                 return msysPipeNameRegex.MatchString(name)
99         }
100
101         return false
102 }