aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/mattn/go-isatty/isatty_windows.go
blob: af51cbcaa4853196e055d1ca1c2eb34a440b6918 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
// +build windows
// +build !appengine

package isatty

import (
    "strings"
    "syscall"
    "unicode/utf16"
    "unsafe"
)

const (
    fileNameInfo uintptr = 2
    fileTypePipe         = 3
)

var (
    kernel32                         = syscall.NewLazyDLL("kernel32.dll")
    procGetConsoleMode               = kernel32.NewProc("GetConsoleMode")
    procGetFileInformationByHandleEx = kernel32.NewProc("GetFileInformationByHandleEx")
    procGetFileType                  = kernel32.NewProc("GetFileType")
)

func init() {
    // Check if GetFileInformationByHandleEx is available.
    if procGetFileInformationByHandleEx.Find() != nil {
        procGetFileInformationByHandleEx = nil
    }
}

// IsTerminal return true if the file descriptor is terminal.
func IsTerminal(fd uintptr) bool {
    var st uint32
    r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, fd, uintptr(unsafe.Pointer(&st)), 0)
    return r != 0 && e == 0
}

// Check pipe name is used for cygwin/msys2 pty.
// Cygwin/MSYS2 PTY has a name like:
//   \{cygwin,msys}-XXXXXXXXXXXXXXXX-ptyN-{from,to}-master
func isCygwinPipeName(name string) bool {
    token := strings.Split(name, "-")
    if len(token) < 5 {
        return false
    }

    if token[0] != `\msys` && token[0] != `\cygwin` {
        return false
    }

    if token[1] == "" {
        return false
    }

    if !strings.HasPrefix(token[2], "pty") {
        return false
    }

    if token[3] != `from` && token[3] != `to` {
        return false
    }

    if token[4] != "master" {
        return false
    }

    return true
}

// IsCygwinTerminal() return true if the file descriptor is a cygwin or msys2
// terminal.
func IsCygwinTerminal(fd uintptr) bool {
    if procGetFileInformationByHandleEx == nil {
        return false
    }

    // Cygwin/msys's pty is a pipe.
    ft, _, e := syscall.Syscall(procGetFileType.Addr(), 1, fd, 0, 0)
    if ft != fileTypePipe || e != 0 {
        return false
    }

    var buf [2 + syscall.MAX_PATH]uint16
    r, _, e := syscall.Syscall6(procGetFileInformationByHandleEx.Addr(),
        4, fd, fileNameInfo, uintptr(unsafe.Pointer(&buf)),
        uintptr(len(buf)*2), 0, 0)
    if r == 0 || e != 0 {
        return false
    }

    l := *(*uint32)(unsafe.Pointer(&buf))
    return isCygwinPipeName(string(utf16.Decode(buf[2 : 2+l/2])))
}