From 7241d6cc35134fcb5ec6dfa81bbd01e430b2415f Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Fri, 15 Apr 2022 13:31:22 -0400 Subject: color: Support a separate $BFS_COLORS environment variable --- bfs.1 | 14 ++++++-- color.c | 123 ++++++++++++++++++++++++++++++++------------------------------- color.h | 6 ++-- parse.c | 2 +- tests.sh | 9 +++-- 5 files changed, 84 insertions(+), 70 deletions(-) diff --git a/bfs.1 b/bfs.1 index b9288e8..53a9831 100644 --- a/bfs.1 +++ b/bfs.1 @@ -715,16 +715,26 @@ Yes/no prompts (e.g. from .BR \-ok ) will also be interpreted according to the current locale. .RE -.TP +.PP .B LS_COLORS +.br +.B BFS_COLORS +.RS Controls the colors used when displaying file paths if .B \-color is enabled. .B bfs -interprets this environment variable is interpreted the same way GNU +interprets +.B LS_COLORS +the same way GNU .BR ls (1) does (see .BR dir_colors (5)). +.B BFS_COLORS +can be used to customize +.B bfs +without affecting other commands. +.RE .TP .B NO_COLOR Causes diff --git a/color.c b/color.c index d59875c..9e267da 100644 --- a/color.c +++ b/color.c @@ -34,9 +34,6 @@ #include #include -/** - * The parsed form of LS_COLORS. - */ struct colors { char *reset; char *leftcode; @@ -198,7 +195,7 @@ static const char *get_ext_color(const struct colors *colors, const char *filena } /** - * Parse a chunk of LS_COLORS that may have escape sequences. The supported + * Parse a chunk of $LS_COLORS that may have escape sequences. The supported * escapes are: * * \a, \b, \f, \n, \r, \t, \v: @@ -358,7 +355,66 @@ fail: return NULL; } -struct colors *parse_colors(const char *ls_colors) { +/** Parse the GNU $LS_COLORS format. */ +static void parse_gnu_ls_colors(struct colors *colors, const char *ls_colors) { + for (const char *chunk = ls_colors, *next; chunk; chunk = next) { + if (chunk[0] == '*') { + char *key = unescape(chunk + 1, '=', &next); + if (!key) { + continue; + } + + char *value = unescape(next, ':', &next); + if (value) { + if (set_ext_color(colors, key, value) != 0) { + dstrfree(value); + } + } + + dstrfree(key); + } else { + const char *equals = strchr(chunk, '='); + if (!equals) { + break; + } + + char *value = unescape(equals + 1, ':', &next); + if (!value) { + continue; + } + + char *key = strndup(chunk, equals - chunk); + if (!key) { + dstrfree(value); + continue; + } + + // All-zero values should be treated like NULL, to fall + // back on any other relevant coloring for that file + if (strspn(value, "0") == strlen(value) + && strcmp(key, "rs") != 0 + && strcmp(key, "lc") != 0 + && strcmp(key, "rc") != 0 + && strcmp(key, "ec") != 0) { + dstrfree(value); + value = NULL; + } + + if (set_color(colors, key, value) != 0) { + dstrfree(value); + } + free(key); + } + } + + if (colors->link && strcmp(colors->link, "target") == 0) { + colors->link_as_target = true; + dstrfree(colors->link); + colors->link = NULL; + } +} + +struct colors *parse_colors() { struct colors *colors = malloc(sizeof(struct colors)); if (!colors) { return NULL; @@ -422,61 +478,8 @@ struct colors *parse_colors(const char *ls_colors) { return NULL; } - for (const char *chunk = ls_colors, *next; chunk; chunk = next) { - if (chunk[0] == '*') { - char *key = unescape(chunk + 1, '=', &next); - if (!key) { - continue; - } - - char *value = unescape(next, ':', &next); - if (value) { - if (set_ext_color(colors, key, value) != 0) { - dstrfree(value); - } - } - - dstrfree(key); - } else { - const char *equals = strchr(chunk, '='); - if (!equals) { - break; - } - - char *value = unescape(equals + 1, ':', &next); - if (!value) { - continue; - } - - char *key = strndup(chunk, equals - chunk); - if (!key) { - dstrfree(value); - continue; - } - - // All-zero values should be treated like NULL, to fall - // back on any other relevant coloring for that file - if (strspn(value, "0") == strlen(value) - && strcmp(key, "rs") != 0 - && strcmp(key, "lc") != 0 - && strcmp(key, "rc") != 0 - && strcmp(key, "ec") != 0) { - dstrfree(value); - value = NULL; - } - - if (set_color(colors, key, value) != 0) { - dstrfree(value); - } - free(key); - } - } - - if (colors->link && strcmp(colors->link, "target") == 0) { - colors->link_as_target = true; - dstrfree(colors->link); - colors->link = NULL; - } + parse_gnu_ls_colors(colors, getenv("LS_COLORS")); + parse_gnu_ls_colors(colors, getenv("BFS_COLORS")); return colors; } diff --git a/color.h b/color.h index 36450bf..edf1ef7 100644 --- a/color.h +++ b/color.h @@ -27,18 +27,16 @@ #include /** - * A lookup table for colors. + * A color scheme. */ struct colors; /** * Parse a color table. * - * @param ls_colors - * A color table in the LS_COLORS environment variable format. * @return The parsed color table. */ -struct colors *parse_colors(const char *ls_colors); +struct colors *parse_colors(void); /** * Free a color table. diff --git a/parse.c b/parse.c index 17aeafe..65087a0 100644 --- a/parse.c +++ b/parse.c @@ -3856,7 +3856,7 @@ struct bfs_ctx *bfs_parse_cmdline(int argc, char *argv[]) { use_color = COLOR_NEVER; } - ctx->colors = parse_colors(getenv("LS_COLORS")); + ctx->colors = parse_colors(); if (!ctx->colors) { ctx->colors_error = errno; } diff --git a/tests.sh b/tests.sh index c31d2c9..6d2c703 100755 --- a/tests.sh +++ b/tests.sh @@ -28,6 +28,9 @@ export MSAN_OPTIONS="abort_on_error=1" export TSAN_OPTIONS="abort_on_error=1" export UBSAN_OPTIONS="abort_on_error=1" +export LS_COLORS="" +unset BFS_COLORS + if [ -t 1 ]; then BLD=$(printf '\033[01m') RED=$(printf '\033[01;31m') @@ -2452,7 +2455,7 @@ function test_printf_must_be_numeric() { } function test_printf_color() { - LS_COLORS="" bfs_diff -color -path './rainbow*' -printf '%H %h %f %p %P %l\n' + bfs_diff -color -path './rainbow*' -printf '%H %h %f %p %P %l\n' } function test_fprintf() { @@ -2552,11 +2555,11 @@ function test_extra_paren() { } function test_color() { - LS_COLORS="" bfs_diff rainbow -color + bfs_diff rainbow -color } function test_color_L() { - LS_COLORS="" bfs_diff -L rainbow -color + bfs_diff -L rainbow -color } function test_color_rs_lc_rc_ec() { -- cgit v1.2.3