aboutsummaryrefslogtreecommitdiffstats
path: root/src/libs/3rdparty/winpty/misc/TestUtil.cc
blob: c832a12b858219583ce5f557af28b3da38c87f48 (plain)
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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
// This file is included into test programs using #include

#include <windows.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <wchar.h>
#include <vector>
#include <string>

#include "../src/shared/DebugClient.h"
#include "../src/shared/TimeMeasurement.h"

#include "../src/shared/DebugClient.cc"
#include "../src/shared/WinptyAssert.cc"
#include "../src/shared/WinptyException.cc"

// Launch this test program again, in a new console that we will destroy.
static void startChildProcess(const wchar_t *args) {
    wchar_t program[1024];
    wchar_t cmdline[1024];
    GetModuleFileNameW(NULL, program, 1024);
    swprintf(cmdline, L"\"%ls\" %ls", program, args);

    STARTUPINFOW sui;
    PROCESS_INFORMATION pi;
    memset(&sui, 0, sizeof(sui));
    memset(&pi, 0, sizeof(pi));
    sui.cb = sizeof(sui);

    CreateProcessW(program, cmdline,
                   NULL, NULL,
                   /*bInheritHandles=*/FALSE,
                   /*dwCreationFlags=*/CREATE_NEW_CONSOLE,
                   NULL, NULL,
                   &sui, &pi);
}

static void setBufferSize(HANDLE conout, int x, int y) {
    COORD size = { static_cast<SHORT>(x), static_cast<SHORT>(y) };
    BOOL success = SetConsoleScreenBufferSize(conout, size);
    trace("setBufferSize: (%d,%d), result=%d", x, y, success);
}

static void setWindowPos(HANDLE conout, int x, int y, int w, int h) {
    SMALL_RECT r = {
        static_cast<SHORT>(x), static_cast<SHORT>(y),
        static_cast<SHORT>(x + w - 1),
        static_cast<SHORT>(y + h - 1)
    };
    BOOL success = SetConsoleWindowInfo(conout, /*bAbsolute=*/TRUE, &r);
    trace("setWindowPos: (%d,%d,%d,%d), result=%d", x, y, w, h, success);
}

static void setCursorPos(HANDLE conout, int x, int y) {
    COORD coord = { static_cast<SHORT>(x), static_cast<SHORT>(y) };
    SetConsoleCursorPosition(conout, coord);
}

static void setBufferSize(int x, int y) {
    setBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), x, y);
}

static void setWindowPos(int x, int y, int w, int h) {
    setWindowPos(GetStdHandle(STD_OUTPUT_HANDLE), x, y, w, h);
}

static void setCursorPos(int x, int y) {
    setCursorPos(GetStdHandle(STD_OUTPUT_HANDLE), x, y);
}

static void countDown(int sec) {
    for (int i = sec; i > 0; --i) {
        printf("%d.. ", i);
        fflush(stdout);
        Sleep(1000);
    }
    printf("\n");
}

static void writeBox(int x, int y, int w, int h, char ch, int attributes=7) {
    CHAR_INFO info = { 0 };
    info.Char.AsciiChar = ch;
    info.Attributes = attributes;
    std::vector<CHAR_INFO> buf(w * h, info);
    HANDLE conout = GetStdHandle(STD_OUTPUT_HANDLE);
    COORD bufSize = { static_cast<SHORT>(w), static_cast<SHORT>(h) };
    COORD bufCoord = { 0, 0 };
    SMALL_RECT writeRegion = {
        static_cast<SHORT>(x),
        static_cast<SHORT>(y),
        static_cast<SHORT>(x + w - 1),
        static_cast<SHORT>(y + h - 1)
    };
    WriteConsoleOutputA(conout, buf.data(), bufSize, bufCoord, &writeRegion);
}

static void setChar(int x, int y, char ch, int attributes=7) {
    writeBox(x, y, 1, 1, ch, attributes);
}

static void fillChar(int x, int y, int repeat, char ch) {
    COORD coord = { static_cast<SHORT>(x), static_cast<SHORT>(y) };
    DWORD actual = 0;
    FillConsoleOutputCharacterA(
        GetStdHandle(STD_OUTPUT_HANDLE),
        ch, repeat, coord, &actual);
}

static void repeatChar(int count, char ch) {
    for (int i = 0; i < count; ++i) {
        putchar(ch);
    }
    fflush(stdout);
}

// I don't know why, but wprintf fails to print this face name,
// "MS ゴシック" (aka MS Gothic).  It helps to use wprintf instead of printf, and
// it helps to call `setlocale(LC_ALL, "")`, but the Japanese symbols are
// ultimately converted to `?` symbols, even though MS Gothic is able to
// display its own name, and the current code page is 932 (Shift-JIS).
static void cvfprintf(HANDLE conout, const wchar_t *fmt, va_list ap) {
    wchar_t buffer[256];
    vswprintf(buffer, 256 - 1, fmt, ap);
    buffer[255] = L'\0';
    DWORD actual = 0;
    if (!WriteConsoleW(conout, buffer, wcslen(buffer), &actual, NULL)) {
        wprintf(L"WriteConsoleW call failed!\n");
    }
}

static void cfprintf(HANDLE conout, const wchar_t *fmt, ...) {
    va_list ap;
    va_start(ap, fmt);
    cvfprintf(conout, fmt, ap);
    va_end(ap);
}

static void cprintf(const wchar_t *fmt, ...) {
    va_list ap;
    va_start(ap, fmt);
    cvfprintf(GetStdHandle(STD_OUTPUT_HANDLE), fmt, ap);
    va_end(ap);
}

static std::string narrowString(const std::wstring &input)
{
    int mblen = WideCharToMultiByte(
        CP_UTF8, 0,
        input.data(), input.size(),
        NULL, 0, NULL, NULL);
    if (mblen <= 0) {
        return std::string();
    }
    std::vector<char> tmp(mblen);
    int mblen2 = WideCharToMultiByte(
        CP_UTF8, 0,
        input.data(), input.size(),
        tmp.data(), tmp.size(),
        NULL, NULL);
    assert(mblen2 == mblen);
    return std::string(tmp.data(), tmp.size());
}

HANDLE openConout() {
    const HANDLE conout = CreateFileW(L"CONOUT$",
                                      GENERIC_READ | GENERIC_WRITE,
                                      FILE_SHARE_READ | FILE_SHARE_WRITE,
                                      NULL, OPEN_EXISTING, 0, NULL);
    ASSERT(conout != INVALID_HANDLE_VALUE);
    return conout;
}