1 // Copyright 2020 The Tint Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <cstring>
16
17 #include "src/diagnostic/printer.h"
18
19 #define WIN32_LEAN_AND_MEAN 1
20 #include <Windows.h>
21
22 namespace tint {
23 namespace diag {
24 namespace {
25
26 struct ConsoleInfo {
27 HANDLE handle = INVALID_HANDLE_VALUE;
28 WORD default_attributes = 0;
operator booltint::diag::__anon71a7f0ff0111::ConsoleInfo29 operator bool() const { return handle != INVALID_HANDLE_VALUE; }
30 };
31
console_info(FILE * file)32 ConsoleInfo console_info(FILE* file) {
33 if (file == nullptr) {
34 return {};
35 }
36
37 ConsoleInfo console{};
38 if (file == stdout) {
39 console.handle = GetStdHandle(STD_OUTPUT_HANDLE);
40 } else if (file == stderr) {
41 console.handle = GetStdHandle(STD_ERROR_HANDLE);
42 } else {
43 return {};
44 }
45
46 CONSOLE_SCREEN_BUFFER_INFO info{};
47 if (GetConsoleScreenBufferInfo(console.handle, &info) == 0) {
48 return {};
49 }
50
51 console.default_attributes = info.wAttributes;
52 return console;
53 }
54
55 class PrinterWindows : public Printer {
56 public:
PrinterWindows(FILE * f,bool use_colors)57 PrinterWindows(FILE* f, bool use_colors)
58 : file(f), console(console_info(use_colors ? f : nullptr)) {}
59
write(const std::string & str,const Style & style)60 void write(const std::string& str, const Style& style) override {
61 write_color(style.color, style.bold);
62 fwrite(str.data(), 1, str.size(), file);
63 write_color(Color::kDefault, false);
64 }
65
66 private:
attributes(Color color,bool bold)67 WORD attributes(Color color, bool bold) {
68 switch (color) {
69 case Color::kDefault:
70 return console.default_attributes;
71 case Color::kBlack:
72 return 0;
73 case Color::kRed:
74 return FOREGROUND_RED | (bold ? FOREGROUND_INTENSITY : 0);
75 case Color::kGreen:
76 return FOREGROUND_GREEN | (bold ? FOREGROUND_INTENSITY : 0);
77 case Color::kYellow:
78 return FOREGROUND_RED | FOREGROUND_GREEN |
79 (bold ? FOREGROUND_INTENSITY : 0);
80 case Color::kBlue:
81 return FOREGROUND_BLUE | (bold ? FOREGROUND_INTENSITY : 0);
82 case Color::kMagenta:
83 return FOREGROUND_RED | FOREGROUND_BLUE |
84 (bold ? FOREGROUND_INTENSITY : 0);
85 case Color::kCyan:
86 return FOREGROUND_GREEN | FOREGROUND_BLUE |
87 (bold ? FOREGROUND_INTENSITY : 0);
88 case Color::kWhite:
89 return FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE |
90 (bold ? FOREGROUND_INTENSITY : 0);
91 }
92 return 0; // unreachable
93 }
94
write_color(Color color,bool bold)95 void write_color(Color color, bool bold) {
96 if (console) {
97 SetConsoleTextAttribute(console.handle, attributes(color, bold));
98 fflush(file);
99 }
100 }
101
102 FILE* const file;
103 const ConsoleInfo console;
104 };
105
106 } // namespace
107
create(FILE * out,bool use_colors)108 std::unique_ptr<Printer> Printer::create(FILE* out, bool use_colors) {
109 return std::make_unique<PrinterWindows>(out, use_colors);
110 }
111
112 } // namespace diag
113 } // namespace tint
114