lib/colors: support schemes customization
* parse terminal-colors.d/*.scheme files, expected format is <name> <color-sequence> * supported color sequences: - color name (e.g. "red") - dir_colors compatible xx;yy (e.g. 01;31) where the sequence may contains control chars like \e \a ..etc. * scheme is parsed on demand Signed-off-by: Karel Zak <kzak@redhat.com>
This commit is contained in:
parent
e66a662726
commit
7a4704d826
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (C) 2012 Ondrej Oprala <ooprala@redhat.com>
|
||||
* Copyright (C) 2012-2014 Karel Zak <kzak@redhat.com>
|
||||
*
|
||||
* This file may be distributed under the terms of the
|
||||
* GNU Lesser General Public License.
|
||||
|
@ -62,12 +63,18 @@ extern void colors_off(void);
|
|||
extern void colors_on(void);
|
||||
|
||||
|
||||
/* Set the color to CLR_SCHEME */
|
||||
extern void color_fenable(const char *clr_scheme, FILE *f);
|
||||
/* Set the color */
|
||||
extern void color_fenable(const char *seq, FILE *f);
|
||||
extern void color_scheme_fenable(const char *name, const char *dflt, FILE *f);
|
||||
|
||||
static inline void color_enable(const char *clr_scheme)
|
||||
static inline void color_enable(const char *seq)
|
||||
{
|
||||
color_fenable(clr_scheme, stdout);
|
||||
color_fenable(seq, stdout);
|
||||
}
|
||||
|
||||
static inline void color_scheme_enable(const char *name, const char *dflt)
|
||||
{
|
||||
color_scheme_fenable(name, dflt, stdout);
|
||||
}
|
||||
|
||||
/* Reset colors to default */
|
||||
|
@ -78,8 +85,8 @@ static inline void color_disable(void)
|
|||
color_fdisable(stdout);
|
||||
}
|
||||
|
||||
|
||||
extern const char *colorscheme_from_string(const char *str);
|
||||
/* converts "red" to UL_COLOR_RED, etc. */
|
||||
extern const char *color_sequence_from_colorname(const char *str);
|
||||
|
||||
|
||||
#endif /* UTIL_LINUX_COLORS_H */
|
||||
|
|
502
lib/colors.c
502
lib/colors.c
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Copyright (C) 2012 Ondrej Oprala <ooprala@redhat.com>
|
||||
* Copyright (C) 2014 Karel Zak <kzak@redhat.com>
|
||||
* Copyright (C) 2012-2014 Karel Zak <kzak@redhat.com>
|
||||
*
|
||||
* This file may be distributed under the terms of the
|
||||
* GNU Lesser General Public License.
|
||||
|
@ -9,11 +9,12 @@
|
|||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "c.h"
|
||||
#include "colors.h"
|
||||
#include "xalloc.h"
|
||||
#include "pathnames.h"
|
||||
#include "strutils.h"
|
||||
|
||||
/*
|
||||
* terminal-colors.d file types
|
||||
|
@ -26,6 +27,11 @@ enum {
|
|||
__UL_COLORFILE_COUNT
|
||||
};
|
||||
|
||||
struct ul_color_scheme {
|
||||
char *name;
|
||||
char *seq;
|
||||
};
|
||||
|
||||
/*
|
||||
* Global colors control struct
|
||||
*
|
||||
|
@ -44,11 +50,16 @@ struct ul_color_ctl {
|
|||
const char *utilname; /* util name */
|
||||
const char *termname; /* terminal name ($TERM) */
|
||||
|
||||
char *scheme; /* path to scheme */
|
||||
char *sfile; /* path to scheme */
|
||||
|
||||
struct ul_color_scheme *schemes; /* array with color schemes */
|
||||
size_t nschemes; /* number of the items */
|
||||
size_t schemes_sz; /* number of the allocated items */
|
||||
|
||||
int mode; /* UL_COLORMODE_* */
|
||||
unsigned int has_colors : 1, /* based on mode and scores[] */
|
||||
disabled : 1, /* disable colors */
|
||||
cs_configured : 1, /* color schemes read */
|
||||
configured : 1; /* terminal-colors.d parsed */
|
||||
|
||||
int scores[__UL_COLORFILE_COUNT]; /* the best match */
|
||||
|
@ -56,17 +67,67 @@ struct ul_color_ctl {
|
|||
|
||||
static struct ul_color_ctl ul_colors;
|
||||
|
||||
static void colors_free_schemes(struct ul_color_ctl *cc);
|
||||
static int colors_read_schemes(struct ul_color_ctl *cc);
|
||||
|
||||
/*
|
||||
* Reset control struct (note that we don't allocate the struct)
|
||||
* qsort/bsearch buddy
|
||||
*/
|
||||
static int cmp_scheme_name(const void *a0, const void *b0)
|
||||
{
|
||||
struct ul_color_scheme *a = (struct ul_color_scheme *) a0,
|
||||
*b = (struct ul_color_scheme *) b0;
|
||||
return strcmp(a->name, b->name);
|
||||
}
|
||||
|
||||
/*
|
||||
* Maintains human readable color names
|
||||
*/
|
||||
const char *color_sequence_from_colorname(const char *str)
|
||||
{
|
||||
static const struct ul_color_scheme basic_schemes[] = {
|
||||
{ "black", UL_COLOR_BLACK },
|
||||
{ "blue", UL_COLOR_BLUE },
|
||||
{ "brown", UL_COLOR_BROWN },
|
||||
{ "cyan", UL_COLOR_CYAN },
|
||||
{ "darkgray", UL_COLOR_DARK_GRAY },
|
||||
{ "gray", UL_COLOR_GRAY },
|
||||
{ "green", UL_COLOR_GREEN },
|
||||
{ "lightblue", UL_COLOR_BOLD_BLUE },
|
||||
{ "lightcyan", UL_COLOR_BOLD_CYAN },
|
||||
{ "lightgray,", UL_COLOR_GRAY },
|
||||
{ "lightgreen", UL_COLOR_BOLD_GREEN },
|
||||
{ "lightmagenta", UL_COLOR_BOLD_MAGENTA },
|
||||
{ "lightred", UL_COLOR_BOLD_RED },
|
||||
{ "magenta", UL_COLOR_MAGENTA },
|
||||
{ "red", UL_COLOR_RED },
|
||||
{ "yellow", UL_COLOR_BOLD_YELLOW },
|
||||
};
|
||||
struct ul_color_scheme key = { .name = (char *) str }, *res;
|
||||
|
||||
if (!str)
|
||||
return NULL;
|
||||
|
||||
res = bsearch(&key, basic_schemes, ARRAY_SIZE(basic_schemes),
|
||||
sizeof(struct ul_color_scheme),
|
||||
cmp_scheme_name);
|
||||
return res ? res->seq : NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Resets control struct (note that we don't allocate the struct)
|
||||
*/
|
||||
static void colors_reset(struct ul_color_ctl *cc)
|
||||
{
|
||||
if (!cc)
|
||||
return;
|
||||
|
||||
free(cc->scheme);
|
||||
colors_free_schemes(cc);
|
||||
|
||||
cc->scheme = NULL;
|
||||
free(cc->sfile);
|
||||
|
||||
cc->sfile = NULL;
|
||||
cc->utilname = NULL;
|
||||
cc->termname = NULL;
|
||||
cc->mode = UL_COLORMODE_UNDEF;
|
||||
|
@ -85,12 +146,18 @@ static void colors_debug(struct ul_color_ctl *cc)
|
|||
printf("Colors:\n");
|
||||
printf("\tutilname = '%s'\n", cc->utilname);
|
||||
printf("\ttermname = '%s'\n", cc->termname);
|
||||
printf("\tscheme = '%s'\n", cc->scheme);
|
||||
printf("\tscheme file = '%s'\n", cc->sfile);
|
||||
printf("\tmode = %s\n",
|
||||
cc->mode == UL_COLORMODE_UNDEF ? "undefined" :
|
||||
cc->mode == UL_COLORMODE_AUTO ? "auto" :
|
||||
cc->mode == UL_COLORMODE_NEVER ? "never" :
|
||||
cc->mode == UL_COLORMODE_ALWAYS ? "always" : "???");
|
||||
printf("\thas_colors = %d\n", cc->has_colors);
|
||||
printf("\tdisabled = %d\n", cc->disabled);
|
||||
printf("\tconfigured = %d\n", cc->configured);
|
||||
printf("\tcs configured = %d\n", cc->cs_configured);
|
||||
|
||||
fputc('\n', stdout);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cc->scores); i++)
|
||||
printf("\tscore %s = %d\n",
|
||||
|
@ -98,6 +165,17 @@ static void colors_debug(struct ul_color_ctl *cc)
|
|||
i == UL_COLORFILE_ENABLE ? "enable" :
|
||||
i == UL_COLORFILE_SCHEME ? "scheme" : "???",
|
||||
cc->scores[i]);
|
||||
|
||||
fputc('\n', stdout);
|
||||
|
||||
for (i = 0; i < cc->nschemes; i++) {
|
||||
printf("\tscheme #%02d ", i);
|
||||
color_scheme_enable(cc->schemes[i].name, NULL);
|
||||
fputs(cc->schemes[i].name, stdout);
|
||||
color_disable();
|
||||
fputc('\n', stdout);
|
||||
}
|
||||
fputc('\n', stdout);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -159,7 +237,7 @@ static int colors_readdir(struct ul_color_ctl *cc, const char *dirname)
|
|||
DIR *dir;
|
||||
int rc = 0;
|
||||
struct dirent *d;
|
||||
char scheme[PATH_MAX] = { '\0' };
|
||||
char sfile[PATH_MAX] = { '\0' };
|
||||
size_t namesz, termsz;
|
||||
|
||||
if (!dirname || !cc || !cc->utilname || !*cc->utilname)
|
||||
|
@ -194,10 +272,12 @@ static int colors_readdir(struct ul_color_ctl *cc, const char *dirname)
|
|||
score += 20;
|
||||
if (tk_term)
|
||||
score += 10;
|
||||
|
||||
/*
|
||||
fprintf(stderr, "%20s score: %2d [cur max: %2d]\n",
|
||||
d->d_name, score, cc->scores[type]);
|
||||
*/
|
||||
|
||||
if (score < cc->scores[type])
|
||||
continue;
|
||||
|
||||
|
@ -205,19 +285,19 @@ static int colors_readdir(struct ul_color_ctl *cc, const char *dirname)
|
|||
if (tk_namesz != namesz
|
||||
|| strncmp(tk_name, cc->utilname, namesz) != 0)
|
||||
continue;
|
||||
if (tk_termsz != termsz
|
||||
|| termsz == 0
|
||||
|| strncmp(tk_term, cc->termname, termsz) != 0)
|
||||
|
||||
if (tk_termsz && (termsz == 0 || tk_termsz != termsz ||
|
||||
strncmp(tk_term, cc->termname, termsz) != 0))
|
||||
continue;
|
||||
|
||||
cc->scores[type] = score;
|
||||
if (type == UL_COLORFILE_SCHEME)
|
||||
strncpy(scheme, d->d_name, sizeof(scheme));
|
||||
strncpy(sfile, d->d_name, sizeof(sfile));
|
||||
}
|
||||
|
||||
if (*scheme) {
|
||||
scheme[sizeof(scheme) - 1] = '\0';
|
||||
if (asprintf(&cc->scheme, "%s/%s", dirname, scheme) <= 0)
|
||||
if (*sfile) {
|
||||
sfile[sizeof(sfile) - 1] = '\0';
|
||||
if (asprintf(&cc->sfile, "%s/%s", dirname, sfile) <= 0)
|
||||
rc = -ENOMEM;
|
||||
}
|
||||
|
||||
|
@ -252,6 +332,194 @@ 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;
|
||||
|
||||
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 (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++ = '?'; /* Qestion mark */
|
||||
break;
|
||||
default:
|
||||
*out++ = *in;
|
||||
*out++ = *(in + 1);
|
||||
break;
|
||||
}
|
||||
in++;
|
||||
}
|
||||
*out = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Adds one color sequence to array with color scheme,
|
||||
* @seq and @name have to be allocated strings
|
||||
*/
|
||||
static int colors_add_scheme(struct ul_color_ctl *cc,
|
||||
char *name,
|
||||
char *seq0)
|
||||
{
|
||||
struct ul_color_scheme *cs;
|
||||
char *seq;
|
||||
int rc;
|
||||
|
||||
if (!cc || !name || !*name || !seq0 || !*seq0)
|
||||
return -EINVAL;
|
||||
|
||||
rc = cn_sequence(seq0, &seq);
|
||||
if (rc)
|
||||
return rc;
|
||||
free(seq0);
|
||||
|
||||
/* 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)
|
||||
return -EINVAL;
|
||||
p = strdup(s);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
free(seq);
|
||||
seq = p;
|
||||
}
|
||||
|
||||
/* enlarge the array */
|
||||
if (cc->nschemes == cc->schemes_sz) {
|
||||
void *tmp = realloc(cc->schemes, (cc->nschemes + 10)
|
||||
* sizeof(struct ul_color_scheme));
|
||||
if (!tmp)
|
||||
return -ENOMEM;
|
||||
cc->schemes = tmp;
|
||||
cc->schemes_sz = cc->nschemes + 10;
|
||||
}
|
||||
|
||||
/* add a new item */
|
||||
cs = &cc->schemes[cc->nschemes++];
|
||||
cs->name = name;
|
||||
cs->seq = seq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Deallocates all regards to color schemes
|
||||
*/
|
||||
static void colors_free_schemes(struct ul_color_ctl *cc)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < cc->nschemes; i++) {
|
||||
free(cc->schemes[i].name);
|
||||
free(cc->schemes[i].seq);
|
||||
}
|
||||
|
||||
free(cc->schemes);
|
||||
cc->schemes = NULL;
|
||||
cc->nschemes = 0;
|
||||
cc->schemes_sz = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The scheme configuration has to be sorted for bsearch
|
||||
*/
|
||||
static void colors_sort_schemes(struct ul_color_ctl *cc)
|
||||
{
|
||||
if (!cc->nschemes)
|
||||
return;
|
||||
|
||||
qsort(cc->schemes, cc->nschemes,
|
||||
sizeof(struct ul_color_scheme), cmp_scheme_name);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns just one color scheme
|
||||
*/
|
||||
static struct ul_color_scheme *colors_get_scheme(struct ul_color_ctl *cc,
|
||||
const char *name)
|
||||
{
|
||||
struct ul_color_scheme key = { .name = (char *) name}, *res;
|
||||
|
||||
if (!cc || !name || !*name)
|
||||
return NULL;
|
||||
|
||||
if (!cc->cs_configured) {
|
||||
int rc = colors_read_schemes(cc);
|
||||
if (rc)
|
||||
return NULL;
|
||||
}
|
||||
if (!cc->nschemes)
|
||||
return NULL;
|
||||
|
||||
res = bsearch(&key, cc->schemes, cc->nschemes,
|
||||
sizeof(struct ul_color_scheme),
|
||||
cmp_scheme_name);
|
||||
|
||||
return res && res->seq ? res : NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parses filenames in terminal-colors.d
|
||||
*/
|
||||
static int colors_read_configuration(struct ul_color_ctl *cc)
|
||||
{
|
||||
int rc = -ENOENT;
|
||||
|
@ -270,8 +538,71 @@ static int colors_read_configuration(struct ul_color_ctl *cc)
|
|||
}
|
||||
|
||||
/*
|
||||
* Initialize private color control struct, @mode is UL_COLORMODE_*
|
||||
* and @name is util argv[0]
|
||||
* Reads terminal-colors.d/ scheme file into array schemes
|
||||
*/
|
||||
static int colors_read_schemes(struct ul_color_ctl *cc)
|
||||
{
|
||||
int rc = 0;
|
||||
FILE *f = NULL;
|
||||
char buf[BUFSIZ];
|
||||
|
||||
if (!cc->configured)
|
||||
rc = colors_read_configuration(cc);
|
||||
|
||||
cc->cs_configured = 1;
|
||||
|
||||
if (rc || !cc->sfile)
|
||||
goto done;
|
||||
|
||||
f = fopen(cc->sfile, "r");
|
||||
if (!f) {
|
||||
rc = -errno;
|
||||
goto done;
|
||||
}
|
||||
|
||||
while (fgets(buf, sizeof(buf), f)) {
|
||||
char *cn = NULL, *seq = NULL;
|
||||
char *p = strchr(buf, '\n');
|
||||
|
||||
if (!p) {
|
||||
if (feof(f))
|
||||
p = strchr(buf, '\0');
|
||||
else {
|
||||
rc = -errno;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
*p = '\0';
|
||||
p = (char *) skip_blank(buf);
|
||||
if (*p == '\0' || *p == '#')
|
||||
continue;
|
||||
|
||||
rc = sscanf(p, UL_SCNsA" " /* name */
|
||||
UL_SCNsA, /* color */
|
||||
&cn, &seq);
|
||||
if (rc == 2 && cn && seq)
|
||||
rc = colors_add_scheme(cc, cn, seq); /* set rc=0 on success */
|
||||
if (rc) {
|
||||
free(cn);
|
||||
free(seq);
|
||||
}
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
done:
|
||||
if (f)
|
||||
fclose(f);
|
||||
colors_sort_schemes(cc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize private color control struct and initialize the colors
|
||||
* status. The color schemes are parsed on demand by colors_get_scheme().
|
||||
*
|
||||
* @mode: UL_COLORMODE_*
|
||||
* @name: util argv[0]
|
||||
*/
|
||||
int colors_init(int mode, const char *name)
|
||||
{
|
||||
|
@ -311,33 +642,65 @@ int colors_init(int mode, const char *name)
|
|||
return cc->has_colors;
|
||||
}
|
||||
|
||||
/*
|
||||
* Temporary disable colors (this setting is independent on terminal-colors.d/)
|
||||
*/
|
||||
void colors_off(void)
|
||||
{
|
||||
ul_colors.disabled = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable colors
|
||||
*/
|
||||
void colors_on(void)
|
||||
{
|
||||
ul_colors.disabled = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Is terminal-colors.d/ configured to use colors?
|
||||
*/
|
||||
int colors_wanted(void)
|
||||
{
|
||||
return !ul_colors.disabled && ul_colors.has_colors;
|
||||
return ul_colors.has_colors;
|
||||
}
|
||||
|
||||
void color_fenable(const char *color_scheme, FILE *f)
|
||||
/*
|
||||
* Enable @seq color
|
||||
*/
|
||||
void color_fenable(const char *seq, FILE *f)
|
||||
{
|
||||
if (!ul_colors.disabled && ul_colors.has_colors && color_scheme)
|
||||
fputs(color_scheme, f);
|
||||
if (!ul_colors.disabled && ul_colors.has_colors && seq)
|
||||
fputs(seq, f);
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable color by logical @name
|
||||
*/
|
||||
void color_scheme_fenable(const char *name, const char *dflt, FILE *f)
|
||||
{
|
||||
struct ul_color_scheme *cs;
|
||||
|
||||
if (ul_colors.disabled || !ul_colors.has_colors)
|
||||
return;
|
||||
|
||||
cs = colors_get_scheme(&ul_colors, name);
|
||||
color_fenable(cs && cs->seq ? cs->seq : dflt, f);
|
||||
}
|
||||
|
||||
/*
|
||||
* Disable previously enabled color
|
||||
*/
|
||||
void color_fdisable(FILE *f)
|
||||
{
|
||||
if (!ul_colors.disabled && ul_colors.has_colors)
|
||||
fputs(UL_COLOR_RESET, f);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parses @str to return UL_COLORMODE_*
|
||||
*/
|
||||
int colormode_from_string(const char *str)
|
||||
{
|
||||
size_t i;
|
||||
|
@ -361,6 +724,9 @@ int colormode_from_string(const char *str)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parses @str and exit(EXIT_FAILURE) on error
|
||||
*/
|
||||
int colormode_or_err(const char *str, const char *errmsg)
|
||||
{
|
||||
const char *p = str && *str == '=' ? str + 1 : str;
|
||||
|
@ -373,89 +739,59 @@ int colormode_or_err(const char *str, const char *errmsg)
|
|||
return colormode;
|
||||
}
|
||||
|
||||
struct colorscheme {
|
||||
const char *name, *scheme;
|
||||
};
|
||||
|
||||
static int cmp_colorscheme_name(const void *a0, const void *b0)
|
||||
{
|
||||
struct colorscheme *a = (struct colorscheme *) a0,
|
||||
*b = (struct colorscheme *) b0;
|
||||
return strcmp(a->name, b->name);
|
||||
}
|
||||
|
||||
const char *colorscheme_from_string(const char *str)
|
||||
{
|
||||
static const struct colorscheme basic_schemes[] = {
|
||||
{ "black", UL_COLOR_BLACK },
|
||||
{ "blue", UL_COLOR_BLUE },
|
||||
{ "brown", UL_COLOR_BROWN },
|
||||
{ "cyan", UL_COLOR_CYAN },
|
||||
{ "darkgray", UL_COLOR_DARK_GRAY },
|
||||
{ "gray", UL_COLOR_GRAY },
|
||||
{ "green", UL_COLOR_GREEN },
|
||||
{ "lightblue", UL_COLOR_BOLD_BLUE },
|
||||
{ "lightcyan", UL_COLOR_BOLD_CYAN },
|
||||
{ "lightgray,", UL_COLOR_GRAY },
|
||||
{ "lightgreen", UL_COLOR_BOLD_GREEN },
|
||||
{ "lightmagenta", UL_COLOR_BOLD_MAGENTA },
|
||||
{ "lightred", UL_COLOR_BOLD_RED },
|
||||
{ "magenta", UL_COLOR_MAGENTA },
|
||||
{ "red", UL_COLOR_RED },
|
||||
{ "yellow", UL_COLOR_BOLD_YELLOW },
|
||||
};
|
||||
struct colorscheme key = { .name = str }, *res;
|
||||
if (!str)
|
||||
return NULL;
|
||||
|
||||
res = bsearch(&key, basic_schemes, ARRAY_SIZE(basic_schemes),
|
||||
sizeof(struct colorscheme),
|
||||
cmp_colorscheme_name);
|
||||
return res ? res->scheme : NULL;
|
||||
}
|
||||
|
||||
#ifdef TEST_PROGRAM
|
||||
# include <getopt.h>
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
static const struct option longopts[] = {
|
||||
{ "mode", optional_argument, 0, 'm' },
|
||||
{ "color", required_argument, 0, 'c' },
|
||||
{ "read-dir", required_argument, 0, 'd' },
|
||||
{ "mode", required_argument, 0, 'm' },
|
||||
{ "color", required_argument, 0, 'c' },
|
||||
{ "color-scheme", required_argument, 0, 'C' },
|
||||
{ "name", required_argument, 0, 'n' },
|
||||
{ NULL, 0, 0, 0 }
|
||||
};
|
||||
int c, mode = UL_COLORMODE_UNDEF; /* default */
|
||||
const char *color = "red", *dir = NULL;
|
||||
const char *color = "red", *name = NULL, *color_scheme = NULL;
|
||||
const char *seq = NULL;
|
||||
|
||||
while ((c = getopt_long(argc, argv, "m::c:d:", longopts, NULL)) != -1) {
|
||||
while ((c = getopt_long(argc, argv, "C:c:m:n:", longopts, NULL)) != -1) {
|
||||
switch (c) {
|
||||
case 'm':
|
||||
if (optarg)
|
||||
mode = colormode_or_err(optarg, "unsupported color mode");
|
||||
break;
|
||||
case 'c':
|
||||
color = optarg;
|
||||
break;
|
||||
case 'd':
|
||||
dir = optarg;
|
||||
case 'C':
|
||||
color_scheme = optarg;
|
||||
break;
|
||||
case 'm':
|
||||
mode = colormode_or_err(optarg, "unsupported color mode");
|
||||
break;
|
||||
case 'n':
|
||||
name = optarg;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "usage: %s [options]\n"
|
||||
" -m, --mode <auto|never|always> default is undefined\n"
|
||||
" -c, --color <red|blue|...> color for the test message\n"
|
||||
" -C, --color-scheme <name> color for the test message\n"
|
||||
" -n, --name <utilname> util name\n",
|
||||
program_invocation_short_name);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
if (dir) {
|
||||
struct ul_color_ctl cc = { .utilname = "foo",
|
||||
.termname = "footerm" };
|
||||
colors_init(mode, name ? name : program_invocation_short_name);
|
||||
|
||||
colors_readdir(&cc, dir);
|
||||
colors_debug(&cc);
|
||||
colors_reset(&cc);
|
||||
}
|
||||
seq = color_sequence_from_colorname(color);
|
||||
|
||||
colors_init(mode, program_invocation_short_name);
|
||||
|
||||
color_enable(colorscheme_from_string(color));
|
||||
if (color_scheme)
|
||||
color_scheme_enable(color_scheme, seq);
|
||||
else
|
||||
color_enable(seq);
|
||||
printf("Hello World!");
|
||||
color_disable();
|
||||
fputc('\n', stdout);
|
||||
|
||||
colors_debug(&ul_colors);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue