1// +build windows
2
3package flags
4
5import (
6	"syscall"
7	"unsafe"
8)
9
10type (
11	SHORT int16
12	WORD  uint16
13
14	SMALL_RECT struct {
15		Left   SHORT
16		Top    SHORT
17		Right  SHORT
18		Bottom SHORT
19	}
20
21	COORD struct {
22		X SHORT
23		Y SHORT
24	}
25
26	CONSOLE_SCREEN_BUFFER_INFO struct {
27		Size              COORD
28		CursorPosition    COORD
29		Attributes        WORD
30		Window            SMALL_RECT
31		MaximumWindowSize COORD
32	}
33)
34
35var kernel32DLL = syscall.NewLazyDLL("kernel32.dll")
36var getConsoleScreenBufferInfoProc = kernel32DLL.NewProc("GetConsoleScreenBufferInfo")
37
38func getError(r1, r2 uintptr, lastErr error) error {
39	// If the function fails, the return value is zero.
40	if r1 == 0 {
41		if lastErr != nil {
42			return lastErr
43		}
44		return syscall.EINVAL
45	}
46	return nil
47}
48
49func getStdHandle(stdhandle int) (uintptr, error) {
50	handle, err := syscall.GetStdHandle(stdhandle)
51	if err != nil {
52		return 0, err
53	}
54	return uintptr(handle), nil
55}
56
57// GetConsoleScreenBufferInfo retrieves information about the specified console screen buffer.
58// http://msdn.microsoft.com/en-us/library/windows/desktop/ms683171(v=vs.85).aspx
59func GetConsoleScreenBufferInfo(handle uintptr) (*CONSOLE_SCREEN_BUFFER_INFO, error) {
60	var info CONSOLE_SCREEN_BUFFER_INFO
61	if err := getError(getConsoleScreenBufferInfoProc.Call(handle, uintptr(unsafe.Pointer(&info)), 0)); err != nil {
62		return nil, err
63	}
64	return &info, nil
65}
66
67func getTerminalColumns() int {
68	defaultWidth := 80
69
70	stdoutHandle, err := getStdHandle(syscall.STD_OUTPUT_HANDLE)
71	if err != nil {
72		return defaultWidth
73	}
74
75	info, err := GetConsoleScreenBufferInfo(stdoutHandle)
76	if err != nil {
77		return defaultWidth
78	}
79
80	if info.MaximumWindowSize.X > 0 {
81		return int(info.MaximumWindowSize.X)
82	}
83
84	return defaultWidth
85}
86