1 #include "cache.h"
2 #include "config.h"
3 #include "color.h"
4 
5 static int git_use_color_default = GIT_COLOR_AUTO;
6 int color_stdout_is_tty = -1;
7 
8 /*
9  * The list of available column colors.
10  */
11 const char *column_colors_ansi[] = {
12 	GIT_COLOR_RED,
13 	GIT_COLOR_GREEN,
14 	GIT_COLOR_YELLOW,
15 	GIT_COLOR_BLUE,
16 	GIT_COLOR_MAGENTA,
17 	GIT_COLOR_CYAN,
18 	GIT_COLOR_BOLD_RED,
19 	GIT_COLOR_BOLD_GREEN,
20 	GIT_COLOR_BOLD_YELLOW,
21 	GIT_COLOR_BOLD_BLUE,
22 	GIT_COLOR_BOLD_MAGENTA,
23 	GIT_COLOR_BOLD_CYAN,
24 	GIT_COLOR_RESET,
25 };
26 
27 enum {
28 	COLOR_BACKGROUND_OFFSET = 10,
29 	COLOR_FOREGROUND_ANSI = 30,
30 	COLOR_FOREGROUND_RGB = 38,
31 	COLOR_FOREGROUND_256 = 38,
32 	COLOR_FOREGROUND_BRIGHT_ANSI = 90,
33 };
34 
35 /* Ignore the RESET at the end when giving the size */
36 const int column_colors_ansi_max = ARRAY_SIZE(column_colors_ansi) - 1;
37 
38 /* An individual foreground or background color. */
39 struct color {
40 	enum {
41 		COLOR_UNSPECIFIED = 0,
42 		COLOR_NORMAL,
43 		COLOR_ANSI, /* basic 0-7 ANSI colors */
44 		COLOR_256,
45 		COLOR_RGB
46 	} type;
47 	/* The numeric value for ANSI and 256-color modes */
48 	unsigned char value;
49 	/* 24-bit RGB color values */
50 	unsigned char red, green, blue;
51 };
52 
53 /*
54  * "word" is a buffer of length "len"; does it match the NUL-terminated
55  * "match" exactly?
56  */
match_word(const char * word,int len,const char * match)57 static int match_word(const char *word, int len, const char *match)
58 {
59 	return !strncasecmp(word, match, len) && !match[len];
60 }
61 
get_hex_color(const char * in,unsigned char * out)62 static int get_hex_color(const char *in, unsigned char *out)
63 {
64 	unsigned int val;
65 	val = (hexval(in[0]) << 4) | hexval(in[1]);
66 	if (val & ~0xff)
67 		return -1;
68 	*out = val;
69 	return 0;
70 }
71 
72 /*
73  * If an ANSI color is recognized in "name", fill "out" and return 0.
74  * Otherwise, leave out unchanged and return -1.
75  */
parse_ansi_color(struct color * out,const char * name,int len)76 static int parse_ansi_color(struct color *out, const char *name, int len)
77 {
78 	/* Positions in array must match ANSI color codes */
79 	static const char * const color_names[] = {
80 		"black", "red", "green", "yellow",
81 		"blue", "magenta", "cyan", "white"
82 	};
83 	int i;
84 	int color_offset = COLOR_FOREGROUND_ANSI;
85 
86 	if (strncasecmp(name, "bright", 6) == 0) {
87 		color_offset = COLOR_FOREGROUND_BRIGHT_ANSI;
88 		name += 6;
89 		len -= 6;
90 	}
91 	for (i = 0; i < ARRAY_SIZE(color_names); i++) {
92 		if (match_word(name, len, color_names[i])) {
93 			out->type = COLOR_ANSI;
94 			out->value = i + color_offset;
95 			return 0;
96 		}
97 	}
98 	return -1;
99 }
100 
parse_color(struct color * out,const char * name,int len)101 static int parse_color(struct color *out, const char *name, int len)
102 {
103 	char *end;
104 	long val;
105 
106 	/* First try the special word "normal"... */
107 	if (match_word(name, len, "normal")) {
108 		out->type = COLOR_NORMAL;
109 		return 0;
110 	}
111 
112 	/* Try a 24-bit RGB value */
113 	if (len == 7 && name[0] == '#') {
114 		if (!get_hex_color(name + 1, &out->red) &&
115 		    !get_hex_color(name + 3, &out->green) &&
116 		    !get_hex_color(name + 5, &out->blue)) {
117 			out->type = COLOR_RGB;
118 			return 0;
119 		}
120 	}
121 
122 	/* Then pick from our human-readable color names... */
123 	if (parse_ansi_color(out, name, len) == 0) {
124 		return 0;
125 	}
126 
127 	/* And finally try a literal 256-color-mode number */
128 	val = strtol(name, &end, 10);
129 	if (end - name == len) {
130 		/*
131 		 * Allow "-1" as an alias for "normal", but other negative
132 		 * numbers are bogus.
133 		 */
134 		if (val < -1)
135 			; /* fall through to error */
136 		else if (val < 0) {
137 			out->type = COLOR_NORMAL;
138 			return 0;
139 		/* Rewrite 0-7 as more-portable standard colors. */
140 		} else if (val < 8) {
141 			out->type = COLOR_ANSI;
142 			out->value = val + COLOR_FOREGROUND_ANSI;
143 			return 0;
144 		/* Rewrite 8-15 as more-portable aixterm colors. */
145 		} else if (val < 16) {
146 			out->type = COLOR_ANSI;
147 			out->value = val - 8 + COLOR_FOREGROUND_BRIGHT_ANSI;
148 			return 0;
149 		} else if (val < 256) {
150 			out->type = COLOR_256;
151 			out->value = val;
152 			return 0;
153 		}
154 	}
155 
156 	return -1;
157 }
158 
parse_attr(const char * name,size_t len)159 static int parse_attr(const char *name, size_t len)
160 {
161 	static const struct {
162 		const char *name;
163 		size_t len;
164 		int val, neg;
165 	} attrs[] = {
166 #define ATTR(x, val, neg) { (x), sizeof(x)-1, (val), (neg) }
167 		ATTR("bold",      1, 22),
168 		ATTR("dim",       2, 22),
169 		ATTR("italic",    3, 23),
170 		ATTR("ul",        4, 24),
171 		ATTR("blink",     5, 25),
172 		ATTR("reverse",   7, 27),
173 		ATTR("strike",    9, 29)
174 #undef ATTR
175 	};
176 	int negate = 0;
177 	int i;
178 
179 	if (skip_prefix_mem(name, len, "no", &name, &len)) {
180 		skip_prefix_mem(name, len, "-", &name, &len);
181 		negate = 1;
182 	}
183 
184 	for (i = 0; i < ARRAY_SIZE(attrs); i++) {
185 		if (attrs[i].len == len && !memcmp(attrs[i].name, name, len))
186 			return negate ? attrs[i].neg : attrs[i].val;
187 	}
188 	return -1;
189 }
190 
color_parse(const char * value,char * dst)191 int color_parse(const char *value, char *dst)
192 {
193 	return color_parse_mem(value, strlen(value), dst);
194 }
195 
196 /*
197  * Write the ANSI color codes for "c" to "out"; the string should
198  * already have the ANSI escape code in it. "out" should have enough
199  * space in it to fit any color.
200  */
color_output(char * out,int len,const struct color * c,int background)201 static char *color_output(char *out, int len, const struct color *c, int background)
202 {
203 	int offset = 0;
204 
205 	if (background)
206 		offset = COLOR_BACKGROUND_OFFSET;
207 	switch (c->type) {
208 	case COLOR_UNSPECIFIED:
209 	case COLOR_NORMAL:
210 		break;
211 	case COLOR_ANSI:
212 		out += xsnprintf(out, len, "%d", c->value + offset);
213 		break;
214 	case COLOR_256:
215 		out += xsnprintf(out, len, "%d;5;%d", COLOR_FOREGROUND_256 + offset,
216 				 c->value);
217 		break;
218 	case COLOR_RGB:
219 		out += xsnprintf(out, len, "%d;2;%d;%d;%d",
220 				 COLOR_FOREGROUND_RGB + offset,
221 				 c->red, c->green, c->blue);
222 		break;
223 	}
224 	return out;
225 }
226 
color_empty(const struct color * c)227 static int color_empty(const struct color *c)
228 {
229 	return c->type <= COLOR_NORMAL;
230 }
231 
color_parse_mem(const char * value,int value_len,char * dst)232 int color_parse_mem(const char *value, int value_len, char *dst)
233 {
234 	const char *ptr = value;
235 	int len = value_len;
236 	char *end = dst + COLOR_MAXLEN;
237 	unsigned int attr = 0;
238 	struct color fg = { COLOR_UNSPECIFIED };
239 	struct color bg = { COLOR_UNSPECIFIED };
240 
241 	while (len > 0 && isspace(*ptr)) {
242 		ptr++;
243 		len--;
244 	}
245 
246 	if (!len) {
247 		dst[0] = '\0';
248 		return 0;
249 	}
250 
251 	if (!strncasecmp(ptr, "reset", len)) {
252 		xsnprintf(dst, end - dst, GIT_COLOR_RESET);
253 		return 0;
254 	}
255 
256 	/* [fg [bg]] [attr]... */
257 	while (len > 0) {
258 		const char *word = ptr;
259 		struct color c = { COLOR_UNSPECIFIED };
260 		int val, wordlen = 0;
261 
262 		while (len > 0 && !isspace(word[wordlen])) {
263 			wordlen++;
264 			len--;
265 		}
266 
267 		ptr = word + wordlen;
268 		while (len > 0 && isspace(*ptr)) {
269 			ptr++;
270 			len--;
271 		}
272 
273 		if (!parse_color(&c, word, wordlen)) {
274 			if (fg.type == COLOR_UNSPECIFIED) {
275 				fg = c;
276 				continue;
277 			}
278 			if (bg.type == COLOR_UNSPECIFIED) {
279 				bg = c;
280 				continue;
281 			}
282 			goto bad;
283 		}
284 		val = parse_attr(word, wordlen);
285 		if (0 <= val)
286 			attr |= (1 << val);
287 		else
288 			goto bad;
289 	}
290 
291 #undef OUT
292 #define OUT(x) do { \
293 	if (dst == end) \
294 		BUG("color parsing ran out of space"); \
295 	*dst++ = (x); \
296 } while(0)
297 
298 	if (attr || !color_empty(&fg) || !color_empty(&bg)) {
299 		int sep = 0;
300 		int i;
301 
302 		OUT('\033');
303 		OUT('[');
304 
305 		for (i = 0; attr; i++) {
306 			unsigned bit = (1 << i);
307 			if (!(attr & bit))
308 				continue;
309 			attr &= ~bit;
310 			if (sep++)
311 				OUT(';');
312 			dst += xsnprintf(dst, end - dst, "%d", i);
313 		}
314 		if (!color_empty(&fg)) {
315 			if (sep++)
316 				OUT(';');
317 			dst = color_output(dst, end - dst, &fg, 0);
318 		}
319 		if (!color_empty(&bg)) {
320 			if (sep++)
321 				OUT(';');
322 			dst = color_output(dst, end - dst, &bg, 1);
323 		}
324 		OUT('m');
325 	}
326 	OUT(0);
327 	return 0;
328 bad:
329 	return error(_("invalid color value: %.*s"), value_len, value);
330 #undef OUT
331 }
332 
git_config_colorbool(const char * var,const char * value)333 int git_config_colorbool(const char *var, const char *value)
334 {
335 	if (value) {
336 		if (!strcasecmp(value, "never"))
337 			return 0;
338 		if (!strcasecmp(value, "always"))
339 			return 1;
340 		if (!strcasecmp(value, "auto"))
341 			return GIT_COLOR_AUTO;
342 	}
343 
344 	if (!var)
345 		return -1;
346 
347 	/* Missing or explicit false to turn off colorization */
348 	if (!git_config_bool(var, value))
349 		return 0;
350 
351 	/* any normal truth value defaults to 'auto' */
352 	return GIT_COLOR_AUTO;
353 }
354 
check_auto_color(int fd)355 static int check_auto_color(int fd)
356 {
357 	static int color_stderr_is_tty = -1;
358 	int *is_tty_p = fd == 1 ? &color_stdout_is_tty : &color_stderr_is_tty;
359 	if (*is_tty_p < 0)
360 		*is_tty_p = isatty(fd);
361 	if (*is_tty_p || (fd == 1 && pager_in_use() && pager_use_color)) {
362 		if (!is_terminal_dumb())
363 			return 1;
364 	}
365 	return 0;
366 }
367 
want_color_fd(int fd,int var)368 int want_color_fd(int fd, int var)
369 {
370 	/*
371 	 * NEEDSWORK: This function is sometimes used from multiple threads, and
372 	 * we end up using want_auto racily. That "should not matter" since
373 	 * we always write the same value, but it's still wrong. This function
374 	 * is listed in .tsan-suppressions for the time being.
375 	 */
376 
377 	static int want_auto[3] = { -1, -1, -1 };
378 
379 	if (fd < 1 || fd >= ARRAY_SIZE(want_auto))
380 		BUG("file descriptor out of range: %d", fd);
381 
382 	if (var < 0)
383 		var = git_use_color_default;
384 
385 	if (var == GIT_COLOR_AUTO) {
386 		if (want_auto[fd] < 0)
387 			want_auto[fd] = check_auto_color(fd);
388 		return want_auto[fd];
389 	}
390 	return var;
391 }
392 
git_color_config(const char * var,const char * value,void * cb)393 int git_color_config(const char *var, const char *value, void *cb)
394 {
395 	if (!strcmp(var, "color.ui")) {
396 		git_use_color_default = git_config_colorbool(var, value);
397 		return 0;
398 	}
399 
400 	return 0;
401 }
402 
git_color_default_config(const char * var,const char * value,void * cb)403 int git_color_default_config(const char *var, const char *value, void *cb)
404 {
405 	if (git_color_config(var, value, cb) < 0)
406 		return -1;
407 
408 	return git_default_config(var, value, cb);
409 }
410 
color_print_strbuf(FILE * fp,const char * color,const struct strbuf * sb)411 void color_print_strbuf(FILE *fp, const char *color, const struct strbuf *sb)
412 {
413 	if (*color)
414 		fprintf(fp, "%s", color);
415 	fprintf(fp, "%s", sb->buf);
416 	if (*color)
417 		fprintf(fp, "%s", GIT_COLOR_RESET);
418 }
419 
color_vfprintf(FILE * fp,const char * color,const char * fmt,va_list args,const char * trail)420 static int color_vfprintf(FILE *fp, const char *color, const char *fmt,
421 		va_list args, const char *trail)
422 {
423 	int r = 0;
424 
425 	if (*color)
426 		r += fprintf(fp, "%s", color);
427 	r += vfprintf(fp, fmt, args);
428 	if (*color)
429 		r += fprintf(fp, "%s", GIT_COLOR_RESET);
430 	if (trail)
431 		r += fprintf(fp, "%s", trail);
432 	return r;
433 }
434 
color_fprintf(FILE * fp,const char * color,const char * fmt,...)435 int color_fprintf(FILE *fp, const char *color, const char *fmt, ...)
436 {
437 	va_list args;
438 	int r;
439 	va_start(args, fmt);
440 	r = color_vfprintf(fp, color, fmt, args, NULL);
441 	va_end(args);
442 	return r;
443 }
444 
color_fprintf_ln(FILE * fp,const char * color,const char * fmt,...)445 int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...)
446 {
447 	va_list args;
448 	int r;
449 	va_start(args, fmt);
450 	r = color_vfprintf(fp, color, fmt, args, "\n");
451 	va_end(args);
452 	return r;
453 }
454 
color_is_nil(const char * c)455 int color_is_nil(const char *c)
456 {
457 	return !strcmp(c, "NIL");
458 }
459