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::__anon41110df00111::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   ConsoleInfo const 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