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