]> git.ipfire.org Git - thirdparty/git.git/blame - color.c
color.c: support bright aixterm colors
[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;
139 /* Rewrite low numbers as more-portable standard colors. */
140 } else if (val < 8) {
141 out->type = COLOR_ANSI;
4a28eb0a 142 out->value = val + COLOR_FOREGROUND_ANSI;
3759d27a 143 return 0;
695d95df
JK
144 } else if (val < 256) {
145 out->type = COLOR_256;
146 out->value = val;
147 return 0;
148 }
149 }
150
151 return -1;
7c92fe0e
JK
152}
153
df8e472c 154static int parse_attr(const char *name, size_t len)
7c92fe0e 155{
df8e472c
JK
156 static const struct {
157 const char *name;
158 size_t len;
159 int val, neg;
160 } attrs[] = {
161#define ATTR(x, val, neg) { (x), sizeof(x)-1, (val), (neg) }
162 ATTR("bold", 1, 22),
163 ATTR("dim", 2, 22),
54590a0e 164 ATTR("italic", 3, 23),
df8e472c
JK
165 ATTR("ul", 4, 24),
166 ATTR("blink", 5, 25),
9dc3515c
JK
167 ATTR("reverse", 7, 27),
168 ATTR("strike", 9, 29)
df8e472c 169#undef ATTR
7c92fe0e 170 };
df8e472c 171 int negate = 0;
7c92fe0e 172 int i;
df8e472c 173
5621068f
JK
174 if (skip_prefix_mem(name, len, "no", &name, &len)) {
175 skip_prefix_mem(name, len, "-", &name, &len);
df8e472c 176 negate = 1;
5621068f 177 }
df8e472c
JK
178
179 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
180 if (attrs[i].len == len && !memcmp(attrs[i].name, name, len))
181 return negate ? attrs[i].neg : attrs[i].val;
7c92fe0e
JK
182 }
183 return -1;
184}
185
f6c5a296 186int color_parse(const char *value, char *dst)
2c2dc7c8 187{
f6c5a296 188 return color_parse_mem(value, strlen(value), dst);
2c2dc7c8
RS
189}
190
695d95df
JK
191/*
192 * Write the ANSI color codes for "c" to "out"; the string should
193 * already have the ANSI escape code in it. "out" should have enough
194 * space in it to fit any color.
195 */
4a28eb0a 196static char *color_output(char *out, int len, const struct color *c, int background)
695d95df 197{
4a28eb0a
ES
198 int offset = 0;
199
200 if (background)
201 offset = COLOR_BACKGROUND_OFFSET;
695d95df
JK
202 switch (c->type) {
203 case COLOR_UNSPECIFIED:
204 case COLOR_NORMAL:
205 break;
206 case COLOR_ANSI:
4a28eb0a 207 out += xsnprintf(out, len, "%d", c->value + offset);
695d95df
JK
208 break;
209 case COLOR_256:
4a28eb0a
ES
210 out += xsnprintf(out, len, "%d;5;%d", COLOR_FOREGROUND_256 + offset,
211 c->value);
695d95df 212 break;
17a4be26 213 case COLOR_RGB:
4a28eb0a
ES
214 out += xsnprintf(out, len, "%d;2;%d;%d;%d",
215 COLOR_FOREGROUND_RGB + offset,
cbc8feea 216 c->red, c->green, c->blue);
17a4be26 217 break;
695d95df
JK
218 }
219 return out;
220}
221
222static int color_empty(const struct color *c)
223{
224 return c->type <= COLOR_NORMAL;
225}
226
f6c5a296 227int color_parse_mem(const char *value, int value_len, char *dst)
7c92fe0e
JK
228{
229 const char *ptr = value;
2c2dc7c8 230 int len = value_len;
cbc8feea 231 char *end = dst + COLOR_MAXLEN;
8b124135 232 unsigned int attr = 0;
695d95df
JK
233 struct color fg = { COLOR_UNSPECIFIED };
234 struct color bg = { COLOR_UNSPECIFIED };
7c92fe0e 235
bc407565
NTND
236 while (len > 0 && isspace(*ptr)) {
237 ptr++;
238 len--;
239 }
240
55cccf4b
JK
241 if (!len) {
242 dst[0] = '\0';
243 return 0;
244 }
c2f41bf5 245
bc407565 246 if (!strncasecmp(ptr, "reset", len)) {
cbc8feea 247 xsnprintf(dst, end - dst, GIT_COLOR_RESET);
f6c5a296 248 return 0;
7c92fe0e
JK
249 }
250
8b124135 251 /* [fg [bg]] [attr]... */
2c2dc7c8 252 while (len > 0) {
7c92fe0e 253 const char *word = ptr;
3e1952ed 254 struct color c = { COLOR_UNSPECIFIED };
2c2dc7c8 255 int val, wordlen = 0;
7c92fe0e 256
2c2dc7c8
RS
257 while (len > 0 && !isspace(word[wordlen])) {
258 wordlen++;
259 len--;
260 }
7c92fe0e 261
2c2dc7c8
RS
262 ptr = word + wordlen;
263 while (len > 0 && isspace(*ptr)) {
7c92fe0e 264 ptr++;
2c2dc7c8
RS
265 len--;
266 }
7c92fe0e 267
695d95df
JK
268 if (!parse_color(&c, word, wordlen)) {
269 if (fg.type == COLOR_UNSPECIFIED) {
270 fg = c;
7c92fe0e
JK
271 continue;
272 }
695d95df
JK
273 if (bg.type == COLOR_UNSPECIFIED) {
274 bg = c;
7c92fe0e
JK
275 continue;
276 }
277 goto bad;
278 }
2c2dc7c8 279 val = parse_attr(word, wordlen);
8b124135
JH
280 if (0 <= val)
281 attr |= (1 << val);
282 else
7c92fe0e 283 goto bad;
7c92fe0e
JK
284 }
285
cbc8feea
JK
286#undef OUT
287#define OUT(x) do { \
288 if (dst == end) \
033abf97 289 BUG("color parsing ran out of space"); \
cbc8feea
JK
290 *dst++ = (x); \
291} while(0)
292
695d95df 293 if (attr || !color_empty(&fg) || !color_empty(&bg)) {
7c92fe0e 294 int sep = 0;
8b124135 295 int i;
7c92fe0e 296
cbc8feea
JK
297 OUT('\033');
298 OUT('[');
8b124135
JH
299
300 for (i = 0; attr; i++) {
301 unsigned bit = (1 << i);
302 if (!(attr & bit))
303 continue;
304 attr &= ~bit;
305 if (sep++)
cbc8feea
JK
306 OUT(';');
307 dst += xsnprintf(dst, end - dst, "%d", i);
7c92fe0e 308 }
695d95df 309 if (!color_empty(&fg)) {
7c92fe0e 310 if (sep++)
cbc8feea 311 OUT(';');
4a28eb0a 312 dst = color_output(dst, end - dst, &fg, 0);
7c92fe0e 313 }
695d95df 314 if (!color_empty(&bg)) {
7c92fe0e 315 if (sep++)
cbc8feea 316 OUT(';');
4a28eb0a 317 dst = color_output(dst, end - dst, &bg, 1);
7c92fe0e 318 }
cbc8feea 319 OUT('m');
7c92fe0e 320 }
cbc8feea 321 OUT(0);
f6c5a296 322 return 0;
7c92fe0e 323bad:
f6c5a296 324 return error(_("invalid color value: %.*s"), value_len, value);
cbc8feea 325#undef OUT
7c92fe0e
JK
326}
327
e269eb79 328int git_config_colorbool(const char *var, const char *value)
7c92fe0e 329{
57f2b842
JH
330 if (value) {
331 if (!strcasecmp(value, "never"))
332 return 0;
333 if (!strcasecmp(value, "always"))
2c1acdf6 334 return 1;
57f2b842 335 if (!strcasecmp(value, "auto"))
daa0c3d9 336 return GIT_COLOR_AUTO;
7c92fe0e 337 }
57f2b842 338
73e9da01
ML
339 if (!var)
340 return -1;
341
57f2b842
JH
342 /* Missing or explicit false to turn off colorization */
343 if (!git_config_bool(var, value))
7c92fe0e 344 return 0;
57f2b842
JH
345
346 /* any normal truth value defaults to 'auto' */
daa0c3d9
JK
347 return GIT_COLOR_AUTO;
348}
349
295d949c 350static int check_auto_color(int fd)
daa0c3d9 351{
295d949c
JS
352 static int color_stderr_is_tty = -1;
353 int *is_tty_p = fd == 1 ? &color_stdout_is_tty : &color_stderr_is_tty;
354 if (*is_tty_p < 0)
355 *is_tty_p = isatty(fd);
356 if (*is_tty_p || (fd == 1 && pager_in_use() && pager_use_color)) {
a64f213d 357 if (!is_terminal_dumb())
57f2b842
JH
358 return 1;
359 }
360 return 0;
7c92fe0e
JK
361}
362
295d949c 363int want_color_fd(int fd, int var)
daa0c3d9 364{
6cdf8a79
365 /*
366 * NEEDSWORK: This function is sometimes used from multiple threads, and
367 * we end up using want_auto racily. That "should not matter" since
368 * we always write the same value, but it's still wrong. This function
369 * is listed in .tsan-suppressions for the time being.
370 */
371
295d949c 372 static int want_auto[3] = { -1, -1, -1 };
daa0c3d9 373
65bb21e7
ES
374 if (fd < 1 || fd >= ARRAY_SIZE(want_auto))
375 BUG("file descriptor out of range: %d", fd);
376
c9bfb953
JK
377 if (var < 0)
378 var = git_use_color_default;
379
daa0c3d9 380 if (var == GIT_COLOR_AUTO) {
295d949c
JS
381 if (want_auto[fd] < 0)
382 want_auto[fd] = check_auto_color(fd);
383 return want_auto[fd];
daa0c3d9 384 }
c9bfb953 385 return var;
daa0c3d9
JK
386}
387
3e1dd17a 388int git_color_config(const char *var, const char *value, void *cb)
6b2f2d98
MK
389{
390 if (!strcmp(var, "color.ui")) {
e269eb79 391 git_use_color_default = git_config_colorbool(var, value);
6b2f2d98
MK
392 return 0;
393 }
394
3e1dd17a
JK
395 return 0;
396}
397
33c643bb
JK
398int git_color_default_config(const char *var, const char *value, void *cb)
399{
400 if (git_color_config(var, value, cb) < 0)
401 return -1;
402
403 return git_default_config(var, value, cb);
404}
405
becbdae8
JN
406void color_print_strbuf(FILE *fp, const char *color, const struct strbuf *sb)
407{
408 if (*color)
409 fprintf(fp, "%s", color);
410 fprintf(fp, "%s", sb->buf);
411 if (*color)
412 fprintf(fp, "%s", GIT_COLOR_RESET);
413}
414
f26a0012 415static int color_vfprintf(FILE *fp, const char *color, const char *fmt,
7c92fe0e
JK
416 va_list args, const char *trail)
417{
418 int r = 0;
419
420 if (*color)
f26a0012
KH
421 r += fprintf(fp, "%s", color);
422 r += vfprintf(fp, fmt, args);
7c92fe0e 423 if (*color)
dc6ebd4c 424 r += fprintf(fp, "%s", GIT_COLOR_RESET);
7c92fe0e 425 if (trail)
f26a0012 426 r += fprintf(fp, "%s", trail);
7c92fe0e
JK
427 return r;
428}
429
f26a0012 430int color_fprintf(FILE *fp, const char *color, const char *fmt, ...)
7c92fe0e
JK
431{
432 va_list args;
433 int r;
434 va_start(args, fmt);
f26a0012 435 r = color_vfprintf(fp, color, fmt, args, NULL);
7c92fe0e
JK
436 va_end(args);
437 return r;
438}
439
f26a0012 440int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...)
7c92fe0e
JK
441{
442 va_list args;
443 int r;
444 va_start(args, fmt);
f26a0012 445 r = color_vfprintf(fp, color, fmt, args, "\n");
7c92fe0e
JK
446 va_end(args);
447 return r;
448}
148135fc
JK
449
450int color_is_nil(const char *c)
451{
452 return !strcmp(c, "NIL");
453}