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