xref: /dflybsd-src/contrib/gcc-8.0/gcc/diagnostic-color.c (revision 38fd149817dfbff97799f62fcb70be98c4e32523)
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