Line | Branch | Exec | Source |
---|---|---|---|
1 | #include <string.h> | ||
2 | #include "style.h" | ||
3 | #include "color.h" | ||
4 | #include "util/array.h" | ||
5 | #include "util/ascii.h" | ||
6 | #include "util/debug.h" | ||
7 | #include "util/numtostr.h" | ||
8 | #include "util/str-util.h" | ||
9 | #include "util/strtonum.h" | ||
10 | #include "util/xmalloc.h" | ||
11 | |||
12 | static const char attr_names[][16] = { | ||
13 | "keep", | ||
14 | "underline", | ||
15 | "reverse", | ||
16 | "blink", | ||
17 | "dim", | ||
18 | "bold", | ||
19 | "invisible", | ||
20 | "italic", | ||
21 | "strikethrough" | ||
22 | }; | ||
23 | |||
24 | static const char color_names[][16] = { | ||
25 | "keep", | ||
26 | "default", | ||
27 | "black", | ||
28 | "red", | ||
29 | "green", | ||
30 | "yellow", | ||
31 | "blue", | ||
32 | "magenta", | ||
33 | "cyan", | ||
34 | "gray", | ||
35 | "darkgray", | ||
36 | "lightred", | ||
37 | "lightgreen", | ||
38 | "lightyellow", | ||
39 | "lightblue", | ||
40 | "lightmagenta", | ||
41 | "lightcyan", | ||
42 | "white" | ||
43 | }; | ||
44 | |||
45 | 18 | UNITTEST { | |
46 | 18 | CHECK_STRING_ARRAY(attr_names); | |
47 | 18 | CHECK_STRING_ARRAY(color_names); | |
48 | 18 | } | |
49 | |||
50 | 292 | static unsigned int lookup_attr(const char *s) | |
51 | { | ||
52 |
2/2✓ Branch 0 taken 1531 times.
✓ Branch 1 taken 23 times.
|
1554 | for (size_t i = 0; i < ARRAYLEN(attr_names); i++) { |
53 |
2/2✓ Branch 0 taken 269 times.
✓ Branch 1 taken 1262 times.
|
1531 | if (streq(s, attr_names[i])) { |
54 | 269 | return 1U << i; | |
55 | } | ||
56 | } | ||
57 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 22 times.
|
23 | if (streq(s, "lowintensity")) { |
58 | 1 | return ATTR_DIM; | |
59 | } | ||
60 | return 0; | ||
61 | } | ||
62 | |||
63 | 800 | static int32_t lookup_color(const char *name) | |
64 | { | ||
65 | 800 | return STR_TO_ENUM_WITH_OFFSET(name, color_names, COLOR_INVALID, -2); | |
66 | } | ||
67 | |||
68 | 852 | static int32_t parse_color(const char *str) | |
69 | { | ||
70 | 852 | size_t len = strlen(str); | |
71 |
2/2✓ Branch 0 taken 850 times.
✓ Branch 1 taken 2 times.
|
852 | if (unlikely(len == 0)) { |
72 | return COLOR_INVALID; | ||
73 | } | ||
74 | |||
75 | // Parse #rgb or #rrggbb | ||
76 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 838 times.
|
850 | if (str[0] == '#') { |
77 | 12 | return parse_rgb(str + 1, len - 1); | |
78 | } | ||
79 | |||
80 | // Parse r/g/b | ||
81 |
4/4✓ Branch 0 taken 97 times.
✓ Branch 1 taken 741 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 87 times.
|
838 | if (len == 5 && str[1] == '/') { |
82 | 10 | const unsigned char *u_str = str; | |
83 | 10 | uint8_t r = u_str[0] - '0'; | |
84 | 10 | uint8_t g = u_str[2] - '0'; | |
85 | 10 | uint8_t b = u_str[4] - '0'; | |
86 |
5/6✓ Branch 0 taken 8 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
|
10 | if (unlikely(r > 5 || g > 5 || b > 5 || str[3] != '/')) { |
87 | return COLOR_INVALID; | ||
88 | } | ||
89 | // Convert to color index 16..231 (xterm 6x6x6 color cube) | ||
90 | 6 | return 16 + (r * 36) + (g * 6) + b; | |
91 | } | ||
92 | |||
93 | // Parse -2 .. 255 | ||
94 |
6/6✓ Branch 0 taken 92 times.
✓ Branch 1 taken 736 times.
✓ Branch 2 taken 89 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 25 times.
✓ Branch 5 taken 64 times.
|
828 | if (len <= 3 && (str[0] == '-' || ascii_isdigit(str[0]))) { |
95 | 28 | int x; | |
96 |
5/6✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 26 times.
✓ Branch 5 taken 1 times.
|
28 | if (unlikely(!str_to_int(str, &x) || x < -2 || x > 255)) { |
97 | return COLOR_INVALID; | ||
98 | } | ||
99 | 26 | return x; | |
100 | } | ||
101 | |||
102 | 800 | return lookup_color(str); | |
103 | } | ||
104 | |||
105 | // Note: this function returns the number of valid strings parsed, or -1 if | ||
106 | // more than 2 valid colors were encountered. Thus, success is indicated by | ||
107 | // a return value equal to `nstrs`. | ||
108 | 599 | ssize_t parse_term_style(TermStyle *style, char **strs, size_t nstrs) | |
109 | { | ||
110 | 599 | int32_t colors[2] = {COLOR_DEFAULT, COLOR_DEFAULT}; | |
111 | 599 | unsigned int attrs = 0; | |
112 | 599 | size_t i = 0; | |
113 | |||
114 |
2/2✓ Branch 0 taken 852 times.
✓ Branch 1 taken 575 times.
|
1427 | for (size_t nr_colors = 0; i < nstrs; i++) { |
115 | 852 | const char *str = strs[i]; | |
116 | 852 | int32_t c = parse_color(str); | |
117 |
2/2✓ Branch 0 taken 292 times.
✓ Branch 1 taken 560 times.
|
852 | if (c == COLOR_INVALID) { |
118 | 292 | unsigned int attr = lookup_attr(str); | |
119 |
2/2✓ Branch 0 taken 270 times.
✓ Branch 1 taken 22 times.
|
292 | if (likely(attr)) { |
120 | 270 | attrs |= attr; | |
121 | 270 | continue; | |
122 | } | ||
123 | // Invalid color or attribute | ||
124 | 22 | return i; | |
125 | } | ||
126 |
2/2✓ Branch 0 taken 29 times.
✓ Branch 1 taken 531 times.
|
560 | if (nr_colors == ARRAYLEN(colors)) { |
127 |
2/2✓ Branch 0 taken 27 times.
✓ Branch 1 taken 2 times.
|
29 | if (likely(c == COLOR_KEEP)) { |
128 | // "keep" is also a valid attribute | ||
129 | 27 | attrs |= ATTR_KEEP; | |
130 | 27 | continue; | |
131 | } | ||
132 | // Too many colors | ||
133 | return -1; | ||
134 | } | ||
135 | 531 | colors[nr_colors++] = c; | |
136 | } | ||
137 | |||
138 | 575 | *style = (TermStyle) { | |
139 | 575 | .fg = colors[0], | |
140 | 575 | .bg = colors[1], | |
141 | .attr = attrs | ||
142 | }; | ||
143 | 575 | return i; | |
144 | } | ||
145 | |||
146 | 1 | void collect_colors_and_attributes(PointerArray *a, const char *prefix) | |
147 | { | ||
148 |
2/2✓ Branch 0 taken 17 times.
✓ Branch 1 taken 1 times.
|
18 | for (size_t i = 1; i < ARRAYLEN(color_names); i++) { |
149 |
1/2✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
|
17 | if (str_has_prefix(color_names[i], prefix)) { |
150 | 17 | ptr_array_append(a, xstrdup(color_names[i])); | |
151 | } | ||
152 | } | ||
153 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1 times.
|
10 | for (size_t i = 0; i < ARRAYLEN(attr_names); i++) { |
154 |
1/2✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
|
9 | if (str_has_prefix(attr_names[i], prefix)) { |
155 | 9 | ptr_array_append(a, xstrdup(attr_names[i])); | |
156 | } | ||
157 | } | ||
158 | 1 | } | |
159 | |||
160 | 113 | size_t color_to_str(char buf[COLOR_STR_BUFSIZE], int32_t color) | |
161 | { | ||
162 | 113 | BUG_ON(!color_is_valid(color)); | |
163 |
2/2✓ Branch 0 taken 94 times.
✓ Branch 1 taken 19 times.
|
113 | if (color < 16) { |
164 | 94 | static_assert(sizeof(color_names[0]) <= COLOR_STR_BUFSIZE); | |
165 | 94 | memcpy(buf, color_names[color + 2], sizeof(color_names[0])); | |
166 | 94 | return strlen(buf); | |
167 | } | ||
168 | |||
169 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 10 times.
|
19 | if (color < 256) { |
170 | 9 | return buf_u8_to_str((uint8_t)color, buf); | |
171 | } | ||
172 | |||
173 | 10 | size_t i = 0; | |
174 | 10 | buf[i++] = '#'; | |
175 | 10 | i += hex_encode_byte(buf + i, color_r(color)); | |
176 | 10 | i += hex_encode_byte(buf + i, color_g(color)); | |
177 | 10 | i += hex_encode_byte(buf + i, color_b(color)); | |
178 | 10 | BUG_ON(i != 7); | |
179 | return i; | ||
180 | } | ||
181 | |||
182 | 71 | const char *term_style_to_string(char buf[TERM_STYLE_BUFSIZE], const TermStyle *style) | |
183 | { | ||
184 | 71 | size_t pos = color_to_str(buf, style->fg); | |
185 | |||
186 |
4/4✓ Branch 0 taken 51 times.
✓ Branch 1 taken 20 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 50 times.
|
71 | if (style->bg != COLOR_DEFAULT || (style->attr & ATTR_KEEP) != 0) { |
187 | 21 | buf[pos++] = ' '; | |
188 | 21 | pos += color_to_str(buf + pos, style->bg); | |
189 | } | ||
190 | |||
191 |
2/2✓ Branch 0 taken 639 times.
✓ Branch 1 taken 71 times.
|
710 | for (size_t i = 0; i < ARRAYLEN(attr_names); i++) { |
192 |
2/2✓ Branch 0 taken 42 times.
✓ Branch 1 taken 597 times.
|
639 | if (style->attr & (1U << i)) { |
193 | 42 | BUG_ON(pos + 2 + sizeof(attr_names[0]) >= TERM_STYLE_BUFSIZE); | |
194 | 42 | buf[pos++] = ' '; | |
195 | 42 | memcpy(buf + pos, attr_names[i], sizeof(attr_names[0])); | |
196 | 42 | pos += strlen(buf + pos); | |
197 | } | ||
198 | } | ||
199 | |||
200 | 71 | buf[pos] = '\0'; | |
201 | 71 | return buf; | |
202 | } | ||
203 |