]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/diagnostic-color.c
c++: Handle multiple aggregate overloads [PR95319].
[thirdparty/gcc.git] / gcc / diagnostic-color.c
1 /* Output colorization.
2 Copyright (C) 2011-2020 Free Software Foundation, Inc.
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"
22 #include "diagnostic-url.h"
23
24 #ifdef __MINGW32__
25 # include <windows.h>
26 #endif
27
28 #include "color-macros.h"
29
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
75 {
76 const char *name;
77 const char *val;
78 unsigned char name_len;
79 bool free_val;
80 };
81
82 /* For GCC_COLORS. */
83 static struct color_cap color_dict[] =
84 {
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 { "fixit-insert", SGR_SEQ (COLOR_FG_GREEN), 12, false },
95 { "fixit-delete", SGR_SEQ (COLOR_FG_RED), 12, false },
96 { "diff-filename", SGR_SEQ (COLOR_BOLD), 13, false },
97 { "diff-hunk", SGR_SEQ (COLOR_FG_CYAN), 9, false },
98 { "diff-delete", SGR_SEQ (COLOR_FG_RED), 11, false },
99 { "diff-insert", SGR_SEQ (COLOR_FG_GREEN), 11, false },
100 { "type-diff", SGR_SEQ (COLOR_BOLD COLOR_SEPARATOR COLOR_FG_GREEN), 9, false },
101 { NULL, NULL, 0, false }
102 };
103
104 const char *
105 colorize_start (bool show_color, const char *name, size_t name_len)
106 {
107 struct color_cap const *cap;
108
109 if (!show_color)
110 return "";
111
112 for (cap = color_dict; cap->name; cap++)
113 if (cap->name_len == name_len
114 && memcmp (cap->name, name, name_len) == 0)
115 break;
116 if (cap->name == NULL)
117 return "";
118
119 return cap->val;
120 }
121
122 const char *
123 colorize_stop (bool show_color)
124 {
125 return show_color ? SGR_RESET : "";
126 }
127
128 /* Parse GCC_COLORS. The default would look like:
129 GCC_COLORS='error=01;31:warning=01;35:note=01;36:\
130 range1=32:range2=34:locus=01:quote=01:path=01;36:\
131 fixit-insert=32:fixit-delete=31:'\
132 diff-filename=01:diff-hunk=32:diff-delete=31:diff-insert=32:\
133 type-diff=01;32'
134 No character escaping is needed or supported. */
135 static bool
136 parse_gcc_colors (void)
137 {
138 const char *p, *q, *name, *val;
139 char *b;
140 size_t name_len = 0, val_len = 0;
141
142 p = getenv ("GCC_COLORS"); /* Plural! */
143 if (p == NULL)
144 return true;
145 if (*p == '\0')
146 return false;
147
148 name = q = p;
149 val = NULL;
150 /* From now on, be well-formed or you're gone. */
151 for (;;)
152 if (*q == ':' || *q == '\0')
153 {
154 struct color_cap *cap;
155
156 if (val)
157 val_len = q - val;
158 else
159 name_len = q - name;
160 /* Empty name without val (empty cap)
161 won't match and will be ignored. */
162 for (cap = color_dict; cap->name; cap++)
163 if (cap->name_len == name_len
164 && memcmp (cap->name, name, name_len) == 0)
165 break;
166 /* If name unknown, go on for forward compatibility. */
167 if (cap->val && val)
168 {
169 if (cap->free_val)
170 free (CONST_CAST (char *, cap->val));
171 b = XNEWVEC (char, val_len + sizeof (SGR_SEQ ("")));
172 memcpy (b, SGR_START, strlen (SGR_START));
173 memcpy (b + strlen (SGR_START), val, val_len);
174 memcpy (b + strlen (SGR_START) + val_len, SGR_END,
175 sizeof (SGR_END));
176 cap->val = (const char *) b;
177 cap->free_val = true;
178 }
179 if (*q == '\0')
180 return true;
181 name = ++q;
182 val = NULL;
183 }
184 else if (*q == '=')
185 {
186 if (q == name || val)
187 return true;
188
189 name_len = q - name;
190 val = ++q; /* Can be the empty string. */
191 }
192 else if (val == NULL)
193 q++; /* Accumulate name. */
194 else if (*q == ';' || (*q >= '0' && *q <= '9'))
195 q++; /* Accumulate val. Protect the terminal from being sent
196 garbage. */
197 else
198 return true;
199 }
200
201 /* Return true if we should use color when in auto mode, false otherwise. */
202 static bool
203 should_colorize (void)
204 {
205 #ifdef __MINGW32__
206 /* For consistency reasons, one should check the handle returned by
207 _get_osfhandle(_fileno(stderr)) because the function
208 pp_write_text_to_stream() in pretty-print.c calls fputs() on
209 that stream. However, the code below for non-Windows doesn't seem
210 to care about it either... */
211 HANDLE h;
212 DWORD m;
213
214 h = GetStdHandle (STD_ERROR_HANDLE);
215 return (h != INVALID_HANDLE_VALUE) && (h != NULL)
216 && GetConsoleMode (h, &m);
217 #else
218 char const *t = getenv ("TERM");
219 /* emacs M-x shell sets TERM="dumb". */
220 return t && strcmp (t, "dumb") != 0 && isatty (STDERR_FILENO);
221 #endif
222 }
223
224 bool
225 colorize_init (diagnostic_color_rule_t rule)
226 {
227 switch (rule)
228 {
229 case DIAGNOSTICS_COLOR_NO:
230 return false;
231 case DIAGNOSTICS_COLOR_YES:
232 return parse_gcc_colors ();
233 case DIAGNOSTICS_COLOR_AUTO:
234 if (should_colorize ())
235 return parse_gcc_colors ();
236 else
237 return false;
238 default:
239 gcc_unreachable ();
240 }
241 }
242
243 /* Return URL_FORMAT_XXX which tells how we should emit urls
244 when in always mode.
245 We use GCC_URLS and if that is not defined TERM_URLS.
246 If neither is defined the feature is enabled by default. */
247
248 static diagnostic_url_format
249 parse_env_vars_for_urls ()
250 {
251 const char *p;
252
253 p = getenv ("GCC_URLS"); /* Plural! */
254 if (p == NULL)
255 p = getenv ("TERM_URLS");
256
257 if (p == NULL)
258 return URL_FORMAT_DEFAULT;
259
260 if (*p == '\0')
261 return URL_FORMAT_NONE;
262
263 if (!strcmp (p, "no"))
264 return URL_FORMAT_NONE;
265
266 if (!strcmp (p, "st"))
267 return URL_FORMAT_ST;
268
269 if (!strcmp (p, "bel"))
270 return URL_FORMAT_BEL;
271
272 return URL_FORMAT_DEFAULT;
273 }
274
275 /* Return true if we should use urls when in auto mode, false otherwise. */
276
277 static bool
278 auto_enable_urls ()
279 {
280 #ifdef __MINGW32__
281 return false;
282 #else
283 const char *term, *colorterm;
284
285 /* First check the terminal is capable of printing color escapes,
286 if not URLs won't work either. */
287 if (!should_colorize ())
288 return false;
289
290 /* xfce4-terminal is known to not implement URLs at this time.
291 Recently new installations (0.8) will safely ignore the URL escape
292 sequences, but a large number of legacy installations (0.6.3) print
293 garbage when URLs are printed. Therefore we lose nothing by
294 disabling this feature for that specific terminal type. */
295 colorterm = getenv ("COLORTERM");
296 if (colorterm && !strcmp (colorterm, "xfce4-terminal"))
297 return false;
298
299 /* Old versions of gnome-terminal where URL escapes cause screen
300 corruptions set COLORTERM="gnome-terminal", recent versions
301 with working URL support set this to "truecolor". */
302 if (colorterm && !strcmp (colorterm, "gnome-terminal"))
303 return false;
304
305 /* Since the following checks are less specific than the ones
306 above, let GCC_URLS and TERM_URLS override the decision. */
307 if (getenv ("GCC_URLS") || getenv ("TERM_URLS"))
308 return true;
309
310 /* In an ssh session the COLORTERM is not there, but TERM=xterm
311 can be used as an indication of a incompatible terminal while
312 TERM=xterm-256color appears to be a working terminal. */
313 term = getenv ("TERM");
314 if (!colorterm && term && !strcmp (term, "xterm"))
315 return false;
316
317 /* When logging in a linux over serial line, we see TERM=linux
318 and no COLORTERM, it is unlikely that the URL escapes will
319 work in that environmen either. */
320 if (!colorterm && term && !strcmp (term, "linux"))
321 return false;
322
323 return true;
324 #endif
325 }
326
327 /* Determine if URLs should be enabled, based on RULE,
328 and, if so, which format to use.
329 This reuses the logic for colorization. */
330
331 diagnostic_url_format
332 determine_url_format (diagnostic_url_rule_t rule)
333 {
334 switch (rule)
335 {
336 case DIAGNOSTICS_URL_NO:
337 return URL_FORMAT_NONE;
338 case DIAGNOSTICS_URL_YES:
339 return parse_env_vars_for_urls ();
340 case DIAGNOSTICS_URL_AUTO:
341 if (auto_enable_urls ())
342 return parse_env_vars_for_urls ();
343 else
344 return URL_FORMAT_NONE;
345 default:
346 gcc_unreachable ();
347 }
348 }