Add diagnostic paths
[platform/upstream/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   return t && strcmp (t, "dumb") != 0 && isatty (STDERR_FILENO);
220 #endif
221 }
222
223 bool
224 colorize_init (diagnostic_color_rule_t rule)
225 {
226   switch (rule)
227     {
228     case DIAGNOSTICS_COLOR_NO:
229       return false;
230     case DIAGNOSTICS_COLOR_YES:
231       return parse_gcc_colors ();
232     case DIAGNOSTICS_COLOR_AUTO:
233       if (should_colorize ())
234         return parse_gcc_colors ();
235       else
236         return false;
237     default:
238       gcc_unreachable ();
239     }
240 }
241
242 /* Determine if URLs should be enabled, based on RULE.
243    This reuses the logic for colorization.  */
244
245 bool
246 diagnostic_urls_enabled_p (diagnostic_url_rule_t rule)
247 {
248   switch (rule)
249     {
250     case DIAGNOSTICS_URL_NO:
251       return false;
252     case DIAGNOSTICS_URL_YES:
253       return true;
254     case DIAGNOSTICS_URL_AUTO:
255       return should_colorize ();
256     default:
257       gcc_unreachable ();
258     }
259 }