]>
Commit | Line | Data |
---|---|---|
adc604d4 | 1 | /* Output colorization. |
fbd26352 | 2 | Copyright (C) 2011-2019 Free Software Foundation, Inc. |
adc604d4 | 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 | ||
b9653739 | 23 | #ifdef __MINGW32__ |
24 | # include <windows.h> | |
25 | #endif | |
26 | ||
c536c15f | 27 | #include "color-macros.h" |
adc604d4 | 28 | |
29 | /* The context and logic for choosing default --color screen attributes | |
30 | (foreground and background colors, etc.) are the following. | |
31 | -- There are eight basic colors available, each with its own | |
32 | nominal luminosity to the human eye and foreground/background | |
33 | codes (black [0 %, 30/40], blue [11 %, 34/44], red [30 %, 31/41], | |
34 | magenta [41 %, 35/45], green [59 %, 32/42], cyan [70 %, 36/46], | |
35 | yellow [89 %, 33/43], and white [100 %, 37/47]). | |
36 | -- Sometimes, white as a background is actually implemented using | |
37 | a shade of light gray, so that a foreground white can be visible | |
38 | on top of it (but most often not). | |
39 | -- Sometimes, black as a foreground is actually implemented using | |
40 | a shade of dark gray, so that it can be visible on top of a | |
41 | background black (but most often not). | |
42 | -- Sometimes, more colors are available, as extensions. | |
43 | -- Other attributes can be selected/deselected (bold [1/22], | |
44 | underline [4/24], standout/inverse [7/27], blink [5/25], and | |
45 | invisible/hidden [8/28]). They are sometimes implemented by | |
46 | using colors instead of what their names imply; e.g., bold is | |
47 | often achieved by using brighter colors. In practice, only bold | |
48 | is really available to us, underline sometimes being mapped by | |
49 | the terminal to some strange color choice, and standout best | |
50 | being left for use by downstream programs such as less(1). | |
51 | -- We cannot assume that any of the extensions or special features | |
52 | are available for the purpose of choosing defaults for everyone. | |
53 | -- The most prevalent default terminal backgrounds are pure black | |
54 | and pure white, and are not necessarily the same shades of | |
55 | those as if they were selected explicitly with SGR sequences. | |
56 | Some terminals use dark or light pictures as default background, | |
57 | but those are covered over by an explicit selection of background | |
58 | color with an SGR sequence; their users will appreciate their | |
59 | background pictures not be covered like this, if possible. | |
60 | -- Some uses of colors attributes is to make some output items | |
61 | more understated (e.g., context lines); this cannot be achieved | |
62 | by changing the background color. | |
63 | -- For these reasons, the GCC color defaults should strive not | |
64 | to change the background color from its default, unless it's | |
65 | for a short item that should be highlighted, not understated. | |
66 | -- The GCC foreground color defaults (without an explicitly set | |
67 | background) should provide enough contrast to be readable on any | |
68 | terminal with either a black (dark) or white (light) background. | |
69 | This only leaves red, magenta, green, and cyan (and their bold | |
70 | counterparts) and possibly bold blue. */ | |
71 | /* Default colors. The user can overwrite them using environment | |
72 | variable GCC_COLORS. */ | |
73 | struct color_cap | |
74 | { | |
75 | const char *name; | |
76 | const char *val; | |
77 | unsigned char name_len; | |
78 | bool free_val; | |
79 | }; | |
80 | ||
81 | /* For GCC_COLORS. */ | |
82 | static struct color_cap color_dict[] = | |
83 | { | |
84 | { "error", SGR_SEQ (COLOR_BOLD COLOR_SEPARATOR COLOR_FG_RED), 5, false }, | |
85 | { "warning", SGR_SEQ (COLOR_BOLD COLOR_SEPARATOR COLOR_FG_MAGENTA), | |
86 | 7, false }, | |
87 | { "note", SGR_SEQ (COLOR_BOLD COLOR_SEPARATOR COLOR_FG_CYAN), 4, false }, | |
f0479000 | 88 | { "range1", SGR_SEQ (COLOR_FG_GREEN), 6, false }, |
89 | { "range2", SGR_SEQ (COLOR_FG_BLUE), 6, false }, | |
adc604d4 | 90 | { "locus", SGR_SEQ (COLOR_BOLD), 5, false }, |
91 | { "quote", SGR_SEQ (COLOR_BOLD), 5, false }, | |
df4248fb | 92 | { "fixit-insert", SGR_SEQ (COLOR_FG_GREEN), 12, false }, |
93 | { "fixit-delete", SGR_SEQ (COLOR_FG_RED), 12, false }, | |
fe066ce3 | 94 | { "diff-filename", SGR_SEQ (COLOR_BOLD), 13, false }, |
95 | { "diff-hunk", SGR_SEQ (COLOR_FG_CYAN), 9, false }, | |
96 | { "diff-delete", SGR_SEQ (COLOR_FG_RED), 11, false }, | |
97 | { "diff-insert", SGR_SEQ (COLOR_FG_GREEN), 11, false }, | |
4d1eda3a | 98 | { "type-diff", SGR_SEQ (COLOR_BOLD COLOR_SEPARATOR COLOR_FG_GREEN), 9, false }, |
adc604d4 | 99 | { NULL, NULL, 0, false } |
100 | }; | |
101 | ||
102 | const char * | |
103 | colorize_start (bool show_color, const char *name, size_t name_len) | |
104 | { | |
105 | struct color_cap const *cap; | |
106 | ||
107 | if (!show_color) | |
108 | return ""; | |
109 | ||
110 | for (cap = color_dict; cap->name; cap++) | |
111 | if (cap->name_len == name_len | |
112 | && memcmp (cap->name, name, name_len) == 0) | |
113 | break; | |
114 | if (cap->name == NULL) | |
115 | return ""; | |
116 | ||
117 | return cap->val; | |
118 | } | |
119 | ||
120 | const char * | |
121 | colorize_stop (bool show_color) | |
122 | { | |
123 | return show_color ? SGR_RESET : ""; | |
124 | } | |
125 | ||
126 | /* Parse GCC_COLORS. The default would look like: | |
df4248fb | 127 | GCC_COLORS='error=01;31:warning=01;35:note=01;36:\ |
128 | range1=32:range2=34:locus=01:quote=01:\ | |
4d1eda3a | 129 | fixit-insert=32:fixit-delete=31:'\ |
130 | diff-filename=01:diff-hunk=32:diff-delete=31:diff-insert=32:\ | |
131 | type-diff=01;32' | |
adc604d4 | 132 | No character escaping is needed or supported. */ |
133 | static bool | |
134 | parse_gcc_colors (void) | |
135 | { | |
136 | const char *p, *q, *name, *val; | |
137 | char *b; | |
138 | size_t name_len = 0, val_len = 0; | |
139 | ||
140 | p = getenv ("GCC_COLORS"); /* Plural! */ | |
141 | if (p == NULL) | |
142 | return true; | |
143 | if (*p == '\0') | |
144 | return false; | |
145 | ||
146 | name = q = p; | |
147 | val = NULL; | |
148 | /* From now on, be well-formed or you're gone. */ | |
149 | for (;;) | |
150 | if (*q == ':' || *q == '\0') | |
151 | { | |
152 | struct color_cap *cap; | |
153 | ||
154 | if (val) | |
155 | val_len = q - val; | |
156 | else | |
157 | name_len = q - name; | |
158 | /* Empty name without val (empty cap) | |
159 | won't match and will be ignored. */ | |
160 | for (cap = color_dict; cap->name; cap++) | |
161 | if (cap->name_len == name_len | |
162 | && memcmp (cap->name, name, name_len) == 0) | |
163 | break; | |
164 | /* If name unknown, go on for forward compatibility. */ | |
165 | if (cap->val && val) | |
166 | { | |
167 | if (cap->free_val) | |
168 | free (CONST_CAST (char *, cap->val)); | |
169 | b = XNEWVEC (char, val_len + sizeof (SGR_SEQ (""))); | |
170 | memcpy (b, SGR_START, strlen (SGR_START)); | |
171 | memcpy (b + strlen (SGR_START), val, val_len); | |
172 | memcpy (b + strlen (SGR_START) + val_len, SGR_END, | |
173 | sizeof (SGR_END)); | |
174 | cap->val = (const char *) b; | |
175 | cap->free_val = true; | |
176 | } | |
177 | if (*q == '\0') | |
178 | return true; | |
179 | name = ++q; | |
180 | val = NULL; | |
181 | } | |
182 | else if (*q == '=') | |
183 | { | |
184 | if (q == name || val) | |
185 | return true; | |
186 | ||
187 | name_len = q - name; | |
188 | val = ++q; /* Can be the empty string. */ | |
189 | } | |
190 | else if (val == NULL) | |
191 | q++; /* Accumulate name. */ | |
192 | else if (*q == ';' || (*q >= '0' && *q <= '9')) | |
193 | q++; /* Accumulate val. Protect the terminal from being sent | |
194 | garbage. */ | |
195 | else | |
196 | return true; | |
197 | } | |
198 | ||
adc604d4 | 199 | /* Return true if we should use color when in auto mode, false otherwise. */ |
200 | static bool | |
201 | should_colorize (void) | |
202 | { | |
b9653739 | 203 | #ifdef __MINGW32__ |
204 | /* For consistency reasons, one should check the handle returned by | |
205 | _get_osfhandle(_fileno(stderr)) because the function | |
206 | pp_write_text_to_stream() in pretty-print.c calls fputs() on | |
207 | that stream. However, the code below for non-Windows doesn't seem | |
208 | to care about it either... */ | |
209 | HANDLE h; | |
210 | DWORD m; | |
211 | ||
212 | h = GetStdHandle (STD_ERROR_HANDLE); | |
213 | return (h != INVALID_HANDLE_VALUE) && (h != NULL) | |
214 | && GetConsoleMode (h, &m); | |
215 | #else | |
adc604d4 | 216 | char const *t = getenv ("TERM"); |
217 | return t && strcmp (t, "dumb") != 0 && isatty (STDERR_FILENO); | |
b9653739 | 218 | #endif |
adc604d4 | 219 | } |
220 | ||
adc604d4 | 221 | bool |
222 | colorize_init (diagnostic_color_rule_t rule) | |
223 | { | |
224 | switch (rule) | |
225 | { | |
226 | case DIAGNOSTICS_COLOR_NO: | |
227 | return false; | |
228 | case DIAGNOSTICS_COLOR_YES: | |
229 | return parse_gcc_colors (); | |
230 | case DIAGNOSTICS_COLOR_AUTO: | |
231 | if (should_colorize ()) | |
232 | return parse_gcc_colors (); | |
233 | else | |
234 | return false; | |
235 | default: | |
236 | gcc_unreachable (); | |
237 | } | |
238 | } |