|
|
@@ -4,12 +4,30 @@
|
|
|
package isatty
|
|
|
|
|
|
import (
|
|
|
+ "strings"
|
|
|
"syscall"
|
|
|
+ "unicode/utf16"
|
|
|
"unsafe"
|
|
|
)
|
|
|
|
|
|
-var kernel32 = syscall.NewLazyDLL("kernel32.dll")
|
|
|
-var procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
|
|
|
+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 {
|
|
|
@@ -17,3 +35,60 @@ func IsTerminal(fd uintptr) bool {
|
|
|
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])))
|
|
|
+}
|