Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/core/string/print_string.cpp
9903 views
1
/**************************************************************************/
2
/* print_string.cpp */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
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 "print_string.h"
32
33
#include "core/core_globals.h"
34
#include "core/os/os.h"
35
36
static PrintHandlerList *print_handler_list = nullptr;
37
static thread_local bool is_printing = false;
38
39
static void __print_fallback(const String &p_string, bool p_err) {
40
fprintf(p_err ? stderr : stdout, "While attempting to print a message, another message was printed:\n%s\n", p_string.utf8().get_data());
41
}
42
43
void add_print_handler(PrintHandlerList *p_handler) {
44
_global_lock();
45
p_handler->next = print_handler_list;
46
print_handler_list = p_handler;
47
_global_unlock();
48
}
49
50
void remove_print_handler(const PrintHandlerList *p_handler) {
51
_global_lock();
52
53
PrintHandlerList *prev = nullptr;
54
PrintHandlerList *l = print_handler_list;
55
56
while (l) {
57
if (l == p_handler) {
58
if (prev) {
59
prev->next = l->next;
60
} else {
61
print_handler_list = l->next;
62
}
63
break;
64
}
65
prev = l;
66
l = l->next;
67
}
68
//OS::get_singleton()->print("print handler list is %p\n",print_handler_list);
69
70
_global_unlock();
71
ERR_FAIL_NULL(l);
72
}
73
74
void __print_line(const String &p_string) {
75
if (!CoreGlobals::print_line_enabled) {
76
return;
77
}
78
79
if (is_printing) {
80
__print_fallback(p_string, false);
81
return;
82
}
83
84
is_printing = true;
85
86
OS::get_singleton()->print("%s\n", p_string.utf8().get_data());
87
88
_global_lock();
89
PrintHandlerList *l = print_handler_list;
90
while (l) {
91
l->printfunc(l->userdata, p_string, false, false);
92
l = l->next;
93
}
94
95
_global_unlock();
96
97
is_printing = false;
98
}
99
100
void __print_line_rich(const String &p_string) {
101
if (!CoreGlobals::print_line_enabled) {
102
return;
103
}
104
105
// Convert a subset of BBCode tags to ANSI escape codes for correct display in the terminal.
106
// Support of those ANSI escape codes varies across terminal emulators,
107
// especially for italic and strikethrough.
108
109
String output;
110
int pos = 0;
111
while (pos <= p_string.length()) {
112
int brk_pos = p_string.find_char('[', pos);
113
114
if (brk_pos < 0) {
115
brk_pos = p_string.length();
116
}
117
118
String txt = brk_pos > pos ? p_string.substr(pos, brk_pos - pos) : "";
119
if (brk_pos == p_string.length()) {
120
output += txt;
121
break;
122
}
123
124
int brk_end = p_string.find_char(']', brk_pos + 1);
125
126
if (brk_end == -1) {
127
txt += p_string.substr(brk_pos);
128
output += txt;
129
break;
130
}
131
pos = brk_end + 1;
132
output += txt;
133
134
String tag = p_string.substr(brk_pos + 1, brk_end - brk_pos - 1);
135
if (tag == "b") {
136
output += "\u001b[1m";
137
} else if (tag == "/b") {
138
output += "\u001b[22m";
139
} else if (tag == "i") {
140
output += "\u001b[3m";
141
} else if (tag == "/i") {
142
output += "\u001b[23m";
143
} else if (tag == "u") {
144
output += "\u001b[4m";
145
} else if (tag == "/u") {
146
output += "\u001b[24m";
147
} else if (tag == "s") {
148
output += "\u001b[9m";
149
} else if (tag == "/s") {
150
output += "\u001b[29m";
151
} else if (tag == "indent") {
152
output += " ";
153
} else if (tag == "/indent") {
154
output += "";
155
} else if (tag == "code") {
156
output += "\u001b[2m";
157
} else if (tag == "/code") {
158
output += "\u001b[22m";
159
} else if (tag == "url") {
160
output += "";
161
} else if (tag == "/url") {
162
output += "";
163
} else if (tag == "center") {
164
output += "\n\t\t\t";
165
} else if (tag == "/center") {
166
output += "";
167
} else if (tag == "right") {
168
output += "\n\t\t\t\t\t\t";
169
} else if (tag == "/right") {
170
output += "";
171
} else if (tag.begins_with("color=")) {
172
String color_name = tag.trim_prefix("color=");
173
if (color_name == "black") {
174
output += "\u001b[30m";
175
} else if (color_name == "red") {
176
output += "\u001b[91m";
177
} else if (color_name == "green") {
178
output += "\u001b[92m";
179
} else if (color_name == "lime") {
180
output += "\u001b[92m";
181
} else if (color_name == "yellow") {
182
output += "\u001b[93m";
183
} else if (color_name == "blue") {
184
output += "\u001b[94m";
185
} else if (color_name == "magenta") {
186
output += "\u001b[95m";
187
} else if (color_name == "pink") {
188
output += "\u001b[38;5;218m";
189
} else if (color_name == "purple") {
190
output += "\u001b[38;5;98m";
191
} else if (color_name == "cyan") {
192
output += "\u001b[96m";
193
} else if (color_name == "white") {
194
output += "\u001b[97m";
195
} else if (color_name == "orange") {
196
output += "\u001b[38;5;208m";
197
} else if (color_name == "gray") {
198
output += "\u001b[90m";
199
} else {
200
Color c = Color::from_string(color_name, Color());
201
output += vformat("\u001b[38;2;%d;%d;%dm", c.r * 255, c.g * 255, c.b * 255);
202
}
203
} else if (tag == "/color") {
204
output += "\u001b[39m";
205
} else if (tag.begins_with("bgcolor=")) {
206
String color_name = tag.trim_prefix("bgcolor=");
207
if (color_name == "black") {
208
output += "\u001b[40m";
209
} else if (color_name == "red") {
210
output += "\u001b[101m";
211
} else if (color_name == "green") {
212
output += "\u001b[102m";
213
} else if (color_name == "lime") {
214
output += "\u001b[102m";
215
} else if (color_name == "yellow") {
216
output += "\u001b[103m";
217
} else if (color_name == "blue") {
218
output += "\u001b[104m";
219
} else if (color_name == "magenta") {
220
output += "\u001b[105m";
221
} else if (color_name == "pink") {
222
output += "\u001b[48;5;218m";
223
} else if (color_name == "purple") {
224
output += "\u001b[48;5;98m";
225
} else if (color_name == "cyan") {
226
output += "\u001b[106m";
227
} else if (color_name == "white") {
228
output += "\u001b[107m";
229
} else if (color_name == "orange") {
230
output += "\u001b[48;5;208m";
231
} else if (color_name == "gray") {
232
output += "\u001b[100m";
233
} else {
234
Color c = Color::from_string(color_name, Color());
235
output += vformat("\u001b[48;2;%d;%d;%dm", c.r * 255, c.g * 255, c.b * 255);
236
}
237
} else if (tag == "/bgcolor") {
238
output += "\u001b[49m";
239
} else if (tag.begins_with("fgcolor=")) {
240
String color_name = tag.trim_prefix("fgcolor=");
241
if (color_name == "black") {
242
output += "\u001b[30;40m";
243
} else if (color_name == "red") {
244
output += "\u001b[91;101m";
245
} else if (color_name == "green") {
246
output += "\u001b[92;102m";
247
} else if (color_name == "lime") {
248
output += "\u001b[92;102m";
249
} else if (color_name == "yellow") {
250
output += "\u001b[93;103m";
251
} else if (color_name == "blue") {
252
output += "\u001b[94;104m";
253
} else if (color_name == "magenta") {
254
output += "\u001b[95;105m";
255
} else if (color_name == "pink") {
256
output += "\u001b[38;5;218;48;5;218m";
257
} else if (color_name == "purple") {
258
output += "\u001b[38;5;98;48;5;98m";
259
} else if (color_name == "cyan") {
260
output += "\u001b[96;106m";
261
} else if (color_name == "white") {
262
output += "\u001b[97;107m";
263
} else if (color_name == "orange") {
264
output += "\u001b[38;5;208;48;5;208m";
265
} else if (color_name == "gray") {
266
output += "\u001b[90;100m";
267
} else {
268
Color c = Color::from_string(color_name, Color());
269
output += vformat("\u001b[38;2;%d;%d;%d;48;2;%d;%d;%dm", c.r * 255, c.g * 255, c.b * 255, c.r * 255, c.g * 255, c.b * 255);
270
}
271
} else if (tag == "/fgcolor") {
272
output += "\u001b[39;49m";
273
} else {
274
output += "[";
275
pos = brk_pos + 1;
276
}
277
}
278
output += "\u001b[0m"; // Reset.
279
280
if (is_printing) {
281
__print_fallback(output, false);
282
return;
283
}
284
285
is_printing = true;
286
287
OS::get_singleton()->print_rich("%s\n", output.utf8().get_data());
288
289
_global_lock();
290
PrintHandlerList *l = print_handler_list;
291
while (l) {
292
l->printfunc(l->userdata, p_string, false, true);
293
l = l->next;
294
}
295
296
_global_unlock();
297
298
is_printing = false;
299
}
300
301
void print_raw(const String &p_string) {
302
if (is_printing) {
303
__print_fallback(p_string, true);
304
return;
305
}
306
307
is_printing = true;
308
309
OS::get_singleton()->print("%s", p_string.utf8().get_data());
310
311
is_printing = false;
312
}
313
314
void print_error(const String &p_string) {
315
if (!CoreGlobals::print_error_enabled) {
316
return;
317
}
318
319
if (is_printing) {
320
__print_fallback(p_string, true);
321
return;
322
}
323
324
is_printing = true;
325
326
OS::get_singleton()->printerr("%s\n", p_string.utf8().get_data());
327
328
_global_lock();
329
PrintHandlerList *l = print_handler_list;
330
while (l) {
331
l->printfunc(l->userdata, p_string, true, false);
332
l = l->next;
333
}
334
335
_global_unlock();
336
337
is_printing = false;
338
}
339
340
bool is_print_verbose_enabled() {
341
return OS::get_singleton()->is_stdout_verbose();
342
}
343
344
String stringify_variants(const Variant &p_var) {
345
return p_var.operator String();
346
}
347
348