Objective-C, NeXT, v2: Correct a regression in code-gen.
[official-gcc.git] / gcc / diagnostic-color.cc
blobf01a0fc2e3775c974ce1ffcb1d5f1ba74cf41c84
1 /* Output colorization.
2 Copyright (C) 2011-2024 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 # define WIN32_LEAN_AND_MEAN
26 # include <windows.h>
27 #endif
29 #include "color-macros.h"
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. */
75 struct color_cap
77 const char *name;
78 const char *val;
79 unsigned char name_len;
80 bool free_val;
83 /* For GCC_COLORS. */
84 static struct color_cap color_dict[] =
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 },
90 { "range1", SGR_SEQ (COLOR_FG_GREEN), 6, false },
91 { "range2", SGR_SEQ (COLOR_FG_BLUE), 6, false },
92 { "locus", SGR_SEQ (COLOR_BOLD), 5, false },
93 { "quote", SGR_SEQ (COLOR_BOLD), 5, false },
94 { "path", SGR_SEQ (COLOR_BOLD COLOR_SEPARATOR COLOR_FG_CYAN), 4, false },
95 { "fnname", SGR_SEQ (COLOR_BOLD COLOR_SEPARATOR COLOR_FG_GREEN), 6, false },
96 { "targs", SGR_SEQ (COLOR_FG_MAGENTA), 5, false },
97 { "fixit-insert", SGR_SEQ (COLOR_FG_GREEN), 12, false },
98 { "fixit-delete", SGR_SEQ (COLOR_FG_RED), 12, false },
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 },
103 { "type-diff", SGR_SEQ (COLOR_BOLD COLOR_SEPARATOR COLOR_FG_GREEN), 9, false },
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 },
106 { NULL, NULL, 0, false }
109 const char *
110 colorize_start (bool show_color, const char *name, size_t name_len)
112 struct color_cap const *cap;
114 if (!show_color)
115 return "";
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 "";
124 return cap->val;
127 const char *
128 colorize_stop (bool show_color)
130 return show_color ? SGR_RESET : "";
133 /* Parse GCC_COLORS. The default would look like:
134 GCC_COLORS='error=01;31:warning=01;35:note=01;36:\
135 range1=32:range2=34:locus=01:quote=01:path=01;36:\
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'
139 No character escaping is needed or supported. */
140 static bool
141 parse_gcc_colors (void)
143 const char *p, *q, *name, *val;
144 char *b;
145 size_t name_len = 0, val_len = 0;
147 p = getenv ("GCC_COLORS"); /* Plural! */
148 if (p == NULL)
149 return true;
150 if (*p == '\0')
151 return false;
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')
159 struct color_cap *cap;
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)
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;
184 if (*q == '\0')
185 return true;
186 name = ++q;
187 val = NULL;
189 else if (*q == '=')
191 if (q == name || val)
192 return true;
194 name_len = q - name;
195 val = ++q; /* Can be the empty string. */
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;
206 /* Return true if we should use color when in auto mode, false otherwise. */
207 static bool
208 should_colorize (void)
210 #ifdef __MINGW32__
211 /* For consistency reasons, one should check the handle returned by
212 _get_osfhandle(_fileno(stderr)) because the function
213 pp_write_text_to_stream() in pretty-print.cc calls fputs() on
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;
219 h = GetStdHandle (STD_ERROR_HANDLE);
220 return (h != INVALID_HANDLE_VALUE) && (h != NULL)
221 && GetConsoleMode (h, &m);
222 #else
223 char const *t = getenv ("TERM");
224 /* emacs M-x shell sets TERM="dumb". */
225 return t && strcmp (t, "dumb") != 0 && isatty (STDERR_FILENO);
226 #endif
229 bool
230 colorize_init (diagnostic_color_rule_t rule)
232 switch (rule)
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 ();
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. */
253 static diagnostic_url_format
254 parse_env_vars_for_urls ()
256 const char *p;
258 p = getenv ("GCC_URLS"); /* Plural! */
259 if (p == NULL)
260 p = getenv ("TERM_URLS");
262 if (p == NULL)
263 return URL_FORMAT_DEFAULT;
265 if (*p == '\0')
266 return URL_FORMAT_NONE;
268 if (!strcmp (p, "no"))
269 return URL_FORMAT_NONE;
271 if (!strcmp (p, "st"))
272 return URL_FORMAT_ST;
274 if (!strcmp (p, "bel"))
275 return URL_FORMAT_BEL;
277 return URL_FORMAT_DEFAULT;
280 /* Return true if we should use urls when in auto mode, false otherwise. */
282 static bool
283 auto_enable_urls ()
285 #ifdef __MINGW32__
286 return false;
287 #else
288 const char *term, *colorterm;
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;
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;
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;
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;
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;
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;
328 return true;
329 #endif
332 /* Determine if URLs should be enabled, based on RULE,
333 and, if so, which format to use.
334 This reuses the logic for colorization. */
336 diagnostic_url_format
337 determine_url_format (diagnostic_url_rule_t rule)
339 switch (rule)
341 case DIAGNOSTICS_URL_NO:
342 return URL_FORMAT_NONE;
343 case DIAGNOSTICS_URL_YES:
344 return parse_env_vars_for_urls ();
345 case DIAGNOSTICS_URL_AUTO:
346 if (auto_enable_urls ())
347 return parse_env_vars_for_urls ();
348 else
349 return URL_FORMAT_NONE;
350 default:
351 gcc_unreachable ();