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