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