1 /* Output colorization. 2 Copyright (C) 2011-2018 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 23 #ifdef __MINGW32__ 24 # include <windows.h> 25 #endif 26 27 #include "color-macros.h" 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 }, 88 { "range1", SGR_SEQ (COLOR_FG_GREEN), 6, false }, 89 { "range2", SGR_SEQ (COLOR_FG_BLUE), 6, false }, 90 { "locus", SGR_SEQ (COLOR_BOLD), 5, false }, 91 { "quote", SGR_SEQ (COLOR_BOLD), 5, false }, 92 { "fixit-insert", SGR_SEQ (COLOR_FG_GREEN), 12, false }, 93 { "fixit-delete", SGR_SEQ (COLOR_FG_RED), 12, false }, 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 }, 98 { "type-diff", SGR_SEQ (COLOR_BOLD COLOR_SEPARATOR COLOR_FG_GREEN), 9, false }, 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: 127 GCC_COLORS='error=01;31:warning=01;35:note=01;36:\ 128 range1=32:range2=34:locus=01:quote=01:\ 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' 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 199 /* Return true if we should use color when in auto mode, false otherwise. */ 200 static bool 201 should_colorize (void) 202 { 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 216 char const *t = getenv ("TERM"); 217 return t && strcmp (t, "dumb") != 0 && isatty (STDERR_FILENO); 218 #endif 219 } 220 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 } 239