blob: 7a336307e505c3753e31b19792a3137e166e0cc5 [file] [log] [blame]
David K. Bainbridge215e0242017-09-05 23:18:24 -07001// 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,!appengine
7
8package logrus
9
10import (
11 "bytes"
12 "errors"
13 "io"
14 "os"
15 "os/exec"
16 "strconv"
17 "strings"
18 "syscall"
19 "unsafe"
20)
21
22var kernel32 = syscall.NewLazyDLL("kernel32.dll")
23
24var (
25 procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
26 procSetConsoleMode = kernel32.NewProc("SetConsoleMode")
27)
28
29const (
30 enableProcessedOutput = 0x0001
31 enableWrapAtEolOutput = 0x0002
32 enableVirtualTerminalProcessing = 0x0004
33)
34
35func getVersion() (float64, error) {
36 stdout, stderr := &bytes.Buffer{}, &bytes.Buffer{}
37 cmd := exec.Command("cmd", "ver")
38 cmd.Stdout = stdout
39 cmd.Stderr = stderr
40 err := cmd.Run()
41 if err != nil {
42 return -1, err
43 }
44
45 // The output should be like "Microsoft Windows [Version XX.X.XXXXXX]"
46 version := strings.Replace(stdout.String(), "\n", "", -1)
47 version = strings.Replace(version, "\r\n", "", -1)
48
49 x1 := strings.Index(version, "[Version")
50
51 if x1 == -1 || strings.Index(version, "]") == -1 {
52 return -1, errors.New("Can't determine Windows version")
53 }
54
55 return strconv.ParseFloat(version[x1+9:x1+13], 64)
56}
57
58func init() {
59 ver, err := getVersion()
60 if err != nil {
61 return
62 }
63
64 // Activate Virtual Processing for Windows CMD
65 // Info: https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx
66 if ver >= 10 {
67 handle := syscall.Handle(os.Stderr.Fd())
68 procSetConsoleMode.Call(uintptr(handle), enableProcessedOutput|enableWrapAtEolOutput|enableVirtualTerminalProcessing)
69 }
70}
71
72// IsTerminal returns true if stderr's file descriptor is a terminal.
73func IsTerminal(f io.Writer) bool {
74 switch v := f.(type) {
75 case *os.File:
76 var st uint32
77 r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(v.Fd()), uintptr(unsafe.Pointer(&st)), 0)
78 return r != 0 && e == 0
79 default:
80 return false
81 }
82}