1 /* radare - LGPL - Copyright 2013-2020 - pancake, sghctoma, xarkes */
2 
3 #include <r_cons.h>
4 
5 #define RCOLOR_AT(i) (RColor *) (((ut8 *) &(r_cons_singleton ()->context->cpal)) + keys[i].coff)
6 #define COLOR_AT(i) (char **) (((ut8 *) &(r_cons_singleton ()->context->pal)) + keys[i].off)
7 
8 static struct {
9 	const char *name;
10 	int off;  // RConsPrintablePalette offset
11 	int coff; // RConsPalette offset
12 } keys[] = {
13 	{ "comment", r_offsetof (RConsPrintablePalette, comment), r_offsetof (RConsPalette, comment) },
14 	{ "usrcmt", r_offsetof (RConsPrintablePalette, usercomment), r_offsetof (RConsPalette, usercomment) },
15 	{ "args", r_offsetof (RConsPrintablePalette, args), r_offsetof (RConsPalette, args) },
16 	{ "fname", r_offsetof (RConsPrintablePalette, fname), r_offsetof (RConsPalette, fname) },
17 	{ "floc", r_offsetof (RConsPrintablePalette, floc), r_offsetof (RConsPalette, floc) },
18 	{ "fline", r_offsetof (RConsPrintablePalette, fline), r_offsetof (RConsPalette, fline) },
19 	{ "flag", r_offsetof (RConsPrintablePalette, flag), r_offsetof (RConsPalette, flag) },
20 	{ "label", r_offsetof (RConsPrintablePalette, label), r_offsetof (RConsPalette, label) },
21 	{ "help", r_offsetof (RConsPrintablePalette, help), r_offsetof (RConsPalette, help) },
22 	{ "flow", r_offsetof (RConsPrintablePalette, flow), r_offsetof (RConsPalette, flow) },
23 	{ "flow2", r_offsetof (RConsPrintablePalette, flow2), r_offsetof (RConsPalette, flow2) },
24 	{ "prompt", r_offsetof (RConsPrintablePalette, prompt), r_offsetof (RConsPalette, prompt) },
25 	{ "offset", r_offsetof (RConsPrintablePalette, offset), r_offsetof (RConsPalette, offset) },
26 	{ "input", r_offsetof (RConsPrintablePalette, input), r_offsetof (RConsPalette, input) },
27 	{ "invalid", r_offsetof (RConsPrintablePalette, invalid), r_offsetof (RConsPalette, invalid) },
28 	{ "other", r_offsetof (RConsPrintablePalette, other), r_offsetof (RConsPalette, other) },
29 	{ "b0x00", r_offsetof (RConsPrintablePalette, b0x00), r_offsetof (RConsPalette, b0x00) },
30 	{ "b0x7f", r_offsetof (RConsPrintablePalette, b0x7f), r_offsetof (RConsPalette, b0x7f) },
31 	{ "b0xff", r_offsetof (RConsPrintablePalette, b0xff), r_offsetof (RConsPalette, b0xff) },
32 	{ "math", r_offsetof (RConsPrintablePalette, math), r_offsetof (RConsPalette, math) },
33 	{ "bin", r_offsetof (RConsPrintablePalette, bin), r_offsetof (RConsPalette, bin) },
34 	{ "btext", r_offsetof (RConsPrintablePalette, btext), r_offsetof (RConsPalette, btext) },
35 	{ "push",  r_offsetof (RConsPrintablePalette, push), r_offsetof (RConsPalette, push) },
36 	{ "pop", r_offsetof (RConsPrintablePalette, pop), r_offsetof (RConsPalette, pop) },
37 	{ "crypto", r_offsetof (RConsPrintablePalette, crypto), r_offsetof (RConsPalette, crypto) },
38 	{ "jmp", r_offsetof (RConsPrintablePalette, jmp), r_offsetof (RConsPalette, jmp) },
39 	{ "cjmp", r_offsetof (RConsPrintablePalette, cjmp), r_offsetof (RConsPalette, cjmp) },
40 	{ "call", r_offsetof (RConsPrintablePalette, call), r_offsetof (RConsPalette, call) },
41 	{ "nop", r_offsetof (RConsPrintablePalette, nop), r_offsetof (RConsPalette, nop) },
42 	{ "ret", r_offsetof (RConsPrintablePalette, ret), r_offsetof (RConsPalette, ret) },
43 	{ "trap", r_offsetof (RConsPrintablePalette, trap), r_offsetof (RConsPalette, trap) },
44 	{ "ucall", r_offsetof (RConsPrintablePalette, ucall), r_offsetof (RConsPalette, ucall) },
45 	{ "ujmp", r_offsetof (RConsPrintablePalette, ujmp), r_offsetof (RConsPalette, ujmp) },
46 	{ "swi", r_offsetof (RConsPrintablePalette, swi), r_offsetof (RConsPalette, swi) },
47 	{ "cmp", r_offsetof (RConsPrintablePalette, cmp), r_offsetof (RConsPalette, cmp) },
48 	{ "reg", r_offsetof (RConsPrintablePalette, reg), r_offsetof (RConsPalette, reg) },
49 	{ "creg", r_offsetof (RConsPrintablePalette, creg), r_offsetof (RConsPalette, creg) },
50 	{ "num", r_offsetof (RConsPrintablePalette, num), r_offsetof (RConsPalette, num) },
51 	{ "mov", r_offsetof (RConsPrintablePalette, mov), r_offsetof (RConsPalette, mov) },
52 	{ "func_var", r_offsetof (RConsPrintablePalette, func_var), r_offsetof (RConsPalette, func_var) },
53 	{ "func_var_type", r_offsetof (RConsPrintablePalette, func_var_type), r_offsetof (RConsPalette, func_var_type) },
54 	{ "func_var_addr", r_offsetof (RConsPrintablePalette, func_var_addr), r_offsetof (RConsPalette, func_var_addr) },
55 	{ "widget_bg", r_offsetof (RConsPrintablePalette, widget_bg), r_offsetof (RConsPalette, widget_bg) },
56 	{ "widget_sel", r_offsetof (RConsPrintablePalette, widget_sel), r_offsetof (RConsPalette, widget_sel) },
57 
58 	{ "ai.read", r_offsetof (RConsPrintablePalette, ai_read), r_offsetof (RConsPalette, ai_read) },
59 	{ "ai.write", r_offsetof (RConsPrintablePalette, ai_write), r_offsetof (RConsPalette, ai_write) },
60 	{ "ai.exec", r_offsetof (RConsPrintablePalette, ai_exec), r_offsetof (RConsPalette, ai_exec) },
61 	{ "ai.seq", r_offsetof (RConsPrintablePalette, ai_seq), r_offsetof (RConsPalette, ai_seq) },
62 	{ "ai.ascii", r_offsetof (RConsPrintablePalette, ai_ascii), r_offsetof (RConsPalette, ai_ascii) },
63 
64 
65 	{ "graph.box", r_offsetof (RConsPrintablePalette, graph_box), r_offsetof (RConsPalette, graph_box) },
66 	{ "graph.box2", r_offsetof (RConsPrintablePalette, graph_box2), r_offsetof (RConsPalette, graph_box2) },
67 	{ "graph.box3", r_offsetof (RConsPrintablePalette, graph_box3), r_offsetof (RConsPalette, graph_box3) },
68 	{ "graph.box4", r_offsetof (RConsPrintablePalette, graph_box4), r_offsetof (RConsPalette, graph_box4) },
69 	{ "graph.true", r_offsetof (RConsPrintablePalette, graph_true), r_offsetof (RConsPalette, graph_true) },
70 	{ "graph.false", r_offsetof (RConsPrintablePalette, graph_false), r_offsetof (RConsPalette, graph_false) },
71 	{ "graph.trufae", r_offsetof (RConsPrintablePalette, graph_trufae), r_offsetof (RConsPalette, graph_trufae) },
72 	{ "graph.current", r_offsetof (RConsPrintablePalette, graph_current), r_offsetof (RConsPalette, graph_current) },
73 	{ "graph.traced", r_offsetof (RConsPrintablePalette, graph_traced), r_offsetof (RConsPalette, graph_traced) },
74 
75         { "graph.diff.unknown", r_offsetof (RConsPrintablePalette, graph_diff_unknown), r_offsetof (RConsPalette, graph_diff_unknown) },
76         { "graph.diff.new", r_offsetof (RConsPrintablePalette, graph_diff_new), r_offsetof (RConsPalette, graph_diff_new) },
77         { "graph.diff.match", r_offsetof (RConsPrintablePalette, graph_diff_match), r_offsetof (RConsPalette, graph_diff_match) },
78         { "graph.diff.unmatch", r_offsetof (RConsPrintablePalette, graph_diff_unmatch), r_offsetof (RConsPalette, graph_diff_unmatch) },
79 
80 	{ "gui.cflow", r_offsetof (RConsPrintablePalette, gui_cflow), r_offsetof (RConsPalette, gui_cflow) },
81 	{ "gui.dataoffset", r_offsetof (RConsPrintablePalette, gui_dataoffset), r_offsetof (RConsPalette, gui_dataoffset) },
82 	{ "gui.background", r_offsetof (RConsPrintablePalette, gui_background), r_offsetof (RConsPalette, gui_background) },
83 	{ "gui.alt_background", r_offsetof (RConsPrintablePalette, gui_alt_background), r_offsetof (RConsPalette, gui_alt_background) },
84 	{ "gui.border", r_offsetof (RConsPrintablePalette, gui_border), r_offsetof (RConsPalette, gui_border) },
85 	{ "wordhl", r_offsetof (RConsPrintablePalette, wordhl), r_offsetof (RConsPalette, wordhl) },
86 	{ "linehl", r_offsetof (RConsPrintablePalette, linehl), r_offsetof (RConsPalette, linehl) },
87 
88 
89 	{ NULL, 0, 0 }
90 };
91 static const int keys_len = sizeof (keys) / sizeof (keys[0]) - 1;
92 
93 struct {
94 	const char *name;
95 	RColor rcolor;
96 	const char *code;
97 	const char *bgcode;
98 } colors[] = {
99 	{ "black",    RColor_BLACK,    Color_BLACK,    Color_BGBLACK },
100 	{ "red",      RColor_RED,      Color_RED,      Color_BGRED },
101 	{ "white",    RColor_WHITE,    Color_WHITE,    Color_BGWHITE },
102 	{ "green",    RColor_GREEN,    Color_GREEN,    Color_BGGREEN },
103 	{ "magenta",  RColor_MAGENTA,  Color_MAGENTA,  Color_BGMAGENTA },
104 	{ "yellow",   RColor_YELLOW,   Color_YELLOW,   Color_BGYELLOW },
105 	{ "cyan",     RColor_CYAN,     Color_CYAN,     Color_BGCYAN },
106 	{ "blue",     RColor_BLUE,     Color_BLUE,     Color_BGBLUE },
107 	{ "gray",     RColor_GRAY,     Color_GRAY,     Color_BGGRAY },
108 	{ "bblack",   RColor_BBLACK,   Color_BBLACK,   Color_BBGBLACK },
109 	{ "bred",     RColor_BRED,     Color_BRED,     Color_BBGRED },
110 	{ "bwhite",   RColor_BWHITE,   Color_BWHITE,   Color_BBGWHITE },
111 	{ "bgreen",   RColor_BGREEN,   Color_BGREEN,   Color_BBGGREEN },
112 	{ "bmagenta", RColor_BMAGENTA, Color_BMAGENTA, Color_BBGMAGENTA },
113 	{ "byellow",  RColor_BYELLOW,  Color_BYELLOW,  Color_BBGYELLOW },
114 	{ "bcyan",    RColor_BCYAN,    Color_BCYAN,    Color_BBGCYAN },
115 	{ "bblue",    RColor_BBLUE,    Color_BBLUE,    Color_BBGBLUE },
116 	{ "none",     RColor_NULL,     Color_RESET,    Color_RESET },
117 	{ NULL, RColor_NULL, NULL, NULL }
118 };
119 
rgbnum(const char ch1,const char ch2)120 static inline ut8 rgbnum(const char ch1, const char ch2) {
121 	ut8 r = 0, r2 = 0;
122 	r_hex_to_byte (&r, ch1);
123 	r_hex_to_byte (&r2, ch2);
124 	return r << 4 | r2;
125 }
126 
__cons_pal_update_event(RConsContext * ctx)127 static void __cons_pal_update_event(RConsContext *ctx) {
128 	Sdb *db = sdb_new0 ();
129 	int i, n = 0;
130 	/* Compute cons->pal values */
131 	for (i = 0; keys[i].name; i++) {
132 		RColor *rcolor = (RColor *) (((ut8 *) &(ctx->cpal)) + keys[i].coff);
133 		char **color = (char **) (((ut8 *) &(ctx->pal)) + keys[i].off);
134 		// Color is dynamically allocated, needs to be freed
135 		R_FREE (*color);
136 		*color = r_cons_rgb_str_mode (ctx->color_mode, NULL, 0, rcolor);
137 		const char *rgb = sdb_fmt ("rgb:%02x%02x%02x", rcolor->r, rcolor->g, rcolor->b);
138 		sdb_set (db, rgb, "1", 0);
139 	}
140 	SdbList *list = sdb_foreach_list (db, true);
141 	SdbListIter *iter;
142 	SdbKv *kv;
143 	r_cons_rainbow_free (ctx);
144 	r_cons_rainbow_new (ctx, list->length);
145 	ls_foreach (list, iter, kv) {
146 		ctx->pal.rainbow[n++] = strdup (sdbkv_key (kv));
147 	}
148 	ctx->pal.rainbow_sz = n;
149 	ls_free (list);
150 	sdb_free (db);
151 }
152 
r_cons_pal_init(RConsContext * ctx)153 R_API void r_cons_pal_init(RConsContext *ctx) {
154 	memset (&ctx->cpal, 0, sizeof (ctx->cpal));
155 
156 	ctx->cpal.b0x00              = (RColor) RColor_GREEN;
157 	ctx->cpal.b0x7f              = (RColor) RColor_CYAN;
158 	ctx->cpal.b0xff              = (RColor) RColor_RED;
159 	ctx->cpal.args               = (RColor) RColor_YELLOW;
160 	ctx->cpal.bin                = (RColor) RColor_CYAN;
161 	ctx->cpal.btext              = (RColor) RColor_YELLOW;
162 	ctx->cpal.call               = (RColor) RColor_BGREEN;
163 	ctx->cpal.call.attr          = R_CONS_ATTR_BOLD;
164 	ctx->cpal.ucall              = (RColor) RColor_GREEN;
165 	ctx->cpal.ujmp               = (RColor) RColor_GREEN;
166 	ctx->cpal.cjmp               = (RColor) RColor_GREEN;
167 	ctx->cpal.cmp                = (RColor) RColor_CYAN;
168 	ctx->cpal.comment            = (RColor) RColor_RED;
169 	ctx->cpal.usercomment        = (RColor) RColor_WHITE;
170 	ctx->cpal.creg               = (RColor) RColor_CYAN;
171 	ctx->cpal.flag               = (RColor) RColor_CYAN;
172 	ctx->cpal.fline              = (RColor) RColor_CYAN;
173 	ctx->cpal.floc               = (RColor) RColor_CYAN;
174 	ctx->cpal.flow               = (RColor) RColor_CYAN;
175 	ctx->cpal.flow2              = (RColor) RColor_BLUE;
176 	ctx->cpal.fname              = (RColor) RColor_RED;
177 	ctx->cpal.help               = (RColor) RColor_GREEN;
178 	ctx->cpal.input              = (RColor) RColor_WHITE;
179 	ctx->cpal.invalid            = (RColor) RColor_BRED;
180 	ctx->cpal.invalid.attr       = R_CONS_ATTR_BOLD;
181 	ctx->cpal.jmp                = (RColor) RColor_GREEN;
182 	ctx->cpal.label              = (RColor) RColor_CYAN;
183 	ctx->cpal.math               = (RColor) RColor_YELLOW;
184 	ctx->cpal.mov                = (RColor) RColor_WHITE;
185 	ctx->cpal.nop                = (RColor) RColor_BLUE;
186 	ctx->cpal.num                = (RColor) RColor_YELLOW;
187 	ctx->cpal.offset             = (RColor) RColor_GREEN;
188 	ctx->cpal.other              = (RColor) RColor_WHITE;
189 	ctx->cpal.pop                = (RColor) RColor_BMAGENTA;
190 	ctx->cpal.pop.attr           = R_CONS_ATTR_BOLD;
191 	ctx->cpal.prompt             = (RColor) RColor_YELLOW;
192 	ctx->cpal.push               = (RColor) RColor_MAGENTA;
193 	ctx->cpal.crypto             = (RColor) RColor_BGBLUE;
194 	ctx->cpal.reg                = (RColor) RColor_CYAN;
195 	ctx->cpal.ret                = (RColor) RColor_RED;
196 	ctx->cpal.swi                = (RColor) RColor_MAGENTA;
197 	ctx->cpal.trap               = (RColor) RColor_BRED;
198 	ctx->cpal.trap.attr          = R_CONS_ATTR_BOLD;
199 
200 	ctx->cpal.ai_read            = (RColor) RColor_GREEN;
201 	ctx->cpal.ai_write           = (RColor) RColor_BLUE;
202 	ctx->cpal.ai_exec            = (RColor) RColor_RED;
203 	ctx->cpal.ai_seq             = (RColor) RColor_MAGENTA;
204 	ctx->cpal.ai_ascii           = (RColor) RColor_YELLOW;
205 
206 	ctx->cpal.gui_cflow          = (RColor) RColor_YELLOW;
207 	ctx->cpal.gui_dataoffset     = (RColor) RColor_YELLOW;
208 	ctx->cpal.gui_background     = (RColor) RColor_BLACK;
209 	ctx->cpal.gui_alt_background = (RColor) RColor_WHITE;
210 	ctx->cpal.gui_border         = (RColor) RColor_BLACK;
211 	ctx->cpal.wordhl             = (RColor) RColor_BGRED;
212 	// No good choice for fallback ansi16 color
213 #if __WINDOWS__
214 	ctx->cpal.linehl             = (RColor) RCOLOR (ALPHA_BG, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 4);
215 #else
216 	ctx->cpal.linehl             = (RColor) RCOLOR (ALPHA_BG, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 4);
217 #endif
218 
219 	ctx->cpal.func_var           = (RColor) RColor_WHITE;
220 	ctx->cpal.func_var_type      = (RColor) RColor_BLUE;
221 	ctx->cpal.func_var_addr      = (RColor) RColor_CYAN;
222 
223 	ctx->cpal.widget_bg          = (RColor) RCOLOR (ALPHA_BG, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0);
224 	ctx->cpal.widget_sel         = (RColor) RColor_BGRED;
225 
226 	ctx->cpal.graph_box          = (RColor) RColor_NULL;
227 	ctx->cpal.graph_box2         = (RColor) RColor_YELLOW;
228 	ctx->cpal.graph_box3         = (RColor) RColor_MAGENTA;
229 	ctx->cpal.graph_box4         = (RColor) RColor_GRAY;
230 	ctx->cpal.graph_true         = (RColor) RColor_GREEN;
231 	ctx->cpal.graph_false        = (RColor) RColor_RED;
232 	ctx->cpal.graph_trufae       = (RColor) RColor_CYAN; // single jump
233 	ctx->cpal.graph_traced       = (RColor) RColor_YELLOW;
234 	ctx->cpal.graph_current      = (RColor) RColor_BLUE;
235 	ctx->cpal.graph_diff_unknown = (RColor) RColor_MAGENTA;
236 	ctx->cpal.graph_diff_new     =  (RColor) RColor_RED;
237 	ctx->cpal.graph_diff_match   =  (RColor) RColor_GRAY;
238 	ctx->cpal.graph_diff_unmatch =  (RColor) RColor_YELLOW;
239 
240 
241 	r_cons_pal_free (ctx);
242 	ctx->pal.reset = Color_RESET; // reset is not user accessible, const char* is ok
243 	__cons_pal_update_event (ctx);
244 }
245 
r_cons_pal_free(RConsContext * ctx)246 R_API void r_cons_pal_free(RConsContext *ctx) {
247 	int i;
248 	for (i = 0; keys[i].name; i++) {
249 		char **color = (char **) (((ut8 *) &(ctx->pal)) + keys[i].off);
250 		if (color && *color) {
251 			R_FREE (*color);
252 		}
253 	}
254 	r_cons_rainbow_free (ctx);
255 }
256 
r_cons_pal_copy(RConsContext * dst,RConsContext * src)257 R_API void r_cons_pal_copy(RConsContext *dst, RConsContext *src) {
258 	memcpy (&dst->cpal, &src->cpal, sizeof (src->cpal));
259 	memset (&dst->pal, 0, sizeof (dst->pal));
260 
261 	dst->pal.rainbow = NULL;
262 	dst->pal.rainbow_sz = 0;
263 
264 	dst->pal.reset = Color_RESET; // reset is not user accessible, const char* is ok
265 
266 	__cons_pal_update_event (dst);
267 }
268 
r_cons_pal_random(void)269 R_API void r_cons_pal_random(void) {
270 	int i;
271 	RColor *rcolor;
272 	for (i = 0; keys[i].name; i++) {
273 		rcolor = RCOLOR_AT (i);
274 		*rcolor = r_cons_color_random (ALPHA_FG);
275 	}
276 	r_cons_pal_update_event ();
277 }
278 
279 /* Return NULL if outcol is given */
r_cons_pal_parse(const char * str,RColor * outcol)280 R_API char *r_cons_pal_parse(const char *str, RColor *outcol) {
281 	int i;
282 	RColor rcolor = (RColor) RColor_BLACK;
283 	rcolor.id16 = -1;
284 	char *fgcolor;
285 	char *bgcolor;
286 	char *attr = NULL;
287 	char out[128];
288 	if (!str) {
289 		return NULL;
290 	}
291 	fgcolor = strdup (str);
292 	if (!fgcolor) {
293 		return NULL;
294 	}
295 	bgcolor = strchr (fgcolor + 1, ' ');
296 	out[0] = 0;
297 	if (bgcolor) {
298 		*bgcolor++ = '\0';
299 		attr = strchr (bgcolor, ' ');
300 		if (attr) {
301 			*attr++ = '\0';
302 		}
303 	}
304 
305 	// Handle first color (fgcolor)
306 	if (!strcmp (fgcolor, "random")) {
307 		rcolor = r_cons_color_random (ALPHA_FG);
308 		if (!outcol) {
309 			r_cons_rgb_str (out, sizeof (out), &rcolor);
310 		}
311 	} else if (!strncmp (fgcolor, "#", 1)) { // "#00ff00" HTML format
312 		if (strlen (fgcolor) == 7) {
313 			i = sscanf (fgcolor + 1, "%02hhx%02hhx%02hhx", &rcolor.r, &rcolor.g, &rcolor.b);
314 			if (i != 3) {
315 				eprintf ("Error while parsing HTML color: %s\n", fgcolor);
316 			}
317 			if (!outcol) {
318 				r_cons_rgb_str (out, sizeof (out), &rcolor);
319 			}
320 		} else {
321 			eprintf ("Invalid html color code\n");
322 		}
323 	} else if (!strncmp (fgcolor, "rgb:", 4)) { // "rgb:123" rgb format
324 		if (strlen (fgcolor) == 7) {
325 			rcolor.r = rgbnum (fgcolor[4], '0');
326 			rcolor.g = rgbnum (fgcolor[5], '0');
327 			rcolor.b = rgbnum (fgcolor[6], '0');
328 			if (!outcol) {
329 				r_cons_rgb_str (out, sizeof (out), &rcolor);
330 			}
331 		} else if (strlen (fgcolor) == 10) {
332 			rcolor.r = rgbnum (fgcolor[4], fgcolor[5]);
333 			rcolor.g = rgbnum (fgcolor[6], fgcolor[7]);
334 			rcolor.b = rgbnum (fgcolor[8], fgcolor[9]);
335 			if (!outcol) {
336 				r_cons_rgb_str (out, sizeof (out), &rcolor);
337 			}
338 		}
339 	}
340 	// Handle second color (bgcolor)
341 	if (bgcolor && !strncmp (bgcolor, "rgb:", 4)) { // "rgb:123" rgb format
342 		if (strlen (bgcolor) == 7) {
343 			rcolor.a |= ALPHA_BG;
344 			rcolor.r2 = rgbnum (bgcolor[4], '0');
345 			rcolor.g2 = rgbnum (bgcolor[5], '0');
346 			rcolor.b2 = rgbnum (bgcolor[6], '0');
347 			if (!outcol) {
348 				size_t len = strlen (out);
349 				r_cons_rgb_str (out + len, sizeof (out) - len, &rcolor);
350 			}
351 		} else if (strlen (bgcolor) == 10) {
352 			rcolor.a |= ALPHA_BG;
353 			rcolor.r2 = rgbnum (bgcolor[4], bgcolor[5]);
354 			rcolor.g2 = rgbnum (bgcolor[6], bgcolor[7]);
355 			rcolor.b2 = rgbnum (bgcolor[8], bgcolor[9]);
356 			if (!outcol) {
357 				size_t len = strlen (out);
358 				r_cons_rgb_str (out + len, sizeof (out) - len, &rcolor);
359 			}
360 		}
361 	}
362 	// No suitable format, checking if colors are named
363 	for (i = 0; colors[i].name; i++) {
364 		if (!strcmp (fgcolor, colors[i].name)) {
365 			rcolor.r = colors[i].rcolor.r;
366 			rcolor.g = colors[i].rcolor.g;
367 			rcolor.b = colors[i].rcolor.b;
368 			rcolor.id16 = colors[i].rcolor.id16;
369 			if (!outcol) {
370 				size_t n = strlen (out);
371 				snprintf (out + n, sizeof (out) - n, "%s", colors[i].code);
372 			}
373 		}
374 		if (bgcolor && !strcmp (bgcolor, colors[i].name)) {
375 			rcolor.a |= ALPHA_BG;
376 			rcolor.r2 = colors[i].rcolor.r; // Initial color doesn't
377 			rcolor.g2 = colors[i].rcolor.g; // have r2, g2, b2
378 			rcolor.b2 = colors[i].rcolor.b;
379 			rcolor.id16 = colors[i].rcolor.id16;
380 			if (!outcol) {
381 				size_t n = strlen (out);
382 				snprintf (out + n, sizeof (out) - n, "%s", colors[i].bgcode);
383 			}
384 		}
385 	}
386 	if (attr) {
387 		// Parse extra attributes.
388 		const char *p = attr;
389 		while (p) {
390 			if (!strncmp(p, "bold", 4)) {
391 				rcolor.attr |= R_CONS_ATTR_BOLD;
392 			} else if (!strncmp(p, "dim", 3)) {
393 				rcolor.attr |= R_CONS_ATTR_DIM;
394 			} else if (!strncmp(p, "italic", 6)) {
395 				rcolor.attr |= R_CONS_ATTR_ITALIC;
396 			} else if (!strncmp(p, "underline", 9)) {
397 				rcolor.attr |= R_CONS_ATTR_UNDERLINE;
398 			} else if (!strncmp(p, "blink", 5)) {
399 				rcolor.attr |= R_CONS_ATTR_BLINK;
400 			} else {
401 				eprintf ("Failed to parse terminal attributes: %s\n", p);
402 				break;
403 			}
404 			p = strchr (p, ' ');
405 			if (p) {
406 				p++;
407 			}
408 		}
409 	}
410 	if (outcol) {
411 		if (outcol->a == ALPHA_BG && !bgcolor) {
412 			rcolor.a = ALPHA_BG;
413 		}
414 		*outcol = rcolor;
415 	}
416 	free (fgcolor);
417 	return (*out && !outcol) ? strdup (out) : NULL;
418 }
419 
r_cons_pal_show_gs(void)420 static void r_cons_pal_show_gs(void) {
421 	int i, n;
422 	r_cons_print ("\nGreyscale:\n");
423 	RColor rcolor = RColor_BLACK;
424 	for (i = 0x08, n = 0;  i <= 0xee; i += 0xa) {
425 		char fg[32], bg[32];
426 		rcolor.r = i;
427 		rcolor.g = i;
428 		rcolor.b = i;
429 
430 		if (i < 0x76) {
431 			strcpy (fg, Color_WHITE);
432 		} else {
433 			strcpy (fg, Color_BLACK);
434 		}
435 		r_cons_rgb_str (bg, sizeof (bg), &rcolor);
436 		r_cons_printf ("%s%s rgb:%02x%02x%02x "Color_RESET,
437 			fg, bg, i, i, i);
438 		if (n++ == 5) {
439 			n = 0;
440 			r_cons_newline ();
441 		}
442 	}
443 }
444 
r_cons_pal_show_256(void)445 static void r_cons_pal_show_256(void) {
446 	RColor rc = RColor_BLACK;
447 	r_cons_print ("\n\nXTerm colors:\n");
448 	int r = 0;
449 	int g = 0;
450 	int b = 0;
451 	for (r = 0x00; r <= 0xff; r += 0x28) {
452 		rc.r = r;
453 		if (rc.r == 0x28) {
454 			rc.r = 0x5f;
455 		}
456 		for (b = 0x00; b <= 0xff; b += 0x28) {
457 			rc.b = b;
458 			if (rc.b == 0x28) {
459 				rc.b = 0x5f;
460 			}
461 			for (g = 0x00; g <= 0xff; g += 0x28) {
462 				rc.g = g;
463 				char bg[32];
464 				if (rc.g == 0x28) {
465 					rc.g = 0x5f;
466 				}
467 				const char *fg = ((rc.r <= 0x5f) && (rc.g <= 0x5f)) ? Color_WHITE: Color_BLACK;
468 				r_cons_rgb_str (bg, sizeof (bg), &rc);
469 				r_cons_printf ("%s%s rgb:%02x%02x%02x "
470 					Color_RESET, fg, bg, rc.r, rc.g, rc.b);
471 			}
472 			r_cons_newline ();
473 		}
474 	}
475 }
476 
r_cons_pal_show_rgb(void)477 static void r_cons_pal_show_rgb(void) {
478 	const int inc = 3;
479 	int i, j, k, n = 0;
480 	RColor rc = RColor_BLACK;
481 	r_cons_print ("\n\nRGB:\n");
482 	for (i = n = 0; i <= 0xf; i += inc) {
483 		for (k = 0; k <= 0xf; k += inc) {
484 			for (j = 0; j <= 0xf; j += inc) {
485 				char fg[32], bg[32];
486 				rc.r = i * 16;
487 				rc.g = j * 16;
488 				rc.b = k * 16;
489 				strcpy (fg, ((i < 6) && (j < 5))
490 					? Color_WHITE: Color_BLACK);
491 				r_cons_rgb_str (bg, sizeof (bg), &rc);
492 				r_cons_printf ("%s%s rgb:%02x%02x%02x "
493 					Color_RESET, fg, bg, rc.r, rc.g, rc.b);
494 				if (n ++== 5) {
495 					n = 0;
496 					r_cons_newline ();
497 				}
498 			}
499 		}
500 	}
501 }
502 
r_cons_pal_show(void)503 R_API void r_cons_pal_show(void) {
504 	int i;
505 	for (i = 0; colors[i].name; i++) {
506 		r_cons_printf ("%s%s__"Color_RESET" %s\n",
507 			colors[i].code,
508 			colors[i].bgcode,
509 			colors[i].name);
510 	}
511 	switch (r_cons_singleton ()->context->color_mode) {
512 	case COLOR_MODE_256: // 256 color palette
513 		r_cons_pal_show_gs ();
514 		r_cons_pal_show_256 ();
515 		break;
516 	case COLOR_MODE_16M: // 16M (truecolor)
517 		r_cons_pal_show_gs ();
518 		r_cons_pal_show_rgb ();
519 		break;
520 	default:
521 		break;
522 	}
523 }
524 
525 typedef struct {
526 	int val;
527 	const char *str;
528 } RAttrStr;
529 
r_cons_pal_list(int rad,const char * arg)530 R_API void r_cons_pal_list(int rad, const char *arg) {
531 	char *name, **color;
532 	const char *hasnext;
533 	int i;
534 	if (rad == 'j') {
535 		r_cons_print ("{");
536 	}
537 	for (i = 0; keys[i].name; i++) {
538 		RColor *rcolor = RCOLOR_AT (i);
539 		color = COLOR_AT (i);
540 		switch (rad) {
541 		case 'j':
542 			hasnext = (keys[i + 1].name) ? "," : "";
543 			r_cons_printf ("\"%s\":[%d,%d,%d]%s",
544 				keys[i].name, rcolor->r, rcolor->g, rcolor->b, hasnext);
545 			break;
546 		case 'c': {
547 			const char *prefix = r_str_trim_head_ro (arg);
548 			if (!prefix) {
549 				prefix = "";
550 			}
551 			hasnext = (keys[i + 1].name) ? "\n" : "";
552 			// TODO Need to replace the '.' char because this is not valid CSS
553 			char *name = strdup (keys[i].name);
554 			int j, len = strlen (name);
555 			for (j = 0; j < len; j++) {
556 				if (name[j] == '.') {
557 					name[j] = '_';
558 				}
559 			}
560 			r_cons_printf (".%s%s { color: rgb(%d, %d, %d); }%s",
561 				prefix, name, rcolor->r, rcolor->g, rcolor->b, hasnext);
562 			free (name);
563 			}
564 			break;
565 		case 'h':
566 			name = strdup (keys[i].name);
567 			r_str_replace_char (name, '.', '_');
568 			r_cons_printf (".%s { color:#%02x%02x%02x }\n",
569 				name, rcolor->r, rcolor->g, rcolor->b);
570 			free (name);
571 			break;
572 		case '*':
573 		case 'r':
574 		case 1:
575 			r_cons_printf ("ec %s rgb:%02x%02x%02x",
576 				keys[i].name, rcolor->r, rcolor->g, rcolor->b);
577 			if (rcolor->a == ALPHA_FGBG) {
578 				r_cons_printf (" rgb:%02x%02x%02x",
579 					rcolor->r2, rcolor->g2, rcolor->b2);
580 			}
581 			if (rcolor->attr) {
582 				const RAttrStr attrs[] = {
583 				    { R_CONS_ATTR_BOLD, "bold" },
584 				    { R_CONS_ATTR_DIM, "dim" },
585 				    { R_CONS_ATTR_ITALIC, "italic" },
586 				    { R_CONS_ATTR_UNDERLINE, "underline" },
587 				    { R_CONS_ATTR_BLINK, "blink" }
588 				};
589 				int j;
590 				if (rcolor->a != ALPHA_FGBG) {
591 					r_cons_strcat (" .");
592 				}
593 				for (j = 0; j < R_ARRAY_SIZE (attrs); j++) {
594 					if (rcolor->attr & attrs[j].val) {
595 						r_cons_printf (" %s", attrs[j].str);
596 					}
597 				}
598 			}
599 			r_cons_newline ();
600 			break;
601 		default:
602 			r_cons_printf (" %s##"Color_RESET"  %s\n", *color,
603 				keys[i].name);
604 		}
605 	}
606 	if (rad == 'j') {
607 		r_cons_print ("}\n");
608 	}
609 }
610 
611 /* Modify the palette to set a color value.
612  * r_cons_pal_update_event () must be called after this function
613  * so the changes take effect. */
r_cons_pal_set(const char * key,const char * val)614 R_API int r_cons_pal_set(const char *key, const char *val) {
615 	int i;
616 	RColor *rcolor;
617 	for (i = 0; keys[i].name; i++) {
618 		if (!strcmp (key, keys[i].name)) {
619 			rcolor = RCOLOR_AT (i);
620 			char *r = r_cons_pal_parse (val, rcolor);
621 			free (r);
622 			return true;
623 		}
624 	}
625 	eprintf ("r_cons_pal_set: Invalid color %s\n", key);
626 	return false;
627 }
628 
629 /* Get the named RColor */
r_cons_pal_get(const char * key)630 R_API RColor r_cons_pal_get(const char *key) {
631 	int i;
632 	RColor *rcolor;
633 	for (i = 0; keys[i].name; i++) {
634 		if (!strcmp (key, keys[i].name)) {
635 			rcolor = RCOLOR_AT (i);
636 			return rcolor? *rcolor: (RColor) RColor_NULL;
637 		}
638 	}
639 	return (RColor) RColor_NULL;
640 }
641 
642 /* Get the RColor at specified index */
r_cons_pal_get_i(int index)643 R_API RColor r_cons_pal_get_i(int index) {
644 	return *(RCOLOR_AT (index));
645 }
646 
647 /* Get color name at index */
r_cons_pal_get_name(int index)648 R_API const char *r_cons_pal_get_name(int index) {
649 	return (index >= 0 && index < keys_len) ? keys[index].name : NULL;
650 }
651 
r_cons_pal_len(void)652 R_API int r_cons_pal_len(void) {
653 	return keys_len;
654 }
655 
r_cons_pal_update_event(void)656 R_API void r_cons_pal_update_event(void) {
657 	__cons_pal_update_event (r_cons_singleton ()->context);
658 }
659 
r_cons_rainbow_new(RConsContext * ctx,int sz)660 R_API void r_cons_rainbow_new(RConsContext *ctx, int sz) {
661 	ctx->pal.rainbow_sz = sz;
662 	free (ctx->pal.rainbow);
663 	ctx->pal.rainbow = calloc (sizeof (char *), sz);
664 }
665 
r_cons_rainbow_free(RConsContext * ctx)666 R_API void r_cons_rainbow_free(RConsContext *ctx) {
667 	int i, sz = ctx->pal.rainbow_sz;
668 	if (ctx->pal.rainbow) {
669 		for (i = 0; i < sz; i++) {
670 			free (ctx->pal.rainbow[i]);
671 		}
672 	}
673 	ctx->pal.rainbow_sz = 0;
674 	R_FREE (ctx->pal.rainbow);
675 }
676 
r_cons_rainbow_get(int idx,int last,bool bg)677 R_API char *r_cons_rainbow_get(int idx, int last, bool bg) {
678 	RCons *cons = r_cons_singleton ();
679 	if (last < 0) {
680 		last = cons->context->pal.rainbow_sz;
681 	}
682 	if (idx < 0 || idx >= last || !cons->context->pal.rainbow) {
683 		return NULL;
684 	}
685 	int x = (last == cons->context->pal.rainbow_sz)
686 		? idx : (cons->context->pal.rainbow_sz * idx) / (last + 1);
687 	const char *a = cons->context->pal.rainbow[x];
688 	if (bg) {
689 		char *dup = r_str_newf ("%s %s", a, a);
690 		char *res = r_cons_pal_parse (dup, NULL);
691 		free (dup);
692 		return res;
693 	}
694 	return r_cons_pal_parse (a, NULL);
695 }
696