From: Karel Zak Date: Mon, 27 Feb 2023 16:43:11 +0000 (+0100) Subject: lib/colors: move colors canonicalization to lib/color-names.c X-Git-Tag: v2.39-rc1~51 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=208480c4bafb7e01b6ff89fa1dd7316ee73cdc53;p=thirdparty%2Futil-linux.git lib/colors: move colors canonicalization to lib/color-names.c * let's make simplified sequences (e.g. "35;4") used without lib/colors.c (without color schemes) * add function to detect already usable esc sequence * support this new feature in "test_colors --color " ./test_colors --color "red" ./test_colors --color "35;5" Signed-off-by: Karel Zak --- diff --git a/include/color-names.h b/include/color-names.h index 42f6f8f6e2..c6ab7ba4bb 100644 --- a/include/color-names.h +++ b/include/color-names.h @@ -41,4 +41,7 @@ extern const char *color_sequence_from_colorname(const char *str); +extern int color_is_sequence(const char *color); +extern char *color_get_sequence(const char *color); + #endif /* UTIL_LINUX_COLOR_NAMES_H */ diff --git a/lib/color-names.c b/lib/color-names.c index 9b1505e4b0..d6a3fc9ee6 100644 --- a/lib/color-names.c +++ b/lib/color-names.c @@ -7,6 +7,8 @@ #include "c.h" #include "color-names.h" +#include + struct ul_color_name { const char *name; const char *seq; @@ -62,3 +64,108 @@ const char *color_sequence_from_colorname(const char *str) cmp_color_name); return res ? res->seq : NULL; } + + +int color_is_sequence(const char *color) +{ + if (color && *color == 0x1B) { + size_t len = strlen(color); + + if (len >= 4 && + *(color + 1) == '[' && + isdigit(*(color + 2)) && + *(color + len - 1) == 'm') + return 1; + } + + return 0; +} + +/* canonicalize sequence */ +static int __color_canonicalize(const char *str, char **seq) +{ + char *in, *out; + int len; + + if (!str) + return -EINVAL; + + *seq = NULL; + + /* convert color names like "red" to the real sequence */ + if (*str != '\\' && isalpha(*str)) { + const char *s = color_sequence_from_colorname(str); + *seq = strdup(s ? s : str); + + return *seq ? 0 : -ENOMEM; + } + + /* convert xx;yy sequences to "\033[xx;yy" */ + if ((len = asprintf(seq, "\033[%sm", str)) < 1) + return -ENOMEM; + + for (in = *seq, out = *seq; in && *in; in++) { + if (*in != '\\') { + *out++ = *in; + continue; + } + switch(*(in + 1)) { + case 'a': + *out++ = '\a'; /* Bell */ + break; + case 'b': + *out++ = '\b'; /* Backspace */ + break; + case 'e': + *out++ = '\033'; /* Escape */ + break; + case 'f': + *out++ = '\f'; /* Form Feed */ + break; + case 'n': + *out++ = '\n'; /* Newline */ + break; + case 'r': + *out++ = '\r'; /* Carriage Return */ + break; + case 't': + *out++ = '\t'; /* Tab */ + break; + case 'v': + *out++ = '\v'; /* Vertical Tab */ + break; + case '\\': + *out++ = '\\'; /* Backslash */ + break; + case '_': + *out++ = ' '; /* Space */ + break; + case '#': + *out++ = '#'; /* Hash mark */ + break; + case '?': + *out++ = '?'; /* Question mark */ + break; + default: + *out++ = *in; + *out++ = *(in + 1); + break; + } + in++; + } + + if (out) { + assert ((out - *seq) <= len); + *out = '\0'; + } + + return 0; +} + +char *color_get_sequence(const char *color) +{ + char *seq = NULL; + int rc = __color_canonicalize(color, &seq); + + return rc ? NULL : seq; +} diff --git a/lib/colors.c b/lib/colors.c index 886dd81d70..621dca3364 100644 --- a/lib/colors.c +++ b/lib/colors.c @@ -353,88 +353,6 @@ static char *colors_get_homedir(char *buf, size_t bufsz) return NULL; } -/* canonicalize sequence */ -static int cn_sequence(const char *str, char **seq) -{ - char *in, *out; - int len; - - if (!str) - return -EINVAL; - - *seq = NULL; - - /* convert logical names like "red" to the real sequence */ - if (*str != '\\' && isalpha(*str)) { - const char *s = color_sequence_from_colorname(str); - *seq = strdup(s ? s : str); - - return *seq ? 0 : -ENOMEM; - } - - /* convert xx;yy sequences to "\033[xx;yy" */ - if ((len = asprintf(seq, "\033[%sm", str)) < 1) - return -ENOMEM; - - for (in = *seq, out = *seq; in && *in; in++) { - if (*in != '\\') { - *out++ = *in; - continue; - } - switch(*(in + 1)) { - case 'a': - *out++ = '\a'; /* Bell */ - break; - case 'b': - *out++ = '\b'; /* Backspace */ - break; - case 'e': - *out++ = '\033'; /* Escape */ - break; - case 'f': - *out++ = '\f'; /* Form Feed */ - break; - case 'n': - *out++ = '\n'; /* Newline */ - break; - case 'r': - *out++ = '\r'; /* Carriage Return */ - break; - case 't': - *out++ = '\t'; /* Tab */ - break; - case 'v': - *out++ = '\v'; /* Vertical Tab */ - break; - case '\\': - *out++ = '\\'; /* Backslash */ - break; - case '_': - *out++ = ' '; /* Space */ - break; - case '#': - *out++ = '#'; /* Hash mark */ - break; - case '?': - *out++ = '?'; /* Question mark */ - break; - default: - *out++ = *in; - *out++ = *(in + 1); - break; - } - in++; - } - - if (out) { - assert ((out - *seq) <= len); - *out = '\0'; - } - - return 0; -} - - /* * Adds one color sequence to array with color scheme. * When returning success (0) this function takes ownership of @@ -453,30 +371,11 @@ static int colors_add_scheme(struct ul_color_ctl *cc, DBG(SCHEME, ul_debug("add '%s'", name)); - rc = cn_sequence(seq0, &seq); - if (rc) - return rc; - + seq = color_get_sequence(seq0); + if (!seq) + return -EINVAL; rc = -ENOMEM; - /* convert logical name (e.g. "red") to real ESC code */ - if (isalpha(*seq)) { - const char *s = color_sequence_from_colorname(seq); - char *p; - - if (!s) { - DBG(SCHEME, ul_debug("unknown logical name: %s", seq)); - rc = -EINVAL; - goto err; - } - - p = strdup(s); - if (!p) - goto err; - free(seq); - seq = p; - } - /* enlarge the array */ if (cc->nschemes == cc->schemes_sz) { void *tmp = realloc(cc->schemes, (cc->nschemes + 10) @@ -875,7 +774,7 @@ int main(int argc, char *argv[]) }; int c, mode = UL_COLORMODE_UNDEF; /* default */ const char *color = "red", *name = NULL, *color_scheme = NULL; - const char *seq = NULL; + char *seq = NULL; while ((c = getopt_long(argc, argv, "C:c:m:n:", longopts, NULL)) != -1) { switch (c) { @@ -904,7 +803,10 @@ int main(int argc, char *argv[]) colors_init(mode, name ? name : program_invocation_short_name); - seq = color_sequence_from_colorname(color); + if (color_is_sequence(color)) + seq = strdup(color); + else + seq = color_get_sequence(color); if (color_scheme) color_scheme_enable(color_scheme, seq); @@ -914,6 +816,8 @@ int main(int argc, char *argv[]) color_disable(); fputc('\n', stdout); + free(seq); + return EXIT_SUCCESS; } #endif /* TEST_PROGRAM_COLORS */