1 /*************************************************************************/
2 /* windows_terminal_logger.cpp */
3 /*************************************************************************/
4 /* This file is part of: */
5 /* GODOT ENGINE */
6 /* https://godotengine.org */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
9 /* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
10 /* */
11 /* Permission is hereby granted, free of charge, to any person obtaining */
12 /* a copy of this software and associated documentation files (the */
13 /* "Software"), to deal in the Software without restriction, including */
14 /* without limitation the rights to use, copy, modify, merge, publish, */
15 /* distribute, sublicense, and/or sell copies of the Software, and to */
16 /* permit persons to whom the Software is furnished to do so, subject to */
17 /* the following conditions: */
18 /* */
19 /* The above copyright notice and this permission notice shall be */
20 /* included in all copies or substantial portions of the Software. */
21 /* */
22 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
25 /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26 /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29 /*************************************************************************/
30
31 #include "windows_terminal_logger.h"
32
33 #ifdef WINDOWS_ENABLED
34
35 #include <stdio.h>
36 #include <windows.h>
37
logv(const char * p_format,va_list p_list,bool p_err)38 void WindowsTerminalLogger::logv(const char *p_format, va_list p_list, bool p_err) {
39 if (!should_log(p_err)) {
40 return;
41 }
42
43 const unsigned int BUFFER_SIZE = 16384;
44 char buf[BUFFER_SIZE + 1]; // +1 for the terminating character
45 int len = vsnprintf(buf, BUFFER_SIZE, p_format, p_list);
46 if (len <= 0)
47 return;
48 if ((unsigned int)len >= BUFFER_SIZE)
49 len = BUFFER_SIZE; // Output is too big, will be truncated
50 buf[len] = 0;
51
52 int wlen = MultiByteToWideChar(CP_UTF8, 0, buf, len, NULL, 0);
53 if (wlen < 0)
54 return;
55
56 wchar_t *wbuf = (wchar_t *)malloc((len + 1) * sizeof(wchar_t));
57 MultiByteToWideChar(CP_UTF8, 0, buf, len, wbuf, wlen);
58 wbuf[wlen] = 0;
59
60 if (p_err)
61 fwprintf(stderr, L"%ls", wbuf);
62 else
63 wprintf(L"%ls", wbuf);
64
65 free(wbuf);
66
67 #ifdef DEBUG_ENABLED
68 fflush(stdout);
69 #endif
70 }
71
log_error(const char * p_function,const char * p_file,int p_line,const char * p_code,const char * p_rationale,ErrorType p_type)72 void WindowsTerminalLogger::log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type) {
73 if (!should_log(true)) {
74 return;
75 }
76
77 #ifndef UWP_ENABLED
78 HANDLE hCon = GetStdHandle(STD_OUTPUT_HANDLE);
79 if (!hCon || hCon == INVALID_HANDLE_VALUE) {
80 #endif
81 StdLogger::log_error(p_function, p_file, p_line, p_code, p_rationale, p_type);
82 #ifndef UWP_ENABLED
83 } else {
84
85 CONSOLE_SCREEN_BUFFER_INFO sbi; //original
86 GetConsoleScreenBufferInfo(hCon, &sbi);
87
88 WORD current_fg = sbi.wAttributes & (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
89 WORD current_bg = sbi.wAttributes & (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY);
90
91 uint32_t basecol = 0;
92 switch (p_type) {
93 case ERR_ERROR: basecol = FOREGROUND_RED; break;
94 case ERR_WARNING: basecol = FOREGROUND_RED | FOREGROUND_GREEN; break;
95 case ERR_SCRIPT: basecol = FOREGROUND_RED | FOREGROUND_BLUE; break;
96 case ERR_SHADER: basecol = FOREGROUND_GREEN | FOREGROUND_BLUE; break;
97 }
98
99 basecol |= current_bg;
100
101 if (p_rationale && p_rationale[0]) {
102
103 SetConsoleTextAttribute(hCon, basecol | FOREGROUND_INTENSITY);
104 switch (p_type) {
105 case ERR_ERROR: logf("ERROR: "); break;
106 case ERR_WARNING: logf("WARNING: "); break;
107 case ERR_SCRIPT: logf("SCRIPT ERROR: "); break;
108 case ERR_SHADER: logf("SHADER ERROR: "); break;
109 }
110
111 SetConsoleTextAttribute(hCon, current_fg | current_bg | FOREGROUND_INTENSITY);
112 logf("%s\n", p_rationale);
113
114 SetConsoleTextAttribute(hCon, basecol);
115 switch (p_type) {
116 case ERR_ERROR: logf(" At: "); break;
117 case ERR_WARNING: logf(" At: "); break;
118 case ERR_SCRIPT: logf(" At: "); break;
119 case ERR_SHADER: logf(" At: "); break;
120 }
121
122 SetConsoleTextAttribute(hCon, current_fg | current_bg);
123 logf("%s:%i\n", p_file, p_line);
124
125 } else {
126
127 SetConsoleTextAttribute(hCon, basecol | FOREGROUND_INTENSITY);
128 switch (p_type) {
129 case ERR_ERROR: logf("ERROR: %s: ", p_function); break;
130 case ERR_WARNING: logf("WARNING: %s: ", p_function); break;
131 case ERR_SCRIPT: logf("SCRIPT ERROR: %s: ", p_function); break;
132 case ERR_SHADER: logf("SCRIPT ERROR: %s: ", p_function); break;
133 }
134
135 SetConsoleTextAttribute(hCon, current_fg | current_bg | FOREGROUND_INTENSITY);
136 logf("%s\n", p_code);
137
138 SetConsoleTextAttribute(hCon, basecol);
139 switch (p_type) {
140 case ERR_ERROR: logf(" At: "); break;
141 case ERR_WARNING: logf(" At: "); break;
142 case ERR_SCRIPT: logf(" At: "); break;
143 case ERR_SHADER: logf(" At: "); break;
144 }
145
146 SetConsoleTextAttribute(hCon, current_fg | current_bg);
147 logf("%s:%i\n", p_file, p_line);
148 }
149
150 SetConsoleTextAttribute(hCon, sbi.wAttributes);
151 }
152 #endif
153 }
154
~WindowsTerminalLogger()155 WindowsTerminalLogger::~WindowsTerminalLogger() {}
156
157 #endif
158