]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/diagnostic-color.cc
fortran: Assume there is no cyclic reference with submodule symbols [PR99798]
[thirdparty/gcc.git] / gcc / diagnostic-color.cc
CommitLineData
f3065bdb 1/* Output colorization.
a945c346 2 Copyright (C) 2011-2024 Free Software Foundation, Inc.
f3065bdb
JJ
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
17 02110-1301, USA. */
18
19#include "config.h"
20#include "system.h"
21#include "diagnostic-color.h"
d2608235 22#include "diagnostic-url.h"
f3065bdb 23
db0d1bae 24#ifdef __MINGW32__
902c7559 25# define WIN32_LEAN_AND_MEAN
db0d1bae
LH
26# include <windows.h>
27#endif
28
28f4a4a8 29#include "color-macros.h"
f3065bdb
JJ
30
31/* The context and logic for choosing default --color screen attributes
32 (foreground and background colors, etc.) are the following.
33 -- There are eight basic colors available, each with its own
34 nominal luminosity to the human eye and foreground/background
35 codes (black [0 %, 30/40], blue [11 %, 34/44], red [30 %, 31/41],
36 magenta [41 %, 35/45], green [59 %, 32/42], cyan [70 %, 36/46],
37 yellow [89 %, 33/43], and white [100 %, 37/47]).
38 -- Sometimes, white as a background is actually implemented using
39 a shade of light gray, so that a foreground white can be visible
40 on top of it (but most often not).
41 -- Sometimes, black as a foreground is actually implemented using
42 a shade of dark gray, so that it can be visible on top of a
43 background black (but most often not).
44 -- Sometimes, more colors are available, as extensions.
45 -- Other attributes can be selected/deselected (bold [1/22],
46 underline [4/24], standout/inverse [7/27], blink [5/25], and
47 invisible/hidden [8/28]). They are sometimes implemented by
48 using colors instead of what their names imply; e.g., bold is
49 often achieved by using brighter colors. In practice, only bold
50 is really available to us, underline sometimes being mapped by
51 the terminal to some strange color choice, and standout best
52 being left for use by downstream programs such as less(1).
53 -- We cannot assume that any of the extensions or special features
54 are available for the purpose of choosing defaults for everyone.
55 -- The most prevalent default terminal backgrounds are pure black
56 and pure white, and are not necessarily the same shades of
57 those as if they were selected explicitly with SGR sequences.
58 Some terminals use dark or light pictures as default background,
59 but those are covered over by an explicit selection of background
60 color with an SGR sequence; their users will appreciate their
61 background pictures not be covered like this, if possible.
62 -- Some uses of colors attributes is to make some output items
63 more understated (e.g., context lines); this cannot be achieved
64 by changing the background color.
65 -- For these reasons, the GCC color defaults should strive not
66 to change the background color from its default, unless it's
67 for a short item that should be highlighted, not understated.
68 -- The GCC foreground color defaults (without an explicitly set
69 background) should provide enough contrast to be readable on any
70 terminal with either a black (dark) or white (light) background.
71 This only leaves red, magenta, green, and cyan (and their bold
72 counterparts) and possibly bold blue. */
73/* Default colors. The user can overwrite them using environment
74 variable GCC_COLORS. */
75struct color_cap
76{
77 const char *name;
78 const char *val;
79 unsigned char name_len;
80 bool free_val;
81};
82
83/* For GCC_COLORS. */
84static struct color_cap color_dict[] =
85{
86 { "error", SGR_SEQ (COLOR_BOLD COLOR_SEPARATOR COLOR_FG_RED), 5, false },
87 { "warning", SGR_SEQ (COLOR_BOLD COLOR_SEPARATOR COLOR_FG_MAGENTA),
88 7, false },
89 { "note", SGR_SEQ (COLOR_BOLD COLOR_SEPARATOR COLOR_FG_CYAN), 4, false },
8a645150
DM
90 { "range1", SGR_SEQ (COLOR_FG_GREEN), 6, false },
91 { "range2", SGR_SEQ (COLOR_FG_BLUE), 6, false },
f3065bdb
JJ
92 { "locus", SGR_SEQ (COLOR_BOLD), 5, false },
93 { "quote", SGR_SEQ (COLOR_BOLD), 5, false },
4bc1899b 94 { "path", SGR_SEQ (COLOR_BOLD COLOR_SEPARATOR COLOR_FG_CYAN), 4, false },
69dd5ca3
JM
95 { "fnname", SGR_SEQ (COLOR_BOLD COLOR_SEPARATOR COLOR_FG_GREEN), 6, false },
96 { "targs", SGR_SEQ (COLOR_FG_MAGENTA), 5, false },
d41e76cf
DM
97 { "fixit-insert", SGR_SEQ (COLOR_FG_GREEN), 12, false },
98 { "fixit-delete", SGR_SEQ (COLOR_FG_RED), 12, false },
c65236d6
DM
99 { "diff-filename", SGR_SEQ (COLOR_BOLD), 13, false },
100 { "diff-hunk", SGR_SEQ (COLOR_FG_CYAN), 9, false },
101 { "diff-delete", SGR_SEQ (COLOR_FG_RED), 11, false },
102 { "diff-insert", SGR_SEQ (COLOR_FG_GREEN), 11, false },
f012c8ef 103 { "type-diff", SGR_SEQ (COLOR_BOLD COLOR_SEPARATOR COLOR_FG_GREEN), 9, false },
4b02dd48
DM
104 { "valid", SGR_SEQ (COLOR_BOLD COLOR_SEPARATOR COLOR_FG_GREEN), 5, false },
105 { "invalid", SGR_SEQ (COLOR_BOLD COLOR_SEPARATOR COLOR_FG_RED), 7, false },
f3065bdb
JJ
106 { NULL, NULL, 0, false }
107};
108
109const char *
110colorize_start (bool show_color, const char *name, size_t name_len)
111{
112 struct color_cap const *cap;
113
114 if (!show_color)
115 return "";
116
117 for (cap = color_dict; cap->name; cap++)
118 if (cap->name_len == name_len
119 && memcmp (cap->name, name, name_len) == 0)
120 break;
121 if (cap->name == NULL)
122 return "";
123
124 return cap->val;
125}
126
127const char *
128colorize_stop (bool show_color)
129{
130 return show_color ? SGR_RESET : "";
131}
132
133/* Parse GCC_COLORS. The default would look like:
d41e76cf 134 GCC_COLORS='error=01;31:warning=01;35:note=01;36:\
4bc1899b 135 range1=32:range2=34:locus=01:quote=01:path=01;36:\
f012c8ef
DM
136 fixit-insert=32:fixit-delete=31:'\
137 diff-filename=01:diff-hunk=32:diff-delete=31:diff-insert=32:\
138 type-diff=01;32'
f3065bdb
JJ
139 No character escaping is needed or supported. */
140static bool
141parse_gcc_colors (void)
142{
143 const char *p, *q, *name, *val;
144 char *b;
145 size_t name_len = 0, val_len = 0;
146
147 p = getenv ("GCC_COLORS"); /* Plural! */
148 if (p == NULL)
149 return true;
150 if (*p == '\0')
151 return false;
152
153 name = q = p;
154 val = NULL;
155 /* From now on, be well-formed or you're gone. */
156 for (;;)
157 if (*q == ':' || *q == '\0')
158 {
159 struct color_cap *cap;
160
161 if (val)
162 val_len = q - val;
163 else
164 name_len = q - name;
165 /* Empty name without val (empty cap)
166 won't match and will be ignored. */
167 for (cap = color_dict; cap->name; cap++)
168 if (cap->name_len == name_len
169 && memcmp (cap->name, name, name_len) == 0)
170 break;
171 /* If name unknown, go on for forward compatibility. */
172 if (cap->val && val)
173 {
174 if (cap->free_val)
175 free (CONST_CAST (char *, cap->val));
176 b = XNEWVEC (char, val_len + sizeof (SGR_SEQ ("")));
177 memcpy (b, SGR_START, strlen (SGR_START));
178 memcpy (b + strlen (SGR_START), val, val_len);
179 memcpy (b + strlen (SGR_START) + val_len, SGR_END,
180 sizeof (SGR_END));
181 cap->val = (const char *) b;
182 cap->free_val = true;
183 }
184 if (*q == '\0')
185 return true;
186 name = ++q;
187 val = NULL;
188 }
189 else if (*q == '=')
190 {
191 if (q == name || val)
192 return true;
193
194 name_len = q - name;
195 val = ++q; /* Can be the empty string. */
196 }
197 else if (val == NULL)
198 q++; /* Accumulate name. */
199 else if (*q == ';' || (*q >= '0' && *q <= '9'))
200 q++; /* Accumulate val. Protect the terminal from being sent
201 garbage. */
202 else
203 return true;
204}
205
f3065bdb
JJ
206/* Return true if we should use color when in auto mode, false otherwise. */
207static bool
208should_colorize (void)
209{
db0d1bae
LH
210#ifdef __MINGW32__
211 /* For consistency reasons, one should check the handle returned by
212 _get_osfhandle(_fileno(stderr)) because the function
e53b6e56 213 pp_write_text_to_stream() in pretty-print.cc calls fputs() on
db0d1bae
LH
214 that stream. However, the code below for non-Windows doesn't seem
215 to care about it either... */
216 HANDLE h;
217 DWORD m;
218
219 h = GetStdHandle (STD_ERROR_HANDLE);
220 return (h != INVALID_HANDLE_VALUE) && (h != NULL)
221 && GetConsoleMode (h, &m);
222#else
f3065bdb 223 char const *t = getenv ("TERM");
458c8d64 224 /* emacs M-x shell sets TERM="dumb". */
f3065bdb 225 return t && strcmp (t, "dumb") != 0 && isatty (STDERR_FILENO);
db0d1bae 226#endif
f3065bdb
JJ
227}
228
f3065bdb
JJ
229bool
230colorize_init (diagnostic_color_rule_t rule)
231{
232 switch (rule)
233 {
234 case DIAGNOSTICS_COLOR_NO:
235 return false;
236 case DIAGNOSTICS_COLOR_YES:
237 return parse_gcc_colors ();
238 case DIAGNOSTICS_COLOR_AUTO:
239 if (should_colorize ())
240 return parse_gcc_colors ();
241 else
242 return false;
243 default:
244 gcc_unreachable ();
245 }
246}
d2608235 247
458c8d64
BE
248/* Return URL_FORMAT_XXX which tells how we should emit urls
249 when in always mode.
250 We use GCC_URLS and if that is not defined TERM_URLS.
251 If neither is defined the feature is enabled by default. */
252
253static diagnostic_url_format
254parse_env_vars_for_urls ()
255{
256 const char *p;
257
258 p = getenv ("GCC_URLS"); /* Plural! */
259 if (p == NULL)
260 p = getenv ("TERM_URLS");
261
262 if (p == NULL)
263 return URL_FORMAT_DEFAULT;
264
265 if (*p == '\0')
266 return URL_FORMAT_NONE;
267
268 if (!strcmp (p, "no"))
269 return URL_FORMAT_NONE;
270
271 if (!strcmp (p, "st"))
272 return URL_FORMAT_ST;
273
274 if (!strcmp (p, "bel"))
275 return URL_FORMAT_BEL;
276
277 return URL_FORMAT_DEFAULT;
278}
279
280/* Return true if we should use urls when in auto mode, false otherwise. */
281
282static bool
283auto_enable_urls ()
284{
285#ifdef __MINGW32__
286 return false;
287#else
288 const char *term, *colorterm;
289
290 /* First check the terminal is capable of printing color escapes,
291 if not URLs won't work either. */
292 if (!should_colorize ())
293 return false;
294
295 /* xfce4-terminal is known to not implement URLs at this time.
296 Recently new installations (0.8) will safely ignore the URL escape
297 sequences, but a large number of legacy installations (0.6.3) print
298 garbage when URLs are printed. Therefore we lose nothing by
299 disabling this feature for that specific terminal type. */
300 colorterm = getenv ("COLORTERM");
301 if (colorterm && !strcmp (colorterm, "xfce4-terminal"))
302 return false;
303
304 /* Old versions of gnome-terminal where URL escapes cause screen
305 corruptions set COLORTERM="gnome-terminal", recent versions
306 with working URL support set this to "truecolor". */
307 if (colorterm && !strcmp (colorterm, "gnome-terminal"))
308 return false;
309
310 /* Since the following checks are less specific than the ones
311 above, let GCC_URLS and TERM_URLS override the decision. */
312 if (getenv ("GCC_URLS") || getenv ("TERM_URLS"))
313 return true;
314
315 /* In an ssh session the COLORTERM is not there, but TERM=xterm
316 can be used as an indication of a incompatible terminal while
317 TERM=xterm-256color appears to be a working terminal. */
318 term = getenv ("TERM");
319 if (!colorterm && term && !strcmp (term, "xterm"))
320 return false;
321
322 /* When logging in a linux over serial line, we see TERM=linux
323 and no COLORTERM, it is unlikely that the URL escapes will
324 work in that environmen either. */
325 if (!colorterm && term && !strcmp (term, "linux"))
326 return false;
327
328 return true;
329#endif
330}
331
332/* Determine if URLs should be enabled, based on RULE,
333 and, if so, which format to use.
d2608235
DM
334 This reuses the logic for colorization. */
335
458c8d64
BE
336diagnostic_url_format
337determine_url_format (diagnostic_url_rule_t rule)
d2608235
DM
338{
339 switch (rule)
340 {
341 case DIAGNOSTICS_URL_NO:
458c8d64 342 return URL_FORMAT_NONE;
d2608235 343 case DIAGNOSTICS_URL_YES:
458c8d64 344 return parse_env_vars_for_urls ();
d2608235 345 case DIAGNOSTICS_URL_AUTO:
458c8d64
BE
346 if (auto_enable_urls ())
347 return parse_env_vars_for_urls ();
348 else
349 return URL_FORMAT_NONE;
d2608235
DM
350 default:
351 gcc_unreachable ();
352 }
353}