]> git.ipfire.org Git - thirdparty/util-linux.git/blob - lib/color-names.c
lib/colors: move colors canonicalization to lib/color-names.c
[thirdparty/util-linux.git] / lib / color-names.c
1 /*
2 * No copyright is claimed. This code is in the public domain; do with
3 * it what you wish.
4 *
5 * Written by Karel Zak <kzak@redhat.com>
6 */
7 #include "c.h"
8 #include "color-names.h"
9
10 #include <ctype.h>
11
12 struct ul_color_name {
13 const char *name;
14 const char *seq;
15 };
16
17 /*
18 * qsort/bsearch buddy
19 */
20 static int cmp_color_name(const void *a0, const void *b0)
21 {
22 const struct ul_color_name
23 *a = (const struct ul_color_name *) a0,
24 *b = (const struct ul_color_name *) b0;
25 return strcmp(a->name, b->name);
26 }
27
28 /*
29 * Maintains human readable color names
30 */
31 const char *color_sequence_from_colorname(const char *str)
32 {
33 static const struct ul_color_name basic_schemes[] = {
34 { "black", UL_COLOR_BLACK },
35 { "blink", UL_COLOR_BLINK },
36 { "blue", UL_COLOR_BLUE },
37 { "bold", UL_COLOR_BOLD },
38 { "brown", UL_COLOR_BROWN },
39 { "cyan", UL_COLOR_CYAN },
40 { "darkgray", UL_COLOR_DARK_GRAY },
41 { "gray", UL_COLOR_GRAY },
42 { "green", UL_COLOR_GREEN },
43 { "halfbright", UL_COLOR_HALFBRIGHT },
44 { "lightblue", UL_COLOR_BOLD_BLUE },
45 { "lightcyan", UL_COLOR_BOLD_CYAN },
46 { "lightgray,", UL_COLOR_GRAY },
47 { "lightgreen", UL_COLOR_BOLD_GREEN },
48 { "lightmagenta", UL_COLOR_BOLD_MAGENTA },
49 { "lightred", UL_COLOR_BOLD_RED },
50 { "magenta", UL_COLOR_MAGENTA },
51 { "red", UL_COLOR_RED },
52 { "reset", UL_COLOR_RESET, },
53 { "reverse", UL_COLOR_REVERSE },
54 { "yellow", UL_COLOR_BOLD_YELLOW },
55 { "white", UL_COLOR_WHITE }
56 };
57 struct ul_color_name key = { .name = str }, *res;
58
59 if (!str)
60 return NULL;
61
62 res = bsearch(&key, basic_schemes, ARRAY_SIZE(basic_schemes),
63 sizeof(struct ul_color_name),
64 cmp_color_name);
65 return res ? res->seq : NULL;
66 }
67
68
69 int color_is_sequence(const char *color)
70 {
71 if (color && *color == 0x1B) {
72 size_t len = strlen(color);
73
74 if (len >= 4 &&
75 *(color + 1) == '[' &&
76 isdigit(*(color + 2)) &&
77 *(color + len - 1) == 'm')
78 return 1;
79 }
80
81 return 0;
82 }
83
84 /* canonicalize sequence */
85 static int __color_canonicalize(const char *str, char **seq)
86 {
87 char *in, *out;
88 int len;
89
90 if (!str)
91 return -EINVAL;
92
93 *seq = NULL;
94
95 /* convert color names like "red" to the real sequence */
96 if (*str != '\\' && isalpha(*str)) {
97 const char *s = color_sequence_from_colorname(str);
98 *seq = strdup(s ? s : str);
99
100 return *seq ? 0 : -ENOMEM;
101 }
102
103 /* convert xx;yy sequences to "\033[xx;yy" */
104 if ((len = asprintf(seq, "\033[%sm", str)) < 1)
105 return -ENOMEM;
106
107 for (in = *seq, out = *seq; in && *in; in++) {
108 if (*in != '\\') {
109 *out++ = *in;
110 continue;
111 }
112 switch(*(in + 1)) {
113 case 'a':
114 *out++ = '\a'; /* Bell */
115 break;
116 case 'b':
117 *out++ = '\b'; /* Backspace */
118 break;
119 case 'e':
120 *out++ = '\033'; /* Escape */
121 break;
122 case 'f':
123 *out++ = '\f'; /* Form Feed */
124 break;
125 case 'n':
126 *out++ = '\n'; /* Newline */
127 break;
128 case 'r':
129 *out++ = '\r'; /* Carriage Return */
130 break;
131 case 't':
132 *out++ = '\t'; /* Tab */
133 break;
134 case 'v':
135 *out++ = '\v'; /* Vertical Tab */
136 break;
137 case '\\':
138 *out++ = '\\'; /* Backslash */
139 break;
140 case '_':
141 *out++ = ' '; /* Space */
142 break;
143 case '#':
144 *out++ = '#'; /* Hash mark */
145 break;
146 case '?':
147 *out++ = '?'; /* Question mark */
148 break;
149 default:
150 *out++ = *in;
151 *out++ = *(in + 1);
152 break;
153 }
154 in++;
155 }
156
157 if (out) {
158 assert ((out - *seq) <= len);
159 *out = '\0';
160 }
161
162 return 0;
163 }
164
165 char *color_get_sequence(const char *color)
166 {
167 char *seq = NULL;
168 int rc = __color_canonicalize(color, &seq);
169
170 return rc ? NULL : seq;
171 }