text: // +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])))
  }
  