2006-09-08 16:03:18 +08:00
|
|
|
#include "cache.h"
|
2017-06-15 02:07:36 +08:00
|
|
|
#include "config.h"
|
2006-12-20 06:34:12 +08:00
|
|
|
#include "color.h"
|
2006-09-08 16:03:18 +08:00
|
|
|
|
make color.ui default to 'auto'
Most users seem to like having colors enabled, and colors can help
beginners to understand the output of some commands (e.g. notice
immediately the boundary between commits in the output of "git log").
Many tutorials tell the users to set color.ui=auto as a very first step,
which tend to indicate that color.ui=none is not the recommanded value,
hence should not be the default.
These tutorials would benefit from skipping this step and starting the
real Git manipulations earlier. Other beginners do not know about
color.ui=auto, and may not discover it by themselves, hence live with
black&white outputs while they may have preferred colors.
A few people (e.g. color-blind) prefer having no colors, but they can
easily set color.ui=never for this (and googling "disable colors in git"
already tells them how to do so), but this needs not occupy space in
beginner-oriented documentations.
A transition period with Git emitting a warning when color.ui is unset
would be possible, but the discomfort of having the warning seems
superior to the benefit: users may be surprised by the change, but not
harmed by it.
The default value is changed, and the documentation is reworded to
mention "color.ui=false" first, since the primary use of color.ui after
this change is to disable colors, not to enable it.
Signed-off-by: Matthieu Moy <Matthieu.Moy@imag.fr>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-06-10 22:26:09 +08:00
|
|
|
static int git_use_color_default = GIT_COLOR_AUTO;
|
2011-08-18 13:03:48 +08:00
|
|
|
int color_stdout_is_tty = -1;
|
2008-02-18 15:26:03 +08:00
|
|
|
|
2011-04-05 13:40:23 +08:00
|
|
|
/*
|
|
|
|
* The list of available column colors.
|
|
|
|
*/
|
|
|
|
const char *column_colors_ansi[] = {
|
|
|
|
GIT_COLOR_RED,
|
|
|
|
GIT_COLOR_GREEN,
|
|
|
|
GIT_COLOR_YELLOW,
|
|
|
|
GIT_COLOR_BLUE,
|
|
|
|
GIT_COLOR_MAGENTA,
|
|
|
|
GIT_COLOR_CYAN,
|
|
|
|
GIT_COLOR_BOLD_RED,
|
|
|
|
GIT_COLOR_BOLD_GREEN,
|
|
|
|
GIT_COLOR_BOLD_YELLOW,
|
|
|
|
GIT_COLOR_BOLD_BLUE,
|
|
|
|
GIT_COLOR_BOLD_MAGENTA,
|
|
|
|
GIT_COLOR_BOLD_CYAN,
|
|
|
|
GIT_COLOR_RESET,
|
|
|
|
};
|
|
|
|
|
2020-01-22 00:56:21 +08:00
|
|
|
enum {
|
|
|
|
COLOR_BACKGROUND_OFFSET = 10,
|
|
|
|
COLOR_FOREGROUND_ANSI = 30,
|
|
|
|
COLOR_FOREGROUND_RGB = 38,
|
|
|
|
COLOR_FOREGROUND_256 = 38,
|
2020-01-22 00:56:22 +08:00
|
|
|
COLOR_FOREGROUND_BRIGHT_ANSI = 90,
|
2020-01-22 00:56:21 +08:00
|
|
|
};
|
|
|
|
|
2011-04-05 13:40:23 +08:00
|
|
|
/* Ignore the RESET at the end when giving the size */
|
|
|
|
const int column_colors_ansi_max = ARRAY_SIZE(column_colors_ansi) - 1;
|
|
|
|
|
parse_color: refactor color storage
When we parse a color name like "red" into its ANSI color
value, we pack the storage into a single int that may take
on many values:
1. If it's "-2", no value has been specified.
2. If it's "-1", the value is "normal" (i.e., no color).
3. If it's 0 through 7, the value is a standard ANSI
color.
4. If it's larger (up to 255), it is a 256-color extended
value.
Given these magic numbers, it is often hard to see what is
going on in the code. Let's refactor this into a struct with
a flag that tells which scheme we are using, along with a
numeric value. This is more verbose, but should hopefully be
simpler to follow. It will also allow us to easily add
support for more schemes, like 24-bit RGB values.
The result is also slightly less efficient to store, but
that's OK; we only store this intermediate state during the
parse, after which we write out the actual ANSI bytes.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-11-20 23:17:05 +08:00
|
|
|
/* An individual foreground or background color. */
|
|
|
|
struct color {
|
|
|
|
enum {
|
|
|
|
COLOR_UNSPECIFIED = 0,
|
|
|
|
COLOR_NORMAL,
|
|
|
|
COLOR_ANSI, /* basic 0-7 ANSI colors */
|
2014-11-20 23:25:39 +08:00
|
|
|
COLOR_256,
|
|
|
|
COLOR_RGB
|
parse_color: refactor color storage
When we parse a color name like "red" into its ANSI color
value, we pack the storage into a single int that may take
on many values:
1. If it's "-2", no value has been specified.
2. If it's "-1", the value is "normal" (i.e., no color).
3. If it's 0 through 7, the value is a standard ANSI
color.
4. If it's larger (up to 255), it is a 256-color extended
value.
Given these magic numbers, it is often hard to see what is
going on in the code. Let's refactor this into a struct with
a flag that tells which scheme we are using, along with a
numeric value. This is more verbose, but should hopefully be
simpler to follow. It will also allow us to easily add
support for more schemes, like 24-bit RGB values.
The result is also slightly less efficient to store, but
that's OK; we only store this intermediate state during the
parse, after which we write out the actual ANSI bytes.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-11-20 23:17:05 +08:00
|
|
|
} type;
|
|
|
|
/* The numeric value for ANSI and 256-color modes */
|
|
|
|
unsigned char value;
|
2014-11-20 23:25:39 +08:00
|
|
|
/* 24-bit RGB color values */
|
|
|
|
unsigned char red, green, blue;
|
parse_color: refactor color storage
When we parse a color name like "red" into its ANSI color
value, we pack the storage into a single int that may take
on many values:
1. If it's "-2", no value has been specified.
2. If it's "-1", the value is "normal" (i.e., no color).
3. If it's 0 through 7, the value is a standard ANSI
color.
4. If it's larger (up to 255), it is a 256-color extended
value.
Given these magic numbers, it is often hard to see what is
going on in the code. Let's refactor this into a struct with
a flag that tells which scheme we are using, along with a
numeric value. This is more verbose, but should hopefully be
simpler to follow. It will also allow us to easily add
support for more schemes, like 24-bit RGB values.
The result is also slightly less efficient to store, but
that's OK; we only store this intermediate state during the
parse, after which we write out the actual ANSI bytes.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-11-20 23:17:05 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "word" is a buffer of length "len"; does it match the NUL-terminated
|
|
|
|
* "match" exactly?
|
|
|
|
*/
|
|
|
|
static int match_word(const char *word, int len, const char *match)
|
2006-09-08 16:03:18 +08:00
|
|
|
{
|
parse_color: refactor color storage
When we parse a color name like "red" into its ANSI color
value, we pack the storage into a single int that may take
on many values:
1. If it's "-2", no value has been specified.
2. If it's "-1", the value is "normal" (i.e., no color).
3. If it's 0 through 7, the value is a standard ANSI
color.
4. If it's larger (up to 255), it is a 256-color extended
value.
Given these magic numbers, it is often hard to see what is
going on in the code. Let's refactor this into a struct with
a flag that tells which scheme we are using, along with a
numeric value. This is more verbose, but should hopefully be
simpler to follow. It will also allow us to easily add
support for more schemes, like 24-bit RGB values.
The result is also slightly less efficient to store, but
that's OK; we only store this intermediate state during the
parse, after which we write out the actual ANSI bytes.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-11-20 23:17:05 +08:00
|
|
|
return !strncasecmp(word, match, len) && !match[len];
|
|
|
|
}
|
|
|
|
|
2014-11-20 23:25:39 +08:00
|
|
|
static int get_hex_color(const char *in, unsigned char *out)
|
|
|
|
{
|
|
|
|
unsigned int val;
|
|
|
|
val = (hexval(in[0]) << 4) | hexval(in[1]);
|
|
|
|
if (val & ~0xff)
|
|
|
|
return -1;
|
|
|
|
*out = val;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-01-22 00:56:22 +08:00
|
|
|
/*
|
|
|
|
* If an ANSI color is recognized in "name", fill "out" and return 0.
|
|
|
|
* Otherwise, leave out unchanged and return -1.
|
|
|
|
*/
|
|
|
|
static int parse_ansi_color(struct color *out, const char *name, int len)
|
parse_color: refactor color storage
When we parse a color name like "red" into its ANSI color
value, we pack the storage into a single int that may take
on many values:
1. If it's "-2", no value has been specified.
2. If it's "-1", the value is "normal" (i.e., no color).
3. If it's 0 through 7, the value is a standard ANSI
color.
4. If it's larger (up to 255), it is a 256-color extended
value.
Given these magic numbers, it is often hard to see what is
going on in the code. Let's refactor this into a struct with
a flag that tells which scheme we are using, along with a
numeric value. This is more verbose, but should hopefully be
simpler to follow. It will also allow us to easily add
support for more schemes, like 24-bit RGB values.
The result is also slightly less efficient to store, but
that's OK; we only store this intermediate state during the
parse, after which we write out the actual ANSI bytes.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-11-20 23:17:05 +08:00
|
|
|
{
|
|
|
|
/* Positions in array must match ANSI color codes */
|
2006-09-08 16:03:18 +08:00
|
|
|
static const char * const color_names[] = {
|
parse_color: refactor color storage
When we parse a color name like "red" into its ANSI color
value, we pack the storage into a single int that may take
on many values:
1. If it's "-2", no value has been specified.
2. If it's "-1", the value is "normal" (i.e., no color).
3. If it's 0 through 7, the value is a standard ANSI
color.
4. If it's larger (up to 255), it is a 256-color extended
value.
Given these magic numbers, it is often hard to see what is
going on in the code. Let's refactor this into a struct with
a flag that tells which scheme we are using, along with a
numeric value. This is more verbose, but should hopefully be
simpler to follow. It will also allow us to easily add
support for more schemes, like 24-bit RGB values.
The result is also slightly less efficient to store, but
that's OK; we only store this intermediate state during the
parse, after which we write out the actual ANSI bytes.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-11-20 23:17:05 +08:00
|
|
|
"black", "red", "green", "yellow",
|
2006-09-08 16:03:18 +08:00
|
|
|
"blue", "magenta", "cyan", "white"
|
|
|
|
};
|
|
|
|
int i;
|
2020-01-22 00:56:22 +08:00
|
|
|
int color_offset = COLOR_FOREGROUND_ANSI;
|
|
|
|
|
|
|
|
if (strncasecmp(name, "bright", 6) == 0) {
|
|
|
|
color_offset = COLOR_FOREGROUND_BRIGHT_ANSI;
|
|
|
|
name += 6;
|
|
|
|
len -= 6;
|
|
|
|
}
|
|
|
|
for (i = 0; i < ARRAY_SIZE(color_names); i++) {
|
|
|
|
if (match_word(name, len, color_names[i])) {
|
|
|
|
out->type = COLOR_ANSI;
|
|
|
|
out->value = i + color_offset;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int parse_color(struct color *out, const char *name, int len)
|
|
|
|
{
|
|
|
|
char *end;
|
parse_color: refactor color storage
When we parse a color name like "red" into its ANSI color
value, we pack the storage into a single int that may take
on many values:
1. If it's "-2", no value has been specified.
2. If it's "-1", the value is "normal" (i.e., no color).
3. If it's 0 through 7, the value is a standard ANSI
color.
4. If it's larger (up to 255), it is a 256-color extended
value.
Given these magic numbers, it is often hard to see what is
going on in the code. Let's refactor this into a struct with
a flag that tells which scheme we are using, along with a
numeric value. This is more verbose, but should hopefully be
simpler to follow. It will also allow us to easily add
support for more schemes, like 24-bit RGB values.
The result is also slightly less efficient to store, but
that's OK; we only store this intermediate state during the
parse, after which we write out the actual ANSI bytes.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-11-20 23:17:05 +08:00
|
|
|
long val;
|
|
|
|
|
|
|
|
/* First try the special word "normal"... */
|
|
|
|
if (match_word(name, len, "normal")) {
|
|
|
|
out->type = COLOR_NORMAL;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-11-20 23:25:39 +08:00
|
|
|
/* Try a 24-bit RGB value */
|
|
|
|
if (len == 7 && name[0] == '#') {
|
|
|
|
if (!get_hex_color(name + 1, &out->red) &&
|
|
|
|
!get_hex_color(name + 3, &out->green) &&
|
|
|
|
!get_hex_color(name + 5, &out->blue)) {
|
|
|
|
out->type = COLOR_RGB;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
parse_color: refactor color storage
When we parse a color name like "red" into its ANSI color
value, we pack the storage into a single int that may take
on many values:
1. If it's "-2", no value has been specified.
2. If it's "-1", the value is "normal" (i.e., no color).
3. If it's 0 through 7, the value is a standard ANSI
color.
4. If it's larger (up to 255), it is a 256-color extended
value.
Given these magic numbers, it is often hard to see what is
going on in the code. Let's refactor this into a struct with
a flag that tells which scheme we are using, along with a
numeric value. This is more verbose, but should hopefully be
simpler to follow. It will also allow us to easily add
support for more schemes, like 24-bit RGB values.
The result is also slightly less efficient to store, but
that's OK; we only store this intermediate state during the
parse, after which we write out the actual ANSI bytes.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-11-20 23:17:05 +08:00
|
|
|
/* Then pick from our human-readable color names... */
|
2020-01-22 00:56:22 +08:00
|
|
|
if (parse_ansi_color(out, name, len) == 0) {
|
|
|
|
return 0;
|
2006-09-08 16:03:18 +08:00
|
|
|
}
|
parse_color: refactor color storage
When we parse a color name like "red" into its ANSI color
value, we pack the storage into a single int that may take
on many values:
1. If it's "-2", no value has been specified.
2. If it's "-1", the value is "normal" (i.e., no color).
3. If it's 0 through 7, the value is a standard ANSI
color.
4. If it's larger (up to 255), it is a 256-color extended
value.
Given these magic numbers, it is often hard to see what is
going on in the code. Let's refactor this into a struct with
a flag that tells which scheme we are using, along with a
numeric value. This is more verbose, but should hopefully be
simpler to follow. It will also allow us to easily add
support for more schemes, like 24-bit RGB values.
The result is also slightly less efficient to store, but
that's OK; we only store this intermediate state during the
parse, after which we write out the actual ANSI bytes.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-11-20 23:17:05 +08:00
|
|
|
|
|
|
|
/* And finally try a literal 256-color-mode number */
|
|
|
|
val = strtol(name, &end, 10);
|
|
|
|
if (end - name == len) {
|
|
|
|
/*
|
|
|
|
* Allow "-1" as an alias for "normal", but other negative
|
|
|
|
* numbers are bogus.
|
|
|
|
*/
|
|
|
|
if (val < -1)
|
|
|
|
; /* fall through to error */
|
|
|
|
else if (val < 0) {
|
|
|
|
out->type = COLOR_NORMAL;
|
|
|
|
return 0;
|
2020-01-22 00:56:23 +08:00
|
|
|
/* Rewrite 0-7 as more-portable standard colors. */
|
parse_color: refactor color storage
When we parse a color name like "red" into its ANSI color
value, we pack the storage into a single int that may take
on many values:
1. If it's "-2", no value has been specified.
2. If it's "-1", the value is "normal" (i.e., no color).
3. If it's 0 through 7, the value is a standard ANSI
color.
4. If it's larger (up to 255), it is a 256-color extended
value.
Given these magic numbers, it is often hard to see what is
going on in the code. Let's refactor this into a struct with
a flag that tells which scheme we are using, along with a
numeric value. This is more verbose, but should hopefully be
simpler to follow. It will also allow us to easily add
support for more schemes, like 24-bit RGB values.
The result is also slightly less efficient to store, but
that's OK; we only store this intermediate state during the
parse, after which we write out the actual ANSI bytes.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-11-20 23:17:05 +08:00
|
|
|
} else if (val < 8) {
|
|
|
|
out->type = COLOR_ANSI;
|
2020-01-22 00:56:21 +08:00
|
|
|
out->value = val + COLOR_FOREGROUND_ANSI;
|
2015-01-21 06:14:48 +08:00
|
|
|
return 0;
|
2020-01-22 00:56:23 +08:00
|
|
|
/* Rewrite 8-15 as more-portable aixterm colors. */
|
|
|
|
} else if (val < 16) {
|
|
|
|
out->type = COLOR_ANSI;
|
|
|
|
out->value = val - 8 + COLOR_FOREGROUND_BRIGHT_ANSI;
|
|
|
|
return 0;
|
parse_color: refactor color storage
When we parse a color name like "red" into its ANSI color
value, we pack the storage into a single int that may take
on many values:
1. If it's "-2", no value has been specified.
2. If it's "-1", the value is "normal" (i.e., no color).
3. If it's 0 through 7, the value is a standard ANSI
color.
4. If it's larger (up to 255), it is a 256-color extended
value.
Given these magic numbers, it is often hard to see what is
going on in the code. Let's refactor this into a struct with
a flag that tells which scheme we are using, along with a
numeric value. This is more verbose, but should hopefully be
simpler to follow. It will also allow us to easily add
support for more schemes, like 24-bit RGB values.
The result is also slightly less efficient to store, but
that's OK; we only store this intermediate state during the
parse, after which we write out the actual ANSI bytes.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-11-20 23:17:05 +08:00
|
|
|
} else if (val < 256) {
|
|
|
|
out->type = COLOR_256;
|
|
|
|
out->value = val;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
2006-09-08 16:03:18 +08:00
|
|
|
}
|
|
|
|
|
color: refactor parse_attr
The list of attributes we recognize is a bit unwieldy, as we
actually have two arrays that must be kept in sync. Instead,
let's have a single array-of-struct to represent our
mapping. That means we can never have an accident that
causes us to read off the end of an array, and it makes
diffs for adding new attributes much easier to read.
This also makes it easy to handle the "no" cases without
having to repeat each attribute (this shortens the list,
making it easier to read, but also also cuts the size of our
linear search in half). Technically this makes it impossible
for us to add an attribute that starts with "no" (we could
confuse "nobody" for the negation of "body"), but since this
is a constrained set of attributes, that's OK.
Since we can also store the length of each name in the
struct, that makes it easy for us to avoid reading past the
"len" parameter given to us (though in practice it was not a
bug, since all of our current callers are interested in a
subset of a NUL-terminated buffer, not a true undelimited
range of memory).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-06-24 01:38:13 +08:00
|
|
|
static int parse_attr(const char *name, size_t len)
|
2006-09-08 16:03:18 +08:00
|
|
|
{
|
color: refactor parse_attr
The list of attributes we recognize is a bit unwieldy, as we
actually have two arrays that must be kept in sync. Instead,
let's have a single array-of-struct to represent our
mapping. That means we can never have an accident that
causes us to read off the end of an array, and it makes
diffs for adding new attributes much easier to read.
This also makes it easy to handle the "no" cases without
having to repeat each attribute (this shortens the list,
making it easier to read, but also also cuts the size of our
linear search in half). Technically this makes it impossible
for us to add an attribute that starts with "no" (we could
confuse "nobody" for the negation of "body"), but since this
is a constrained set of attributes, that's OK.
Since we can also store the length of each name in the
struct, that makes it easy for us to avoid reading past the
"len" parameter given to us (though in practice it was not a
bug, since all of our current callers are interested in a
subset of a NUL-terminated buffer, not a true undelimited
range of memory).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-06-24 01:38:13 +08:00
|
|
|
static const struct {
|
|
|
|
const char *name;
|
|
|
|
size_t len;
|
|
|
|
int val, neg;
|
|
|
|
} attrs[] = {
|
|
|
|
#define ATTR(x, val, neg) { (x), sizeof(x)-1, (val), (neg) }
|
|
|
|
ATTR("bold", 1, 22),
|
|
|
|
ATTR("dim", 2, 22),
|
2016-06-24 01:39:07 +08:00
|
|
|
ATTR("italic", 3, 23),
|
color: refactor parse_attr
The list of attributes we recognize is a bit unwieldy, as we
actually have two arrays that must be kept in sync. Instead,
let's have a single array-of-struct to represent our
mapping. That means we can never have an accident that
causes us to read off the end of an array, and it makes
diffs for adding new attributes much easier to read.
This also makes it easy to handle the "no" cases without
having to repeat each attribute (this shortens the list,
making it easier to read, but also also cuts the size of our
linear search in half). Technically this makes it impossible
for us to add an attribute that starts with "no" (we could
confuse "nobody" for the negation of "body"), but since this
is a constrained set of attributes, that's OK.
Since we can also store the length of each name in the
struct, that makes it easy for us to avoid reading past the
"len" parameter given to us (though in practice it was not a
bug, since all of our current callers are interested in a
subset of a NUL-terminated buffer, not a true undelimited
range of memory).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-06-24 01:38:13 +08:00
|
|
|
ATTR("ul", 4, 24),
|
|
|
|
ATTR("blink", 5, 25),
|
2016-06-24 01:40:16 +08:00
|
|
|
ATTR("reverse", 7, 27),
|
|
|
|
ATTR("strike", 9, 29)
|
color: refactor parse_attr
The list of attributes we recognize is a bit unwieldy, as we
actually have two arrays that must be kept in sync. Instead,
let's have a single array-of-struct to represent our
mapping. That means we can never have an accident that
causes us to read off the end of an array, and it makes
diffs for adding new attributes much easier to read.
This also makes it easy to handle the "no" cases without
having to repeat each attribute (this shortens the list,
making it easier to read, but also also cuts the size of our
linear search in half). Technically this makes it impossible
for us to add an attribute that starts with "no" (we could
confuse "nobody" for the negation of "body"), but since this
is a constrained set of attributes, that's OK.
Since we can also store the length of each name in the
struct, that makes it easy for us to avoid reading past the
"len" parameter given to us (though in practice it was not a
bug, since all of our current callers are interested in a
subset of a NUL-terminated buffer, not a true undelimited
range of memory).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-06-24 01:38:13 +08:00
|
|
|
#undef ATTR
|
2006-09-08 16:03:18 +08:00
|
|
|
};
|
color: refactor parse_attr
The list of attributes we recognize is a bit unwieldy, as we
actually have two arrays that must be kept in sync. Instead,
let's have a single array-of-struct to represent our
mapping. That means we can never have an accident that
causes us to read off the end of an array, and it makes
diffs for adding new attributes much easier to read.
This also makes it easy to handle the "no" cases without
having to repeat each attribute (this shortens the list,
making it easier to read, but also also cuts the size of our
linear search in half). Technically this makes it impossible
for us to add an attribute that starts with "no" (we could
confuse "nobody" for the negation of "body"), but since this
is a constrained set of attributes, that's OK.
Since we can also store the length of each name in the
struct, that makes it easy for us to avoid reading past the
"len" parameter given to us (though in practice it was not a
bug, since all of our current callers are interested in a
subset of a NUL-terminated buffer, not a true undelimited
range of memory).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-06-24 01:38:13 +08:00
|
|
|
int negate = 0;
|
2006-09-08 16:03:18 +08:00
|
|
|
int i;
|
color: refactor parse_attr
The list of attributes we recognize is a bit unwieldy, as we
actually have two arrays that must be kept in sync. Instead,
let's have a single array-of-struct to represent our
mapping. That means we can never have an accident that
causes us to read off the end of an array, and it makes
diffs for adding new attributes much easier to read.
This also makes it easy to handle the "no" cases without
having to repeat each attribute (this shortens the list,
making it easier to read, but also also cuts the size of our
linear search in half). Technically this makes it impossible
for us to add an attribute that starts with "no" (we could
confuse "nobody" for the negation of "body"), but since this
is a constrained set of attributes, that's OK.
Since we can also store the length of each name in the
struct, that makes it easy for us to avoid reading past the
"len" parameter given to us (though in practice it was not a
bug, since all of our current callers are interested in a
subset of a NUL-terminated buffer, not a true undelimited
range of memory).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-06-24 01:38:13 +08:00
|
|
|
|
2016-06-24 01:38:44 +08:00
|
|
|
if (skip_prefix_mem(name, len, "no", &name, &len)) {
|
|
|
|
skip_prefix_mem(name, len, "-", &name, &len);
|
color: refactor parse_attr
The list of attributes we recognize is a bit unwieldy, as we
actually have two arrays that must be kept in sync. Instead,
let's have a single array-of-struct to represent our
mapping. That means we can never have an accident that
causes us to read off the end of an array, and it makes
diffs for adding new attributes much easier to read.
This also makes it easy to handle the "no" cases without
having to repeat each attribute (this shortens the list,
making it easier to read, but also also cuts the size of our
linear search in half). Technically this makes it impossible
for us to add an attribute that starts with "no" (we could
confuse "nobody" for the negation of "body"), but since this
is a constrained set of attributes, that's OK.
Since we can also store the length of each name in the
struct, that makes it easy for us to avoid reading past the
"len" parameter given to us (though in practice it was not a
bug, since all of our current callers are interested in a
subset of a NUL-terminated buffer, not a true undelimited
range of memory).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-06-24 01:38:13 +08:00
|
|
|
negate = 1;
|
2016-06-24 01:38:44 +08:00
|
|
|
}
|
color: refactor parse_attr
The list of attributes we recognize is a bit unwieldy, as we
actually have two arrays that must be kept in sync. Instead,
let's have a single array-of-struct to represent our
mapping. That means we can never have an accident that
causes us to read off the end of an array, and it makes
diffs for adding new attributes much easier to read.
This also makes it easy to handle the "no" cases without
having to repeat each attribute (this shortens the list,
making it easier to read, but also also cuts the size of our
linear search in half). Technically this makes it impossible
for us to add an attribute that starts with "no" (we could
confuse "nobody" for the negation of "body"), but since this
is a constrained set of attributes, that's OK.
Since we can also store the length of each name in the
struct, that makes it easy for us to avoid reading past the
"len" parameter given to us (though in practice it was not a
bug, since all of our current callers are interested in a
subset of a NUL-terminated buffer, not a true undelimited
range of memory).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-06-24 01:38:13 +08:00
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(attrs); i++) {
|
|
|
|
if (attrs[i].len == len && !memcmp(attrs[i].name, name, len))
|
|
|
|
return negate ? attrs[i].neg : attrs[i].val;
|
2006-09-08 16:03:18 +08:00
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-10-08 03:33:09 +08:00
|
|
|
int color_parse(const char *value, char *dst)
|
2009-01-20 12:30:30 +08:00
|
|
|
{
|
2014-10-08 03:33:09 +08:00
|
|
|
return color_parse_mem(value, strlen(value), dst);
|
2009-01-20 12:30:30 +08:00
|
|
|
}
|
|
|
|
|
parse_color: refactor color storage
When we parse a color name like "red" into its ANSI color
value, we pack the storage into a single int that may take
on many values:
1. If it's "-2", no value has been specified.
2. If it's "-1", the value is "normal" (i.e., no color).
3. If it's 0 through 7, the value is a standard ANSI
color.
4. If it's larger (up to 255), it is a 256-color extended
value.
Given these magic numbers, it is often hard to see what is
going on in the code. Let's refactor this into a struct with
a flag that tells which scheme we are using, along with a
numeric value. This is more verbose, but should hopefully be
simpler to follow. It will also allow us to easily add
support for more schemes, like 24-bit RGB values.
The result is also slightly less efficient to store, but
that's OK; we only store this intermediate state during the
parse, after which we write out the actual ANSI bytes.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-11-20 23:17:05 +08:00
|
|
|
/*
|
|
|
|
* Write the ANSI color codes for "c" to "out"; the string should
|
|
|
|
* already have the ANSI escape code in it. "out" should have enough
|
|
|
|
* space in it to fit any color.
|
|
|
|
*/
|
2020-01-22 00:56:21 +08:00
|
|
|
static char *color_output(char *out, int len, const struct color *c, int background)
|
parse_color: refactor color storage
When we parse a color name like "red" into its ANSI color
value, we pack the storage into a single int that may take
on many values:
1. If it's "-2", no value has been specified.
2. If it's "-1", the value is "normal" (i.e., no color).
3. If it's 0 through 7, the value is a standard ANSI
color.
4. If it's larger (up to 255), it is a 256-color extended
value.
Given these magic numbers, it is often hard to see what is
going on in the code. Let's refactor this into a struct with
a flag that tells which scheme we are using, along with a
numeric value. This is more verbose, but should hopefully be
simpler to follow. It will also allow us to easily add
support for more schemes, like 24-bit RGB values.
The result is also slightly less efficient to store, but
that's OK; we only store this intermediate state during the
parse, after which we write out the actual ANSI bytes.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-11-20 23:17:05 +08:00
|
|
|
{
|
2020-01-22 00:56:21 +08:00
|
|
|
int offset = 0;
|
|
|
|
|
|
|
|
if (background)
|
|
|
|
offset = COLOR_BACKGROUND_OFFSET;
|
parse_color: refactor color storage
When we parse a color name like "red" into its ANSI color
value, we pack the storage into a single int that may take
on many values:
1. If it's "-2", no value has been specified.
2. If it's "-1", the value is "normal" (i.e., no color).
3. If it's 0 through 7, the value is a standard ANSI
color.
4. If it's larger (up to 255), it is a 256-color extended
value.
Given these magic numbers, it is often hard to see what is
going on in the code. Let's refactor this into a struct with
a flag that tells which scheme we are using, along with a
numeric value. This is more verbose, but should hopefully be
simpler to follow. It will also allow us to easily add
support for more schemes, like 24-bit RGB values.
The result is also slightly less efficient to store, but
that's OK; we only store this intermediate state during the
parse, after which we write out the actual ANSI bytes.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-11-20 23:17:05 +08:00
|
|
|
switch (c->type) {
|
|
|
|
case COLOR_UNSPECIFIED:
|
|
|
|
case COLOR_NORMAL:
|
|
|
|
break;
|
|
|
|
case COLOR_ANSI:
|
2020-01-22 00:56:21 +08:00
|
|
|
out += xsnprintf(out, len, "%d", c->value + offset);
|
parse_color: refactor color storage
When we parse a color name like "red" into its ANSI color
value, we pack the storage into a single int that may take
on many values:
1. If it's "-2", no value has been specified.
2. If it's "-1", the value is "normal" (i.e., no color).
3. If it's 0 through 7, the value is a standard ANSI
color.
4. If it's larger (up to 255), it is a 256-color extended
value.
Given these magic numbers, it is often hard to see what is
going on in the code. Let's refactor this into a struct with
a flag that tells which scheme we are using, along with a
numeric value. This is more verbose, but should hopefully be
simpler to follow. It will also allow us to easily add
support for more schemes, like 24-bit RGB values.
The result is also slightly less efficient to store, but
that's OK; we only store this intermediate state during the
parse, after which we write out the actual ANSI bytes.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-11-20 23:17:05 +08:00
|
|
|
break;
|
|
|
|
case COLOR_256:
|
2020-01-22 00:56:21 +08:00
|
|
|
out += xsnprintf(out, len, "%d;5;%d", COLOR_FOREGROUND_256 + offset,
|
|
|
|
c->value);
|
parse_color: refactor color storage
When we parse a color name like "red" into its ANSI color
value, we pack the storage into a single int that may take
on many values:
1. If it's "-2", no value has been specified.
2. If it's "-1", the value is "normal" (i.e., no color).
3. If it's 0 through 7, the value is a standard ANSI
color.
4. If it's larger (up to 255), it is a 256-color extended
value.
Given these magic numbers, it is often hard to see what is
going on in the code. Let's refactor this into a struct with
a flag that tells which scheme we are using, along with a
numeric value. This is more verbose, but should hopefully be
simpler to follow. It will also allow us to easily add
support for more schemes, like 24-bit RGB values.
The result is also slightly less efficient to store, but
that's OK; we only store this intermediate state during the
parse, after which we write out the actual ANSI bytes.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-11-20 23:17:05 +08:00
|
|
|
break;
|
2014-11-20 23:25:39 +08:00
|
|
|
case COLOR_RGB:
|
2020-01-22 00:56:21 +08:00
|
|
|
out += xsnprintf(out, len, "%d;2;%d;%d;%d",
|
|
|
|
COLOR_FOREGROUND_RGB + offset,
|
2015-09-25 05:08:07 +08:00
|
|
|
c->red, c->green, c->blue);
|
2014-11-20 23:25:39 +08:00
|
|
|
break;
|
parse_color: refactor color storage
When we parse a color name like "red" into its ANSI color
value, we pack the storage into a single int that may take
on many values:
1. If it's "-2", no value has been specified.
2. If it's "-1", the value is "normal" (i.e., no color).
3. If it's 0 through 7, the value is a standard ANSI
color.
4. If it's larger (up to 255), it is a 256-color extended
value.
Given these magic numbers, it is often hard to see what is
going on in the code. Let's refactor this into a struct with
a flag that tells which scheme we are using, along with a
numeric value. This is more verbose, but should hopefully be
simpler to follow. It will also allow us to easily add
support for more schemes, like 24-bit RGB values.
The result is also slightly less efficient to store, but
that's OK; we only store this intermediate state during the
parse, after which we write out the actual ANSI bytes.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-11-20 23:17:05 +08:00
|
|
|
}
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int color_empty(const struct color *c)
|
|
|
|
{
|
|
|
|
return c->type <= COLOR_NORMAL;
|
|
|
|
}
|
|
|
|
|
2014-10-08 03:33:09 +08:00
|
|
|
int color_parse_mem(const char *value, int value_len, char *dst)
|
2006-09-08 16:03:18 +08:00
|
|
|
{
|
|
|
|
const char *ptr = value;
|
2009-01-20 12:30:30 +08:00
|
|
|
int len = value_len;
|
2015-09-25 05:08:07 +08:00
|
|
|
char *end = dst + COLOR_MAXLEN;
|
2010-02-28 10:56:38 +08:00
|
|
|
unsigned int attr = 0;
|
parse_color: refactor color storage
When we parse a color name like "red" into its ANSI color
value, we pack the storage into a single int that may take
on many values:
1. If it's "-2", no value has been specified.
2. If it's "-1", the value is "normal" (i.e., no color).
3. If it's 0 through 7, the value is a standard ANSI
color.
4. If it's larger (up to 255), it is a 256-color extended
value.
Given these magic numbers, it is often hard to see what is
going on in the code. Let's refactor this into a struct with
a flag that tells which scheme we are using, along with a
numeric value. This is more verbose, but should hopefully be
simpler to follow. It will also allow us to easily add
support for more schemes, like 24-bit RGB values.
The result is also slightly less efficient to store, but
that's OK; we only store this intermediate state during the
parse, after which we write out the actual ANSI bytes.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-11-20 23:17:05 +08:00
|
|
|
struct color fg = { COLOR_UNSPECIFIED };
|
|
|
|
struct color bg = { COLOR_UNSPECIFIED };
|
2006-09-08 16:03:18 +08:00
|
|
|
|
2017-01-19 19:41:22 +08:00
|
|
|
while (len > 0 && isspace(*ptr)) {
|
|
|
|
ptr++;
|
|
|
|
len--;
|
|
|
|
}
|
|
|
|
|
color_parse_mem: allow empty color spec
Prior to c2f41bf52 (color.c: fix color_parse_mem() with
value_len == 0, 2017-01-19), the empty string was
interpreted as a color "reset". This was an accidental
outcome, and that commit turned it into an error.
However, scripts may pass the empty string as a default
value to "git config --get-color" to disable color when the
value is not defined. The git-add--interactive script does
this. As a result, the script is unusable since c2f41bf52
unless you have color.diff.plain defined (if it is defined,
then we don't parse the empty default at all).
Our test scripts didn't notice the recent breakage because
they run without a terminal, and thus without color. They
never hit this code path at all. And nobody noticed the
original buggy "reset" behavior, because it was effectively
a noop.
Let's fix the code to have an empty color name produce an
empty sequence of color codes. The tests need a few fixups:
- we'll add a new test in t4026 to cover this case. But
note that we need to tweak the color() helper. While
we're there, let's factor out the literal ANSI ESC
character. Otherwise it makes the diff quite hard to
read.
- we'll add a basic sanity-check in t4026 that "git add
-p" works at all when color is enabled. That would have
caught this bug, as well as any others that are specific
to the color code paths.
- 73c727d69 (log --graph: customize the graph lines with
config log.graphColors, 2017-01-19) added a test to
t4202 that checks some "invalid" graph color config.
Since ",, blue" before yielded only "blue" as valid, and
now yields "empty, empty, blue", we don't match the
expected output.
One way to fix this would be to change the expectation
to the empty color strings. But that makes the test much
less interesting, since we show only two graph lines,
both of which would be colorless.
Since the empty-string case is now covered by t4026,
let's remove them entirely here. They're just in the way
of the primary thing the test is supposed to be
checking.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-02-01 08:21:29 +08:00
|
|
|
if (!len) {
|
|
|
|
dst[0] = '\0';
|
|
|
|
return 0;
|
|
|
|
}
|
2017-01-19 19:41:21 +08:00
|
|
|
|
2017-01-19 19:41:22 +08:00
|
|
|
if (!strncasecmp(ptr, "reset", len)) {
|
2015-09-25 05:08:07 +08:00
|
|
|
xsnprintf(dst, end - dst, GIT_COLOR_RESET);
|
2014-10-08 03:33:09 +08:00
|
|
|
return 0;
|
2006-09-08 16:03:18 +08:00
|
|
|
}
|
|
|
|
|
2010-02-28 10:56:38 +08:00
|
|
|
/* [fg [bg]] [attr]... */
|
2009-01-20 12:30:30 +08:00
|
|
|
while (len > 0) {
|
2006-09-08 16:03:18 +08:00
|
|
|
const char *word = ptr;
|
color_parse_mem: initialize "struct color" temporary
Compiling color.c with gcc 6.2.0 using -O3 produces some
-Wmaybe-uninitialized false positives:
color.c: In function ‘color_parse_mem’:
color.c:189:10: warning: ‘bg.blue’ may be used uninitialized in this function [-Wmaybe-uninitialized]
out += xsnprintf(out, len, "%c8;2;%d;%d;%d", type,
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
c->red, c->green, c->blue);
~~~~~~~~~~~~~~~~~~~~~~~~~~
color.c:208:15: note: ‘bg.blue’ was declared here
struct color bg = { COLOR_UNSPECIFIED };
^~
[ditto for bg.green, bg.red, fg.blue, etc]
This is doubly confusing, because the declaration shows it
being initialized! Even though we do not explicitly
initialize the color components, an incomplete initializer
sets the unmentioned members to zero.
What the warning doesn't show is that we later do this:
struct color c;
if (!parse_color(&c, ...)) {
if (fg.type == COLOR_UNSPECIFIED)
fg = c;
...
}
gcc is clever enough to realize that a struct assignment
from an uninitialized variable taints the destination. But
unfortunately it's _not_ clever enough to realize that we
only look at those members when type is set to COLOR_RGB, in
which case they are always initialized.
With -O2, gcc does not look into parse_color() and must
assume that "c" emerges fully initialized. With -O3, it
inlines parse_color(), and learns just enough to get
confused.
We can silence the false positive by initializing the
temporary "c". This also future-proofs us against
violating the type assumptions (the result would probably
still be buggy, but in a deterministic way).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-08-31 11:43:07 +08:00
|
|
|
struct color c = { COLOR_UNSPECIFIED };
|
2009-01-20 12:30:30 +08:00
|
|
|
int val, wordlen = 0;
|
2006-09-08 16:03:18 +08:00
|
|
|
|
2009-01-20 12:30:30 +08:00
|
|
|
while (len > 0 && !isspace(word[wordlen])) {
|
|
|
|
wordlen++;
|
|
|
|
len--;
|
|
|
|
}
|
2006-09-08 16:03:18 +08:00
|
|
|
|
2009-01-20 12:30:30 +08:00
|
|
|
ptr = word + wordlen;
|
|
|
|
while (len > 0 && isspace(*ptr)) {
|
2006-09-08 16:03:18 +08:00
|
|
|
ptr++;
|
2009-01-20 12:30:30 +08:00
|
|
|
len--;
|
|
|
|
}
|
2006-09-08 16:03:18 +08:00
|
|
|
|
parse_color: refactor color storage
When we parse a color name like "red" into its ANSI color
value, we pack the storage into a single int that may take
on many values:
1. If it's "-2", no value has been specified.
2. If it's "-1", the value is "normal" (i.e., no color).
3. If it's 0 through 7, the value is a standard ANSI
color.
4. If it's larger (up to 255), it is a 256-color extended
value.
Given these magic numbers, it is often hard to see what is
going on in the code. Let's refactor this into a struct with
a flag that tells which scheme we are using, along with a
numeric value. This is more verbose, but should hopefully be
simpler to follow. It will also allow us to easily add
support for more schemes, like 24-bit RGB values.
The result is also slightly less efficient to store, but
that's OK; we only store this intermediate state during the
parse, after which we write out the actual ANSI bytes.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-11-20 23:17:05 +08:00
|
|
|
if (!parse_color(&c, word, wordlen)) {
|
|
|
|
if (fg.type == COLOR_UNSPECIFIED) {
|
|
|
|
fg = c;
|
2006-09-08 16:03:18 +08:00
|
|
|
continue;
|
|
|
|
}
|
parse_color: refactor color storage
When we parse a color name like "red" into its ANSI color
value, we pack the storage into a single int that may take
on many values:
1. If it's "-2", no value has been specified.
2. If it's "-1", the value is "normal" (i.e., no color).
3. If it's 0 through 7, the value is a standard ANSI
color.
4. If it's larger (up to 255), it is a 256-color extended
value.
Given these magic numbers, it is often hard to see what is
going on in the code. Let's refactor this into a struct with
a flag that tells which scheme we are using, along with a
numeric value. This is more verbose, but should hopefully be
simpler to follow. It will also allow us to easily add
support for more schemes, like 24-bit RGB values.
The result is also slightly less efficient to store, but
that's OK; we only store this intermediate state during the
parse, after which we write out the actual ANSI bytes.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-11-20 23:17:05 +08:00
|
|
|
if (bg.type == COLOR_UNSPECIFIED) {
|
|
|
|
bg = c;
|
2006-09-08 16:03:18 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
goto bad;
|
|
|
|
}
|
2009-01-20 12:30:30 +08:00
|
|
|
val = parse_attr(word, wordlen);
|
2010-02-28 10:56:38 +08:00
|
|
|
if (0 <= val)
|
|
|
|
attr |= (1 << val);
|
|
|
|
else
|
2006-09-08 16:03:18 +08:00
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
|
2015-09-25 05:08:07 +08:00
|
|
|
#undef OUT
|
|
|
|
#define OUT(x) do { \
|
|
|
|
if (dst == end) \
|
2018-05-02 17:38:39 +08:00
|
|
|
BUG("color parsing ran out of space"); \
|
2015-09-25 05:08:07 +08:00
|
|
|
*dst++ = (x); \
|
|
|
|
} while(0)
|
|
|
|
|
parse_color: refactor color storage
When we parse a color name like "red" into its ANSI color
value, we pack the storage into a single int that may take
on many values:
1. If it's "-2", no value has been specified.
2. If it's "-1", the value is "normal" (i.e., no color).
3. If it's 0 through 7, the value is a standard ANSI
color.
4. If it's larger (up to 255), it is a 256-color extended
value.
Given these magic numbers, it is often hard to see what is
going on in the code. Let's refactor this into a struct with
a flag that tells which scheme we are using, along with a
numeric value. This is more verbose, but should hopefully be
simpler to follow. It will also allow us to easily add
support for more schemes, like 24-bit RGB values.
The result is also slightly less efficient to store, but
that's OK; we only store this intermediate state during the
parse, after which we write out the actual ANSI bytes.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-11-20 23:17:05 +08:00
|
|
|
if (attr || !color_empty(&fg) || !color_empty(&bg)) {
|
2006-09-08 16:03:18 +08:00
|
|
|
int sep = 0;
|
2010-02-28 10:56:38 +08:00
|
|
|
int i;
|
2006-09-08 16:03:18 +08:00
|
|
|
|
2015-09-25 05:08:07 +08:00
|
|
|
OUT('\033');
|
|
|
|
OUT('[');
|
2010-02-28 10:56:38 +08:00
|
|
|
|
|
|
|
for (i = 0; attr; i++) {
|
|
|
|
unsigned bit = (1 << i);
|
|
|
|
if (!(attr & bit))
|
|
|
|
continue;
|
|
|
|
attr &= ~bit;
|
|
|
|
if (sep++)
|
2015-09-25 05:08:07 +08:00
|
|
|
OUT(';');
|
|
|
|
dst += xsnprintf(dst, end - dst, "%d", i);
|
2006-09-08 16:03:18 +08:00
|
|
|
}
|
parse_color: refactor color storage
When we parse a color name like "red" into its ANSI color
value, we pack the storage into a single int that may take
on many values:
1. If it's "-2", no value has been specified.
2. If it's "-1", the value is "normal" (i.e., no color).
3. If it's 0 through 7, the value is a standard ANSI
color.
4. If it's larger (up to 255), it is a 256-color extended
value.
Given these magic numbers, it is often hard to see what is
going on in the code. Let's refactor this into a struct with
a flag that tells which scheme we are using, along with a
numeric value. This is more verbose, but should hopefully be
simpler to follow. It will also allow us to easily add
support for more schemes, like 24-bit RGB values.
The result is also slightly less efficient to store, but
that's OK; we only store this intermediate state during the
parse, after which we write out the actual ANSI bytes.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-11-20 23:17:05 +08:00
|
|
|
if (!color_empty(&fg)) {
|
2006-09-08 16:03:18 +08:00
|
|
|
if (sep++)
|
2015-09-25 05:08:07 +08:00
|
|
|
OUT(';');
|
2020-01-22 00:56:21 +08:00
|
|
|
dst = color_output(dst, end - dst, &fg, 0);
|
2006-09-08 16:03:18 +08:00
|
|
|
}
|
parse_color: refactor color storage
When we parse a color name like "red" into its ANSI color
value, we pack the storage into a single int that may take
on many values:
1. If it's "-2", no value has been specified.
2. If it's "-1", the value is "normal" (i.e., no color).
3. If it's 0 through 7, the value is a standard ANSI
color.
4. If it's larger (up to 255), it is a 256-color extended
value.
Given these magic numbers, it is often hard to see what is
going on in the code. Let's refactor this into a struct with
a flag that tells which scheme we are using, along with a
numeric value. This is more verbose, but should hopefully be
simpler to follow. It will also allow us to easily add
support for more schemes, like 24-bit RGB values.
The result is also slightly less efficient to store, but
that's OK; we only store this intermediate state during the
parse, after which we write out the actual ANSI bytes.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-11-20 23:17:05 +08:00
|
|
|
if (!color_empty(&bg)) {
|
2006-09-08 16:03:18 +08:00
|
|
|
if (sep++)
|
2015-09-25 05:08:07 +08:00
|
|
|
OUT(';');
|
2020-01-22 00:56:21 +08:00
|
|
|
dst = color_output(dst, end - dst, &bg, 1);
|
2006-09-08 16:03:18 +08:00
|
|
|
}
|
2015-09-25 05:08:07 +08:00
|
|
|
OUT('m');
|
2006-09-08 16:03:18 +08:00
|
|
|
}
|
2015-09-25 05:08:07 +08:00
|
|
|
OUT(0);
|
2014-10-08 03:33:09 +08:00
|
|
|
return 0;
|
2006-09-08 16:03:18 +08:00
|
|
|
bad:
|
2014-10-08 03:33:09 +08:00
|
|
|
return error(_("invalid color value: %.*s"), value_len, value);
|
2015-09-25 05:08:07 +08:00
|
|
|
#undef OUT
|
2006-09-08 16:03:18 +08:00
|
|
|
}
|
|
|
|
|
2011-08-18 13:03:48 +08:00
|
|
|
int git_config_colorbool(const char *var, const char *value)
|
2006-09-08 16:03:18 +08:00
|
|
|
{
|
2007-11-27 06:30:28 +08:00
|
|
|
if (value) {
|
|
|
|
if (!strcasecmp(value, "never"))
|
|
|
|
return 0;
|
|
|
|
if (!strcasecmp(value, "always"))
|
Revert "color: make "always" the same as "auto" in config"
This reverts commit 6be4595edb8e5b616c6e8b9fbc78b0f831fa2a87.
That commit weakened the "always" setting of color config so
that it acted as "auto". This was meant to solve regressions
in v2.14.2 in which setting "color.ui=always" in the on-disk
config broke scripts like add--interactive, because the
plumbing diff commands began to generate color output.
This was due to 136c8c8b8f (color: check color.ui in
git_default_config(), 2017-07-13), which was in turn trying
to fix issues caused by 4c7f1819b3 (make color.ui default to
'auto', 2013-06-10). But in weakening "always", we created
even more problems, as people expect to be able to use "git
-c color.ui=always" to force color (especially because some
commands don't have their own --color flag). We can fix that
by special-casing the command-line "-c", but now things are
getting pretty confusing.
Instead of piling hacks upon hacks, let's start peeling off
the hacks. The first step is dropping the weakening of
"always", which this revert does.
Note that we could actually revert the whole series merged
in by da15b78e52642bd45fd5513ab0000fdf2e58a6f4. Most of that
series consists of preparations to the tests to handle the
weakening of "-c color.ui=always". But it's worth keeping
for a few reasons:
- there are some other preparatory cleanups, like
e433749d86 (test-terminal: set TERM=vt100, 2017-10-03)
- it adds "--color" options more consistently in
0c88bf5050 (provide --color option for all ref-filter
users, 2017-10-03)
- some of the cases dropping "-c" end up being more robust
and realistic tests, as in 01c94e9001 (t7508: use
test_terminal for color output, 2017-10-03)
- the preferred tool for overriding config is "--color",
and we should be modeling that consistently
We can individually revert the few commits necessary to
restore some useful tests (which will be done on top of this
patch).
Note that this isn't a pure revert; we'll keep the test
added in t3701, but mark it as failure for now.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-10-14 01:23:24 +08:00
|
|
|
return 1;
|
2007-11-27 06:30:28 +08:00
|
|
|
if (!strcasecmp(value, "auto"))
|
color: delay auto-color decision until point of use
When we read a color value either from a config file or from
the command line, we use git_config_colorbool to convert it
from the tristate always/never/auto into a single yes/no
boolean value.
This has some timing implications with respect to starting
a pager.
If we start (or decide not to start) the pager before
checking the colorbool, everything is fine. Either isatty(1)
will give us the right information, or we will properly
check for pager_in_use().
However, if we decide to start a pager after we have checked
the colorbool, things are not so simple. If stdout is a tty,
then we will have already decided to use color. However, the
user may also have configured color.pager not to use color
with the pager. In this case, we need to actually turn off
color. Unfortunately, the pager code has no idea which color
variables were turned on (and there are many of them
throughout the code, and they may even have been manipulated
after the colorbool selection by something like "--color" on
the command line).
This bug can be seen any time a pager is started after
config and command line options are checked. This has
affected "git diff" since 89d07f7 (diff: don't run pager if
user asked for a diff style exit code, 2007-08-12). It has
also affect the log family since 1fda91b (Fix 'git log'
early pager startup error case, 2010-08-24).
This patch splits the notion of parsing a colorbool and
actually checking the configuration. The "use_color"
variables now have an additional possible value,
GIT_COLOR_AUTO. Users of the variable should use the new
"want_color()" wrapper, which will lazily determine and
cache the auto-color decision.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-08-18 13:04:23 +08:00
|
|
|
return GIT_COLOR_AUTO;
|
2006-09-08 16:03:18 +08:00
|
|
|
}
|
2007-11-27 06:30:28 +08:00
|
|
|
|
Add an optional argument for --color options
Make git-branch, git-show-branch, git-grep, and all the diff-based
programs accept an optional argument <when> for --color. The argument
is a colorbool: "always", "never", or "auto". If no argument is given,
"always" is used; --no-color is an alias for --color=never. This makes
the command-line interface consistent with other GNU tools, such as `ls'
and `grep', and with the git-config color options. Note that, without
an argument, --color and --no-color work exactly as before.
To implement this, two internal changes were made:
1. Allow the first argument of git_config_colorbool() to be NULL,
in which case it returns -1 if the argument isn't "always", "never",
or "auto".
2. Add OPT_COLOR_FLAG(), OPT__COLOR(), and parse_opt_color_flag_cb()
to the option parsing library. The callback uses
git_config_colorbool(), so color.h is now a dependency
of parse-options.c.
Signed-off-by: Mark Lodato <lodatom@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-02-17 12:55:58 +08:00
|
|
|
if (!var)
|
|
|
|
return -1;
|
|
|
|
|
2007-11-27 06:30:28 +08:00
|
|
|
/* Missing or explicit false to turn off colorization */
|
|
|
|
if (!git_config_bool(var, value))
|
2006-09-08 16:03:18 +08:00
|
|
|
return 0;
|
2007-11-27 06:30:28 +08:00
|
|
|
|
|
|
|
/* any normal truth value defaults to 'auto' */
|
color: delay auto-color decision until point of use
When we read a color value either from a config file or from
the command line, we use git_config_colorbool to convert it
from the tristate always/never/auto into a single yes/no
boolean value.
This has some timing implications with respect to starting
a pager.
If we start (or decide not to start) the pager before
checking the colorbool, everything is fine. Either isatty(1)
will give us the right information, or we will properly
check for pager_in_use().
However, if we decide to start a pager after we have checked
the colorbool, things are not so simple. If stdout is a tty,
then we will have already decided to use color. However, the
user may also have configured color.pager not to use color
with the pager. In this case, we need to actually turn off
color. Unfortunately, the pager code has no idea which color
variables were turned on (and there are many of them
throughout the code, and they may even have been manipulated
after the colorbool selection by something like "--color" on
the command line).
This bug can be seen any time a pager is started after
config and command line options are checked. This has
affected "git diff" since 89d07f7 (diff: don't run pager if
user asked for a diff style exit code, 2007-08-12). It has
also affect the log family since 1fda91b (Fix 'git log'
early pager startup error case, 2010-08-24).
This patch splits the notion of parsing a colorbool and
actually checking the configuration. The "use_color"
variables now have an additional possible value,
GIT_COLOR_AUTO. Users of the variable should use the new
"want_color()" wrapper, which will lazily determine and
cache the auto-color decision.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-08-18 13:04:23 +08:00
|
|
|
return GIT_COLOR_AUTO;
|
|
|
|
}
|
|
|
|
|
2018-04-21 18:09:57 +08:00
|
|
|
static int check_auto_color(int fd)
|
color: delay auto-color decision until point of use
When we read a color value either from a config file or from
the command line, we use git_config_colorbool to convert it
from the tristate always/never/auto into a single yes/no
boolean value.
This has some timing implications with respect to starting
a pager.
If we start (or decide not to start) the pager before
checking the colorbool, everything is fine. Either isatty(1)
will give us the right information, or we will properly
check for pager_in_use().
However, if we decide to start a pager after we have checked
the colorbool, things are not so simple. If stdout is a tty,
then we will have already decided to use color. However, the
user may also have configured color.pager not to use color
with the pager. In this case, we need to actually turn off
color. Unfortunately, the pager code has no idea which color
variables were turned on (and there are many of them
throughout the code, and they may even have been manipulated
after the colorbool selection by something like "--color" on
the command line).
This bug can be seen any time a pager is started after
config and command line options are checked. This has
affected "git diff" since 89d07f7 (diff: don't run pager if
user asked for a diff style exit code, 2007-08-12). It has
also affect the log family since 1fda91b (Fix 'git log'
early pager startup error case, 2010-08-24).
This patch splits the notion of parsing a colorbool and
actually checking the configuration. The "use_color"
variables now have an additional possible value,
GIT_COLOR_AUTO. Users of the variable should use the new
"want_color()" wrapper, which will lazily determine and
cache the auto-color decision.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-08-18 13:04:23 +08:00
|
|
|
{
|
2018-04-21 18:09:57 +08:00
|
|
|
static int color_stderr_is_tty = -1;
|
|
|
|
int *is_tty_p = fd == 1 ? &color_stdout_is_tty : &color_stderr_is_tty;
|
|
|
|
if (*is_tty_p < 0)
|
|
|
|
*is_tty_p = isatty(fd);
|
|
|
|
if (*is_tty_p || (fd == 1 && pager_in_use() && pager_use_color)) {
|
2017-11-29 22:37:51 +08:00
|
|
|
if (!is_terminal_dumb())
|
2007-11-27 06:30:28 +08:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
2006-09-08 16:03:18 +08:00
|
|
|
}
|
|
|
|
|
2018-04-21 18:09:57 +08:00
|
|
|
int want_color_fd(int fd, int var)
|
color: delay auto-color decision until point of use
When we read a color value either from a config file or from
the command line, we use git_config_colorbool to convert it
from the tristate always/never/auto into a single yes/no
boolean value.
This has some timing implications with respect to starting
a pager.
If we start (or decide not to start) the pager before
checking the colorbool, everything is fine. Either isatty(1)
will give us the right information, or we will properly
check for pager_in_use().
However, if we decide to start a pager after we have checked
the colorbool, things are not so simple. If stdout is a tty,
then we will have already decided to use color. However, the
user may also have configured color.pager not to use color
with the pager. In this case, we need to actually turn off
color. Unfortunately, the pager code has no idea which color
variables were turned on (and there are many of them
throughout the code, and they may even have been manipulated
after the colorbool selection by something like "--color" on
the command line).
This bug can be seen any time a pager is started after
config and command line options are checked. This has
affected "git diff" since 89d07f7 (diff: don't run pager if
user asked for a diff style exit code, 2007-08-12). It has
also affect the log family since 1fda91b (Fix 'git log'
early pager startup error case, 2010-08-24).
This patch splits the notion of parsing a colorbool and
actually checking the configuration. The "use_color"
variables now have an additional possible value,
GIT_COLOR_AUTO. Users of the variable should use the new
"want_color()" wrapper, which will lazily determine and
cache the auto-color decision.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-08-18 13:04:23 +08:00
|
|
|
{
|
2017-08-22 01:43:48 +08:00
|
|
|
/*
|
|
|
|
* NEEDSWORK: This function is sometimes used from multiple threads, and
|
|
|
|
* we end up using want_auto racily. That "should not matter" since
|
|
|
|
* we always write the same value, but it's still wrong. This function
|
|
|
|
* is listed in .tsan-suppressions for the time being.
|
|
|
|
*/
|
|
|
|
|
2018-04-21 18:09:57 +08:00
|
|
|
static int want_auto[3] = { -1, -1, -1 };
|
color: delay auto-color decision until point of use
When we read a color value either from a config file or from
the command line, we use git_config_colorbool to convert it
from the tristate always/never/auto into a single yes/no
boolean value.
This has some timing implications with respect to starting
a pager.
If we start (or decide not to start) the pager before
checking the colorbool, everything is fine. Either isatty(1)
will give us the right information, or we will properly
check for pager_in_use().
However, if we decide to start a pager after we have checked
the colorbool, things are not so simple. If stdout is a tty,
then we will have already decided to use color. However, the
user may also have configured color.pager not to use color
with the pager. In this case, we need to actually turn off
color. Unfortunately, the pager code has no idea which color
variables were turned on (and there are many of them
throughout the code, and they may even have been manipulated
after the colorbool selection by something like "--color" on
the command line).
This bug can be seen any time a pager is started after
config and command line options are checked. This has
affected "git diff" since 89d07f7 (diff: don't run pager if
user asked for a diff style exit code, 2007-08-12). It has
also affect the log family since 1fda91b (Fix 'git log'
early pager startup error case, 2010-08-24).
This patch splits the notion of parsing a colorbool and
actually checking the configuration. The "use_color"
variables now have an additional possible value,
GIT_COLOR_AUTO. Users of the variable should use the new
"want_color()" wrapper, which will lazily determine and
cache the auto-color decision.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-08-18 13:04:23 +08:00
|
|
|
|
2018-08-03 14:07:49 +08:00
|
|
|
if (fd < 1 || fd >= ARRAY_SIZE(want_auto))
|
|
|
|
BUG("file descriptor out of range: %d", fd);
|
|
|
|
|
2011-08-18 13:05:35 +08:00
|
|
|
if (var < 0)
|
|
|
|
var = git_use_color_default;
|
|
|
|
|
color: delay auto-color decision until point of use
When we read a color value either from a config file or from
the command line, we use git_config_colorbool to convert it
from the tristate always/never/auto into a single yes/no
boolean value.
This has some timing implications with respect to starting
a pager.
If we start (or decide not to start) the pager before
checking the colorbool, everything is fine. Either isatty(1)
will give us the right information, or we will properly
check for pager_in_use().
However, if we decide to start a pager after we have checked
the colorbool, things are not so simple. If stdout is a tty,
then we will have already decided to use color. However, the
user may also have configured color.pager not to use color
with the pager. In this case, we need to actually turn off
color. Unfortunately, the pager code has no idea which color
variables were turned on (and there are many of them
throughout the code, and they may even have been manipulated
after the colorbool selection by something like "--color" on
the command line).
This bug can be seen any time a pager is started after
config and command line options are checked. This has
affected "git diff" since 89d07f7 (diff: don't run pager if
user asked for a diff style exit code, 2007-08-12). It has
also affect the log family since 1fda91b (Fix 'git log'
early pager startup error case, 2010-08-24).
This patch splits the notion of parsing a colorbool and
actually checking the configuration. The "use_color"
variables now have an additional possible value,
GIT_COLOR_AUTO. Users of the variable should use the new
"want_color()" wrapper, which will lazily determine and
cache the auto-color decision.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-08-18 13:04:23 +08:00
|
|
|
if (var == GIT_COLOR_AUTO) {
|
2018-04-21 18:09:57 +08:00
|
|
|
if (want_auto[fd] < 0)
|
|
|
|
want_auto[fd] = check_auto_color(fd);
|
|
|
|
return want_auto[fd];
|
color: delay auto-color decision until point of use
When we read a color value either from a config file or from
the command line, we use git_config_colorbool to convert it
from the tristate always/never/auto into a single yes/no
boolean value.
This has some timing implications with respect to starting
a pager.
If we start (or decide not to start) the pager before
checking the colorbool, everything is fine. Either isatty(1)
will give us the right information, or we will properly
check for pager_in_use().
However, if we decide to start a pager after we have checked
the colorbool, things are not so simple. If stdout is a tty,
then we will have already decided to use color. However, the
user may also have configured color.pager not to use color
with the pager. In this case, we need to actually turn off
color. Unfortunately, the pager code has no idea which color
variables were turned on (and there are many of them
throughout the code, and they may even have been manipulated
after the colorbool selection by something like "--color" on
the command line).
This bug can be seen any time a pager is started after
config and command line options are checked. This has
affected "git diff" since 89d07f7 (diff: don't run pager if
user asked for a diff style exit code, 2007-08-12). It has
also affect the log family since 1fda91b (Fix 'git log'
early pager startup error case, 2010-08-24).
This patch splits the notion of parsing a colorbool and
actually checking the configuration. The "use_color"
variables now have an additional possible value,
GIT_COLOR_AUTO. Users of the variable should use the new
"want_color()" wrapper, which will lazily determine and
cache the auto-color decision.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-08-18 13:04:23 +08:00
|
|
|
}
|
2011-08-18 13:05:35 +08:00
|
|
|
return var;
|
color: delay auto-color decision until point of use
When we read a color value either from a config file or from
the command line, we use git_config_colorbool to convert it
from the tristate always/never/auto into a single yes/no
boolean value.
This has some timing implications with respect to starting
a pager.
If we start (or decide not to start) the pager before
checking the colorbool, everything is fine. Either isatty(1)
will give us the right information, or we will properly
check for pager_in_use().
However, if we decide to start a pager after we have checked
the colorbool, things are not so simple. If stdout is a tty,
then we will have already decided to use color. However, the
user may also have configured color.pager not to use color
with the pager. In this case, we need to actually turn off
color. Unfortunately, the pager code has no idea which color
variables were turned on (and there are many of them
throughout the code, and they may even have been manipulated
after the colorbool selection by something like "--color" on
the command line).
This bug can be seen any time a pager is started after
config and command line options are checked. This has
affected "git diff" since 89d07f7 (diff: don't run pager if
user asked for a diff style exit code, 2007-08-12). It has
also affect the log family since 1fda91b (Fix 'git log'
early pager startup error case, 2010-08-24).
This patch splits the notion of parsing a colorbool and
actually checking the configuration. The "use_color"
variables now have an additional possible value,
GIT_COLOR_AUTO. Users of the variable should use the new
"want_color()" wrapper, which will lazily determine and
cache the auto-color decision.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-08-18 13:04:23 +08:00
|
|
|
}
|
|
|
|
|
2011-08-18 13:05:08 +08:00
|
|
|
int git_color_config(const char *var, const char *value, void *cb)
|
2008-02-18 15:26:03 +08:00
|
|
|
{
|
|
|
|
if (!strcmp(var, "color.ui")) {
|
2011-08-18 13:03:48 +08:00
|
|
|
git_use_color_default = git_config_colorbool(var, value);
|
2008-02-18 15:26:03 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-08-18 13:05:08 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-10-14 01:24:31 +08:00
|
|
|
int git_color_default_config(const char *var, const char *value, void *cb)
|
|
|
|
{
|
|
|
|
if (git_color_config(var, value, cb) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return git_default_config(var, value, cb);
|
|
|
|
}
|
|
|
|
|
2011-02-26 13:09:41 +08:00
|
|
|
void color_print_strbuf(FILE *fp, const char *color, const struct strbuf *sb)
|
|
|
|
{
|
|
|
|
if (*color)
|
|
|
|
fprintf(fp, "%s", color);
|
|
|
|
fprintf(fp, "%s", sb->buf);
|
|
|
|
if (*color)
|
|
|
|
fprintf(fp, "%s", GIT_COLOR_RESET);
|
|
|
|
}
|
|
|
|
|
2007-09-18 08:06:42 +08:00
|
|
|
static int color_vfprintf(FILE *fp, const char *color, const char *fmt,
|
2006-09-08 16:03:18 +08:00
|
|
|
va_list args, const char *trail)
|
|
|
|
{
|
|
|
|
int r = 0;
|
|
|
|
|
|
|
|
if (*color)
|
2007-09-18 08:06:42 +08:00
|
|
|
r += fprintf(fp, "%s", color);
|
|
|
|
r += vfprintf(fp, fmt, args);
|
2006-09-08 16:03:18 +08:00
|
|
|
if (*color)
|
2009-02-14 05:53:40 +08:00
|
|
|
r += fprintf(fp, "%s", GIT_COLOR_RESET);
|
2006-09-08 16:03:18 +08:00
|
|
|
if (trail)
|
2007-09-18 08:06:42 +08:00
|
|
|
r += fprintf(fp, "%s", trail);
|
2006-09-08 16:03:18 +08:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2007-09-18 08:06:42 +08:00
|
|
|
int color_fprintf(FILE *fp, const char *color, const char *fmt, ...)
|
2006-09-08 16:03:18 +08:00
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
int r;
|
|
|
|
va_start(args, fmt);
|
2007-09-18 08:06:42 +08:00
|
|
|
r = color_vfprintf(fp, color, fmt, args, NULL);
|
2006-09-08 16:03:18 +08:00
|
|
|
va_end(args);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2007-09-18 08:06:42 +08:00
|
|
|
int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...)
|
2006-09-08 16:03:18 +08:00
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
int r;
|
|
|
|
va_start(args, fmt);
|
2007-09-18 08:06:42 +08:00
|
|
|
r = color_vfprintf(fp, color, fmt, args, "\n");
|
2006-09-08 16:03:18 +08:00
|
|
|
va_end(args);
|
|
|
|
return r;
|
|
|
|
}
|
2010-12-10 01:27:08 +08:00
|
|
|
|
|
|
|
int color_is_nil(const char *c)
|
|
|
|
{
|
|
|
|
return !strcmp(c, "NIL");
|
|
|
|
}
|