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