]> git.ipfire.org Git - thirdparty/git.git/blame - color.c
Merge branch 'rs/pull-leakfix'
[thirdparty/git.git] / color.c
CommitLineData
7c92fe0e 1#include "cache.h"
b2141fc1 2#include "config.h"
85023577 3#include "color.h"
7c92fe0e 4
4c7f1819 5static int git_use_color_default = GIT_COLOR_AUTO;
e269eb79 6int color_stdout_is_tty = -1;
6b2f2d98 7
7cd52b5b
DM
8/*
9 * The list of available column colors.
10 */
11const 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
4a28eb0a
ES
27enum {
28 COLOR_BACKGROUND_OFFSET = 10,
29 COLOR_FOREGROUND_ANSI = 30,
30 COLOR_FOREGROUND_RGB = 38,
31 COLOR_FOREGROUND_256 = 38,
1751b09a 32 COLOR_FOREGROUND_BRIGHT_ANSI = 90,
4a28eb0a
ES
33};
34
7cd52b5b
DM
35/* Ignore the RESET at the end when giving the size */
36const int column_colors_ansi_max = ARRAY_SIZE(column_colors_ansi) - 1;
37
695d95df
JK
38/* An individual foreground or background color. */
39struct color {
40 enum {
41 COLOR_UNSPECIFIED = 0,
42 COLOR_NORMAL,
43 COLOR_ANSI, /* basic 0-7 ANSI colors */
17a4be26
JK
44 COLOR_256,
45 COLOR_RGB
695d95df
JK
46 } type;
47 /* The numeric value for ANSI and 256-color modes */
48 unsigned char value;
17a4be26
JK
49 /* 24-bit RGB color values */
50 unsigned char red, green, blue;
695d95df
JK
51};
52
53/*
54 * "word" is a buffer of length "len"; does it match the NUL-terminated
55 * "match" exactly?
56 */
57static int match_word(const char *word, int len, const char *match)
7c92fe0e 58{
695d95df
JK
59 return !strncasecmp(word, match, len) && !match[len];
60}
61
17a4be26
JK
62static 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
1751b09a
ES
72/*
73 * If an ANSI color is recognized in "name", fill "out" and return 0.
74 * Otherwise, leave out unchanged and return -1.
75 */
76static int parse_ansi_color(struct color *out, const char *name, int len)
695d95df
JK
77{
78 /* Positions in array must match ANSI color codes */
7c92fe0e 79 static const char * const color_names[] = {
695d95df 80 "black", "red", "green", "yellow",
7c92fe0e
JK
81 "blue", "magenta", "cyan", "white"
82 };
7c92fe0e 83 int i;
1751b09a
ES
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
101static int parse_color(struct color *out, const char *name, int len)
102{
103 char *end;
695d95df
JK
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
17a4be26
JK
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
695d95df 122 /* Then pick from our human-readable color names... */
1751b09a
ES
123 if (parse_ansi_color(out, name, len) == 0) {
124 return 0;
7c92fe0e 125 }
695d95df
JK
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;
c444f032 139 /* Rewrite 0-7 as more-portable standard colors. */
695d95df
JK
140 } else if (val < 8) {
141 out->type = COLOR_ANSI;
4a28eb0a 142 out->value = val + COLOR_FOREGROUND_ANSI;
3759d27a 143 return 0;
c444f032
ES
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;
695d95df
JK
149 } else if (val < 256) {
150 out->type = COLOR_256;
151 out->value = val;
152 return 0;
153 }
154 }
155
156 return -1;
7c92fe0e
JK
157}
158
df8e472c 159static int parse_attr(const char *name, size_t len)
7c92fe0e 160{
df8e472c
JK
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),
54590a0e 169 ATTR("italic", 3, 23),
df8e472c
JK
170 ATTR("ul", 4, 24),
171 ATTR("blink", 5, 25),
9dc3515c
JK
172 ATTR("reverse", 7, 27),
173 ATTR("strike", 9, 29)
df8e472c 174#undef ATTR
7c92fe0e 175 };
df8e472c 176 int negate = 0;
7c92fe0e 177 int i;
df8e472c 178
5621068f
JK
179 if (skip_prefix_mem(name, len, "no", &name, &len)) {
180 skip_prefix_mem(name, len, "-", &name, &len);
df8e472c 181 negate = 1;
5621068f 182 }
df8e472c
JK
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;
7c92fe0e
JK
187 }
188 return -1;
189}
190
f6c5a296 191int color_parse(const char *value, char *dst)
2c2dc7c8 192{
f6c5a296 193 return color_parse_mem(value, strlen(value), dst);
2c2dc7c8
RS
194}
195
695d95df
JK
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 */
4a28eb0a 201static char *color_output(char *out, int len, const struct color *c, int background)
695d95df 202{
4a28eb0a
ES
203 int offset = 0;
204
205 if (background)
206 offset = COLOR_BACKGROUND_OFFSET;
695d95df
JK
207 switch (c->type) {
208 case COLOR_UNSPECIFIED:
209 case COLOR_NORMAL:
210 break;
211 case COLOR_ANSI:
4a28eb0a 212 out += xsnprintf(out, len, "%d", c->value + offset);
695d95df
JK
213 break;
214 case COLOR_256:
4a28eb0a
ES
215 out += xsnprintf(out, len, "%d;5;%d", COLOR_FOREGROUND_256 + offset,
216 c->value);
695d95df 217 break;
17a4be26 218 case COLOR_RGB:
4a28eb0a
ES
219 out += xsnprintf(out, len, "%d;2;%d;%d;%d",
220 COLOR_FOREGROUND_RGB + offset,
cbc8feea 221 c->red, c->green, c->blue);
17a4be26 222 break;
695d95df
JK
223 }
224 return out;
225}
226
227static int color_empty(const struct color *c)
228{
229 return c->type <= COLOR_NORMAL;
230}
231
f6c5a296 232int color_parse_mem(const char *value, int value_len, char *dst)
7c92fe0e
JK
233{
234 const char *ptr = value;
2c2dc7c8 235 int len = value_len;
cbc8feea 236 char *end = dst + COLOR_MAXLEN;
8b124135 237 unsigned int attr = 0;
695d95df
JK
238 struct color fg = { COLOR_UNSPECIFIED };
239 struct color bg = { COLOR_UNSPECIFIED };
7c92fe0e 240
bc407565
NTND
241 while (len > 0 && isspace(*ptr)) {
242 ptr++;
243 len--;
244 }
245
55cccf4b
JK
246 if (!len) {
247 dst[0] = '\0';
248 return 0;
249 }
c2f41bf5 250
bc407565 251 if (!strncasecmp(ptr, "reset", len)) {
cbc8feea 252 xsnprintf(dst, end - dst, GIT_COLOR_RESET);
f6c5a296 253 return 0;
7c92fe0e
JK
254 }
255
8b124135 256 /* [fg [bg]] [attr]... */
2c2dc7c8 257 while (len > 0) {
7c92fe0e 258 const char *word = ptr;
3e1952ed 259 struct color c = { COLOR_UNSPECIFIED };
2c2dc7c8 260 int val, wordlen = 0;
7c92fe0e 261
2c2dc7c8
RS
262 while (len > 0 && !isspace(word[wordlen])) {
263 wordlen++;
264 len--;
265 }
7c92fe0e 266
2c2dc7c8
RS
267 ptr = word + wordlen;
268 while (len > 0 && isspace(*ptr)) {
7c92fe0e 269 ptr++;
2c2dc7c8
RS
270 len--;
271 }
7c92fe0e 272
695d95df
JK
273 if (!parse_color(&c, word, wordlen)) {
274 if (fg.type == COLOR_UNSPECIFIED) {
275 fg = c;
7c92fe0e
JK
276 continue;
277 }
695d95df
JK
278 if (bg.type == COLOR_UNSPECIFIED) {
279 bg = c;
7c92fe0e
JK
280 continue;
281 }
282 goto bad;
283 }
2c2dc7c8 284 val = parse_attr(word, wordlen);
8b124135
JH
285 if (0 <= val)
286 attr |= (1 << val);
287 else
7c92fe0e 288 goto bad;
7c92fe0e
JK
289 }
290
cbc8feea
JK
291#undef OUT
292#define OUT(x) do { \
293 if (dst == end) \
033abf97 294 BUG("color parsing ran out of space"); \
cbc8feea
JK
295 *dst++ = (x); \
296} while(0)
297
695d95df 298 if (attr || !color_empty(&fg) || !color_empty(&bg)) {
7c92fe0e 299 int sep = 0;
8b124135 300 int i;
7c92fe0e 301
cbc8feea
JK
302 OUT('\033');
303 OUT('[');
8b124135
JH
304
305 for (i = 0; attr; i++) {
306 unsigned bit = (1 << i);
307 if (!(attr & bit))
308 continue;
309 attr &= ~bit;
310 if (sep++)
cbc8feea
JK
311 OUT(';');
312 dst += xsnprintf(dst, end - dst, "%d", i);
7c92fe0e 313 }
695d95df 314 if (!color_empty(&fg)) {
7c92fe0e 315 if (sep++)
cbc8feea 316 OUT(';');
4a28eb0a 317 dst = color_output(dst, end - dst, &fg, 0);
7c92fe0e 318 }
695d95df 319 if (!color_empty(&bg)) {
7c92fe0e 320 if (sep++)
cbc8feea 321 OUT(';');
4a28eb0a 322 dst = color_output(dst, end - dst, &bg, 1);
7c92fe0e 323 }
cbc8feea 324 OUT('m');
7c92fe0e 325 }
cbc8feea 326 OUT(0);
f6c5a296 327 return 0;
7c92fe0e 328bad:
f6c5a296 329 return error(_("invalid color value: %.*s"), value_len, value);
cbc8feea 330#undef OUT
7c92fe0e
JK
331}
332
e269eb79 333int git_config_colorbool(const char *var, const char *value)
7c92fe0e 334{
57f2b842
JH
335 if (value) {
336 if (!strcasecmp(value, "never"))
337 return 0;
338 if (!strcasecmp(value, "always"))
2c1acdf6 339 return 1;
57f2b842 340 if (!strcasecmp(value, "auto"))
daa0c3d9 341 return GIT_COLOR_AUTO;
7c92fe0e 342 }
57f2b842 343
73e9da01
ML
344 if (!var)
345 return -1;
346
57f2b842
JH
347 /* Missing or explicit false to turn off colorization */
348 if (!git_config_bool(var, value))
7c92fe0e 349 return 0;
57f2b842
JH
350
351 /* any normal truth value defaults to 'auto' */
daa0c3d9
JK
352 return GIT_COLOR_AUTO;
353}
354
295d949c 355static int check_auto_color(int fd)
daa0c3d9 356{
295d949c
JS
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)) {
a64f213d 362 if (!is_terminal_dumb())
57f2b842
JH
363 return 1;
364 }
365 return 0;
7c92fe0e
JK
366}
367
295d949c 368int want_color_fd(int fd, int var)
daa0c3d9 369{
6cdf8a79
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
295d949c 377 static int want_auto[3] = { -1, -1, -1 };
daa0c3d9 378
65bb21e7
ES
379 if (fd < 1 || fd >= ARRAY_SIZE(want_auto))
380 BUG("file descriptor out of range: %d", fd);
381
c9bfb953
JK
382 if (var < 0)
383 var = git_use_color_default;
384
daa0c3d9 385 if (var == GIT_COLOR_AUTO) {
295d949c
JS
386 if (want_auto[fd] < 0)
387 want_auto[fd] = check_auto_color(fd);
388 return want_auto[fd];
daa0c3d9 389 }
c9bfb953 390 return var;
daa0c3d9
JK
391}
392
3e1dd17a 393int git_color_config(const char *var, const char *value, void *cb)
6b2f2d98
MK
394{
395 if (!strcmp(var, "color.ui")) {
e269eb79 396 git_use_color_default = git_config_colorbool(var, value);
6b2f2d98
MK
397 return 0;
398 }
399
3e1dd17a
JK
400 return 0;
401}
402
33c643bb
JK
403int 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
becbdae8
JN
411void 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
f26a0012 420static int color_vfprintf(FILE *fp, const char *color, const char *fmt,
7c92fe0e
JK
421 va_list args, const char *trail)
422{
423 int r = 0;
424
425 if (*color)
f26a0012
KH
426 r += fprintf(fp, "%s", color);
427 r += vfprintf(fp, fmt, args);
7c92fe0e 428 if (*color)
dc6ebd4c 429 r += fprintf(fp, "%s", GIT_COLOR_RESET);
7c92fe0e 430 if (trail)
f26a0012 431 r += fprintf(fp, "%s", trail);
7c92fe0e
JK
432 return r;
433}
434
f26a0012 435int color_fprintf(FILE *fp, const char *color, const char *fmt, ...)
7c92fe0e
JK
436{
437 va_list args;
438 int r;
439 va_start(args, fmt);
f26a0012 440 r = color_vfprintf(fp, color, fmt, args, NULL);
7c92fe0e
JK
441 va_end(args);
442 return r;
443}
444
f26a0012 445int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...)
7c92fe0e
JK
446{
447 va_list args;
448 int r;
449 va_start(args, fmt);
f26a0012 450 r = color_vfprintf(fp, color, fmt, args, "\n");
7c92fe0e
JK
451 va_end(args);
452 return r;
453}
148135fc
JK
454
455int color_is_nil(const char *c)
456{
457 return !strcmp(c, "NIL");
458}