1 /* Copyright radare2 2014-2020 - Author: pancake, vane11ope */
2 
3 #include <r_core.h>
4 
5 /* few remaining static functions */
6 static bool __init_panels_menu(RCore *core);
7 static bool __init_panels(RCore *core, RPanels *panels);
8 static void __init_menu_screen_settings_layout(void *_core, const char *parent);
9 static void __init_new_panels_root(RCore *core);
10 static void __init_menu_color_settings_layout(void *core, const char *parent);
11 static void __init_menu_disasm_asm_settings_layout(void *_core, const char *parent);
12 static void __set_dcb(RCore *core, RPanel *p);
13 static void __set_pcb(RPanel *p);
14 static void __panels_refresh(RCore *core);
15 
16 #define MENU_Y 1
17 #define PANEL_NUM_LIMIT 9
18 
19 #define PANEL_TITLE_SYMBOLS          "Symbols"
20 #define PANEL_TITLE_STACK            "Stack"
21 #define PANEL_TITLE_XREFS_HERE       "Xrefs Here"
22 #define PANEL_TITLE_XREFS            "Xrefs"
23 #define PANEL_TITLE_REGISTERS        "Registers"
24 #define PANEL_TITLE_DISASSEMBLY      "Disassembly"
25 #define PANEL_TITLE_DISASMSUMMARY    "Disassemble Summary"
26 #define PANEL_TITLE_ALL_DECOMPILER   "Show All Decompiler Output"
27 #define PANEL_TITLE_DECOMPILER       "Decompiler"
28 #define PANEL_TITLE_DECOMPILER_O     "Decompiler With Offsets"
29 #define PANEL_TITLE_GRAPH            "Graph"
30 #define PANEL_TITLE_TINY_GRAPH       "Tiny Graph"
31 #define PANEL_TITLE_FUNCTIONS        "Functions"
32 #define PANEL_TITLE_FUNCTIONCALLS    "Function Calls"
33 #define PANEL_TITLE_BREAKPOINTS      "Breakpoints"
34 #define PANEL_TITLE_STRINGS_DATA     "Strings in data sections"
35 #define PANEL_TITLE_STRINGS_BIN      "Strings in the whole bin"
36 #define PANEL_TITLE_SECTIONS         "Sections"
37 #define PANEL_TITLE_SEGMENTS         "Segments"
38 #define PANEL_TITLE_COMMENTS         "Comments"
39 
40 #define PANEL_CMD_SYMBOLS            "isq"
41 #define PANEL_CMD_XREFS_HERE         "ax."
42 #define PANEL_CMD_XREFS              "ax"
43 #define PANEL_CMD_STACK              "px"
44 #define PANEL_CMD_REGISTERS          "dr"
45 #define PANEL_CMD_DISASSEMBLY        "pd"
46 #define PANEL_CMD_DISASMSUMMARY      "pdsf"
47 #define PANEL_CMD_DECOMPILER         "pdc"
48 #define PANEL_CMD_DECOMPILER_O       "pddo"
49 #define PANEL_CMD_FUNCTION           "afl"
50 #define PANEL_CMD_GRAPH              "agf"
51 #define PANEL_CMD_TINYGRAPH          "agft"
52 #define PANEL_CMD_HEXDUMP            "xc"
53 #define PANEL_CMD_CONSOLE            "$console"
54 
55 #define PANEL_CONFIG_MENU_MAX    64
56 #define PANEL_CONFIG_PAGE        10
57 #define PANEL_CONFIG_SIDEPANEL_W 60
58 #define PANEL_CONFIG_RESIZE_W    4
59 #define PANEL_CONFIG_RESIZE_H    4
60 
61 #define COUNT(x) (sizeof((x)) / sizeof((*x)) - 1)
62 
63 // TODO: kill mutable globals
64 static bool firstRun = true;
65 static bool fromVisual = false;
66 static char *menus_Colors[128];
67 
68 typedef enum {
69 	LEFT,
70 	RIGHT,
71 	UP,
72 	DOWN
73 } Direction;
74 
75 static const char *panels_dynamic [] = {
76 	"Disassembly", "Stack", "Registers",
77 	NULL
78 };
79 
80 static const char *panels_static [] = {
81 	"Disassembly", "Functions", "Symbols",
82 	NULL
83 };
84 
85 static const char *menus[] = {
86 	"File", "Settings", "Edit", "View", "Tools", "Search", "Emulate", "Debug", "Analyze", "Help",
87 	NULL
88 };
89 
90 static const char *menus_File[] = {
91 	"New", "Open", "ReOpen", "Close", "Save Layout", "Load Layout", "Clear Saved Layouts", "Quit",
92 	NULL
93 };
94 
95 static const char *menus_Settings[] = {
96 	"Colors", "Decompiler", "Disassembly", "Screen",
97 	NULL
98 };
99 
100 static const char *menus_ReOpen[] = {
101 	"In RW", "In Debugger",
102 	NULL
103 };
104 
105 static const char *menus_loadLayout[] = {
106 	"Saved", "Default",
107 	NULL
108 };
109 
110 static const char *menus_Edit[] = {
111 	"Copy", "Paste", "Clipboard", "Write String", "Write Hex", "Write Value", "Assemble", "Fill", "io.cache",
112 	NULL
113 };
114 
115 static const char *menus_iocache[] = {
116 	"On", "Off",
117 	NULL
118 };
119 
120 static const char *menus_View[] = {
121 	"Console", "Hexdump", "Disassembly", "Disassemble Summary", "Decompiler", "Decompiler With Offsets", "Graph", "Tiny Graph",
122 	"Functions", "Function Calls", "Sections", "Segments", PANEL_TITLE_STRINGS_DATA, PANEL_TITLE_STRINGS_BIN, "Symbols", "Imports",
123 	"Info", "Database",  "Breakpoints", "Comments", "Classes", "Entropy", "Entropy Fire", "Stack", "Xrefs Here", "Methods",
124 	"Var READ address", "Var WRITE address", "Summary", "Relocs", "Headers", "File Hashes", PANEL_TITLE_ALL_DECOMPILER,
125 	NULL
126 };
127 
128 static const char *menus_Tools[] = {
129 	"Calculator", "R2 Shell", "System Shell",
130 	NULL
131 };
132 
133 static const char *menus_Search[] = {
134 	"String (Whole Bin)", "String (Data Sections)", "ROP", "Code", "Hexpairs",
135 	NULL
136 };
137 
138 static const char *menus_Emulate[] = {
139 	"Step From", "Step To", "Step Range",
140 	NULL
141 };
142 
143 static const char *menus_Debug[] = {
144 	"Registers", "RegisterRefs", "DRX", "Breakpoints", "Watchpoints",
145 	"Maps", "Modules", "Backtrace", "Locals", "Continue",
146 	"Step", "Step Over", "Reload",
147 	NULL
148 };
149 
150 static const char *menus_Analyze[] = {
151 	"Function", "Symbols", "Program", "BasicBlocks", "Calls", "References",
152 	NULL
153 };
154 
155 static const char *menus_settings_disassembly[] = {
156 	"asm", "hex.section", "io.cache", "hex.pairs", "emu.str",
157 	NULL
158 };
159 
160 static const char *menus_settings_disassembly_asm[] = {
161 	"asm.bytes", "asm.section", "asm.cmt.right", "asm.emu", "asm.var.summary",
162 	"asm.pseudo", "asm.flags.inbytes", "asm.arch", "asm.bits", "asm.cpu",
163 	NULL
164 };
165 
166 static const char *menus_settings_screen[] = {
167 	"scr.bgfill", "scr.color", "scr.utf8", "scr.utf8.curvy", "scr.wheel",
168 	NULL
169 };
170 
171 static const char *menus_Help[] = {
172 	"Toggle Help",
173 	"License", "Version",
174 	"Fortune", "2048",
175 	NULL
176 };
177 
178 static const char *entropy_rotate[] = {
179 	"", "2", "b", "c", "d", "e", "F", "i", "j", "m", "p", "s", "z", "0",
180 	NULL
181 };
182 
183 static char *hexdump_rotate[] = {
184 	"xc", "pxa", "pxr", "prx", "pxb", "pxh", "pxw", "pxq", "pxd", "pxr",
185 	NULL
186 };
187 
188 static const char *register_rotate[] = {
189 	"", "=", "r", "??", "C", "i", "o",
190 	NULL
191 };
192 
193 static const char *function_rotate[] = {
194 	"l", "i", "x",
195 	NULL
196 };
197 
198 static const char *cache_white_list_cmds[] = {
199 	"pdc", "pddo", "agf", "Help",
200 	NULL
201 };
202 
203 static const char *help_msg_panels[] = {
204 	"|",        "split current panel vertically",
205 	"-",        "split current panel horizontally",
206 	":",        "run r2 command in prompt",
207 	";",        "add/remove comment",
208 	"_",        "show hud",
209 	"\\",       "show user-friendly hud",
210 	"?",        "show this help",
211 	"!",        "swap into visual mode",
212 	".",        "seek to PC or entrypoint",
213 	"*",        "show decompiler in the current panel",
214 	"\"",       "create a panel from the list and replace the current one",
215 	"/",        "highlight the keyword",
216 	"(",        "toggle snow",
217 	"&",        "toggle cache",
218 	"[1-9]",    "follow jmp/call identified by shortcut (like ;[1])",
219 	"' '",      "(space) toggle graph / panels",
220 	"tab",      "go to the next panel",
221 	"Enter",    "maximize current panel in zoom mode",
222 	"a",        "toggle auto update for decompiler",
223 	"b",        "browse symbols, flags, configurations, classes, ...",
224 	"c",        "toggle cursor",
225 	"C",        "toggle color",
226 	"d",        "define in the current address. Same as Vd",
227 	"D",        "show disassembly in the current panel",
228 	"e",        "change title and command of current panel",
229 	"f",        "set/add filter keywords",
230 	"F",        "remove all the filters",
231 	"g",        "go/seek to given offset",
232 	"G",        "go/seek to highlight",
233 	"i",        "insert hex",
234 	"hjkl",     "move around (left-down-up-right)",
235 	"HJKL",     "move around (left-down-up-right) by page",
236 	"m",        "select the menu panel",
237 	"M",        "open new custom frame",
238 	"n/N",      "seek next/prev function/flag/hit (scr.nkey)",
239 	"p/P",      "rotate panel layout",
240 	"q",        "quit, or close a tab",
241 	"Q",        "close all the tabs and quit",
242 	"r",        "toggle callhints/jmphints/leahints",
243 	"R",        "randomize color palette (ecr)",
244 	"s/S",      "step in / step over",
245 	"t/T",      "tab prompt / close a tab",
246 	"u/U",      "undo / redo seek",
247 	"w",        "shuffle panels around in window mode",
248 	"V",        "go to the graph mode",
249 	"xX",       "show xrefs/refs of current function from/to data/code",
250 	"z",        "swap current panel with the first one",
251 	NULL
252 };
253 
254 static const char *help_msg_panels_window[] = {
255 	":",        "run r2 command in prompt",
256 	";",        "add/remove comment",
257 	"\"",       "create a panel from the list and replace the current one",
258 	"?",        "show this help",
259 	"|",        "split the current panel vertically",
260 	"-",        "split the current panel horizontally",
261 	"tab",      "go to the next panel",
262 	"Enter",    "maximize current panel in zoom mode",
263 	"d",        "define in the current address. Same as Vd",
264 	"b",        "browse symbols, flags, configurations, classes, ...",
265 	"hjkl",     "move around (left-down-up-right)",
266 	"HJKL",     "resize panels vertically/horizontally",
267 	"Q/q/w",    "quit window mode",
268 	"p/P",      "rotate panel layout",
269 	"t/T",      "rotate related commands in a panel",
270 	"X",        "close current panel",
271 	NULL
272 };
273 
274 static const char *help_msg_panels_zoom[] = {
275 	"?",        "show this help",
276 	":",        "run r2 command in prompt",
277 	";",        "add/remove comment",
278 	"\"",       "create a panel from the list and replace the current one",
279 	"' '",      "(space) toggle graph / panels",
280 	"tab",      "go to the next panel",
281 	"b",        "browse symbols, flags, configurations, classes, ...",
282 	"d",        "define in the current address. Same as Vd",
283 	"c",        "toggle cursor",
284 	"C",        "toggle color",
285 	"hjkl",     "move around (left-down-up-right)",
286 	"p/P",      "seek to next or previous scr.nkey",
287 	"s/S",      "step in / step over",
288 	"t/T",      "rotate related commands in a panel",
289 	"xX",       "show xrefs/refs of current function from/to data/code",
290 	"q/Q/Enter","quit zoom mode",
291 	NULL
292 };
293 
__get_panel(RPanels * panels,int i)294 static RPanel *__get_panel(RPanels *panels, int i) {
295 	return (panels && i < PANEL_NUM_LIMIT)? panels->panel[i]: NULL;
296 }
297 
__update_edge_x(RCore * core,int x)298 static void __update_edge_x(RCore *core, int x) {
299 	RPanels *panels = core->panels;
300 	int i, j;
301 	int tmp_x = 0;
302 	for (i = 0; i < panels->n_panels; i++) {
303 		RPanel *p0 = __get_panel (panels, i);
304 		if (p0 && (p0->view->pos.x - 2 <= panels->mouse_orig_x &&
305 				panels->mouse_orig_x <= p0->view->pos.x + 2)) {
306 			tmp_x = p0->view->pos.x;
307 			p0->view->pos.x += x;
308 			p0->view->pos.w -= x;
309 			for (j = 0; j < panels->n_panels; j++) {
310 				RPanel *p1 = __get_panel (panels, j);
311 				if (p1 && (p1->view->pos.x + p1->view->pos.w - 1 == tmp_x)) {
312 					p1->view->pos.w += x;
313 				}
314 			}
315 		}
316 	}
317 }
318 
__update_edge_y(RCore * core,int y)319 static void __update_edge_y(RCore *core, int y) {
320 	RPanels *panels = core->panels;
321 	size_t i, j;
322 	int tmp_y = 0;
323 	for (i = 0; i < panels->n_panels; i++) {
324 		RPanel *p0 = __get_panel (panels, i);
325 		if (p0 && (p0->view->pos.y - 2 <= panels->mouse_orig_y &&
326 				panels->mouse_orig_y <= p0->view->pos.y + 2)) {
327 			tmp_y = p0->view->pos.y;
328 			p0->view->pos.y += y;
329 			p0->view->pos.h -= y;
330 			for (j = 0; j < panels->n_panels; j++) {
331 				RPanel *p1 = __get_panel (panels, j);
332 				if (p1 && (p1->view->pos.y + p1->view->pos.h - 1 == tmp_y)) {
333 					p1->view->pos.h += y;
334 				}
335 			}
336 		}
337 	}
338 }
339 
__check_if_mouse_x_illegal(RCore * core,int x)340 static bool __check_if_mouse_x_illegal(RCore *core, int x) {
341 	RPanels *panels = core->panels;
342 	RConsCanvas *can = panels->can;
343 	const int edge_x = 1;
344 	if (x <= edge_x || can->w - edge_x <= x) {
345 		return true;
346 	}
347 	return false;
348 }
349 
__check_if_mouse_y_illegal(RCore * core,int y)350 static bool __check_if_mouse_y_illegal(RCore *core, int y) {
351 	RPanels *panels = core->panels;
352 	RConsCanvas *can = panels->can;
353 	const int edge_y = 0;
354 	if (y <= edge_y || can->h - edge_y <= y) {
355 		return true;
356 	}
357 	return false;
358 }
359 
__check_if_mouse_x_on_edge(RCore * core,int x,int y)360 static bool __check_if_mouse_x_on_edge(RCore *core, int x, int y) {
361 	RPanels *panels = core->panels;
362 	const int edge_x = r_config_get_i (core->config, "scr.panelborder")? 3: 1;
363 	int i = 0;
364 	for (; i < panels->n_panels; i++) {
365 		RPanel *panel = __get_panel (panels, i);
366 		if (panel && (x > panel->view->pos.x - (edge_x - 1) && x <= panel->view->pos.x + edge_x)) {
367 			panels->mouse_on_edge_x = true;
368 			panels->mouse_orig_x = x;
369 			return true;
370 		}
371 	}
372 	return false;
373 }
374 
__check_if_mouse_y_on_edge(RCore * core,int x,int y)375 static bool __check_if_mouse_y_on_edge(RCore *core, int x, int y) {
376 	RPanels *panels = core->panels;
377 	const int edge_y = r_config_get_i (core->config, "scr.panelborder")? 3: 1;
378 	int i = 0;
379 	for (; i < panels->n_panels; i++) {
380 		RPanel *panel = __get_panel (panels, i);
381 		if (panel && (x > panel->view->pos.x && x <= panel->view->pos.x + panel->view->pos.w + edge_y)) {
382 			if (y > 2 && y >= panel->view->pos.y && y <= panel->view->pos.y + edge_y) {
383 				panels->mouse_on_edge_y = true;
384 				panels->mouse_orig_y = y;
385 				return true;
386 			}
387 		}
388 	}
389 	return false;
390 }
391 
__get_cur_panel(RPanels * panels)392 static RPanel *__get_cur_panel(RPanels *panels) {
393 	return __get_panel (panels, panels->curnode);
394 }
395 
__check_if_cur_panel(RCore * core,RPanel * panel)396 static bool __check_if_cur_panel(RCore *core, RPanel *panel) {
397 	return __get_cur_panel (core->panels) == panel;
398 }
399 
__check_if_addr(const char * c,int len)400 static bool __check_if_addr(const char *c, int len) {
401 	if (len < 2) {
402 		return false;
403 	}
404 	int i = 0;
405 	for (; i < len; i++) {
406 		if (R_STR_ISNOTEMPTY (c + i) && R_STR_ISNOTEMPTY (c+ i + 1) &&
407 				c[i] == '0' && c[i + 1] == 'x') {
408 			return true;
409 		}
410 	}
411 	return false;
412 }
413 
__check_edge(RCore * core)414 static void __check_edge(RCore *core) {
415 	RPanels *panels = core->panels;
416 	int i;
417 	for (i = 0; i < panels->n_panels; i++) {
418 		RPanel *panel = __get_panel (panels, i);
419 		if (!panel) {
420 			continue;
421 		}
422 		if (panel->view->pos.x + panel->view->pos.w == core->panels->can->w) {
423 			panel->view->edge |= (1 << PANEL_EDGE_RIGHT);
424 		} else {
425 			panel->view->edge &= (1 << PANEL_EDGE_BOTTOM);
426 		}
427 		if (panel->view->pos.y + panel->view->pos.h == core->panels->can->h) {
428 			panel->view->edge |= (1 << PANEL_EDGE_BOTTOM);
429 		} else {
430 			panel->view->edge &= (1 << PANEL_EDGE_RIGHT);
431 		}
432 	}
433 }
434 
__shrink_panels_forward(RCore * core,int target)435 static void __shrink_panels_forward(RCore *core, int target) {
436 	RPanels *panels = core->panels;
437 	int i = target;
438 	for (; i < panels->n_panels - 1; i++) {
439 		panels->panel[i] = panels->panel[i + 1];
440 	}
441 }
442 
__shrink_panels_backward(RCore * core,int target)443 static void __shrink_panels_backward(RCore *core, int target) {
444 	RPanels *panels = core->panels;
445 	int i = target;
446 	for (; i > 0; i--) {
447 		panels->panel[i] = panels->panel[i - 1];
448 	}
449 }
450 
__cache_white_list(RCore * core,RPanel * panel)451 static void __cache_white_list(RCore *core, RPanel *panel) {
452 	int i = 0;
453 	for (; i < COUNT (cache_white_list_cmds); i++) {
454 		if (!strcmp (panel->model->cmd, cache_white_list_cmds[i])) {
455 			panel->model->cache = true;
456 			return;
457 		}
458 	}
459 	panel->model->cache = false;
460 }
461 
__search_db(RCore * core,const char * title)462 static char *__search_db(RCore *core, const char *title) {
463 	RPanels *panels = core->panels;
464 	if (!panels->db) {
465 		return NULL;
466 	}
467 	char *out = sdb_get (panels->db, title, 0);
468 	if (out) {
469 		return out;
470 	}
471 	return NULL;
472 }
473 
__show_status(RCore * core,const char * msg)474 static int __show_status(RCore *core, const char *msg) {
475 	r_cons_gotoxy (0, 0);
476 	r_cons_printf (R_CONS_CLEAR_LINE"%s[Status] %s"Color_RESET, core->cons->context->pal.graph_box2, msg);
477 	r_cons_flush ();
478 	return r_cons_readchar ();
479 }
480 
__show_status_yesno(RCore * core,int def,const char * msg)481 static bool __show_status_yesno(RCore *core, int def, const char *msg) {
482 	r_cons_gotoxy (0, 0);
483 	r_cons_flush ();
484 	return r_cons_yesno (def, R_CONS_CLEAR_LINE"%s[Status] %s"Color_RESET, core->cons->context->pal.graph_box2, msg);
485 }
486 
__show_status_input(RCore * core,const char * msg)487 static char *__show_status_input(RCore *core, const char *msg) {
488 	char *n_msg = r_str_newf (R_CONS_CLEAR_LINE"%s[Status] %s"Color_RESET, core->cons->context->pal.graph_box2, msg);
489 	r_cons_gotoxy (0, 0);
490 	r_cons_flush ();
491 	char *out = r_cons_input (n_msg);
492 	free (n_msg);
493 	return out;
494 }
495 
__check_panel_type(RPanel * panel,const char * type)496 static bool __check_panel_type(RPanel *panel, const char *type) {
497 	if (!panel || !panel->model->cmd || !type) {
498 		return false;
499 	}
500 	char *tmp = r_str_new (panel->model->cmd);
501 	int n = r_str_split (tmp, ' ');
502 	if (!n) {
503 		free (tmp);
504 		return false;
505 	}
506 	const char *base = r_str_word_get0 (tmp, 0);
507 	if (R_STR_ISEMPTY (base)) {
508 		free (tmp);
509 		return false;
510 	}
511 	int len = strlen (type);
512 	if (!strcmp (type, PANEL_CMD_DISASSEMBLY)) {
513 		if (!strncmp (tmp, type, len) &&
514 				strcmp (panel->model->cmd, PANEL_CMD_DECOMPILER) &&
515 				strcmp (panel->model->cmd, PANEL_CMD_DECOMPILER_O) &&
516 				strcmp (panel->model->cmd, PANEL_CMD_DISASMSUMMARY)) {
517 			free (tmp);
518 			return true;
519 		}
520 		free (tmp);
521 		return false;
522 	}
523 	if (!strcmp (type, PANEL_CMD_STACK)) {
524 		if (!strcmp (tmp, PANEL_CMD_STACK)) {
525 			free (tmp);
526 			return true;
527 		}
528 		free (tmp);
529 		return false;
530 	}
531 	if (!strcmp (type, PANEL_CMD_HEXDUMP)) {
532 		int i = 0;
533 		for (; i < COUNT (hexdump_rotate); i++) {
534 			if (!strcmp (tmp, hexdump_rotate[i])) {
535 				free (tmp);
536 				return true;
537 			}
538 		}
539 		free (tmp);
540 		return false;
541 	}
542 	free (tmp);
543 	return !strncmp (panel->model->cmd, type, len);
544 }
545 
__check_root_state(RCore * core,RPanelsRootState state)546 static bool __check_root_state(RCore *core, RPanelsRootState state) {
547 	return core->panels_root->root_state == state;
548 }
549 
search_db_check_panel_type(RCore * core,RPanel * panel,const char * ch)550 static bool search_db_check_panel_type (RCore *core, RPanel *panel, const char *ch) {
551 	char *str = __search_db (core, ch);
552 	bool ret = str && __check_panel_type (panel, str);
553 	free (str);
554 	return ret;
555 }
556 
557 //TODO: Refactroing
__is_abnormal_cursor_type(RCore * core,RPanel * panel)558 static bool __is_abnormal_cursor_type(RCore *core, RPanel *panel) {
559 	if (__check_panel_type (panel, PANEL_CMD_SYMBOLS) || __check_panel_type (panel, PANEL_CMD_FUNCTION)) {
560 		return true;
561 	}
562 	if (search_db_check_panel_type (core, panel, PANEL_TITLE_DISASMSUMMARY)) {
563 		return true;
564 	}
565 	if (search_db_check_panel_type (core, panel, PANEL_TITLE_STRINGS_DATA)) {
566 		return true;
567 	}
568 	if (search_db_check_panel_type (core, panel, PANEL_TITLE_STRINGS_BIN)) {
569 		return true;
570 	}
571 	if (search_db_check_panel_type (core, panel, PANEL_TITLE_BREAKPOINTS)) {
572 		return true;
573 	}
574 	if (search_db_check_panel_type (core, panel, PANEL_TITLE_SECTIONS)) {
575 		return true;
576 	}
577 	if (search_db_check_panel_type (core, panel, PANEL_TITLE_SEGMENTS)) {
578 		return true;
579 	}
580 	if (search_db_check_panel_type (core, panel, PANEL_TITLE_COMMENTS)) {
581 		return true;
582 	}
583 	return false;
584 }
585 
__is_normal_cursor_type(RPanel * panel)586 static bool __is_normal_cursor_type(RPanel *panel) {
587 	return (__check_panel_type (panel, PANEL_CMD_STACK) ||
588 			__check_panel_type (panel, PANEL_CMD_REGISTERS) ||
589 			__check_panel_type (panel, PANEL_CMD_DISASSEMBLY) ||
590 			__check_panel_type (panel, PANEL_CMD_HEXDUMP));
591 }
592 
__set_cmd_str_cache(RCore * core,RPanel * p,char * s)593 static void __set_cmd_str_cache(RCore *core, RPanel *p, char *s) {
594 	free (p->model->cmdStrCache);
595 	p->model->cmdStrCache = s;
596 	__set_dcb (core, p);
597 	__set_pcb (p);
598 }
599 
__set_decompiler_cache(RCore * core,char * s)600 static void __set_decompiler_cache(RCore *core, char *s) {
601 	RAnalFunction *func = r_anal_get_fcn_in (core->anal, core->offset, R_ANAL_FCN_TYPE_NULL);
602 	if (func) {
603 		if (core->panels_root->cur_pdc_cache) {
604 			sdb_ptr_set (core->panels_root->cur_pdc_cache, r_num_as_string (NULL, func->addr, false), r_str_new (s), 0);
605 		} else {
606 			Sdb *sdb = sdb_new0 ();
607 			const char *pdc_now = r_config_get (core->config, "cmd.pdc");
608 			sdb_ptr_set (sdb, r_num_as_string (NULL, func->addr, false), r_str_new (s), 0);
609 			core->panels_root->cur_pdc_cache = sdb;
610 			if (!sdb_exists (core->panels_root->pdc_caches, pdc_now)) {
611 				sdb_ptr_set (core->panels_root->pdc_caches, r_str_new (pdc_now), sdb, 0);
612 			}
613 		}
614 	}
615 }
616 
__set_read_only(RCore * core,RPanel * p,char * s)617 static void __set_read_only(RCore *core, RPanel *p, char *s) {
618 	free (p->model->readOnly);
619 	p->model->readOnly = r_str_new (s);
620 	__set_dcb (core, p);
621 	__set_pcb (p);
622 }
623 
__set_pos(RPanelPos * pos,int x,int y)624 static void __set_pos(RPanelPos *pos, int x, int y) {
625 	pos->x = x;
626 	pos->y = y;
627 }
628 
__set_size(RPanelPos * pos,int w,int h)629 static void __set_size(RPanelPos *pos, int w, int h) {
630 	pos->w = w;
631 	pos->h = h;
632 }
633 
__set_geometry(RPanelPos * pos,int x,int y,int w,int h)634 static void __set_geometry(RPanelPos *pos, int x, int y, int w, int h) {
635 	__set_pos (pos, x, y);
636 	__set_size (pos, w, h);
637 }
638 
__set_panel_addr(RCore * core,RPanel * panel,ut64 addr)639 static void __set_panel_addr(RCore *core, RPanel *panel, ut64 addr) {
640 	panel->model->addr = addr;
641 }
642 
__get_panel_idx_in_pos(RCore * core,int x,int y)643 static int __get_panel_idx_in_pos(RCore *core, int x, int y) {
644 	RPanels *panels = core->panels;
645 	int i = -1;
646 	for (i = 0; i < panels->n_panels; i++) {
647 		RPanel *p = __get_panel (panels, i);
648 		if (p && (x >= p->view->pos.x && x < p->view->pos.x + p->view->pos.w)) {
649 			if (y >= p->view->pos.y && y < p->view->pos.y + p->view->pos.h) {
650 				break;
651 			}
652 		}
653 	}
654 	return i;
655 }
656 
__handlePrompt(RCore * core,RPanels * panels)657 static void __handlePrompt(RCore *core, RPanels *panels) {
658 	r_core_visual_prompt_input (core);
659 	int i;
660 	for (i = 0; i < panels->n_panels; i++) {
661 		RPanel *p = __get_panel (panels, i);
662 		if (p && __check_panel_type (p, PANEL_CMD_DISASSEMBLY)) {
663 			__set_panel_addr (core, p, core->offset);
664 			break;
665 		}
666 	}
667 }
668 
__menu_panel_print(RConsCanvas * can,RPanel * panel,int x,int y,int w,int h)669 static void __menu_panel_print(RConsCanvas *can, RPanel *panel, int x, int y, int w, int h) {
670 	(void) r_cons_canvas_gotoxy (can, panel->view->pos.x + 2, panel->view->pos.y + 2);
671 	char *text = r_str_ansi_crop (panel->model->title, x, y, w, h);
672 	if (text) {
673 		r_cons_canvas_write (can, text);
674 		free (text);
675 	} else {
676 		r_cons_canvas_write (can, panel->model->title);
677 	}
678 }
679 
__update_help_contents(RCore * core,RPanel * panel)680 static void __update_help_contents(RCore *core, RPanel *panel) {
681 	char *read_only = panel->model->readOnly;
682 	char *text = NULL;
683 	int sx = panel->view->sx;
684 	int sy = R_MAX (panel->view->sy, 0);
685 	int x = panel->view->pos.x;
686 	int y = panel->view->pos.y;
687 	int w = panel->view->pos.w;
688 	int h = panel->view->pos.h;
689 	RPanels *panels = core->panels;
690 	RConsCanvas *can = panels->can;
691 	(void) r_cons_canvas_gotoxy (can, x + 2, y + 2);
692 	if (sx < 0) {
693 		char *white = (char*)r_str_pad (' ', 128);
694 		int idx = R_MIN (-sx, strlen (white) - 1);
695 		white[idx] = 0;
696 		text = r_str_ansi_crop (read_only,
697 				0, sy, w + sx - 3, h - 2 + sy);
698 		char *newText = r_str_prefix_all (text, white);
699 		if (newText) {
700 			free (text);
701 			text = newText;
702 		}
703 	} else {
704 		text = r_str_ansi_crop (read_only,
705 				sx, sy, w + sx - 3, h - 2 + sy);
706 	}
707 	if (text) {
708 		r_cons_canvas_write (can, text);
709 		free (text);
710 	}
711 }
712 
__update_help_title(RCore * core,RPanel * panel)713 static void __update_help_title(RCore *core, RPanel *panel) {
714 	RConsCanvas *can = core->panels->can;
715 	RStrBuf *title = r_strbuf_new (NULL);
716 	RStrBuf *cache_title = r_strbuf_new (NULL);
717 	if (__check_if_cur_panel (core, panel)) {
718 		r_strbuf_setf (title, "%s[X] %s"Color_RESET,
719 				core->cons->context->pal.graph_box2, panel->model->title);
720 		r_strbuf_setf (cache_title, "%s[Cache] N/A"Color_RESET,
721 				core->cons->context->pal.graph_box2);
722 	} else {
723 		r_strbuf_setf (title, "[X]   %s   ", panel->model->title);
724 		r_strbuf_setf (cache_title, "[Cache] N/A");
725 	}
726 	if (r_cons_canvas_gotoxy (can, panel->view->pos.x + 1, panel->view->pos.y + 1)) {
727 		r_cons_canvas_write (can, r_strbuf_get (title));
728 	}
729 	if (r_cons_canvas_gotoxy (can, panel->view->pos.x + panel->view->pos.w
730 				- r_str_ansi_len (r_strbuf_get (cache_title)) - 2, panel->view->pos.y + 1)) {
731 		r_cons_canvas_write (can, r_strbuf_get (cache_title));
732 	}
733 	r_strbuf_free (cache_title);
734 	r_strbuf_free (title);
735 }
736 
__update_panel_contents(RCore * core,RPanel * panel,const char * cmdstr)737 static void __update_panel_contents(RCore *core, RPanel *panel, const char *cmdstr) {
738 	bool b = __is_abnormal_cursor_type (core, panel) && core->print->cur_enabled;
739 	int sx = b ? -2 :panel->view->sx;
740 	int sy = R_MAX (panel->view->sy, 0);
741 	int x = panel->view->pos.x;
742 	int y = panel->view->pos.y;
743 	if (x >= core->panels->can->w) {
744 		return;
745 	}
746 	if (y >= core->panels->can->h) {
747 		return;
748 	}
749 	int w = panel->view->pos.w;
750 	int h = panel->view->pos.h;
751 	int graph_pad = __check_panel_type (panel, PANEL_CMD_GRAPH) ? 1 : 0;
752 	char *text = NULL;
753 	RPanels *panels = core->panels;
754 	RConsCanvas *can = panels->can;
755 	(void) r_cons_canvas_gotoxy (can, x + 2, y + 2);
756 	if (sx < 0) {
757 		char *white = (char*)r_str_pad (' ', 128);
758 		int idx = R_MIN (-sx, strlen (white) - 1);
759 		white[idx] = 0;
760 		text = r_str_ansi_crop (cmdstr,
761 				0, sy + graph_pad, w + sx - 3, h - 2 + sy);
762 		char *newText = r_str_prefix_all (text, white);
763 		if (newText) {
764 			free (text);
765 			text = newText;
766 		}
767 	} else {
768 		text = r_str_ansi_crop (cmdstr, sx, sy + graph_pad, w + sx - 3, h - 2 + sy);
769 	}
770 	if (text) {
771 		r_cons_canvas_write (can, text);
772 		free (text);
773 	}
774 	if (b) {
775 		int sub = panel->view->curpos - panel->view->sy;
776 		(void) r_cons_canvas_gotoxy (can, panel->view->pos.x + 2, panel->view->pos.y + 2 + sub);
777 		r_cons_canvas_write (can, "*");
778 	}
779 }
780 
__apply_filter_cmd(RCore * core,RPanel * panel)781 static char *__apply_filter_cmd(RCore *core, RPanel *panel) {
782 	char *out = r_str_ndup (panel->model->cmd, strlen (panel->model->cmd) + 1024);
783 	if (!panel->model->filter) {
784 		return out;
785 	}
786 	int i;
787 	for (i = 0; i < panel->model->n_filter; i++) {
788 		char *filter = panel->model->filter[i];
789 		if (strlen (filter) > 1024) {
790 			(void)__show_status (core, "filter is too big.");
791 			return out;
792 		}
793 		strcat (out, "~");
794 		strcat (out, filter);
795 	}
796 	return out;
797 }
798 
__update_panel_title(RCore * core,RPanel * panel)799 static void __update_panel_title(RCore *core, RPanel *panel) {
800 	RConsCanvas *can = core->panels->can;
801 	RStrBuf *title = r_strbuf_new (NULL);
802 	RStrBuf *cache_title = r_strbuf_new (NULL);
803 	char *cmd_title  = __apply_filter_cmd (core, panel);
804 	if (__check_if_cur_panel (core, panel)) {
805 		if (!strcmp (panel->model->title, cmd_title)) {
806 			r_strbuf_setf (title, "%s[X] %s"Color_RESET, core->cons->context->pal.graph_box2, panel->model->title);
807 		}  else {
808 			r_strbuf_setf (title, "%s[X] %s (%s)"Color_RESET, core->cons->context->pal.graph_box2, panel->model->title, cmd_title);
809 		}
810 		r_strbuf_setf (cache_title, "%s[Cache] %s"Color_RESET, core->cons->context->pal.graph_box2, panel->model->cache ? "On" : "Off");
811 	} else {
812 		if (!strcmp (panel->model->title, cmd_title)) {
813 			r_strbuf_setf (title, "[X]   %s   ", panel->model->title);
814 		} else {
815 			r_strbuf_setf (title, "[X]   %s (%s)  ", panel->model->title, cmd_title);
816 		}
817 		r_strbuf_setf (cache_title, "[Cache] %s", panel->model->cache ? "On" : "Off");
818 	}
819 	r_strbuf_slice (title, 0, panel->view->pos.w);
820 	r_strbuf_slice (cache_title, 0, panel->view->pos.w);
821 	if (r_cons_canvas_gotoxy (can, panel->view->pos.x + 1, panel->view->pos.y + 1)) {
822 		r_cons_canvas_write (can, r_strbuf_get (title));
823 	}
824 	if (r_cons_canvas_gotoxy (can, panel->view->pos.x + panel->view->pos.w - r_str_ansi_len (r_strbuf_get (cache_title)) - 2, panel->view->pos.y + 1)) {
825 		r_cons_canvas_write (can, r_strbuf_get (cache_title));
826 	}
827 	r_strbuf_free (title);
828 	r_strbuf_free (cache_title);
829 	free (cmd_title);
830 }
831 
832 //TODO: make this a task
__update_pdc_contents(RCore * core,RPanel * panel,char * cmdstr)833 static void __update_pdc_contents(RCore *core, RPanel *panel, char *cmdstr) {
834 	RPanels *panels = core->panels;
835 	RConsCanvas *can = panels->can;
836 	int sx = panel->view->sx;
837 	int sy = R_MAX (panel->view->sy, 0);
838 	int x = panel->view->pos.x;
839 	int y = panel->view->pos.y;
840 	int w = panel->view->pos.w;
841 	int h = panel->view->pos.h;
842 	char *text = NULL;
843 
844 	(void) r_cons_canvas_gotoxy (can, x + 2, y + 2);
845 
846 	if (sx < 0) {
847 		char *white = (char*)r_str_pad (' ', 128);
848 		int idx = R_MIN (-sx, strlen (white) - 1);
849 		white[idx] = 0;
850 		text = r_str_ansi_crop (cmdstr, 0, sy, w + sx - 3, h - 2 + sy);
851 		char *newText = r_str_prefix_all (text, white);
852 		if (newText) {
853 			free (text);
854 			text = newText;
855 		}
856 	} else {
857 		text = r_str_ansi_crop (cmdstr, sx, sy, w + sx - 3, h - 2 + sy);
858 	}
859 	if (text) {
860 		r_cons_canvas_write (can, text);
861 		free (text);
862 	}
863 }
864 
__find_cmd_str_cache(RCore * core,RPanel * panel)865 static char *__find_cmd_str_cache(RCore *core, RPanel* panel) {
866 	if (panel->model->cache && panel->model->cmdStrCache) {
867 		return panel->model->cmdStrCache;
868 	}
869 	return NULL;
870 }
871 
__handle_cmd_str_cache(RCore * core,RPanel * panel,bool force_cache)872 static char *__handle_cmd_str_cache(RCore *core, RPanel *panel, bool force_cache) {
873 	char *cmd = __apply_filter_cmd (core, panel);
874 	bool b = core->print->cur_enabled && __get_cur_panel (core->panels) != panel;
875 	if (b) {
876 		core->print->cur_enabled = false;
877 	}
878 	char *out = (*cmd == '.')
879 		? r_core_cmd_str_pipe (core, cmd)
880 		: r_core_cmd_str (core, cmd);
881 	if (force_cache) {
882 		panel->model->cache = true;
883 	}
884 	if (R_STR_ISNOTEMPTY (out)) {
885 		__set_cmd_str_cache (core, panel, out);
886 	} else {
887 		R_FREE (out);
888 	}
889 	free (cmd);
890 	if (b) {
891 		core->print->cur_enabled = true;
892 	}
893 	return out;
894 }
895 
__panel_all_clear(RPanels * panels)896 static void __panel_all_clear(RPanels *panels) {
897 	if (!panels) {
898 		return;
899 	}
900 	int i;
901 	RPanel *panel = NULL;
902 	for (i = 0; i < panels->n_panels; i++) {
903 		panel = __get_panel (panels, i);
904 		if (panel) {
905 			r_cons_canvas_fill (panels->can, panel->view->pos.x, panel->view->pos.y, panel->view->pos.w, panel->view->pos.h, ' ');
906 		}
907 	}
908 	r_cons_canvas_print (panels->can);
909 	r_cons_flush ();
910 }
911 
__layout_default(RPanels * panels)912 static void __layout_default(RPanels *panels) {
913 	RPanel *p0 = __get_panel (panels, 0);
914 	if (!p0){
915 		eprintf("_get_panel (...,0) return null");
916 		return;
917 	}
918 	int h, w = r_cons_get_size (&h);
919 	if (panels->n_panels <= 1) {
920 		__set_geometry (&p0->view->pos, 0, 1, w, h - 1);
921 		return;
922 	}
923 
924 	int ph = (h - 1) / (panels->n_panels - 1);
925 	int colpos = w - panels->columnWidth;
926 	__set_geometry (&p0->view->pos, 0, 1, colpos + 1, h - 1);
927 
928 	int pos_x = p0->view->pos.x + p0->view->pos.w - 1;
929 	int i, total_h = 0;
930 	for (i = 1; i < panels->n_panels; i++) {
931 		RPanel *p = __get_panel (panels, i);
932 		if (!p) {
933 			continue;
934 		}
935 		int tmp_w = R_MAX (w - colpos, 0);
936 		int tmp_h = 0;
937 		if (i + 1 == panels->n_panels) {
938 			tmp_h = h - total_h;
939 		} else {
940 			tmp_h = ph;
941 		}
942 		__set_geometry (&p->view->pos, pos_x, 2 + (ph * (i - 1)) - 1, tmp_w, tmp_h + 1);
943 		total_h += 2 + (ph * (i - 1)) - 1 + tmp_h + 1;
944 	}
945 }
946 
__panels_layout(RPanels * panels)947 static void __panels_layout(RPanels *panels) {
948 	panels->can->sx = 0;
949 	panels->can->sy = 0;
950 	__layout_default (panels);
951 }
952 
__layout_equal_hor(RPanels * panels)953 static void __layout_equal_hor(RPanels *panels) {
954 	int h, w = r_cons_get_size (&h);
955 	int pw = w / panels->n_panels;
956 	int i, cw = 0;
957 	for (i = 0; i < panels->n_panels; i++) {
958 		RPanel *p = __get_panel (panels, i);
959 		if (!p) {
960 			continue;
961 		}
962 		__set_geometry(&p->view->pos, cw, 1, pw, h - 1);
963 		cw += pw - 1;
964 		if (i == panels->n_panels - 2) {
965 			pw = w - cw;
966 		}
967 	}
968 }
969 
__adjust_side_panels(RCore * core)970 static void __adjust_side_panels(RCore *core) {
971 	int i, h;
972 	(void)r_cons_get_size (&h);
973 	RPanels *panels = core->panels;
974 	for (i = 0; i < panels->n_panels; i++) {
975 		RPanel *p = __get_panel (panels, i);
976 		if (p && (p->view->pos.x == 0)) {
977 			if (p->view->pos.w >= PANEL_CONFIG_SIDEPANEL_W) {
978 				p->view->pos.x += PANEL_CONFIG_SIDEPANEL_W - 1;
979 				p->view->pos.w -= PANEL_CONFIG_SIDEPANEL_W - 1;
980 			}
981 		}
982 	}
983 }
984 
__update_help(RCore * core,RPanels * ps)985 static void __update_help(RCore *core, RPanels *ps) {
986 	const char *help = "Help";
987 	int i;
988 	for (i = 0; i < ps->n_panels; i++) {
989 		RPanel *p = __get_panel (ps, i);
990 		if (!p) {
991 			continue;
992 		}
993 		if (!strncmp (p->model->cmd, help, strlen (help))) {
994 			RStrBuf *rsb = r_strbuf_new (NULL);
995 			const char *title;
996 			const char **msg;
997 			switch (ps->mode) {
998 				case PANEL_MODE_WINDOW:
999 					title = "Panels Window Mode";
1000 					msg = help_msg_panels_window;
1001 					break;
1002 				case PANEL_MODE_ZOOM:
1003 					title = "Panels Zoom Mode";
1004 					msg = help_msg_panels_zoom;
1005 					break;
1006 				default:
1007 					title = "Panels Mode";
1008 					msg = help_msg_panels;
1009 					break;
1010 			}
1011 			// panel's title does not change, keep it short and simple
1012 			p->model->title = r_str_dup (p->model->title, help);
1013 			p->model->cmd = r_str_dup (p->model->cmd, help);
1014 			r_core_visual_append_help (rsb, title, msg);
1015 			if (!rsb) {
1016 				break;
1017 			}
1018 			char *drained = r_strbuf_drain (rsb);
1019 			__set_read_only (core, p, drained);
1020 			free (drained);
1021 			p->view->refresh = true;
1022 		}
1023 	}
1024 }
1025 
__set_cursor(RCore * core,bool cur)1026 static void __set_cursor(RCore *core, bool cur) {
1027 	RPanel *p = __get_cur_panel (core->panels);
1028 	RPrint *print = core->print;
1029 	print->cur_enabled = cur;
1030 	if (__is_abnormal_cursor_type (core, p)) {
1031 		return;
1032 	}
1033 	if (cur) {
1034 		print->cur = p->view->curpos;
1035 	} else {
1036 		p->view->curpos = print->cur;
1037 	}
1038 	print->col = print->cur_enabled ? 1: 0;
1039 }
1040 
__set_mode(RCore * core,RPanelsMode mode)1041 static void __set_mode(RCore *core, RPanelsMode mode) {
1042 	RPanels *panels = core->panels;
1043 	__set_cursor (core, false);
1044 	panels->mode = mode;
1045 	__update_help (core, panels);
1046 }
1047 
__set_curnode(RCore * core,int idx)1048 static void __set_curnode(RCore *core, int idx) {
1049 	RPanels *panels = core->panels;
1050 	if (idx >= panels->n_panels) {
1051 		idx = 0;
1052 	}
1053 	if (idx < 0) {
1054 		idx = panels->n_panels - 1;
1055 	}
1056 	panels->curnode = idx;
1057 
1058 	RPanel *cur = __get_cur_panel (panels);
1059 	cur->view->curpos = cur->view->sy;
1060 }
1061 
__check_panel_num(RCore * core)1062 static bool __check_panel_num(RCore *core) {
1063 	RPanels *panels = core->panels;
1064 	if (panels->n_panels + 1 > PANEL_NUM_LIMIT) {
1065 		const char *msg = "panel limit exceeded.";
1066 		(void)__show_status (core, msg);
1067 		return false;
1068 	}
1069 	return true;
1070 }
1071 
__set_rcb(RPanels * ps,RPanel * p)1072 static void __set_rcb(RPanels *ps, RPanel *p) {
1073 	SdbKv *kv;
1074 	SdbListIter *sdb_iter;
1075 	SdbList *sdb_list = sdb_foreach_list (ps->rotate_db, false);
1076 	ls_foreach (sdb_list, sdb_iter, kv) {
1077 		char *key =  sdbkv_key (kv);
1078 		if (!__check_panel_type (p, key)) {
1079 			continue;
1080 		}
1081 		p->model->rotateCb = (RPanelRotateCallback)sdb_ptr_get (ps->rotate_db, key, 0);
1082 		break;
1083 	}
1084 	ls_free (sdb_list);
1085 }
1086 
__init_panel_param(RCore * core,RPanel * p,const char * title,const char * cmd)1087 static void __init_panel_param(RCore *core, RPanel *p, const char *title, const char *cmd) {
1088 	if (!p) {
1089 		return;
1090 	}
1091 	RPanelModel *m = p->model;
1092 	RPanelView *v = p->view;
1093 	m->type = PANEL_TYPE_DEFAULT;
1094 	m->rotate = 0;
1095 	v->curpos = 0;
1096 	__set_panel_addr (core, p, core->offset);
1097 	m->rotateCb = NULL;
1098 	__set_cmd_str_cache (core, p, NULL);
1099 	__set_read_only (core, p, NULL);
1100 	m->funcName = NULL;
1101 	v->refresh = true;
1102 	v->edge = 0;
1103 	if (title) {
1104 		m->title = r_str_dup (m->title, title);
1105 		if (cmd) {
1106 			m->cmd = r_str_dup (m->cmd, cmd);
1107 		} else {
1108 			m->cmd = r_str_dup (m->cmd, "");
1109 		}
1110 	} else if (cmd) {
1111 		m->title = r_str_dup (m->title, cmd);
1112 		m->cmd = r_str_dup (m->cmd, cmd);
1113 	} else {
1114 		m->title = r_str_dup (m->title, "");
1115 		m->cmd = r_str_dup (m->cmd, "");
1116 	}
1117 	__set_pcb (p);
1118 	if (R_STR_ISNOTEMPTY (m->cmd)) {
1119 		__set_dcb (core, p);
1120 		__set_rcb (core->panels, p);
1121 		if (__check_panel_type (p, PANEL_CMD_STACK)) {
1122 			const char *sp = r_reg_get_name (core->anal->reg, R_REG_NAME_SP);
1123 			const ut64 stackbase = r_reg_getv (core->anal->reg, sp);
1124 			m->baseAddr = stackbase;
1125 			__set_panel_addr (core, p, stackbase - r_config_get_i (core->config, "stack.delta"));
1126 		}
1127 	}
1128 	core->panels->n_panels++;
1129 	__cache_white_list (core, p);
1130 	return;
1131 }
1132 
__insert_panel(RCore * core,int n,const char * name,const char * cmd)1133 static void __insert_panel(RCore *core, int n, const char *name, const char *cmd) {
1134 	RPanels *panels = core->panels;
1135 	if (panels->n_panels + 1 > PANEL_NUM_LIMIT) {
1136 		return;
1137 	}
1138 	RPanel **panel = panels->panel;
1139 	int i;
1140 	RPanel *last = panel[panels->n_panels];
1141 	for (i = panels->n_panels - 1; i >= n; i--) {
1142 		panel[i + 1] = panel[i];
1143 	}
1144 	panel[n] = last;
1145 	__init_panel_param (core, panel[n], name, cmd);
1146 }
1147 
__add_cmd_panel(void * user)1148 static int __add_cmd_panel(void *user) {
1149 	RCore *core = (RCore *)user;
1150 	RPanels *panels = core->panels;
1151 	if (!__check_panel_num (core)) {
1152 		return 0;
1153 	}
1154 	RPanelsMenu *menu = core->panels->panels_menu;
1155 	RPanelsMenuItem *parent = menu->history[menu->depth - 1];
1156 	RPanelsMenuItem *child = parent->sub[parent->selectedIndex];
1157 	char *cmd = __search_db (core, child->name);
1158 	if (!cmd) {
1159 		return 0;
1160 	}
1161 	int h;
1162 	(void)r_cons_get_size (&h);
1163 	__adjust_side_panels (core);
1164 	__insert_panel (core, 0, child->name, cmd);
1165 	RPanel *p0 = __get_panel (panels, 0);
1166 	__set_geometry (&p0->view->pos, 0, 1, PANEL_CONFIG_SIDEPANEL_W, h - 1);
1167 	__set_curnode (core, 0);
1168 	__set_mode (core, PANEL_MODE_DEFAULT);
1169 	free (cmd);
1170 	return 0;
1171 }
1172 
__add_help_panel(RCore * core)1173 static void __add_help_panel(RCore *core) {
1174 	//TODO: all these things done below are very hacky and refactoring needed
1175 	RPanels *ps = core->panels;
1176 	int h;
1177 	const char *help = "Help";
1178 	(void)r_cons_get_size (&h);
1179 	__adjust_side_panels (core);
1180 	__insert_panel (core, 0, help, help);
1181 	RPanel *p0 = __get_panel (ps, 0);
1182 	__set_geometry (&p0->view->pos, 0, 1, PANEL_CONFIG_SIDEPANEL_W, h - 1);
1183 	__set_curnode (core, 0);
1184 }
1185 
__load_cmdf(RCore * core,RPanel * p,char * input,char * str)1186 static char *__load_cmdf(RCore *core, RPanel *p, char *input, char *str) {
1187 	char *ret = NULL;
1188 	char *res = __show_status_input (core, input);
1189 	if (res) {
1190 		p->model->cmd = r_str_newf (str, res);
1191 		ret = r_core_cmd_str (core, p->model->cmd);
1192 		free (res);
1193 	}
1194 	return ret;
1195 }
1196 
__add_cmdf_panel(RCore * core,char * input,char * str)1197 static int __add_cmdf_panel(RCore *core, char *input, char *str) {
1198 	RPanels *panels = core->panels;
1199 	if (!__check_panel_num (core)) {
1200 		return 0;
1201 	}
1202 	int h;
1203 	(void)r_cons_get_size (&h);
1204 	RPanelsMenu *menu = core->panels->panels_menu;
1205 	RPanelsMenuItem *parent = menu->history[menu->depth - 1];
1206 	RPanelsMenuItem *child = parent->sub[parent->selectedIndex];
1207 	__adjust_side_panels (core);
1208 	__insert_panel (core, 0, child->name, "");
1209 	RPanel *p0 = __get_panel (panels, 0);
1210 	__set_geometry (&p0->view->pos, 0, 1, PANEL_CONFIG_SIDEPANEL_W, h - 1);
1211 	__set_cmd_str_cache (core, p0, __load_cmdf (core, p0, input, str));
1212 	__set_curnode (core, 0);
1213 	__set_mode (core, PANEL_MODE_DEFAULT);
1214 	return 0;
1215 }
1216 
__fix_layout_w(RCore * core)1217 static void __fix_layout_w(RCore *core) {
1218 	RPanels *panels = core->panels;
1219 	RList *list = r_list_new ();
1220 	int i = 0;
1221 	for (; i < panels->n_panels - 1; i++) {
1222 		RPanel *p = __get_panel (panels, i);
1223 		int64_t t = p->view->pos.x + p->view->pos.w;
1224 		r_list_append (list, (void *)(t));
1225 	}
1226 	RListIter *iter;
1227 	for (i = 0; i < panels->n_panels; i++) {
1228 		RPanel *p = __get_panel (panels, i);
1229 		int tx = p->view->pos.x;
1230 		if (!tx) {
1231 			continue;
1232 		}
1233 		int min = INT8_MAX;
1234 		int target_num = INT8_MAX;
1235 		bool found = false;
1236 		void *num = NULL;
1237 		r_list_foreach (list, iter, num) {
1238 			if ((int64_t)num - 1 == tx) {
1239 				found = true;
1240 				break;
1241 			}
1242 			int sub = (int64_t)num - tx;
1243 			if (min > R_ABS (sub)) {
1244 				min = R_ABS (sub);
1245 				target_num = (int64_t)num;
1246 			}
1247 		}
1248 		if (!found) {
1249 			int t = p->view->pos.x - target_num + 1;
1250 			p->view->pos.x = target_num - 1;
1251 			p->view->pos.w += t;
1252 		}
1253 	}
1254 }
1255 
__fix_layout_h(RCore * core)1256 static void __fix_layout_h(RCore *core) {
1257 	RPanels *panels = core->panels;
1258 	RList *list = r_list_new ();
1259 	int h;
1260 	(void)r_cons_get_size (&h);
1261 	int i = 0;
1262 	for (; i < panels->n_panels - 1; i++) {
1263 		RPanel *p = __get_panel (panels, i);
1264 		int64_t t = p->view->pos.y + p->view->pos.h;
1265 		r_list_append (list, (void *)(t));
1266 	}
1267 	RListIter *iter;
1268 	for (i = 0; i < panels->n_panels; i++) {
1269 		RPanel *p = __get_panel (panels, i);
1270 		int ty = p->view->pos.y;
1271 		int th = p->view->pos.h;
1272 		if (ty == 1 || th == (h - 1)) {
1273 			continue;
1274 		}
1275 		int min = INT8_MAX;
1276 		int target_num = INT8_MAX;
1277 		bool found = false;
1278 		void *num = NULL;
1279 		r_list_foreach (list, iter, num) {
1280 			if ((int64_t)num - 1 == ty) {
1281 				found = true;
1282 				break;
1283 			}
1284 			int sub = (int64_t)num - ty;
1285 			if (min > R_ABS (sub)) {
1286 				min = R_ABS (sub);
1287 				target_num = (int64_t)num;
1288 			}
1289 		}
1290 		if (!found) {
1291 			int t = p->view->pos.y - target_num + 1;
1292 			p->view->pos.y = target_num - 1;
1293 			p->view->pos.h += t;
1294 		}
1295 	}
1296 	r_list_free (list);
1297 }
1298 
__fix_layout(RCore * core)1299 static void __fix_layout(RCore *core) {
1300 	__fix_layout_w (core);
1301 	__fix_layout_h (core);
1302 }
1303 
show_cursor(RCore * core)1304 static void show_cursor(RCore *core) {
1305 	const bool keyCursor = r_config_get_i (core->config, "scr.cursor");
1306 	if (keyCursor) {
1307 		r_cons_gotoxy (core->cons->cpos.x, core->cons->cpos.y);
1308 		r_cons_show_cursor (1);
1309 		r_cons_flush ();
1310 	}
1311 }
1312 
__set_refresh_all(RCore * core,bool clearCache,bool force_refresh)1313 static void __set_refresh_all(RCore *core, bool clearCache, bool force_refresh) {
1314 	RPanels *panels = core->panels;
1315 	int i;
1316 	for (i = 0; i < panels->n_panels; i++) {
1317 		RPanel *panel = __get_panel (panels, i);
1318 		if (!force_refresh && __check_panel_type (panel, PANEL_CMD_CONSOLE)) {
1319 			continue;
1320 		}
1321 		panel->view->refresh = true;
1322 		if (clearCache) {
1323 			__set_cmd_str_cache (core, panel, NULL);
1324 		}
1325 	}
1326 }
1327 
__split_panel_vertical(RCore * core,RPanel * p,const char * name,const char * cmd)1328 static void __split_panel_vertical(RCore *core, RPanel *p, const char *name, const char *cmd) {
1329 	RPanels *panels = core->panels;
1330 	if (!__check_panel_num (core)) {
1331 		return;
1332 	}
1333 	__insert_panel (core, panels->curnode + 1, name, cmd);
1334 	RPanel *next = __get_panel (panels, panels->curnode + 1);
1335 	int owidth = p->view->pos.w;
1336 	p->view->pos.w = owidth / 2 + 1;
1337 	__set_geometry (&next->view->pos, p->view->pos.x + p->view->pos.w - 1,
1338 			p->view->pos.y, owidth - p->view->pos.w + 1, p->view->pos.h);
1339 	__fix_layout (core);
1340 	__set_refresh_all (core, false, true);
1341 }
1342 
__split_panel_horizontal(RCore * core,RPanel * p,const char * name,const char * cmd)1343 static void __split_panel_horizontal(RCore *core, RPanel *p, const char *name, const char *cmd) {
1344 	RPanels *panels = core->panels;
1345 	if (!__check_panel_num (core)) {
1346 		return;
1347 	}
1348 	__insert_panel (core, panels->curnode + 1, name, cmd);
1349 	RPanel *next = __get_panel (panels, panels->curnode + 1);
1350 	int oheight = p->view->pos.h;
1351 	p->view->curpos = 0;
1352 	p->view->pos.h = oheight / 2 + 1;
1353 	__set_geometry (&next->view->pos, p->view->pos.x, p->view->pos.y + p->view->pos.h - 1,
1354 			p->view->pos.w, oheight - p->view->pos.h + 1);
1355 	__fix_layout (core);
1356 	__set_refresh_all (core, false, true);
1357 }
1358 
__panels_check_stackbase(RCore * core)1359 static void __panels_check_stackbase(RCore *core) {
1360 	if (!core || !core->panels) {
1361 		return;
1362 	}
1363 	int i;
1364 	const char *sp = r_reg_get_name (core->anal->reg, R_REG_NAME_SP);
1365 	if (!sp) {
1366 		return;
1367 	}
1368 	const ut64 stackbase = r_reg_getv (core->anal->reg, sp);
1369 	RPanels *panels = core->panels;
1370 	for (i = 1; i < panels->n_panels; i++) {
1371 		RPanel *panel = __get_panel (panels, i);
1372 		if (panel->model->cmd && __check_panel_type (panel, PANEL_CMD_STACK) && panel->model->baseAddr != stackbase) {
1373 			panel->model->baseAddr = stackbase;
1374 			__set_panel_addr (core, panel, stackbase - r_config_get_i (core->config, "stack.delta") + core->print->cur);
1375 		}
1376 	}
1377 }
1378 
__del_panel(RCore * core,int pi)1379 static void __del_panel(RCore *core, int pi) {
1380 	int i;
1381 	RPanels *panels = core->panels;
1382 	RPanel *tmp = __get_panel (panels, pi);
1383 	if (!tmp) {
1384 		return;
1385 	}
1386 	for (i = pi; i < (panels->n_panels - 1); i++) {
1387 		panels->panel[i] = panels->panel[i + 1];
1388 	}
1389 	panels->panel[panels->n_panels - 1] = tmp;
1390 	panels->n_panels--;
1391 	__set_curnode (core, panels->curnode);
1392 }
1393 
__del_invalid_panels(RCore * core)1394 static void __del_invalid_panels(RCore *core) {
1395 	RPanels *panels = core->panels;
1396 	int i;
1397 	for (i = 1; i < panels->n_panels; i++) {
1398 		RPanel *panel = __get_panel (panels, i);
1399 		if (panel->view->pos.w < 2) {
1400 			__del_panel (core, i);
1401 			__del_invalid_panels (core);
1402 			break;
1403 		}
1404 		if (panel->view->pos.h < 2) {
1405 			__del_panel (core, i);
1406 			__del_invalid_panels (core);
1407 			break;
1408 		}
1409 	}
1410 }
1411 
__panels_layout_refresh(RCore * core)1412 static void __panels_layout_refresh(RCore *core) {
1413 	__del_invalid_panels (core);
1414 	__check_edge (core);
1415 	__panels_check_stackbase (core);
1416 	__panels_refresh (core);
1417 }
1418 
__reset_scroll_pos(RPanel * p)1419 static void __reset_scroll_pos(RPanel *p) {
1420 	p->view->sx = 0;
1421 	p->view->sy = 0;
1422 }
1423 
__activate_cursor(RCore * core)1424 static void __activate_cursor(RCore *core) {
1425 	RPanels *panels = core->panels;
1426 	RPanel *cur = __get_cur_panel (panels);
1427 	bool normal = __is_normal_cursor_type (cur);
1428 	bool abnormal = __is_abnormal_cursor_type (core, cur);
1429 	if (normal || abnormal) {
1430 		if (normal && cur->model->cache) {
1431 			if (__show_status_yesno (core, 1, "You need to turn off cache to use cursor. Turn off now?(Y/n)")) {
1432 				cur->model->cache = false;
1433 				__set_cmd_str_cache (core, cur, NULL);
1434 				(void)__show_status (core, "Cache is off and cursor is on");
1435 				__set_cursor (core, !core->print->cur_enabled);
1436 				cur->view->refresh = true;
1437 				__reset_scroll_pos (cur);
1438 			} else {
1439 				(void)__show_status (core, "You can always toggle cache by \'&\' key");
1440 			}
1441 			return;
1442 		}
1443 		__set_cursor (core, !core->print->cur_enabled);
1444 		cur->view->refresh = true;
1445 	} else {
1446 		(void)__show_status (core, "Cursor is not available for the current panel.");
1447 	}
1448 }
1449 
__parse_string_on_cursor(RCore * core,RPanel * panel,int idx)1450 ut64 __parse_string_on_cursor(RCore *core, RPanel *panel, int idx) {
1451 	if (!panel->model->cmdStrCache) {
1452 		return UT64_MAX;
1453 	}
1454 	RStrBuf *buf = r_strbuf_new (NULL);
1455 	char *s = panel->model->cmdStrCache;
1456 	int l = 0;
1457 	while (R_STR_ISNOTEMPTY (s) && l != idx) {
1458 		if (*s == '\n') {
1459 			l++;
1460 		}
1461 		s++;
1462 	}
1463 	while (R_STR_ISNOTEMPTY (s) && R_STR_ISNOTEMPTY (s + 1)) {
1464 		if (*s == '0' && *(s + 1) == 'x') {
1465 			r_strbuf_append_n (buf, s, 2);
1466 			while (*s != ' ') {
1467 				r_strbuf_append_n (buf, s, 1);
1468 				s++;
1469 			}
1470 			ut64 ret = r_num_math (core->num, r_strbuf_get (buf));
1471 			r_strbuf_free (buf);
1472 			return ret;
1473 		}
1474 		s++;
1475 	}
1476 	r_strbuf_free (buf);
1477 	return UT64_MAX;
1478 }
1479 
__fix_cursor_up(RCore * core)1480 static void __fix_cursor_up(RCore *core) {
1481 	RPrint *print = core->print;
1482 	if (print->cur >= 0) {
1483 		return;
1484 	}
1485 	int sz = r_core_visual_prevopsz (core, core->offset + print->cur);
1486 	if (sz < 1) {
1487 		sz = 1;
1488 	}
1489 	r_core_seek_delta (core, -sz);
1490 	print->cur += sz;
1491 	if (print->ocur != -1) {
1492 		print->ocur += sz;
1493 	}
1494 }
1495 
__cursor_left(RCore * core)1496 static void __cursor_left(RCore *core) {
1497 	RPanel *cur = __get_cur_panel (core->panels);
1498 	RPrint *print = core->print;
1499 	if (__check_panel_type (cur, PANEL_CMD_REGISTERS)
1500 			|| __check_panel_type (cur, PANEL_CMD_STACK)) {
1501 		if (print->cur > 0) {
1502 			print->cur--;
1503 			cur->model->addr--;
1504 		}
1505 	} else if (__check_panel_type (cur, PANEL_CMD_DISASSEMBLY)) {
1506 		print->cur--;
1507 		__fix_cursor_up (core);
1508 	} else {
1509 		print->cur--;
1510 	}
1511 }
1512 
__fix_cursor_down(RCore * core)1513 static void __fix_cursor_down(RCore *core) {
1514 	RPrint *print = core->print;
1515 	bool cur_is_visible = core->offset + print->cur + 32 < print->screen_bounds;
1516 	if (!cur_is_visible) {
1517 		int i = 0;
1518 		//XXX: ugly hack
1519 		for (i = 0; i < 2; i++) {
1520 			RAsmOp op;
1521 			int sz = r_asm_disassemble (core->rasm,
1522 					&op, core->block, 32);
1523 			if (sz < 1) {
1524 				sz = 1;
1525 			}
1526 			r_core_seek_delta (core, sz);
1527 			print->cur = R_MAX (print->cur - sz, 0);
1528 			if (print->ocur != -1) {
1529 				print->ocur = R_MAX (print->ocur - sz, 0);
1530 			}
1531 		}
1532 	}
1533 }
1534 
__cursor_right(RCore * core)1535 static void __cursor_right(RCore *core) {
1536 	RPanel *cur = __get_cur_panel (core->panels);
1537 	RPrint *print = core->print;
1538 	if (__check_panel_type (cur, PANEL_CMD_STACK) && print->cur >= 15) {
1539 		return;
1540 	}
1541 	if (__check_panel_type (cur, PANEL_CMD_REGISTERS)
1542 			|| __check_panel_type (cur, PANEL_CMD_STACK)) {
1543 		print->cur++;
1544 		cur->model->addr++;
1545 	} else if (__check_panel_type (cur, PANEL_CMD_DISASSEMBLY)) {
1546 		print->cur++;
1547 		__fix_cursor_down (core);
1548 	} else {
1549 		print->cur++;
1550 	}
1551 }
1552 
__cursor_up(RCore * core)1553 static void __cursor_up(RCore *core) {
1554 	RPrint *print = core->print;
1555 	ut64 addr, oaddr = core->offset + print->cur;
1556 	if (r_core_prevop_addr (core, oaddr, 1, &addr)) {
1557 		const int delta = oaddr - addr;
1558 		print->cur -= delta;
1559 	} else {
1560 		print->cur -= 4;
1561 	}
1562 	__fix_cursor_up (core);
1563 }
1564 
__cursor_down(RCore * core)1565 static void __cursor_down(RCore *core) {
1566 	RPrint *print = core->print;
1567 	RAnalOp *aop = r_core_anal_op (core, core->offset + print->cur, R_ANAL_OP_MASK_BASIC);
1568 	if (aop) {
1569 		print->cur += aop->size;
1570 		r_anal_op_free (aop);
1571 	} else {
1572 		print->cur += 4;
1573 	}
1574 	__fix_cursor_down (core);
1575 }
1576 
__save_panel_pos(RPanel * panel)1577 static void __save_panel_pos(RPanel* panel) {
1578 	if (!panel) {
1579 		return;
1580 	}
1581 	__set_geometry (&panel->view->prevPos, panel->view->pos.x, panel->view->pos.y,
1582 			panel->view->pos.w, panel->view->pos.h);
1583 }
1584 
__restore_panel_pos(RPanel * panel)1585 static void __restore_panel_pos(RPanel* panel) {
1586 	if(!panel){
1587 		return;
1588 	}
1589 	__set_geometry (&panel->view->pos, panel->view->prevPos.x, panel->view->prevPos.y,
1590 			panel->view->prevPos.w, panel->view->prevPos.h);
1591 }
1592 
__maximize_panel_size(RPanels * panels)1593 static void __maximize_panel_size(RPanels *panels) {
1594 	RPanel *cur = __get_cur_panel (panels);
1595 	if(!cur){
1596 		return;
1597 	}
1598 	__set_geometry (&cur->view->pos, 0, 1, panels->can->w, panels->can->h - 1);
1599 	cur->view->refresh = true;
1600 }
1601 
__dismantle_panel(RPanels * ps,RPanel * p)1602 static void __dismantle_panel(RPanels *ps, RPanel *p) {
1603 	if (!p) {
1604 		return;
1605 	}
1606 	RPanel *justLeftPanel = NULL, *justRightPanel = NULL, *justUpPanel = NULL, *justDownPanel = NULL;
1607 	RPanel *tmpPanel = NULL;
1608 	bool leftUpValid = false, leftDownValid = false, rightUpValid = false, rightDownValid = false,
1609 		 upLeftValid = false, upRightValid = false, downLeftValid = false, downRightValid = false;
1610 	int left[PANEL_NUM_LIMIT], right[PANEL_NUM_LIMIT], up[PANEL_NUM_LIMIT], down[PANEL_NUM_LIMIT];
1611 	memset (left, -1, sizeof (left));
1612 	memset (right, -1, sizeof (right));
1613 	memset (up, -1, sizeof (up));
1614 	memset (down, -1, sizeof (down));
1615 	int i, ox, oy, ow, oh;
1616 	ox = p->view->pos.x;
1617 	oy = p->view->pos.y;
1618 	ow = p->view->pos.w;
1619 	oh = p->view->pos.h;
1620 	for (i = 0; i < ps->n_panels; i++) {
1621 		tmpPanel = __get_panel (ps, i);
1622 		if (tmpPanel->view->pos.x + tmpPanel->view->pos.w - 1 == ox) {
1623 			left[i] = 1;
1624 			if (oy == tmpPanel->view->pos.y) {
1625 				leftUpValid = true;
1626 				if (oh == tmpPanel->view->pos.h) {
1627 					justLeftPanel = tmpPanel;
1628 					break;
1629 				}
1630 			}
1631 			if (oy + oh == tmpPanel->view->pos.y + tmpPanel->view->pos.h) {
1632 				leftDownValid = true;
1633 			}
1634 		}
1635 		if (tmpPanel->view->pos.x == ox + ow - 1) {
1636 			right[i] = 1;
1637 			if (oy == tmpPanel->view->pos.y) {
1638 				rightUpValid = true;
1639 				if (oh == tmpPanel->view->pos.h) {
1640 					rightDownValid = true;
1641 					justRightPanel = tmpPanel;
1642 				}
1643 			}
1644 			if (oy + oh == tmpPanel->view->pos.y + tmpPanel->view->pos.h) {
1645 				rightDownValid = true;
1646 			}
1647 		}
1648 		if (tmpPanel->view->pos.y + tmpPanel->view->pos.h - 1 == oy) {
1649 			up[i] = 1;
1650 			if (ox == tmpPanel->view->pos.x) {
1651 				upLeftValid = true;
1652 				if (ow == tmpPanel->view->pos.w) {
1653 					upRightValid = true;
1654 					justUpPanel = tmpPanel;
1655 				}
1656 			}
1657 			if (ox + ow == tmpPanel->view->pos.x + tmpPanel->view->pos.w) {
1658 				upRightValid = true;
1659 			}
1660 		}
1661 		if (tmpPanel->view->pos.y == oy + oh - 1) {
1662 			down[i] = 1;
1663 			if (ox == tmpPanel->view->pos.x) {
1664 				downLeftValid = true;
1665 				if (ow == tmpPanel->view->pos.w) {
1666 					downRightValid = true;
1667 					justDownPanel = tmpPanel;
1668 				}
1669 			}
1670 			if (ox + ow == tmpPanel->view->pos.x + tmpPanel->view->pos.w) {
1671 				downRightValid = true;
1672 			}
1673 		}
1674 	}
1675 	if (justLeftPanel) {
1676 		justLeftPanel->view->pos.w += ox + ow - (justLeftPanel->view->pos.x + justLeftPanel->view->pos.w);
1677 	} else if (justRightPanel) {
1678 		justRightPanel->view->pos.w = justRightPanel->view->pos.x + justRightPanel->view->pos.w - ox;
1679 		justRightPanel->view->pos.x = ox;
1680 	} else if (justUpPanel) {
1681 		justUpPanel->view->pos.h += oy + oh - (justUpPanel->view->pos.y + justUpPanel->view->pos.h);
1682 	} else if (justDownPanel) {
1683 		justDownPanel->view->pos.h = oh + justDownPanel->view->pos.y + justDownPanel->view->pos.h - (oy + oh);
1684 		justDownPanel->view->pos.y = oy;
1685 	} else if (leftUpValid && leftDownValid) {
1686 		for (i = 0; i < ps->n_panels; i++) {
1687 			if (left[i] != -1) {
1688 				tmpPanel = __get_panel (ps, i);
1689 				tmpPanel->view->pos.w += ox + ow - (tmpPanel->view->pos.x + tmpPanel->view->pos.w);
1690 			}
1691 		}
1692 	} else if (rightUpValid && rightDownValid) {
1693 		for (i = 0; i < ps->n_panels; i++) {
1694 			if (right[i] != -1) {
1695 				tmpPanel = __get_panel (ps, i);
1696 				tmpPanel->view->pos.w = tmpPanel->view->pos.x + tmpPanel->view->pos.w - ox;
1697 				tmpPanel->view->pos.x = ox;
1698 			}
1699 		}
1700 	} else if (upLeftValid && upRightValid) {
1701 		for (i = 0; i < ps->n_panels; i++) {
1702 			if (up[i] != -1) {
1703 				tmpPanel = __get_panel (ps, i);
1704 				tmpPanel->view->pos.h += oy + oh - (tmpPanel->view->pos.y + tmpPanel->view->pos.h);
1705 			}
1706 		}
1707 	} else if (downLeftValid && downRightValid) {
1708 		for (i = 0; i < ps->n_panels; i++) {
1709 			if (down[i] != -1) {
1710 				tmpPanel = __get_panel (ps, i);
1711 				tmpPanel->view->pos.h = oh + tmpPanel->view->pos.y + tmpPanel->view->pos.h - (oy + oh);
1712 				tmpPanel->view->pos.y = oy;
1713 			}
1714 		}
1715 	}
1716 }
1717 
__dismantle_del_panel(RCore * core,RPanel * p,int pi)1718 static void __dismantle_del_panel(RCore *core, RPanel *p, int pi) {
1719 	RPanels *panels = core->panels;
1720 	if (panels->n_panels <= 1) {
1721 		return;
1722 	}
1723 	__dismantle_panel (panels, p);
1724 	__del_panel (core, pi);
1725 }
1726 
__toggle_help(RCore * core)1727 static void __toggle_help(RCore *core) {
1728 	RPanels *ps = core->panels;
1729 	int i;
1730 	for (i = 0; i < ps->n_panels; i++) {
1731 		RPanel *p = __get_panel (ps, i);
1732 		if (r_str_endswith (p->model->cmd, "Help")) {
1733 			__dismantle_del_panel (core, p, i);
1734 			if (ps->mode == PANEL_MODE_MENU) {
1735 				__set_mode (core, PANEL_MODE_DEFAULT);
1736 			}
1737 			return;
1738 		}
1739 	}
1740 	__add_help_panel (core);
1741 	if (ps->mode == PANEL_MODE_MENU) {
1742 		__set_mode (core, PANEL_MODE_DEFAULT);
1743 	}
1744 	__update_help (core, ps);
1745 }
1746 
__reset_snow(RPanels * panels)1747 static void __reset_snow(RPanels *panels) {
1748 	RPanel *cur = __get_cur_panel (panels);
1749 	r_list_free (panels->snows);
1750 	panels->snows = NULL;
1751 	cur->view->refresh = true;
1752 }
1753 
__toggle_zoom_mode(RCore * core)1754 static void __toggle_zoom_mode(RCore *core) {
1755 	RPanels *panels = core->panels;
1756 	RPanel *cur = __get_cur_panel (panels);
1757 	if (panels->mode != PANEL_MODE_ZOOM) {
1758 		panels->prevMode = panels->mode;
1759 		__set_mode (core, PANEL_MODE_ZOOM);
1760 		__save_panel_pos (cur);
1761 		__maximize_panel_size (panels);
1762 	} else {
1763 		__set_mode (core, panels->prevMode);
1764 		panels->prevMode = PANEL_MODE_DEFAULT;
1765 		__restore_panel_pos (cur);
1766 		if (panels->fun == PANEL_FUN_SNOW || panels->fun == PANEL_FUN_SAKURA) {
1767 			__reset_snow (panels);
1768 		}
1769 	}
1770 }
1771 
__set_root_state(RCore * core,RPanelsRootState state)1772 static void __set_root_state(RCore *core, RPanelsRootState state) {
1773 	core->panels_root->root_state = state;
1774 }
1775 
__handle_tab_next(RCore * core)1776 static void __handle_tab_next(RCore *core) {
1777 	if (core->panels_root->n_panels > 1) {
1778 		core->panels_root->cur_panels++;
1779 		core->panels_root->cur_panels %= core->panels_root->n_panels;
1780 		__set_root_state (core, ROTATE);
1781 	}
1782 }
1783 
__handle_print_rotate(RCore * core)1784 static void __handle_print_rotate(RCore *core) {
1785 	if (r_config_get_i (core->config, "asm.pseudo")) {
1786 		r_config_toggle (core->config, "asm.pseudo");
1787 		r_config_toggle (core->config, "asm.esil");
1788 	} else if (r_config_get_i (core->config, "asm.esil")) {
1789 		r_config_toggle (core->config, "asm.esil");
1790 	} else {
1791 		r_config_toggle (core->config, "asm.pseudo");
1792 	}
1793 }
1794 
__handle_tab_prev(RCore * core)1795 static void __handle_tab_prev(RCore *core) {
1796 	if (core->panels_root->n_panels > 1) {
1797 		core->panels_root->cur_panels--;
1798 		if (core->panels_root->cur_panels < 0) {
1799 			core->panels_root->cur_panels = core->panels_root->n_panels - 1;
1800 		}
1801 		__set_root_state (core, ROTATE);
1802 	}
1803 }
1804 
__handle_tab_name(RCore * core)1805 static void __handle_tab_name(RCore *core) {
1806 	core->panels->name = __show_status_input (core, "tab name: ");
1807 }
1808 
__handle_tab_new(RCore * core)1809 static void __handle_tab_new(RCore *core) {
1810 	if (core->panels_root->n_panels >= PANEL_NUM_LIMIT) {
1811 		return;
1812 	}
1813 	__init_new_panels_root (core);
1814 }
1815 
__init_sdb(RCore * core)1816 static void __init_sdb(RCore *core) {
1817 	Sdb *db = core->panels->db;
1818 	sdb_set (db, "Symbols", "isq", 0);
1819 	sdb_set (db, "Stack"  , "px 256@r:SP", 0);
1820 	sdb_set (db, "Locals", "afvd", 0);
1821 	sdb_set (db, "Registers", "dr", 0);
1822 	sdb_set (db, "RegisterRefs", "drr", 0);
1823 	sdb_set (db, "Disassembly", "pd", 0);
1824 	sdb_set (db, "Disassemble Summary", "pdsf", 0);
1825 	sdb_set (db, "Decompiler", "pdc", 0);
1826 	sdb_set (db, "Decompiler With Offsets", "pdco", 0);
1827 	sdb_set (db, "Graph", "agf", 0);
1828 	sdb_set (db, "Tiny Graph", "agft", 0);
1829 	sdb_set (db, "Info", "i", 0);
1830 	sdb_set (db, "Database", "k ***", 0);
1831 	sdb_set (db, "Console", "$console", 0);
1832 	sdb_set (db, "Hexdump", "xc $r*16", 0);
1833 	sdb_set (db, "Xrefs", "ax", 0);
1834 	sdb_set (db, "Xrefs Here", "ax.", 0);
1835 	sdb_set (db, "Functions", "afl", 0);
1836 	sdb_set (db, "Function Calls", "aflm", 0);
1837 	sdb_set (db, "Comments", "CC", 0);
1838 	sdb_set (db, "Entropy", "p=e 100", 0);
1839 	sdb_set (db, "Entropy Fire", "p==e 100", 0);
1840 	sdb_set (db, "DRX", "drx", 0);
1841 	sdb_set (db, "Sections", "iSq", 0);
1842 	sdb_set (db, "Segments", "iSSq", 0);
1843 	sdb_set (db, PANEL_TITLE_STRINGS_DATA, "izq", 0);
1844 	sdb_set (db, PANEL_TITLE_STRINGS_BIN, "izzq", 0);
1845 	sdb_set (db, "Maps", "dm", 0);
1846 	sdb_set (db, "Modules", "dmm", 0);
1847 	sdb_set (db, "Backtrace", "dbt", 0);
1848 	sdb_set (db, "Breakpoints", "db", 0);
1849 	sdb_set (db, "Imports", "iiq", 0);
1850 	sdb_set (db, "Clipboard", "yx", 0);
1851 	sdb_set (db, "New", "o", 0);
1852 	sdb_set (db, "Var READ address", "afvR", 0);
1853 	sdb_set (db, "Var WRITE address", "afvW", 0);
1854 	sdb_set (db, "Summary", "pdsf", 0);
1855 	sdb_set (db, "Classes", "icq", 0);
1856 	sdb_set (db, "Methods", "ic", 0);
1857 	sdb_set (db, "Relocs", "ir", 0);
1858 	sdb_set (db, "Headers", "iH", 0);
1859 	sdb_set (db, "File Hashes", "it", 0);
1860 }
1861 
__free_panel_model(RPanel * panel)1862 static void __free_panel_model(RPanel *panel) {
1863 	if (!panel) {
1864 		return;
1865 	}
1866 	free (panel->model->title);
1867 	free (panel->model->cmd);
1868 	free (panel->model->cmdStrCache);
1869 	free (panel->model->readOnly);
1870 	free (panel->model);
1871 }
1872 
__replace_cmd(RCore * core,const char * title,const char * cmd)1873 static void __replace_cmd(RCore *core, const char *title, const char *cmd) {
1874 	RPanels *panels = core->panels;
1875 	RPanel *cur = __get_cur_panel (panels);
1876 	__free_panel_model (cur);
1877 	cur->model = R_NEW0 (RPanelModel);
1878 	cur->model->title = r_str_dup (cur->model->title, title);
1879 	cur->model->cmd = r_str_dup (cur->model->cmd, cmd);
1880 	__set_cmd_str_cache (core, cur, NULL);
1881 	__set_panel_addr (core, cur, core->offset);
1882 	cur->model->type = PANEL_TYPE_DEFAULT;
1883 	__set_dcb (core, cur);
1884 	__set_pcb (cur);
1885 	__set_rcb (panels, cur);
1886 	__cache_white_list (core, cur);
1887 	__set_refresh_all (core, false, true);
1888 }
1889 
__create_panel(RCore * core,RPanel * panel,const RPanelLayout dir,R_NULLABLE const char * title,const char * cmd)1890 static void __create_panel(RCore *core, RPanel *panel, const RPanelLayout dir, R_NULLABLE const char* title, const char *cmd) {
1891 	if (!__check_panel_num (core)) {
1892 		return;
1893 	}
1894 	if (!panel) {
1895 		return;
1896 	}
1897 	switch (dir) {
1898 	case PANEL_LAYOUT_VERTICAL:
1899 		__split_panel_vertical (core, panel, title, cmd);
1900 		break;
1901 	case PANEL_LAYOUT_HORIZONTAL:
1902 		__split_panel_horizontal (core, panel, title, cmd);
1903 		break;
1904 	case PANEL_LAYOUT_NONE:
1905 		__replace_cmd (core, title, cmd);
1906 		break;
1907 	}
1908 }
1909 
__create_panel_db(void * user,RPanel * panel,const RPanelLayout dir,R_NULLABLE const char * title)1910 static void __create_panel_db(void *user, RPanel *panel, const RPanelLayout dir, R_NULLABLE const char *title) {
1911 	RCore *core = (RCore *)user;
1912 	char *cmd = sdb_get (core->panels->db, title, 0);
1913 	if (!cmd) {
1914 		return;
1915 	}
1916 	__create_panel (core, panel, dir, title, cmd);
1917 }
1918 
__create_panel_input(void * user,RPanel * panel,const RPanelLayout dir,R_NULLABLE const char * title)1919 static void __create_panel_input(void *user, RPanel *panel, const RPanelLayout dir, R_NULLABLE const char *title) {
1920 	RCore *core = (RCore *)user;
1921 	char *cmd = __show_status_input (core, "Command: ");
1922 	if (cmd) {
1923 		__create_panel (core, panel, dir, cmd, cmd);
1924 	}
1925 }
1926 
__replace_current_panel_input(void * user,RPanel * panel,const RPanelLayout dir,R_NULLABLE const char * title)1927 static void __replace_current_panel_input(void *user, RPanel *panel, const RPanelLayout dir, R_NULLABLE const char *title) {
1928 	RCore *core = (RCore *)user;
1929 	char *cmd = __show_status_input (core, "New command: ");
1930 	if (R_STR_ISNOTEMPTY (cmd)) {
1931 		__replace_cmd (core, cmd, cmd);
1932 	}
1933 	free (cmd);
1934 }
1935 
__search_strings(RCore * core,bool whole)1936 static char *__search_strings(RCore *core, bool whole) {
1937 	const char *title = whole ? PANEL_TITLE_STRINGS_BIN : PANEL_TITLE_STRINGS_DATA;
1938 	const char *str = __show_status_input (core, "Search Strings: ");
1939 	char *db_val = __search_db (core, title);
1940 	char *ret = r_str_newf ("%s~%s", db_val, str);
1941 	free (db_val);
1942 	return ret;
1943 }
1944 
__search_strings_data_create(void * user,RPanel * panel,const RPanelLayout dir,R_NULLABLE const char * title)1945 static void __search_strings_data_create(void *user, RPanel *panel, const RPanelLayout dir, R_NULLABLE const char *title) {
1946 	RCore *core = (RCore *)user;
1947 	__create_panel (core, panel, dir, title, __search_strings (core, false));
1948 }
1949 
__search_strings_bin_create(void * user,RPanel * panel,const RPanelLayout dir,R_NULLABLE const char * title)1950 static void __search_strings_bin_create(void *user, RPanel *panel, const RPanelLayout dir, R_NULLABLE const char *title) {
1951 	RCore *core = (RCore *)user;
1952 	__create_panel (core, panel, dir, title, __search_strings (core, true));
1953 }
1954 
__get_panels(RPanelsRoot * panels_root,int i)1955 static RPanels *__get_panels(RPanelsRoot *panels_root, int i) {
1956 	if (!panels_root || (i >= PANEL_NUM_LIMIT)) {
1957 		return NULL;
1958 	}
1959 	return panels_root->panels[i];
1960 }
1961 
__update_disassembly_or_open(RCore * core)1962 static void __update_disassembly_or_open (RCore *core) {
1963 	RPanels *panels = core->panels;
1964 	int i;
1965 	bool create_new = true;
1966 	for (i = 0; i < panels->n_panels; i++) {
1967 		RPanel *p = __get_panel (panels, i);
1968 		if (__check_panel_type (p, PANEL_CMD_DISASSEMBLY)) {
1969 			__set_panel_addr (core, p, core->offset);
1970 			create_new = false;
1971 		}
1972 	}
1973 	if (create_new) {
1974 		RPanel *panel = __get_panel (panels, 0);
1975 		int x0 = panel->view->pos.x;
1976 		int y0 = panel->view->pos.y;
1977 		int w0 = panel->view->pos.w;
1978 		int h0 = panel->view->pos.h;
1979 		int threshold_w = x0 + panel->view->pos.w;
1980 		int x1 = x0 + w0 / 2 - 1;
1981 		int w1 = threshold_w - x1;
1982 
1983 		__insert_panel (core, 0, PANEL_TITLE_DISASSEMBLY, PANEL_CMD_DISASSEMBLY);
1984 		RPanel *p0 = __get_panel (panels, 0);
1985 		__set_geometry (&p0->view->pos, x0, y0, w0 / 2, h0);
1986 
1987 		RPanel *p1 = __get_panel (panels, 1);
1988 		__set_geometry (&p1->view->pos, x1, y0, w1, h0);
1989 
1990 		__set_cursor (core, false);
1991 		__set_curnode (core, 0);
1992 	}
1993 }
1994 
__continue_cb(void * user)1995 static int __continue_cb(void *user) {
1996 	RCore *core = (RCore *)user;
1997 	r_core_cmd (core, "dc", 0);
1998 	r_cons_flush ();
1999 	return 0;
2000 }
2001 
__continue_modal_cb(void * user,R_UNUSED RPanel * panel,R_UNUSED const RPanelLayout dir,R_UNUSED R_NULLABLE const char * title)2002 static void __continue_modal_cb(void *user, R_UNUSED RPanel *panel, R_UNUSED const RPanelLayout dir, R_UNUSED R_NULLABLE const char *title) {
2003 	__continue_cb (user);
2004 	__update_disassembly_or_open ((RCore *)user);
2005 }
2006 
__panel_single_step_in(RCore * core)2007 static void __panel_single_step_in(RCore *core) {
2008 	if (r_config_get_i (core->config, "cfg.debug")) {
2009 		r_core_cmd (core, "ds", 0);
2010 		r_core_cmd (core, ".dr*", 0);
2011 	} else {
2012 		r_core_cmd (core, "aes", 0);
2013 		r_core_cmd (core, ".ar*", 0);
2014 	}
2015 }
2016 
__step_cb(void * user)2017 static int __step_cb(void *user) {
2018 	RCore *core = (RCore *)user;
2019 	__panel_single_step_in (core);
2020 	__update_disassembly_or_open (core);
2021 	return 0;
2022 }
2023 
__panel_single_step_over(RCore * core)2024 static void __panel_single_step_over(RCore *core) {
2025 	bool io_cache = r_config_get_i (core->config, "io.cache");
2026 	r_config_set_b (core->config, "io.cache", false);
2027 	if (r_config_get_i (core->config, "cfg.debug")) {
2028 		r_core_cmd (core, "dso", 0);
2029 		r_core_cmd (core, ".dr*", 0);
2030 	} else {
2031 		r_core_cmd (core, "aeso", 0);
2032 		r_core_cmd (core, ".ar*", 0);
2033 	}
2034 	r_config_set_b (core->config, "io.cache", io_cache);
2035 }
2036 
__step_over_cb(void * user)2037 static int __step_over_cb(void *user) {
2038 	RCore *core = (RCore *)user;
2039 	__panel_single_step_over (core);
2040 	__update_disassembly_or_open (core);
2041 	return 0;
2042 }
2043 
__step_modal_cb(void * user,R_UNUSED RPanel * panel,R_UNUSED const RPanelLayout dir,R_UNUSED R_NULLABLE const char * title)2044 static void __step_modal_cb(void *user, R_UNUSED RPanel *panel, R_UNUSED const RPanelLayout dir, R_UNUSED R_NULLABLE const char *title) {
2045 	__step_cb (user);
2046 }
2047 
__panel_prompt(const char * prompt,char * buf,int len)2048 static void __panel_prompt(const char *prompt, char *buf, int len) {
2049 	r_line_set_prompt (prompt);
2050 	*buf = 0;
2051 	r_cons_fgets (buf, len, 0, NULL);
2052 }
2053 
__break_points_cb(void * user)2054 static int __break_points_cb(void *user) {
2055 	RCore *core = (RCore *)user;
2056 	char buf[128];
2057 	const char *prompt = "addr: ";
2058 
2059 	core->cons->line->prompt_type = R_LINE_PROMPT_OFFSET;
2060 	r_line_set_hist_callback (core->cons->line,
2061 		&r_line_hist_offset_up,
2062 		&r_line_hist_offset_down);
2063 	__panel_prompt (prompt, buf, sizeof (buf));
2064 	r_line_set_hist_callback (core->cons->line, &r_line_hist_cmd_up, &r_line_hist_cmd_down);
2065 	core->cons->line->prompt_type = R_LINE_PROMPT_DEFAULT;
2066 
2067 	ut64 addr = r_num_math (core->num, buf);
2068 	r_core_cmdf (core, "dbs 0x%08"PFMT64x, addr);
2069 	return 0;
2070 }
2071 
__put_breakpoints_cb(void * user,R_UNUSED RPanel * panel,R_UNUSED const RPanelLayout dir,R_UNUSED R_NULLABLE const char * title)2072 static void __put_breakpoints_cb(void *user, R_UNUSED RPanel *panel, R_UNUSED const RPanelLayout dir, R_UNUSED R_NULLABLE const char *title) {
2073 	__break_points_cb (user);
2074 }
2075 
__step_over_modal_cb(void * user,R_UNUSED RPanel * panel,R_UNUSED const RPanelLayout dir,R_UNUSED R_NULLABLE const char * title)2076 static void __step_over_modal_cb(void *user, R_UNUSED RPanel *panel, R_UNUSED const RPanelLayout dir, R_UNUSED R_NULLABLE const char *title) {
2077 	__step_over_cb (user);
2078 }
2079 
__show_all_decompiler_cb(void * user)2080 static int __show_all_decompiler_cb(void *user) {
2081 	RCore *core = (RCore *)user;
2082 	RAnalFunction *func = r_anal_get_fcn_in (core->anal, core->offset, R_ANAL_FCN_TYPE_NULL);
2083 	if (!func) {
2084 		return 0;
2085 	}
2086 	RPanelsRoot *root = core->panels_root;
2087 	const char *pdc_now = r_config_get (core->config, "cmd.pdc");
2088 	char *opts = r_core_cmd_str (core, "e cmd.pdc=?");
2089 	RList *optl = r_str_split_list (opts, "\n", 0);
2090 	RListIter *iter;
2091 	char *opt;
2092 	int i = 0;
2093 	__handle_tab_new (core);
2094 	RPanels *panels = __get_panels (root, root->n_panels - 1);
2095 	r_list_foreach (optl, iter, opt) {
2096 		if (R_STR_ISEMPTY (opt)) {
2097 			continue;
2098 		}
2099 		r_config_set (core->config, "cmd.pdc", opt);
2100 		RPanel *panel = __get_panel (panels, i++);
2101 		panels->n_panels = i;
2102 		panel->model->title = r_str_new (opt);
2103 		__set_read_only (core, panel, r_core_cmd_str (core, opt));
2104 	}
2105 	__layout_equal_hor (panels);
2106 	r_list_free (optl);
2107 	free (opts);
2108 	r_config_set (core->config, "cmd.pdc", pdc_now);
2109 	root->cur_panels = root->n_panels - 1;
2110 	__set_root_state (core, ROTATE);
2111 	return 0;
2112 }
2113 
__delegate_show_all_decompiler_cb(void * user,RPanel * panel,const RPanelLayout dir,R_NULLABLE const char * title)2114 static void __delegate_show_all_decompiler_cb(void *user, RPanel *panel, const RPanelLayout dir, R_NULLABLE const char *title) {
2115 	(void)__show_all_decompiler_cb ((RCore *)user);
2116 }
2117 
__init_modal_db(RCore * core)2118 static void __init_modal_db(RCore *core) {
2119 	Sdb *db = core->panels->modal_db;
2120 	SdbKv *kv;
2121 	SdbListIter *sdb_iter;
2122 	SdbList *sdb_list = sdb_foreach_list (core->panels->db, true);
2123 	ls_foreach (sdb_list, sdb_iter, kv) {
2124 		const char *key = sdbkv_key (kv);
2125 		sdb_ptr_set (db, r_str_new (key), &__create_panel_db, 0);
2126 	}
2127 	sdb_ptr_set (db, "Search strings in data sections", &__search_strings_data_create, 0);
2128 	sdb_ptr_set (db, "Search strings in the whole bin", &__search_strings_bin_create, 0);
2129 	sdb_ptr_set (db, "Create New", &__create_panel_input, 0);
2130 	sdb_ptr_set (db, "Change Command of Current Panel", &__replace_current_panel_input, 0);
2131 	sdb_ptr_set (db, PANEL_TITLE_ALL_DECOMPILER, &__delegate_show_all_decompiler_cb, 0);
2132 	if (r_config_get_i (core->config, "cfg.debug")) {
2133 		sdb_ptr_set (db, "Put Breakpoints", &__put_breakpoints_cb, 0);
2134 		sdb_ptr_set (db, "Continue", &__continue_modal_cb, 0);
2135 		sdb_ptr_set (db, "Step", &__step_modal_cb, 0);
2136 		sdb_ptr_set (db, "Step Over", &__step_over_modal_cb, 0);
2137 	}
2138 }
2139 
__renew_filter(RPanel * panel,int n)2140 static void __renew_filter(RPanel *panel, int n) {
2141 	panel->model->n_filter = 0;
2142 	char **filter = calloc (sizeof (char *), n);
2143 	if (!filter) {
2144 		panel->model->filter = NULL;
2145 		return;
2146 	}
2147 	panel->model->filter = filter;
2148 }
2149 
__reset_filter(RCore * core,RPanel * panel)2150 static void __reset_filter(RCore *core, RPanel *panel) {
2151 	free (panel->model->filter);
2152 	panel->model->filter = NULL;
2153 	__renew_filter (panel, PANEL_NUM_LIMIT);
2154 	__set_cmd_str_cache (core, panel, NULL);
2155 	panel->view->refresh = true;
2156 	__reset_scroll_pos (panel);
2157 }
2158 
__rotate_panel_cmds(RCore * core,const char ** cmds,const int cmdslen,const char * prefix,bool rev)2159 static void __rotate_panel_cmds(RCore *core, const char **cmds, const int cmdslen, const char *prefix, bool rev) {
2160 	if (!cmdslen) {
2161 		return;
2162 	}
2163 	RPanel *p = __get_cur_panel (core->panels);
2164 	__reset_filter (core, p);
2165 	if (rev) {
2166 		if (!p->model->rotate) {
2167 			p->model->rotate = cmdslen - 1;
2168 		} else {
2169 			p->model->rotate--;
2170 		}
2171 	} else {
2172 		p->model->rotate++;
2173 	}
2174 	char tmp[64], *between;
2175 	int i = p->model->rotate % cmdslen;
2176 	snprintf (tmp, sizeof (tmp), "%s%s", prefix, cmds[i]);
2177 	between = r_str_between (p->model->cmd, prefix, " ");
2178 	if (between) {
2179 		char replace[64];
2180 		snprintf (replace, sizeof (replace), "%s%s", prefix, between);
2181 		p->model->cmd = r_str_replace (p->model->cmd, replace, tmp, 1);
2182 	} else {
2183 		p->model->cmd = r_str_dup (p->model->cmd, tmp);
2184 	}
2185 	__set_cmd_str_cache (core, p, NULL);
2186 	p->view->refresh = true;
2187 }
2188 
__rotate_entropy_v_cb(void * user,bool rev)2189 static void __rotate_entropy_v_cb(void *user, bool rev) {
2190 	RCore *core = (RCore *)user;
2191 	__rotate_panel_cmds (core, entropy_rotate, COUNT (entropy_rotate), "p=", rev);
2192 }
2193 
__rotate_entropy_h_cb(void * user,bool rev)2194 static void __rotate_entropy_h_cb(void *user, bool rev) {
2195 	RCore *core = (RCore *)user;
2196 	__rotate_panel_cmds (core, entropy_rotate, COUNT (entropy_rotate), "p==", rev);
2197 }
2198 
__rotate_asmemu(RCore * core,RPanel * p)2199 static void __rotate_asmemu(RCore *core, RPanel *p) {
2200 	const bool isEmuStr = r_config_get_i (core->config, "emu.str");
2201 	const bool isEmu = r_config_get_i (core->config, "asm.emu");
2202 	if (isEmu) {
2203 		if (isEmuStr) {
2204 			r_config_set (core->config, "emu.str", "false");
2205 		} else {
2206 			r_config_set (core->config, "asm.emu", "false");
2207 		}
2208 	} else {
2209 		r_config_set (core->config, "emu.str", "true");
2210 	}
2211 	p->view->refresh = true;
2212 }
2213 
__rotate_hexdump_cb(void * user,bool rev)2214 static void __rotate_hexdump_cb(void *user, bool rev) {
2215 	RCore *core = (RCore *)user;
2216 	RPanel *p = __get_cur_panel (core->panels);
2217 
2218 	if (rev) {
2219 		p->model->rotate--;
2220 	} else {
2221 		p->model->rotate++;
2222 	}
2223 	r_core_visual_applyHexMode (core, p->model->rotate);
2224 	__rotate_asmemu (core, p);
2225 }
2226 
__rotate_register_cb(void * user,bool rev)2227 static void __rotate_register_cb(void *user, bool rev) {
2228 	RCore *core = (RCore *)user;
2229 	__rotate_panel_cmds (core, register_rotate, COUNT (register_rotate), "dr", rev);
2230 }
2231 
__rotate_function_cb(void * user,bool rev)2232 static void __rotate_function_cb(void *user, bool rev) {
2233 	RCore *core = (RCore *)user;
2234 	__rotate_panel_cmds (core, function_rotate, COUNT (function_rotate), "af", rev);
2235 }
2236 
__rotate_disasm_cb(void * user,bool rev)2237 static void __rotate_disasm_cb(void *user, bool rev) {
2238 	RCore *core = (RCore *)user;
2239 	RPanel *p = __get_cur_panel (core->panels);
2240 
2241 	//TODO: need to come up with a better solution but okay for now
2242 	if (!strcmp (p->model->cmd, PANEL_CMD_DECOMPILER) ||
2243 			!strcmp (p->model->cmd, PANEL_CMD_DECOMPILER_O)) {
2244 		return;
2245 	}
2246 
2247 	if (rev) {
2248 		if (!p->model->rotate) {
2249 			p->model->rotate = 4;
2250 		} else {
2251 			p->model->rotate--;
2252 		}
2253 	} else {
2254 		p->model->rotate++;
2255 	}
2256 	r_core_visual_applyDisMode (core, p->model->rotate);
2257 	__rotate_asmemu (core, p);
2258 }
2259 
__init_rotate_db(RCore * core)2260 static void __init_rotate_db(RCore *core) {
2261 	Sdb *db = core->panels->rotate_db;
2262 	sdb_ptr_set (db, "pd", &__rotate_disasm_cb, 0);
2263 	sdb_ptr_set (db, "p==", &__rotate_entropy_h_cb, 0);
2264 	sdb_ptr_set (db, "p=", &__rotate_entropy_v_cb, 0);
2265 	sdb_ptr_set (db, "px", &__rotate_hexdump_cb, 0);
2266 	sdb_ptr_set (db, "dr", &__rotate_register_cb, 0);
2267 	sdb_ptr_set (db, "af", &__rotate_function_cb, 0);
2268 	sdb_ptr_set (db, PANEL_CMD_HEXDUMP, &__rotate_hexdump_cb, 0);
2269 }
2270 
__init_all_dbs(RCore * core)2271 static void __init_all_dbs(RCore *core) {
2272 	__init_sdb (core);
2273 	__init_modal_db (core);
2274 	__init_rotate_db (core);
2275 }
2276 
__create_new_canvas(RCore * core,int w,int h)2277 static RConsCanvas *__create_new_canvas(RCore *core, int w, int h) {
2278 	RConsCanvas *can = r_cons_canvas_new (w, h);
2279 	if (!can) {
2280 		eprintf ("Cannot create RCons.canvas context\n");
2281 		return false;
2282 	}
2283 	r_cons_canvas_fill (can, 0, 0, w, h, ' ');
2284 	can->linemode = r_config_get_i (core->config, "graph.linemode");
2285 	can->color = r_config_get_i (core->config, "scr.color");
2286 	return can;
2287 }
2288 
__free_menu_item(RPanelsMenuItem * item)2289 static void __free_menu_item(RPanelsMenuItem *item) {
2290 	if (!item) {
2291 		return;
2292 	}
2293 	size_t i;
2294 	free (item->name);
2295 	free (item->p->model);
2296 	free (item->p->view);
2297 	free (item->p);
2298 	for (i = 0; i < item->n_sub; i++) {
2299 		__free_menu_item (item->sub[i]);
2300 	}
2301 	free (item->sub);
2302 	free (item);
2303 }
2304 
__mht_free_kv(HtPPKv * kv)2305 static void __mht_free_kv(HtPPKv *kv) {
2306 	free (kv->key);
2307 	__free_menu_item ((RPanelsMenuItem *)kv->value);
2308 }
2309 
__init(RCore * core,RPanels * panels,int w,int h)2310 static bool __init(RCore *core, RPanels *panels, int w, int h) {
2311 	panels->panel = NULL;
2312 	panels->n_panels = 0;
2313 	panels->columnWidth = 80;
2314 	if (r_config_get_i (core->config, "cfg.debug")) {
2315 		panels->layout = PANEL_LAYOUT_DEFAULT_DYNAMIC;
2316 	} else {
2317 		panels->layout = PANEL_LAYOUT_DEFAULT_STATIC;
2318 	}
2319 	panels->autoUpdate = false;
2320 	panels->mouse_on_edge_x = false;
2321 	panels->mouse_on_edge_y = false;
2322 	panels->mouse_orig_x = 0;
2323 	panels->mouse_orig_y = 0;
2324 	panels->can = __create_new_canvas (core, w, h);
2325 	panels->db = sdb_new0 ();
2326 	panels->rotate_db = sdb_new0 ();
2327 	panels->modal_db = sdb_new0 ();
2328 	panels->mht = ht_pp_new (NULL, (HtPPKvFreeFunc)__mht_free_kv, (HtPPCalcSizeV)strlen);
2329 	panels->fun = PANEL_FUN_NOFUN;
2330 	panels->prevMode = PANEL_MODE_DEFAULT;
2331 	panels->name = NULL;
2332 
2333 	if (w < 140) {
2334 		panels->columnWidth = w / 3;
2335 	}
2336 	return true;
2337 }
2338 
__panels_new(RCore * core)2339 static RPanels *__panels_new(RCore *core) {
2340 	RPanels *panels = R_NEW0 (RPanels);
2341 	if (!panels) {
2342 		return NULL;
2343 	}
2344 	int h, w = r_cons_get_size (&h);
2345 	firstRun = true;
2346 	if (!__init (core, panels, w, h)) {
2347 		free (panels);
2348 		return NULL;
2349 	}
2350 	return panels;
2351 }
2352 
__handle_tab_new_with_cur_panel(RCore * core)2353 static void __handle_tab_new_with_cur_panel (RCore *core) {
2354 	RPanels *panels = core->panels;
2355 	if (panels->n_panels <= 1) {
2356 		return;
2357 	}
2358 
2359 	RPanelsRoot *root = core->panels_root;
2360 	if (root->n_panels + 1 >= PANEL_NUM_LIMIT) {
2361 		return;
2362 	}
2363 
2364 	RPanel *cur = __get_cur_panel (panels);
2365 
2366 	RPanels *new_panels = __panels_new (core);
2367 	if (!new_panels) {
2368 		return;
2369 	}
2370 	root->panels[root->n_panels] = new_panels;
2371 
2372 	RPanels *prev = core->panels;
2373 	core->panels = new_panels;
2374 
2375 	if (!__init_panels_menu (core) || !__init_panels (core, new_panels)) {
2376 		core->panels = prev;
2377 		return;
2378 	}
2379 	__set_mode (core, PANEL_MODE_DEFAULT);
2380 	__init_all_dbs (core);
2381 
2382 	RPanel *new_panel = __get_panel (new_panels, 0);
2383 	__init_panel_param (core, new_panel, cur->model->title, cur->model->cmd);
2384 	new_panel->model->cache = cur->model->cache;
2385 	new_panel->model->funcName = r_str_new (cur->model->funcName);
2386 	__set_cmd_str_cache (core, new_panel, r_str_new (cur->model->cmdStrCache));
2387 	__maximize_panel_size (new_panels);
2388 
2389 	core->panels = prev;
2390 	__dismantle_del_panel (core, cur, panels->curnode);
2391 
2392 	root->cur_panels = root->n_panels;
2393 	root->n_panels++;
2394 	__set_root_state (core, ROTATE);
2395 }
2396 
__handle_tab_key(RCore * core,bool shift)2397 static void __handle_tab_key(RCore *core, bool shift) {
2398 	__set_cursor (core, false);
2399 	RPanels *panels = core->panels;
2400 	RPanel *cur = __get_cur_panel (panels);
2401 	r_cons_switchbuf (false);
2402 	cur->view->refresh = true;
2403 	if (!shift) {
2404 		if (panels->mode == PANEL_MODE_MENU) {
2405 			__set_curnode (core, 0);
2406 			__set_mode (core, PANEL_MODE_DEFAULT);
2407 		} else if (panels->mode == PANEL_MODE_ZOOM) {
2408 			__set_curnode (core, ++panels->curnode);
2409 		} else {
2410 			__set_curnode (core, ++panels->curnode);
2411 		}
2412 	} else {
2413 		if (panels->mode == PANEL_MODE_MENU) {
2414 			__set_curnode (core, panels->n_panels - 1);
2415 			__set_mode (core, PANEL_MODE_DEFAULT);
2416 		} else if (panels->mode == PANEL_MODE_ZOOM) {
2417 			__set_curnode (core, --panels->curnode);
2418 		} else {
2419 			__set_curnode (core, --panels->curnode);
2420 		}
2421 	}
2422 	cur = __get_cur_panel (panels);
2423 	cur->view->refresh = true;
2424 	if (panels->fun == PANEL_FUN_SNOW || panels->fun == PANEL_FUN_SAKURA) {
2425 		__reset_snow (panels);
2426 	}
2427 }
2428 
__handle_zoom_mode(RCore * core,const int key)2429 static bool __handle_zoom_mode(RCore *core, const int key) {
2430 	RPanels *panels = core->panels;
2431 	r_cons_switchbuf (false);
2432 	switch (key) {
2433 	case 'Q':
2434 	case 'q':
2435 	case 0x0d:
2436 		__toggle_zoom_mode (core);
2437 		break;
2438 	case 'c':
2439 	case 'C':
2440 	case ';':
2441 	case ' ':
2442 	case '_':
2443 	case '/':
2444 	case '"':
2445 	case 'A':
2446 	case 'r':
2447 	case '0':
2448 	case '1':
2449 	case '2':
2450 	case '3':
2451 	case '4':
2452 	case '5':
2453 	case '6':
2454 	case '7':
2455 	case '8':
2456 	case '9':
2457 	case 'u':
2458 	case 'U':
2459 	case 'b':
2460 	case 'd':
2461 	case 'n':
2462 	case 'N':
2463 	case 'g':
2464 	case 'h':
2465 	case 'j':
2466 	case 'k':
2467 	case 'J':
2468 	case 'K':
2469 	case 'l':
2470 	case '.':
2471 	case 'R':
2472 	case 'p':
2473 	case 'P':
2474 	case 's':
2475 	case 'S':
2476 	case 't':
2477 	case 'T':
2478 	case 'x':
2479 	case 'X':
2480 	case ':':
2481 	case '[':
2482 	case ']':
2483 		return false;
2484 	case 9:
2485 		__restore_panel_pos (panels->panel[panels->curnode]);
2486 		__handle_tab_key (core, false);
2487 		__save_panel_pos (panels->panel[panels->curnode]);
2488 		__maximize_panel_size (panels);
2489 		break;
2490 	case 'Z':
2491 		__restore_panel_pos (panels->panel[panels->curnode]);
2492 		__handle_tab_key (core, true);
2493 		__save_panel_pos (panels->panel[panels->curnode]);
2494 		__maximize_panel_size (panels);
2495 		break;
2496 	case '?':
2497 		__toggle_zoom_mode (core);
2498 		__toggle_help (core);
2499 		__toggle_zoom_mode (core);
2500 		break;
2501 	}
2502 	return true;
2503 }
2504 
__set_refresh_by_type(RCore * core,const char * cmd,bool clearCache)2505 static void __set_refresh_by_type(RCore *core, const char *cmd, bool clearCache) {
2506 	RPanels *panels = core->panels;
2507 	int i;
2508 	for (i = 0; i < panels->n_panels; i++) {
2509 		RPanel *p = __get_panel (panels, i);
2510 		if (!__check_panel_type (p, cmd)) {
2511 			continue;
2512 		}
2513 		p->view->refresh = true;
2514 		if (clearCache) {
2515 			__set_cmd_str_cache (core, p, NULL);
2516 		}
2517 	}
2518 }
2519 
filter_arg(char * a)2520 static char *filter_arg(char *a) {
2521 	r_name_filter_print (a);
2522 	char *r = r_str_escape (a);
2523 	free (a);
2524 	return r;
2525 }
2526 
__handleComment(RCore * core)2527 static void __handleComment(RCore *core) {
2528 	RPanel *p = __get_cur_panel (core->panels);
2529 	if (!__check_panel_type (p, PANEL_CMD_DISASSEMBLY)) {
2530 		return;
2531 	}
2532 	char buf[4095];
2533 	char *cmd = NULL;
2534 	r_line_set_prompt ("[Comment]> ");
2535 	if (r_cons_fgets (buf, sizeof (buf), 0, NULL) > 0) {
2536 		ut64 addr, orig;
2537 		addr = orig = core->offset;
2538 		if (core->print->cur_enabled) {
2539 			addr += core->print->cur;
2540 			r_core_seek (core, addr, false);
2541 			r_core_cmdf (core, "s 0x%"PFMT64x, addr);
2542 		}
2543 		if (!strcmp (buf, "-")) {
2544 			cmd = strdup ("CC-");
2545 		} else {
2546 			char *arg = filter_arg (strdup (buf));
2547 			switch (buf[0]) {
2548 			case '-':
2549 				cmd = r_str_newf ("\"CC-%s\"", arg);
2550 				break;
2551 			case '!':
2552 				strcpy (buf, "\"CC!");
2553 				break;
2554 			default:
2555 				cmd = r_str_newf ("\"CC %s\"", arg);
2556 				break;
2557 			}
2558 			free (arg);
2559 		}
2560 		if (cmd) {
2561 			r_core_cmd (core, cmd, 1);
2562 		}
2563 		if (core->print->cur_enabled) {
2564 			r_core_seek (core, orig, true);
2565 		}
2566 		free (cmd);
2567 	}
2568 	__set_refresh_by_type (core, p->model->cmd, true);
2569 }
2570 
__move_to_direction(RCore * core,Direction direction)2571 static bool __move_to_direction(RCore *core, Direction direction) {
2572 	RPanels *panels = core->panels;
2573 	RPanel *cur = __get_cur_panel (panels);
2574 	int cur_x0 = cur->view->pos.x, cur_x1 = cur->view->pos.x + cur->view->pos.w - 1, cur_y0 = cur->view->pos.y, cur_y1 = cur->view->pos.y + cur->view->pos.h - 1;
2575 	int temp_x0, temp_x1, temp_y0, temp_y1;
2576 	int i;
2577 	for (i = 0; i < panels->n_panels; i++) {
2578 		RPanel *p = __get_panel (panels, i);
2579 		temp_x0 = p->view->pos.x;
2580 		temp_x1 = p->view->pos.x + p->view->pos.w - 1;
2581 		temp_y0 = p->view->pos.y;
2582 		temp_y1 = p->view->pos.y + p->view->pos.h - 1;
2583 		switch (direction) {
2584 		case LEFT:
2585 			if (temp_x1 == cur_x0) {
2586 				if (temp_y1 <= cur_y0 || cur_y1 <= temp_y0) {
2587 					continue;
2588 				}
2589 				__set_curnode (core, i);
2590 				return true;
2591 			}
2592 			break;
2593 		case RIGHT:
2594 			if (temp_x0 == cur_x1) {
2595 				if (temp_y1 <= cur_y0 || cur_y1 <= temp_y0) {
2596 					continue;
2597 				}
2598 				__set_curnode (core, i);
2599 				return true;
2600 			}
2601 			break;
2602 		case UP:
2603 			if (temp_y1 == cur_y0) {
2604 				if (temp_x1 <= cur_x0 || cur_x1 <= temp_x0) {
2605 					continue;
2606 				}
2607 				__set_curnode (core, i);
2608 				return true;
2609 			}
2610 			break;
2611 		case DOWN:
2612 			if (temp_y0 == cur_y1) {
2613 				if (temp_x1 <= cur_x0 || cur_x1 <= temp_x0) {
2614 					continue;
2615 				}
2616 				__set_curnode (core, i);
2617 				return true;
2618 			}
2619 			break;
2620 		default:
2621 			break;
2622 		}
2623 	}
2624 	return false;
2625 }
2626 
__direction_default_cb(void * user,int direction)2627 static void __direction_default_cb(void *user, int direction) {
2628 	RCore *core = (RCore *)user;
2629 	RPanel *cur = __get_cur_panel (core->panels);
2630 	cur->view->refresh = true;
2631 	switch ((Direction)direction) {
2632 	case LEFT:
2633 		if (cur->view->sx > 0) {
2634 			cur->view->sx--;
2635 		}
2636 		break;
2637 	case RIGHT:
2638 		cur->view->sx++;
2639 		break;
2640 	case UP:
2641 		if (cur->view->sy > 0) {
2642 			cur->view->sy--;
2643 		}
2644 		break;
2645 	case DOWN:
2646 		cur->view->sy++;
2647 		break;
2648 	}
2649 }
2650 
__direction_disassembly_cb(void * user,int direction)2651 static void __direction_disassembly_cb(void *user, int direction) {
2652 	RCore *core = (RCore *)user;
2653 	RPanels *panels = core->panels;
2654 	RPanel *cur = __get_cur_panel (panels);
2655 	int cols = core->print->cols;
2656 	cur->view->refresh = true;
2657 	switch ((Direction)direction) {
2658 	case LEFT:
2659 		if (core->print->cur_enabled) {
2660 			__cursor_left (core);
2661 			r_core_block_read (core);
2662 			__set_panel_addr (core, cur, core->offset);
2663 		} else if (panels->mode == PANEL_MODE_ZOOM) {
2664 			cur->model->addr--;
2665 		} else if (cur->view->sx > 0) {
2666 			cur->view->sx--;
2667 		}
2668 		break;
2669 	case RIGHT:
2670 		if (core->print->cur_enabled) {
2671 			__cursor_right (core);
2672 			r_core_block_read (core);
2673 			__set_panel_addr (core, cur, core->offset);
2674 		} else if (panels->mode == PANEL_MODE_ZOOM) {
2675 			cur->model->addr++;
2676 		} else {
2677 			cur->view->sx++;
2678 		}
2679 		break;
2680 	case UP:
2681 		core->offset = cur->model->addr;
2682 		if (core->print->cur_enabled) {
2683 			__cursor_up (core);
2684 			r_core_block_read (core);
2685 			__set_panel_addr (core, cur, core->offset);
2686 		} else {
2687 			r_core_visual_disasm_up (core, &cols);
2688 			r_core_seek_delta (core, -cols);
2689 			__set_panel_addr (core, cur, core->offset);
2690 		}
2691 		break;
2692 	case DOWN:
2693 		core->offset = cur->model->addr;
2694 		if (core->print->cur_enabled) {
2695 			__cursor_down (core);
2696 			r_core_block_read (core);
2697 			__set_panel_addr (core, cur, core->offset);
2698 		} else {
2699 			RAsmOp op;
2700 			r_core_visual_disasm_down (core, &op, &cols);
2701 			r_core_seek (core, core->offset + cols, true);
2702 			__set_panel_addr (core, cur, core->offset);
2703 		}
2704 		break;
2705 	}
2706 }
2707 
__direction_graph_cb(void * user,int direction)2708 static void __direction_graph_cb(void *user, int direction) {
2709 	RCore *core = (RCore *)user;
2710 	RPanels *panels = core->panels;
2711 	RPanel *cur = __get_cur_panel (panels);
2712 	cur->view->refresh = true;
2713 	const int speed = r_config_get_i (core->config, "graph.scroll") * 2;
2714 	switch ((Direction)direction) {
2715 	case LEFT:
2716 		if (cur->view->sx > 0) {
2717 			cur->view->sx -= speed;
2718 		}
2719 		break;
2720 	case RIGHT:
2721 		cur->view->sx +=  speed;
2722 		break;
2723 	case UP:
2724 		if (cur->view->sy > 0) {
2725 			cur->view->sy -= speed;
2726 		}
2727 		break;
2728 	case DOWN:
2729 		cur->view->sy += speed;
2730 		break;
2731 	}
2732 }
2733 
__direction_register_cb(void * user,int direction)2734 static void __direction_register_cb(void *user, int direction) {
2735 	RCore *core = (RCore *)user;
2736 	RPanels *panels = core->panels;
2737 	RPanel *cur = __get_cur_panel (panels);
2738 	int cols = core->dbg->regcols;
2739 	cols = cols > 0 ? cols : 3;
2740 	cur->view->refresh = true;
2741 	switch ((Direction)direction) {
2742 	case LEFT:
2743 		if (core->print->cur_enabled) {
2744 			__cursor_left (core);
2745 		} else if (cur->view->sx > 0) {
2746 			cur->view->sx--;
2747 			cur->view->refresh = true;
2748 		}
2749 		break;
2750 	case RIGHT:
2751 		if (core->print->cur_enabled) {
2752 			__cursor_right (core);
2753 		} else {
2754 			cur->view->sx++;
2755 			cur->view->refresh = true;
2756 		}
2757 		break;
2758 	case UP:
2759 		if (core->print->cur_enabled) {
2760 			int tmp = core->print->cur;
2761 			tmp -= cols;
2762 			if (tmp >= 0) {
2763 				core->print->cur = tmp;
2764 			}
2765 		}
2766 		break;
2767 	case DOWN:
2768 		if (core->print->cur_enabled) {
2769 			core->print->cur += cols;
2770 		}
2771 		break;
2772 	}
2773 }
2774 
__direction_stack_cb(void * user,int direction)2775 static void __direction_stack_cb(void *user, int direction) {
2776 	RCore *core = (RCore *)user;
2777 	RPanels *panels = core->panels;
2778 	RPanel *cur = __get_cur_panel (panels);
2779 	int cols = r_config_get_i (core->config, "hex.cols");
2780 	if (cols < 1) {
2781 		cols = 16;
2782 	}
2783 	cur->view->refresh = true;
2784 	switch ((Direction)direction) {
2785 	case LEFT:
2786 		if (core->print->cur_enabled) {
2787 			__cursor_left (core);
2788 		} else if (cur->view->sx > 0) {
2789 			cur->view->sx--;
2790 			cur->view->refresh = true;
2791 		}
2792 		break;
2793 	case RIGHT:
2794 		if (core->print->cur_enabled) {
2795 			__cursor_right (core);
2796 		} else {
2797 			cur->view->sx++;
2798 			cur->view->refresh = true;
2799 		}
2800 		break;
2801 	case UP:
2802 		r_config_set_i (core->config, "stack.delta",
2803 				r_config_get_i (core->config, "stack.delta") + cols);
2804 		cur->model->addr -= cols;
2805 		break;
2806 	case DOWN:
2807 		r_config_set_i (core->config, "stack.delta",
2808 				r_config_get_i (core->config, "stack.delta") - cols);
2809 		cur->model->addr += cols;
2810 		break;
2811 	}
2812 }
2813 
__direction_hexdump_cb(void * user,int direction)2814 static void __direction_hexdump_cb(void *user, int direction) {
2815 	RCore *core = (RCore *)user;
2816 	RPanels *panels = core->panels;
2817 	RPanel *cur = __get_cur_panel (panels);
2818 	int cols = r_config_get_i (core->config, "hex.cols");
2819 	if (cols < 1) {
2820 		cols = 16;
2821 	}
2822 	cur->view->refresh = true;
2823 	switch ((Direction)direction) {
2824 	case LEFT:
2825 		if (!core->print->cur) {
2826 			cur->model->addr -= cols;
2827 			core->print->cur += cols - 1;
2828 		} else if (core->print->cur_enabled) {
2829 			__cursor_left (core);
2830 		} else {
2831 			cur->model->addr--;
2832 		}
2833 		break;
2834 	case RIGHT:
2835 		if (core->print->cur / cols + 1 > cur->view->pos.h - 5
2836 				&& core->print->cur % cols == cols - 1) {
2837 			cur->model->addr += cols;
2838 			core->print->cur -= cols - 1;
2839 		} else if (core->print->cur_enabled) {
2840 			__cursor_right (core);
2841 		} else {
2842 			cur->model->addr++;
2843 		}
2844 		break;
2845 	case UP:
2846 		if (!cur->model->cache) {
2847 			if (core->print->cur_enabled) {
2848 				if (!(core->print->cur / cols)) {
2849 					cur->model->addr -= cols;
2850 				} else {
2851 					core->print->cur -= cols;
2852 				}
2853 			} else {
2854 				if (cur->model->addr <= cols) {
2855 					__set_panel_addr (core, cur, 0);
2856 				} else {
2857 					cur->model->addr -= cols;
2858 				}
2859 			}
2860 		} else if (cur->view->sy > 0) {
2861 			cur->view->sy--;
2862 		}
2863 		break;
2864 	case DOWN:
2865 		if (!cur->model->cache) {
2866 			if (core->print->cur_enabled) {
2867 				if (core->print->cur / cols + 1 > cur->view->pos.h - 5) {
2868 					cur->model->addr += cols;
2869 				} else {
2870 					core->print->cur += cols;
2871 				}
2872 			} else {
2873 				cur->model->addr += cols;
2874 			}
2875 		} else {
2876 			cur->view->sy++;
2877 		}
2878 		break;
2879 	}
2880 }
2881 
__direction_panels_cursor_cb(void * user,int direction)2882 static void __direction_panels_cursor_cb(void *user, int direction) {
2883 	RCore *core = (RCore *)user;
2884 	RPanels *panels = core->panels;
2885 	RPanel *cur = __get_cur_panel (panels);
2886 	cur->view->refresh = true;
2887 	const int THRESHOLD = cur->view->pos.h / 3;
2888 	int sub;
2889 	switch ((Direction)direction) {
2890 	case LEFT:
2891 		if (core->print->cur_enabled) {
2892 			break;
2893 		}
2894 		if (cur->view->sx > 0) {
2895 			cur->view->sx -= r_config_get_i (core->config, "graph.scroll");
2896 		}
2897 		break;
2898 	case RIGHT:
2899 		if (core->print->cur_enabled) {
2900 			break;
2901 		}
2902 		cur->view->sx += r_config_get_i (core->config, "graph.scroll");
2903 		break;
2904 	case UP:
2905 		if (core->print->cur_enabled) {
2906 			if (cur->view->curpos > 0) {
2907 				cur->view->curpos--;
2908 			}
2909 			if (cur->view->sy > 0) {
2910 				sub = cur->view->curpos - cur->view->sy;
2911 				if (sub < 0) {
2912 					cur->view->sy--;
2913 				}
2914 			}
2915 		} else {
2916 			if (cur->view->sy > 0) {
2917 				cur->view->curpos -= 1;
2918 				cur->view->sy -= 1;
2919 			}
2920 		}
2921 		break;
2922 	case DOWN:
2923 		core->offset = cur->model->addr;
2924 		if (core->print->cur_enabled) {
2925 			cur->view->curpos++;
2926 			sub = cur->view->curpos - cur->view->sy;
2927 			if (sub > THRESHOLD) {
2928 				cur->view->sy++;
2929 			}
2930 		} else {
2931 			cur->view->curpos += 1;
2932 			cur->view->sy += 1;
2933 		}
2934 		break;
2935 	}
2936 }
2937 
__toggle_window_mode(RCore * core)2938 static void __toggle_window_mode(RCore *core) {
2939 	RPanels *panels = core->panels;
2940 	if (panels->mode != PANEL_MODE_WINDOW) {
2941 		panels->prevMode = panels->mode;
2942 		__set_mode (core, PANEL_MODE_WINDOW);
2943 	} else {
2944 		__set_mode (core, panels->prevMode);
2945 		panels->prevMode = PANEL_MODE_DEFAULT;
2946 	}
2947 }
2948 
__resize_panel_left(RPanels * panels)2949 static void __resize_panel_left(RPanels *panels) {
2950 	RPanel *cur = __get_cur_panel (panels);
2951 	int i, cx0, cx1, cy0, cy1, tx0, tx1, ty0, ty1, cur1 = 0, cur2 = 0, cur3 = 0, cur4 = 0;
2952 	cx0 = cur->view->pos.x;
2953 	cx1 = cur->view->pos.x + cur->view->pos.w - 1;
2954 	cy0 = cur->view->pos.y;
2955 	cy1 = cur->view->pos.y + cur->view->pos.h - 1;
2956 	RPanel **targets1 = malloc (sizeof (RPanel *) * panels->n_panels);
2957 	RPanel **targets2 = malloc (sizeof (RPanel *) * panels->n_panels);
2958 	RPanel **targets3 = malloc (sizeof (RPanel *) * panels->n_panels);
2959 	RPanel **targets4 = malloc (sizeof (RPanel *) * panels->n_panels);
2960 	if (!targets1 || !targets2 || !targets3 || !targets4) {
2961 		goto beach;
2962 	}
2963 	for (i = 0; i < panels->n_panels; i++) {
2964 		if (i == panels->curnode) {
2965 			continue;
2966 		}
2967 		RPanel *p = __get_panel (panels, i);
2968 		tx0 = p->view->pos.x;
2969 		tx1 = p->view->pos.x + p->view->pos.w - 1;
2970 		ty0 = p->view->pos.y;
2971 		ty1 = p->view->pos.y + p->view->pos.h - 1;
2972 		if (ty0 == cy0 && ty1 == cy1 && tx1 == cx0 && tx1 - PANEL_CONFIG_RESIZE_W > tx0) {
2973 			p->view->pos.w -= PANEL_CONFIG_RESIZE_W;
2974 			cur->view->pos.x -= PANEL_CONFIG_RESIZE_W;
2975 			cur->view->pos.w += PANEL_CONFIG_RESIZE_W;
2976 			p->view->refresh = true;
2977 			cur->view->refresh = true;
2978 			goto beach;
2979 		}
2980 		bool y_included =  (ty1 >= cy0 && cy1 >= ty1) || (ty0 >= cy0 && cy1 >= ty0);
2981 		if (tx1 == cx0 && y_included) {
2982 			if (tx1 - PANEL_CONFIG_RESIZE_W > tx0) {
2983 				targets1[cur1++] = p;
2984 			}
2985 		}
2986 		if (tx0 == cx1 && y_included) {
2987 			if (tx0 - PANEL_CONFIG_RESIZE_W > cx0) {
2988 				targets3[cur3++] = p;
2989 			}
2990 		}
2991 		if (tx0 == cx0) {
2992 			if (tx0 - PANEL_CONFIG_RESIZE_W > 0) {
2993 				targets2[cur2++] = p;
2994 			}
2995 		}
2996 		if (tx1 == cx1) {
2997 			if (tx1 + PANEL_CONFIG_RESIZE_W < panels->can->w) {
2998 				targets4[cur4++] = p;
2999 			}
3000 		}
3001 	}
3002 	if (cur1 > 0) {
3003 		for (i = 0; i < cur1; i++) {
3004 			targets1[i]->view->pos.w -= PANEL_CONFIG_RESIZE_W;
3005 			targets1[i]->view->refresh = true;
3006 		}
3007 		for (i = 0; i < cur2; i++) {
3008 			targets2[i]->view->pos.x -= PANEL_CONFIG_RESIZE_W;
3009 			targets2[i]->view->pos.w += PANEL_CONFIG_RESIZE_W;
3010 			targets2[i]->view->refresh = true;
3011 		}
3012 		cur->view->pos.x -= PANEL_CONFIG_RESIZE_W;
3013 		cur->view->pos.w += PANEL_CONFIG_RESIZE_W;
3014 		cur->view->refresh = true;
3015 	} else if (cur3 > 0) {
3016 		for (i = 0; i < cur3; i++) {
3017 			targets3[i]->view->pos.w += PANEL_CONFIG_RESIZE_W;
3018 			targets3[i]->view->pos.x -= PANEL_CONFIG_RESIZE_W;
3019 			targets3[i]->view->refresh = true;
3020 		}
3021 		for (i = 0; i < cur4; i++) {
3022 			targets4[i]->view->pos.w -= PANEL_CONFIG_RESIZE_W;
3023 			targets4[i]->view->refresh = true;
3024 		}
3025 		cur->view->pos.w -= PANEL_CONFIG_RESIZE_W;
3026 		cur->view->refresh = true;
3027 	}
3028 beach:
3029 	free (targets1);
3030 	free (targets2);
3031 	free (targets3);
3032 	free (targets4);
3033 }
3034 
__resize_panel_right(RPanels * panels)3035 static void __resize_panel_right(RPanels *panels) {
3036 	RPanel *cur = __get_cur_panel (panels);
3037 	int i, tx0, tx1, ty0, ty1, cur1 = 0, cur2 = 0, cur3 = 0, cur4 = 0;
3038 	int cx0 = cur->view->pos.x;
3039 	int cx1 = cur->view->pos.x + cur->view->pos.w - 1;
3040 	int cy0 = cur->view->pos.y;
3041 	int cy1 = cur->view->pos.y + cur->view->pos.h - 1;
3042 	RPanel **targets1 = malloc (sizeof (RPanel *) * panels->n_panels);
3043 	RPanel **targets2 = malloc (sizeof (RPanel *) * panels->n_panels);
3044 	RPanel **targets3 = malloc (sizeof (RPanel *) * panels->n_panels);
3045 	RPanel **targets4 = malloc (sizeof (RPanel *) * panels->n_panels);
3046 	if (!targets1 || !targets2 || !targets3 || !targets4) {
3047 		goto beach;
3048 	}
3049 	for (i = 0; i < panels->n_panels; i++) {
3050 		if (i == panels->curnode) {
3051 			continue;
3052 		}
3053 		RPanel *p = __get_panel (panels, i);
3054 		tx0 = p->view->pos.x;
3055 		tx1 = p->view->pos.x + p->view->pos.w - 1;
3056 		ty0 = p->view->pos.y;
3057 		ty1 = p->view->pos.y + p->view->pos.h - 1;
3058 		if (ty0 == cy0 && ty1 == cy1 && tx0 == cx1 && tx0 + PANEL_CONFIG_RESIZE_W < tx1) {
3059 			p->view->pos.x += PANEL_CONFIG_RESIZE_W;
3060 			p->view->pos.w -= PANEL_CONFIG_RESIZE_W;
3061 			cur->view->pos.w += PANEL_CONFIG_RESIZE_W;
3062 			p->view->refresh = true;
3063 			cur->view->refresh = true;
3064 			goto beach;
3065 		}
3066 		bool y_included =  (ty1 >= cy0 && cy1 >= ty1) || (ty0 >= cy0 && cy1 >= ty0);
3067 		if (tx1 == cx0 && y_included) {
3068 			if (tx1 + PANEL_CONFIG_RESIZE_W < cx1) {
3069 				targets1[cur1++] = p;
3070 			}
3071 		}
3072 		if (tx0 == cx1 && y_included) {
3073 			if (tx0 + PANEL_CONFIG_RESIZE_W < tx1) {
3074 				targets3[cur3++] = p;
3075 			}
3076 		}
3077 		if (tx0 == cx0) {
3078 			if (tx0 + PANEL_CONFIG_RESIZE_W < tx1) {
3079 				targets2[cur2++] = p;
3080 			}
3081 		}
3082 		if (tx1 == cx1) {
3083 			if (tx1 + PANEL_CONFIG_RESIZE_W < panels->can->w) {
3084 				targets4[cur4++] = p;
3085 			}
3086 		}
3087 	}
3088 	if (cur3 > 0) {
3089 		for (i = 0; i < cur3; i++) {
3090 			targets3[i]->view->pos.x += PANEL_CONFIG_RESIZE_W;
3091 			targets3[i]->view->pos.w -= PANEL_CONFIG_RESIZE_W;
3092 			targets3[i]->view->refresh = true;
3093 		}
3094 		for (i = 0; i < cur4; i++) {
3095 			targets4[i]->view->pos.w += PANEL_CONFIG_RESIZE_W;
3096 			targets4[i]->view->refresh = true;
3097 		}
3098 		cur->view->pos.w += PANEL_CONFIG_RESIZE_W;
3099 		cur->view->refresh = true;
3100 	} else if (cur1 > 0) {
3101 		for (i = 0; i < cur1; i++) {
3102 			targets1[i]->view->pos.w += PANEL_CONFIG_RESIZE_W;
3103 			targets1[i]->view->refresh = true;
3104 		}
3105 		for (i = 0; i < cur2; i++) {
3106 			targets2[i]->view->pos.x += PANEL_CONFIG_RESIZE_W;
3107 			targets2[i]->view->pos.w -= PANEL_CONFIG_RESIZE_W;
3108 			targets2[i]->view->refresh = true;
3109 		}
3110 		cur->view->pos.x += PANEL_CONFIG_RESIZE_W;
3111 		cur->view->pos.w -= PANEL_CONFIG_RESIZE_W;
3112 		cur->view->refresh = true;
3113 	}
3114 beach:
3115 	free (targets1);
3116 	free (targets2);
3117 	free (targets3);
3118 	free (targets4);
3119 }
3120 
__resize_panel_up(RPanels * panels)3121 static void __resize_panel_up(RPanels *panels) {
3122 	RPanel *cur = __get_cur_panel (panels);
3123 	int i, tx0, tx1, ty0, ty1, cur1 = 0, cur2 = 0, cur3 = 0, cur4 = 0;
3124 	int cx0 = cur->view->pos.x;
3125 	int cx1 = cur->view->pos.x + cur->view->pos.w - 1;
3126 	int cy0 = cur->view->pos.y;
3127 	int cy1 = cur->view->pos.y + cur->view->pos.h - 1;
3128 	RPanel **targets1 = malloc (sizeof (RPanel *) * panels->n_panels);
3129 	RPanel **targets2 = malloc (sizeof (RPanel *) * panels->n_panels);
3130 	RPanel **targets3 = malloc (sizeof (RPanel *) * panels->n_panels);
3131 	RPanel **targets4 = malloc (sizeof (RPanel *) * panels->n_panels);
3132 	if (!targets1 || !targets2 || !targets3 || !targets4) {
3133 		goto beach;
3134 	}
3135 	for (i = 0; i < panels->n_panels; i++) {
3136 		if (i == panels->curnode) {
3137 			continue;
3138 		}
3139 		RPanel *p = __get_panel (panels, i);
3140 		tx0 = p->view->pos.x;
3141 		tx1 = p->view->pos.x + p->view->pos.w - 1;
3142 		ty0 = p->view->pos.y;
3143 		ty1 = p->view->pos.y + p->view->pos.h - 1;
3144 		if (tx0 == cx0 && tx1 == cx1 && ty1 == cy0 && ty1 - PANEL_CONFIG_RESIZE_H > ty0) {
3145 			p->view->pos.h -= PANEL_CONFIG_RESIZE_H;
3146 			cur->view->pos.y -= PANEL_CONFIG_RESIZE_H;
3147 			cur->view->pos.h += PANEL_CONFIG_RESIZE_H;
3148 			p->view->refresh = true;
3149 			cur->view->refresh = true;
3150 			goto beach;
3151 		}
3152 		bool x_included =  (tx1 >= cx0 && cx1 >= tx1) || (tx0 >= cx0 && cx1 >= tx0);
3153 		if (ty1 == cy0 && x_included) {
3154 			if (ty1 - PANEL_CONFIG_RESIZE_H > ty0) {
3155 				targets1[cur1++] = p;
3156 			}
3157 		}
3158 		if (ty0 == cy1 && x_included) {
3159 			if (ty0 - PANEL_CONFIG_RESIZE_H > cy0) {
3160 				targets3[cur3++] = p;
3161 			}
3162 		}
3163 		if (ty0 == cy0) {
3164 			if (ty0 - PANEL_CONFIG_RESIZE_H > 0) {
3165 				targets2[cur2++] = p;
3166 			}
3167 		}
3168 		if (ty1 == cy1) {
3169 			if (ty1 - PANEL_CONFIG_RESIZE_H > ty0) {
3170 				targets4[cur4++] = p;
3171 			}
3172 		}
3173 	}
3174 	if (cur1 > 0) {
3175 		for (i = 0; i < cur1; i++) {
3176 			targets1[i]->view->pos.h -= PANEL_CONFIG_RESIZE_H;
3177 			targets1[i]->view->refresh = true;
3178 		}
3179 		for (i = 0; i < cur2; i++) {
3180 			targets2[i]->view->pos.y -= PANEL_CONFIG_RESIZE_H;
3181 			targets2[i]->view->pos.h += PANEL_CONFIG_RESIZE_H;
3182 			targets2[i]->view->refresh = true;
3183 		}
3184 		cur->view->pos.y -= PANEL_CONFIG_RESIZE_H;
3185 		cur->view->pos.h += PANEL_CONFIG_RESIZE_H;
3186 		cur->view->refresh = true;
3187 	} else if (cur3 > 0) {
3188 		for (i = 0; i < cur3; i++) {
3189 			targets3[i]->view->pos.h += PANEL_CONFIG_RESIZE_H;
3190 			targets3[i]->view->pos.y -= PANEL_CONFIG_RESIZE_H;
3191 			targets3[i]->view->refresh = true;
3192 		}
3193 		for (i = 0; i < cur4; i++) {
3194 			targets4[i]->view->pos.h -= PANEL_CONFIG_RESIZE_H;
3195 			targets4[i]->view->refresh = true;
3196 		}
3197 		cur->view->pos.h -= PANEL_CONFIG_RESIZE_H;
3198 		cur->view->refresh = true;
3199 	}
3200 beach:
3201 	free (targets1);
3202 	free (targets2);
3203 	free (targets3);
3204 	free (targets4);
3205 }
__resize_panel_down(RPanels * panels)3206 static void __resize_panel_down(RPanels *panels) {
3207 	RPanel *cur = __get_cur_panel (panels);
3208 	int i, tx0, tx1, ty0, ty1, cur1 = 0, cur2 = 0, cur3 = 0, cur4 = 0;
3209 	int cx0 = cur->view->pos.x;
3210 	int cx1 = cur->view->pos.x + cur->view->pos.w - 1;
3211 	int cy0 = cur->view->pos.y;
3212 	int cy1 = cur->view->pos.y + cur->view->pos.h - 1;
3213 	RPanel **targets1 = malloc (sizeof (RPanel *) * panels->n_panels);
3214 	RPanel **targets2 = malloc (sizeof (RPanel *) * panels->n_panels);
3215 	RPanel **targets3 = malloc (sizeof (RPanel *) * panels->n_panels);
3216 	RPanel **targets4 = malloc (sizeof (RPanel *) * panels->n_panels);
3217 	if (!targets1 || !targets2 || !targets3 || !targets4) {
3218 		goto beach;
3219 	}
3220 	for (i = 0; i < panels->n_panels; i++) {
3221 		if (i == panels->curnode) {
3222 			continue;
3223 		}
3224 		RPanel *p = __get_panel (panels, i);
3225 		tx0 = p->view->pos.x;
3226 		tx1 = p->view->pos.x + p->view->pos.w - 1;
3227 		ty0 = p->view->pos.y;
3228 		ty1 = p->view->pos.y + p->view->pos.h - 1;
3229 		if (tx0 == cx0 && tx1 == cx1 && ty0 == cy1 && ty0 + PANEL_CONFIG_RESIZE_H < ty1) {
3230 			p->view->pos.y += PANEL_CONFIG_RESIZE_H;
3231 			p->view->pos.h -= PANEL_CONFIG_RESIZE_H;
3232 			cur->view->pos.h += PANEL_CONFIG_RESIZE_H;
3233 			p->view->refresh = true;
3234 			cur->view->refresh = true;
3235 			goto beach;
3236 		}
3237 		bool x_included =  (tx1 >= cx0 && cx1 >= tx1) || (tx0 >= cx0 && cx1 >= tx0);
3238 		if (ty1 == cy0 && x_included) {
3239 			if (ty1 + PANEL_CONFIG_RESIZE_H < cy1) {
3240 				targets1[cur1++] = p;
3241 			}
3242 		}
3243 		if (ty0 == cy1 && x_included) {
3244 			if (ty0 + PANEL_CONFIG_RESIZE_H < ty1) {
3245 				targets3[cur3++] = p;
3246 			}
3247 		}
3248 		if (ty0 == cy0) {
3249 			if (ty0 + PANEL_CONFIG_RESIZE_H < ty1) {
3250 				targets2[cur2++] = p;
3251 			}
3252 		}
3253 		if (ty1 == cy1) {
3254 			if (ty1 + PANEL_CONFIG_RESIZE_H < panels->can->h) {
3255 				targets4[cur4++] = p;
3256 			}
3257 		}
3258 	}
3259 	if (cur3 > 0) {
3260 		for (i = 0; i < cur3; i++) {
3261 			targets3[i]->view->pos.h -= PANEL_CONFIG_RESIZE_H;
3262 			targets3[i]->view->pos.y += PANEL_CONFIG_RESIZE_H;
3263 			targets3[i]->view->refresh = true;
3264 		}
3265 		for (i = 0; i < cur4; i++) {
3266 			targets4[i]->view->pos.h += PANEL_CONFIG_RESIZE_H;
3267 			targets4[i]->view->refresh = true;
3268 		}
3269 		cur->view->pos.h += PANEL_CONFIG_RESIZE_H;
3270 		cur->view->refresh = true;
3271 	} else if (cur1 > 0) {
3272 		for (i = 0; i < cur1; i++) {
3273 			targets1[i]->view->pos.h += PANEL_CONFIG_RESIZE_H;
3274 			targets1[i]->view->refresh = true;
3275 		}
3276 		for (i = 0; i < cur2; i++) {
3277 			targets2[i]->view->pos.y += PANEL_CONFIG_RESIZE_H;
3278 			targets2[i]->view->pos.h -= PANEL_CONFIG_RESIZE_H;
3279 			targets2[i]->view->refresh = true;
3280 		}
3281 		cur->view->pos.y += PANEL_CONFIG_RESIZE_H;
3282 		cur->view->pos.h -= PANEL_CONFIG_RESIZE_H;
3283 		cur->view->refresh = true;
3284 	}
3285 beach:
3286 	free (targets1);
3287 	free (targets2);
3288 	free (targets3);
3289 	free (targets4);
3290 }
3291 
__handle_window_mode(RCore * core,const int key)3292 static bool __handle_window_mode(RCore *core, const int key) {
3293 	RPanels *panels = core->panels;
3294 	RPanel *cur = __get_cur_panel (panels);
3295 	r_cons_switchbuf (false);
3296 	switch (key) {
3297 	case 'Q':
3298 	case 'q':
3299 	case 'w':
3300 		__toggle_window_mode (core);
3301 		break;
3302 	case 0x0d:
3303 		__toggle_zoom_mode (core);
3304 		break;
3305 	case 9: // tab
3306 		__handle_tab_key (core, false);
3307 		break;
3308 	case 'Z': // shift-tab
3309 		__handle_tab_key (core, true);
3310 		break;
3311 	case 'e':
3312 	{
3313 		char *cmd = __show_status_input (core, "New command: ");
3314 		if (R_STR_ISNOTEMPTY (cmd)) {
3315 			__replace_cmd (core, cmd, cmd);
3316 		}
3317 		free (cmd);
3318 	}
3319 		break;
3320 	case 'h':
3321 		if (r_config_get_i (core->config, "scr.cursor")) {
3322 			core->cons->cpos.x--;
3323 		} else {
3324 			(void)__move_to_direction (core, LEFT);
3325 			if (panels->fun == PANEL_FUN_SNOW || panels->fun == PANEL_FUN_SAKURA) {
3326 				__reset_snow (panels);
3327 			}
3328 		}
3329 		break;
3330 	case 'j':
3331 		if (r_config_get_i (core->config, "scr.cursor")) {
3332 			core->cons->cpos.y++;
3333 		} else {
3334 			(void)__move_to_direction (core, DOWN);
3335 			if (panels->fun == PANEL_FUN_SNOW || panels->fun == PANEL_FUN_SAKURA) {
3336 				__reset_snow (panels);
3337 			}
3338 		}
3339 		break;
3340 	case 'k':
3341 		if (r_config_get_i (core->config, "scr.cursor")) {
3342 			core->cons->cpos.y--;
3343 		} else {
3344 			(void)__move_to_direction (core, UP);
3345 			if (panels->fun == PANEL_FUN_SNOW || panels->fun == PANEL_FUN_SAKURA) {
3346 				__reset_snow (panels);
3347 			}
3348 		}
3349 		break;
3350 	case 'l':
3351 		if (r_config_get_i (core->config, "scr.cursor")) {
3352 			core->cons->cpos.x++;
3353 		} else {
3354 			(void)__move_to_direction (core, RIGHT);
3355 			if (panels->fun == PANEL_FUN_SNOW || panels->fun == PANEL_FUN_SAKURA) {
3356 				__reset_snow (panels);
3357 			}
3358 		}
3359 		break;
3360 	case 'H':
3361 		if (r_config_get_i (core->config, "scr.cursor")) {
3362 			core->cons->cpos.x += 5;
3363 		} else {
3364 			r_cons_switchbuf (false);
3365 			__resize_panel_left (panels);
3366 		}
3367 		break;
3368 	case 'L':
3369 		if (r_config_get_i (core->config, "scr.cursor")) {
3370 			core->cons->cpos.x += 5;
3371 		} else {
3372 			r_cons_switchbuf (false);
3373 			__resize_panel_right (panels);
3374 		}
3375 		break;
3376 	case 'J':
3377 		if (r_config_get_i (core->config, "scr.cursor")) {
3378 			core->cons->cpos.y += 5;
3379 		} else {
3380 			r_cons_switchbuf (false);
3381 			__resize_panel_down (panels);
3382 		}
3383 		break;
3384 	case 'K':
3385 		if (r_config_get_i (core->config, "scr.cursor")) {
3386 			core->cons->cpos.y -= 5;
3387 		} else {
3388 			r_cons_switchbuf (false);
3389 			__resize_panel_up (panels);
3390 		}
3391 		break;
3392 	case 'n':
3393 		__create_panel_input (core, cur, PANEL_LAYOUT_VERTICAL, NULL);
3394 		break;
3395 	case 'N':
3396 		__create_panel_input (core, cur, PANEL_LAYOUT_HORIZONTAL, NULL);
3397 		break;
3398 	case 'X':
3399 		__dismantle_del_panel (core, cur, panels->curnode);
3400 		break;
3401 	case '"':
3402 	case ':':
3403 	case ';':
3404 	case '/':
3405 	case 'd':
3406 	case 'b':
3407 	case 'p':
3408 	case 'P':
3409 	case 't':
3410 	case 'T':
3411 	case '?':
3412 	case '|':
3413 	case '-':
3414 		return false;
3415 	}
3416 	return true;
3417 }
3418 
__jmp_to_cursor_addr(RCore * core,RPanel * panel)3419 static void __jmp_to_cursor_addr(RCore *core, RPanel *panel) {
3420 	ut64 addr = __parse_string_on_cursor (core, panel, panel->view->curpos);
3421 	if (addr == UT64_MAX) {
3422 		return;
3423 	}
3424 	core->offset = addr;
3425 	__update_disassembly_or_open (core);
3426 }
3427 
__set_breakpoints_on_cursor(RCore * core,RPanel * panel)3428 static void __set_breakpoints_on_cursor(RCore *core, RPanel *panel) {
3429 	if (!r_config_get_i (core->config, "cfg.debug")) {
3430 		return;
3431 	}
3432 	if (__check_panel_type (panel, PANEL_CMD_DISASSEMBLY)) {
3433 		r_core_cmdf (core, "dbs 0x%08"PFMT64x, core->offset + core->print->cur);
3434 		panel->view->refresh = true;
3435 	}
3436 }
3437 
__insert_value(RCore * core)3438 static void __insert_value(RCore *core) {
3439 	if (!r_config_get_i (core->config, "io.cache")) {
3440 		if (__show_status_yesno (core, 1, "Insert is not available because io.cache is off. Turn on now?(Y/n)")) {
3441 			r_config_set_b (core->config, "io.cache", true);
3442 			(void)__show_status (core, "io.cache is on and insert is available now.");
3443 		} else {
3444 			(void)__show_status (core, "You can always turn on io.cache in Menu->Edit->io.cache");
3445 			return;
3446 		}
3447 	}
3448 	RPanels *panels = core->panels;
3449 	RPanel *cur = __get_cur_panel (panels);
3450 	char buf[128];
3451 	if (__check_panel_type (cur, PANEL_CMD_STACK)) {
3452 		const char *prompt = "insert hex: ";
3453 		__panel_prompt (prompt, buf, sizeof (buf));
3454 		r_core_cmdf (core, "wx %s @ 0x%08" PFMT64x, buf, cur->model->addr);
3455 		cur->view->refresh = true;
3456 	} else if (__check_panel_type (cur, PANEL_CMD_REGISTERS)) {
3457 		const char *creg = core->dbg->creg;
3458 		if (creg) {
3459 			const char *prompt = "new-reg-value> ";
3460 			__panel_prompt (prompt, buf, sizeof (buf));
3461 			r_core_cmdf (core, "dr %s = %s", creg, buf);
3462 			cur->view->refresh = true;
3463 		}
3464 	} else if (__check_panel_type (cur, PANEL_CMD_DISASSEMBLY)) {
3465 		const char *prompt = "insert hex: ";
3466 		__panel_prompt (prompt, buf, sizeof (buf));
3467 		r_core_cmdf (core, "wx %s @ 0x%08" PFMT64x, buf, core->offset + core->print->cur);
3468 		cur->view->refresh = true;
3469 	} else if (__check_panel_type (cur, PANEL_CMD_HEXDUMP)) {
3470 		const char *prompt = "insert hex: ";
3471 		__panel_prompt (prompt, buf, sizeof (buf));
3472 		r_core_cmdf (core, "wx %s @ 0x%08" PFMT64x, buf, cur->model->addr + core->print->cur);
3473 		cur->view->refresh = true;
3474 	}
3475 }
3476 
__cursor_del_breakpoints(RCore * core,RPanel * panel)3477 static void __cursor_del_breakpoints(RCore *core, RPanel *panel) {
3478 	RListIter *iter;
3479 	RBreakpointItem *b;
3480 	int i = 0;
3481 	r_list_foreach (core->dbg->bp->bps, iter, b) {
3482 		if (panel->view->curpos == i++) {
3483 			r_bp_del (core->dbg->bp, b->addr);
3484 		}
3485 	}
3486 }
3487 
__set_addr_by_type(RCore * core,const char * cmd,ut64 addr)3488 static void __set_addr_by_type(RCore *core, const char *cmd, ut64 addr) {
3489 	RPanels *panels = core->panels;
3490 	int i;
3491 	for (i = 0; i < panels->n_panels; i++) {
3492 		RPanel *p = __get_panel (panels, i);
3493 		if (!__check_panel_type (p, cmd)) {
3494 			continue;
3495 		}
3496 		__set_panel_addr (core, p, addr);
3497 	}
3498 }
3499 
__handle_refs(RCore * core,RPanel * panel,ut64 tmp)3500 static void __handle_refs(RCore *core, RPanel *panel, ut64 tmp) {
3501 	if (tmp != UT64_MAX) {
3502 		core->offset = tmp;
3503 	}
3504 	int key = __show_status(core, "xrefs:x refs:X ");
3505 	switch (key) {
3506 	case 'x':
3507 		(void)r_core_visual_refs (core, true, false);
3508 		break;
3509 	case 'X':
3510 		(void)r_core_visual_refs (core, false, false);
3511 		break;
3512 	default:
3513 		break;
3514 	}
3515 	if (__check_panel_type (panel, PANEL_CMD_DISASSEMBLY)) {
3516 		__set_panel_addr (core, panel, core->offset);
3517 	} else {
3518 		__set_addr_by_type (core, PANEL_CMD_DISASSEMBLY, core->offset);
3519 	}
3520 }
3521 
__handle_cursor_mode(RCore * core,const int key)3522 static bool __handle_cursor_mode(RCore *core, const int key) {
3523 	RPanel *cur = __get_cur_panel (core->panels);
3524 	RPrint *print = core->print;
3525 	char *db_val;
3526 	switch (key) {
3527 	case ':':
3528 	case ';':
3529 	case 'd':
3530 	case 'h':
3531 	case 'j':
3532 	case 'k':
3533 	case 'J':
3534 	case 'K':
3535 	case 'l':
3536 	case 'm':
3537 	case 'Z':
3538 	case '"':
3539 	case 9:
3540 		return false;
3541 	case 'g':
3542 		cur->view->curpos = 0;
3543 		__reset_scroll_pos (cur);
3544 		cur->view->refresh = true;
3545 		break;
3546 	case ']':
3547 		if (__check_panel_type (cur, PANEL_CMD_HEXDUMP)) {
3548 			const int cols = r_config_get_i (core->config, "hex.cols");
3549 			r_config_set_i (core->config, "hex.cols", cols + 1);
3550 		} else {
3551 			const int cmtcol = r_config_get_i (core->config, "asm.cmt.col");
3552 			r_config_set_i (core->config, "asm.cmt.col", cmtcol + 2);
3553 		}
3554 		cur->view->refresh = true;
3555 		break;
3556 	case '[':
3557 		if (__check_panel_type (cur, PANEL_CMD_HEXDUMP)) {
3558 			const int cols = r_config_get_i (core->config, "hex.cols");
3559 			r_config_set_i (core->config, "hex.cols", cols - 1);
3560  		} else {
3561 			int cmtcol = r_config_get_i (core->config, "asm.cmt.col");
3562 			if (cmtcol > 2) {
3563 				r_config_set_i (core->config, "asm.cmt.col", cmtcol - 2);
3564 			}
3565 		}
3566 		cur->view->refresh = true;
3567 		break;
3568 	case 'Q':
3569 	case 'q':
3570 	case 'c':
3571 		__set_cursor (core, !print->cur_enabled);
3572 		cur->view->refresh = true;
3573 		break;
3574 	case 'w':
3575 		__toggle_window_mode (core);
3576 		__set_cursor (core, false);
3577 		cur->view->refresh = true;
3578 		break;
3579 	case 'i':
3580 		__insert_value (core);
3581 		break;
3582 	case '*':
3583 		if (__check_panel_type (cur, PANEL_CMD_DISASSEMBLY)) {
3584 			r_core_cmdf (core, "dr PC=0x%08"PFMT64x, core->offset + print->cur);
3585 			__set_panel_addr (core, cur, core->offset + print->cur);
3586 		}
3587 		break;
3588 	case '-':
3589 		db_val = __search_db (core, "Breakpoints");
3590 		if (__check_panel_type (cur, db_val)) {
3591 			__cursor_del_breakpoints(core, cur);
3592 			free (db_val);
3593 			break;
3594 		}
3595 		free (db_val);
3596 		return false;
3597 	case 'x':
3598 		__handle_refs (core, cur, __parse_string_on_cursor (core, cur, cur->view->curpos));
3599 		break;
3600 	case 0x0d:
3601 		__jmp_to_cursor_addr (core, cur);
3602 		break;
3603 	case 'b':
3604 		__set_breakpoints_on_cursor (core, cur);
3605 		break;
3606 	case 'H':
3607 		cur->view->curpos = cur->view->sy;
3608 		cur->view->refresh = true;
3609 		break;
3610 	}
3611 	return true;
3612 }
3613 
__drag_and_resize(RCore * core)3614 static bool __drag_and_resize(RCore *core) {
3615 	RPanels *panels = core->panels;
3616 	if (panels->mouse_on_edge_x || panels->mouse_on_edge_y) {
3617 		int x, y;
3618 		if (r_cons_get_click (&x, &y)) {
3619 			if (panels->mouse_on_edge_x) {
3620 				__update_edge_x (core, x - panels->mouse_orig_x);
3621 			}
3622 			if (panels->mouse_on_edge_y) {
3623 				__update_edge_y (core, y - panels->mouse_orig_y);
3624 			}
3625 		}
3626 		panels->mouse_on_edge_x = false;
3627 		panels->mouse_on_edge_y = false;
3628 		return true;
3629 	}
3630 	return false;
3631 }
3632 
__get_word_from_canvas(RCore * core,RPanels * panels,int x,int y)3633 static char *__get_word_from_canvas(RCore *core, RPanels *panels, int x, int y) {
3634 	RStrBuf rsb;
3635 	r_strbuf_init (&rsb);
3636 	char *cs = r_cons_canvas_to_string (panels->can);
3637 	r_strbuf_setf (&rsb, " %s", cs);
3638 	char *R = r_str_ansi_crop (r_strbuf_get (&rsb), 0, y - 1, x + 1024, y);
3639 	r_str_ansi_filter (R, NULL, NULL, -1);
3640 	char *r = r_str_ansi_crop (r_strbuf_get (&rsb), x - 1, y - 1, x + 1024, y);
3641 	r_str_ansi_filter (r, NULL, NULL, -1);
3642 	char *pos = strstr (R, r);
3643 	if (!pos) {
3644 		pos = R;
3645 	}
3646 #define TOkENs ":=*+-/()[,] "
3647 	const char *sp = r_str_rsep (R, pos, TOkENs);
3648 	if (sp) {
3649 		sp++;
3650 	} else {
3651 		sp = pos;
3652 	}
3653 	char *sp2 = (char *)r_str_sep (sp, TOkENs);
3654 	if (sp2) {
3655 		*sp2 = 0;
3656 	}
3657 	char *res = strdup (sp);
3658 	free (r);
3659 	free (R);
3660 	free (cs);
3661 	r_strbuf_fini (&rsb);
3662 	return res;
3663 }
3664 
__get_word_from_canvas_for_menu(RCore * core,RPanels * panels,int x,int y)3665 static char *__get_word_from_canvas_for_menu(RCore *core, RPanels *panels, int x, int y) {
3666 	char *cs = r_cons_canvas_to_string (panels->can);
3667 	char *R = r_str_ansi_crop (cs, 0, y - 1, x + 1024, y);
3668 	r_str_ansi_filter (R, NULL, NULL, -1);
3669 	char *r = r_str_ansi_crop (cs, x - 1, y - 1, x + 1024, y);
3670 	r_str_ansi_filter (r, NULL, NULL, -1);
3671 	char *pos = strstr (R, r);
3672 	char *tmp = pos;
3673 	const char *padding = "  ";
3674 	if (!pos) {
3675 		pos = R;
3676 	}
3677 	int i = 0;
3678 	while (pos > R && strncmp (padding, pos, strlen (padding))) {
3679 		pos--;
3680 		i++;
3681 	}
3682 	while (R_STR_ISNOTEMPTY (tmp) && strncmp (padding, tmp, strlen (padding))) {
3683 		tmp++;
3684 		i++;
3685 	}
3686 	char *ret = r_str_newlen (pos += strlen (padding), i - strlen (padding));
3687 	if (!ret) {
3688 		ret = strdup (pos);
3689 	}
3690 	free (r);
3691 	free (R);
3692 	free (cs);
3693 	return ret;
3694 }
3695 
__handle_tab_nth(RCore * core,int ch)3696 static void __handle_tab_nth(RCore *core, int ch) {
3697 	ch -= '0' + 1;
3698 	if (ch < 0) {
3699 		return;
3700 	}
3701 	if (ch != core->panels_root->cur_panels && ch < core->panels_root->n_panels) {
3702 		core->panels_root->cur_panels = ch;
3703 		__set_root_state (core, ROTATE);
3704 	}
3705 }
3706 
__clear_panels_menuRec(RPanelsMenuItem * pmi)3707 static void __clear_panels_menuRec(RPanelsMenuItem *pmi) {
3708 	size_t i = 0;
3709 	for (i = 0; i < pmi->n_sub; i++) {
3710 		RPanelsMenuItem *sub = pmi->sub[i];
3711 		if (sub) {
3712 			sub->selectedIndex = 0;
3713 			__clear_panels_menuRec (sub);
3714 		}
3715 	}
3716 }
3717 
__clear_panels_menu(RCore * core)3718 static void __clear_panels_menu(RCore *core) {
3719 	RPanels *p = core->panels;
3720 	RPanelsMenu *pm = p->panels_menu;
3721 	__clear_panels_menuRec (pm->root);
3722 	pm->root->selectedIndex = 0;
3723 	pm->history[0] = pm->root;
3724 	pm->depth = 1;
3725 	pm->n_refresh = 0;
3726 }
3727 
__handle_mouse_on_top(RCore * core,int x,int y)3728 static bool __handle_mouse_on_top(RCore *core, int x, int y) {
3729 	RPanels *panels = core->panels;
3730 	char *word = __get_word_from_canvas (core, panels, x, y);
3731 	int i;
3732 	for (i = 0; i < COUNT (menus); i++) {
3733 		if (!strcmp (word, menus[i])) {
3734 			__set_mode (core, PANEL_MODE_MENU);
3735 			__clear_panels_menu (core);
3736 			RPanelsMenu *menu = panels->panels_menu;
3737 			RPanelsMenuItem *parent = menu->history[menu->depth - 1];
3738 			parent->selectedIndex = i;
3739 			RPanelsMenuItem *child = parent->sub[parent->selectedIndex];
3740 			(void)(child->cb (core));
3741 			free (word);
3742 			return true;
3743 		}
3744 	}
3745 	if (!strcmp (word, "Tab")) {
3746 		__handle_tab_new (core);
3747 		free (word);
3748 		return true;
3749 	}
3750 	if (word[0] == '[' && word[1] && word[2] == ']') {
3751 		return true;
3752 	}
3753 	if (atoi (word)) {
3754 		__handle_tab_nth (core, word[0]);
3755 		return true;
3756 	}
3757 	return false;
3758 }
3759 
__del_menu(RCore * core)3760 static void __del_menu(RCore *core) {
3761 	RPanels *panels = core->panels;
3762 	RPanelsMenu *menu = panels->panels_menu;
3763 	int i;
3764 	menu->depth--;
3765 	for (i = 1; i < menu->depth; i++) {
3766 		menu->history[i]->p->view->refresh = true;
3767 		menu->refreshPanels[i - 1] = menu->history[i]->p;
3768 	}
3769 	menu->n_refresh = menu->depth - 1;
3770 }
3771 
__draw_menu(RCore * core,RPanelsMenuItem * item)3772 static RStrBuf *__draw_menu(RCore *core, RPanelsMenuItem *item) {
3773 	RStrBuf *buf = r_strbuf_new (NULL);
3774 	if (!buf) {
3775 		return NULL;
3776 	}
3777 	size_t i;
3778 	for (i = 0; i < item->n_sub; i++) {
3779 		if (i == item->selectedIndex) {
3780 			r_strbuf_appendf (buf, "%s> %s"Color_RESET,
3781 					core->cons->context->pal.graph_box2, item->sub[i]->name);
3782 		} else {
3783 			r_strbuf_appendf (buf, "  %s", item->sub[i]->name);
3784 		}
3785 		r_strbuf_append (buf, "          \n");
3786 	}
3787 	return buf;
3788 }
3789 
__update_menu_contents(RCore * core,RPanelsMenu * menu,RPanelsMenuItem * parent)3790 static void __update_menu_contents(RCore *core, RPanelsMenu *menu, RPanelsMenuItem *parent) {
3791 	RPanel *p = parent->p;
3792 	RStrBuf *buf = __draw_menu (core, parent);
3793 	if (!buf) {
3794 		return;
3795 	}
3796 	free (p->model->title);
3797 	p->model->title = r_strbuf_drain (buf);
3798 	int new_w = r_str_bounds (p->model->title, &p->view->pos.h);
3799 	p->view->pos.w = new_w;
3800 	p->view->pos.h += 4;
3801 	p->model->type = PANEL_TYPE_MENU;
3802 	p->view->refresh = true;
3803 	menu->refreshPanels[menu->n_refresh - 1] = p;
3804 }
3805 
__handle_mouse_on_menu(RCore * core,int x,int y)3806 static void __handle_mouse_on_menu(RCore *core, int x, int y) {
3807 	RPanels *panels = core->panels;
3808 	char *word = __get_word_from_canvas_for_menu (core, panels, x, y);
3809 	RPanelsMenu *menu = panels->panels_menu;
3810 	int i, d = menu->depth - 1;
3811 	while (d) {
3812 		RPanelsMenuItem *parent = menu->history[d--];
3813 		for (i = 0; i < parent->n_sub; i++) {
3814 			if (!strcmp (word, parent->sub[i]->name)) {
3815 				parent->selectedIndex = i;
3816 				(void)(parent->sub[parent->selectedIndex]->cb (core));
3817 				__update_menu_contents (core, menu, parent);
3818 				free (word);
3819 				return;
3820 			}
3821 		}
3822 		__del_menu (core);
3823 	}
3824 	__clear_panels_menu (core);
3825 	__set_mode (core, PANEL_MODE_DEFAULT);
3826 	__get_cur_panel (panels)->view->refresh = true;
3827 	free (word);
3828 }
3829 
__toggle_cache(RCore * core,RPanel * p)3830 static void __toggle_cache(RCore *core, RPanel *p) {
3831 	p->model->cache = !p->model->cache;
3832 	__set_cmd_str_cache (core, p, NULL);
3833 	p->view->refresh = true;
3834 }
3835 
__draw_modal(RCore * core,RModal * modal,int range_end,int start,const char * name)3836 static bool __draw_modal(RCore *core, RModal *modal, int range_end, int start, const char *name) {
3837 	if (start < modal->offset) {
3838 		return true;
3839 	}
3840 	if (start >= range_end) {
3841 		return false;
3842 	}
3843 	if (start == modal->idx) {
3844 		r_strbuf_appendf (modal->data, ">  %s%s"Color_RESET, core->cons->context->pal.graph_box2, name);
3845 	} else {
3846 		r_strbuf_appendf (modal->data, "   %s", name);
3847 	}
3848 	r_strbuf_append (modal->data, "          \n");
3849 	return true;
3850 }
3851 
__update_modal(RCore * core,Sdb * menu_db,RModal * modal)3852 static void __update_modal(RCore *core, Sdb *menu_db, RModal *modal) {
3853 	RPanels *panels = core->panels;
3854 	RConsCanvas *can = panels->can;
3855 	modal->data = r_strbuf_new (NULL);
3856 	int count = sdb_count (menu_db);
3857 	if (modal->idx >= count) {
3858 		modal->idx = 0;
3859 		modal->offset = 0;
3860 	} else if (modal->idx >= modal->offset + modal->pos.h) {
3861 		if (modal->offset + modal->pos.h >= count) {
3862 			modal->offset = 0;
3863 			modal->idx = 0;
3864 		} else {
3865 			modal->offset += 1;
3866 		}
3867 	} else if (modal->idx < 0) {
3868 		modal->offset = R_MAX (count - modal->pos.h, 0);
3869 		modal->idx = count - 1;
3870 	} else if (modal->idx < modal->offset) {
3871 		modal->offset -= 1;
3872 	}
3873 	SdbList *l = sdb_foreach_list (menu_db, true);
3874 	SdbKv *kv;
3875 	SdbListIter *iter;
3876 	int i = 0;
3877 	int max_h = R_MIN (modal->offset + modal->pos.h, count);
3878 	ls_foreach (l, iter, kv) {
3879 		if (__draw_modal (core, modal, max_h, i, sdbkv_key (kv))) {
3880 			i++;
3881 		}
3882 	}
3883 	r_cons_gotoxy (0, 0);
3884 	r_cons_canvas_fill (can, modal->pos.x, modal->pos.y, modal->pos.w + 2, modal->pos.h + 2, ' ');
3885 	(void)r_cons_canvas_gotoxy (can, modal->pos.x + 2, modal->pos.y + 1);
3886 	r_cons_canvas_write (can, r_strbuf_get (modal->data));
3887 	r_strbuf_free (modal->data);
3888 
3889 	r_cons_canvas_box (can, modal->pos.x, modal->pos.y, modal->pos.w + 2, modal->pos.h + 2, core->cons->context->pal.graph_box2);
3890 
3891 	r_cons_canvas_print (can);
3892 	r_cons_flush ();
3893 	show_cursor (core);
3894 }
3895 
__exec_modal(RCore * core,RPanel * panel,RModal * modal,Sdb * menu_db,RPanelLayout dir)3896 static void __exec_modal(RCore *core, RPanel *panel, RModal *modal, Sdb *menu_db, RPanelLayout dir) {
3897 	SdbList *l = sdb_foreach_list (menu_db, true);
3898 	SdbKv *kv;
3899 	SdbListIter *iter;
3900 	int i = 0;
3901 	ls_foreach (l, iter, kv) {
3902 		if (i++ == modal->idx) {
3903 			RPanelAlmightyCallback cb = sdb_ptr_get (menu_db, sdbkv_key (kv), 0);
3904 			cb (core, panel, dir, sdbkv_key (kv));
3905 			break;
3906 		}
3907 	}
3908 }
3909 
__delete_modal(RCore * core,RModal * modal,Sdb * menu_db)3910 static void __delete_modal(RCore *core, RModal *modal, Sdb *menu_db) {
3911 	SdbList *l = sdb_foreach_list (menu_db, true);
3912 	SdbKv *kv;
3913 	SdbListIter *iter;
3914 	int i = 0;
3915 	ls_foreach (l, iter, kv) {
3916 		if (i++ == modal->idx) {
3917 			sdb_remove (menu_db, sdbkv_key (kv), 0);
3918 		}
3919 	}
3920 }
3921 
__init_modal(void)3922 static RModal *__init_modal(void) {
3923 	RModal *modal = R_NEW0 (RModal);
3924 	if (modal) {
3925 		__set_pos (&modal->pos, 0, 0);
3926 		modal->idx = 0;
3927 		modal->offset = 0;
3928 	}
3929 	return modal;
3930 }
3931 
__free_modal(RModal ** modal)3932 static void __free_modal(RModal **modal) {
3933 	free (*modal);
3934 	*modal = NULL;
3935 }
3936 
__create_modal(RCore * core,RPanel * panel,Sdb * menu_db)3937 static void __create_modal(RCore *core, RPanel *panel, Sdb *menu_db) {
3938 	__set_cursor (core, false);
3939 	const int w = 40;
3940 	const int h = 20;
3941 	const int x = (core->panels->can->w - w) / 2;
3942 	const int y = (core->panels->can->h - h) / 2;
3943 	RModal *modal = __init_modal ();
3944 	__set_geometry (&modal->pos, x, y, w, h);
3945 	int okey, key, cx, cy;
3946 	char *word = NULL;
3947 	__update_modal (core, menu_db, modal);
3948 	while (modal) {
3949 		okey = r_cons_readchar ();
3950 		key = r_cons_arrow_to_hjkl (okey);
3951 		word = NULL;
3952 		if (key == INT8_MAX - 1) {
3953 			if (r_cons_get_click (&cx, &cy)) {
3954 				if ((cx < x || x + w < cx) || ((cy < y || y + h < cy))) {
3955 					key = 'q';
3956 				} else {
3957 					word = __get_word_from_canvas_for_menu (core, core->panels, cx, cy);
3958 					if (word) {
3959 						void *cb = sdb_ptr_get (menu_db, word, 0);
3960 						if (cb) {
3961 							((RPanelAlmightyCallback)cb) (core, panel, PANEL_LAYOUT_NONE, word);
3962 							__free_modal (&modal);
3963 							free (word);
3964 							break;
3965 						}
3966 						free (word);
3967 					}
3968 				}
3969 			}
3970 		}
3971 		switch (key) {
3972 		case 'e':
3973 			{
3974 				__free_modal (&modal);
3975 				char *cmd = __show_status_input (core, "New command: ");
3976 				if (R_STR_ISNOTEMPTY (cmd)) {
3977 					__replace_cmd (core, cmd, cmd);
3978 				}
3979 				free (cmd);
3980 			}
3981 		break;
3982 		case 'j':
3983 			modal->idx++;
3984 			__update_modal (core, menu_db, modal);
3985 			break;
3986 		case 'k':
3987 			modal->idx--;
3988 			__update_modal (core, menu_db, modal);
3989 			break;
3990 		case 'v':
3991 			__exec_modal (core, panel, modal, menu_db, PANEL_LAYOUT_VERTICAL);
3992 			__free_modal (&modal);
3993 			break;
3994 		case 'h':
3995 			__exec_modal (core, panel, modal, menu_db, PANEL_LAYOUT_HORIZONTAL);
3996 			__free_modal (&modal);
3997 			break;
3998 		case 0x0d:
3999 			__exec_modal (core, panel, modal, menu_db, PANEL_LAYOUT_NONE);
4000 			__free_modal (&modal);
4001 			break;
4002 		case '-':
4003 			__delete_modal (core, modal, menu_db);
4004 			__update_modal (core, menu_db, modal);
4005 			break;
4006 		case 'q':
4007 		case '"':
4008 			__free_modal (&modal);
4009 			break;
4010 		}
4011 	}
4012 }
4013 
__handle_mouse_on_X(RCore * core,int x,int y)4014 static bool __handle_mouse_on_X(RCore *core, int x, int y) {
4015 	RPanels *panels = core->panels;
4016 	const int idx = __get_panel_idx_in_pos (core, x, y);
4017 	char *word = __get_word_from_canvas (core, panels, x, y);
4018 	if (idx == -1) {
4019 		return false;
4020 	}
4021 	RPanel *ppos = __get_panel(panels, idx);
4022 	const int TITLE_Y = ppos->view->pos.y + 2;
4023 	if (y == TITLE_Y && strcmp (word, " X ")) {
4024 		int fx = ppos->view->pos.x;
4025 		int fX = fx + ppos->view->pos.w;
4026 		__set_curnode (core, idx);
4027 		__set_refresh_all (core, true, true);
4028 		if (x > (fX - 13) && x < fX) {
4029 			__toggle_cache (core, __get_cur_panel (panels));
4030 		} else if (x > fx && x < (fx + 5)) {
4031 			__dismantle_del_panel (core, ppos, idx);
4032 		} else {
4033 			__create_modal (core, __get_panel (panels, 0), panels->modal_db);
4034 			__set_mode (core, PANEL_MODE_DEFAULT);
4035 		}
4036 		free (word);
4037 		return true;
4038 	}
4039 	free (word);
4040 	return false;
4041 }
4042 
__seek_all(RCore * core,ut64 addr)4043 static void __seek_all(RCore *core, ut64 addr) {
4044 	RPanels *panels = core->panels;
4045 	int i;
4046 	for (i = 0; i < panels->n_panels; i++) {
4047 		RPanel *panel = __get_panel (panels, i);
4048 		panel->model->addr = addr;
4049 	}
4050 }
4051 
__handle_mouse_on_panel(RCore * core,RPanel * panel,int x,int y,int * key)4052 static bool __handle_mouse_on_panel(RCore *core, RPanel *panel, int x, int y, int *key) {
4053 	RPanels *panels = core->panels;
4054 	int h;
4055 	(void)r_cons_get_size (&h);
4056 	const int idx = __get_panel_idx_in_pos (core, x, y);
4057 	char *word = __get_word_from_canvas (core, panels, x, y);
4058 	if (idx == -1) {
4059 		return false;
4060 	}
4061 	__set_curnode (core, idx);
4062 	__set_refresh_all (core, true, true);
4063 	RPanel *ppos = __get_panel(panels, idx);
4064 	if (word) {
4065 		const ut64 addr = r_num_math (core->num, word);
4066 		if (__check_panel_type (panel, PANEL_CMD_FUNCTION) &&
4067 				__check_if_addr (word, strlen (word))) {
4068 			r_core_seek (core, addr, true);
4069 			__set_addr_by_type (core, PANEL_CMD_DISASSEMBLY, addr);
4070 		}
4071 		r_flag_set (core->flags, "panel.addr", addr, 1);
4072 		r_config_set (core->config, "scr.highlight", word);
4073 		{
4074 			ut64 addr = r_num_math (core->num, word);
4075 			if (addr > 0) {
4076 				// TODO implement proper panel offset sync
4077 				// __set_panel_addr (core, cur, addr);
4078 				__seek_all (core, addr);
4079 			}
4080 		}
4081 		free (word);
4082 	}
4083 	if (x >= ppos->view->pos.x && x < ppos->view->pos.x + 4) {
4084 		*key = 'c';
4085 		return false;
4086 	}
4087 	return true;
4088 }
4089 
__handle_mouse(RCore * core,RPanel * panel,int * key)4090 static bool __handle_mouse(RCore *core, RPanel *panel, int *key) {
4091 	RPanels *panels = core->panels;
4092 	if (__drag_and_resize (core)) {
4093 		return true;
4094 	}
4095 	if (key && !*key) {
4096 		int x, y;
4097 		if (!r_cons_get_click (&x, &y)) {
4098 			return false;
4099 		}
4100 		if (y == MENU_Y && __handle_mouse_on_top (core, x, y)) {
4101 			return true;
4102 		}
4103 		if (panels->mode == PANEL_MODE_MENU) {
4104 			__handle_mouse_on_menu (core, x, y);
4105 			return true;
4106 		}
4107 		if (__handle_mouse_on_X (core, x, y)) {
4108 			return true;
4109 		}
4110 		if (__check_if_mouse_x_illegal (core, x) || __check_if_mouse_y_illegal (core, y)) {
4111 			panels->mouse_on_edge_x = false;
4112 			panels->mouse_on_edge_y = false;
4113 			return true;
4114 		}
4115 		panels->mouse_on_edge_x = __check_if_mouse_x_on_edge (core, x, y);
4116 		panels->mouse_on_edge_y = __check_if_mouse_y_on_edge (core, x, y);
4117 		if (panels->mouse_on_edge_x || panels->mouse_on_edge_y) {
4118 			return true;
4119 		}
4120 		if (__handle_mouse_on_panel (core, panel, x, y, key)) {
4121 			return true;
4122 		}
4123 		int h, w = r_cons_get_size (&h);
4124 		if (y == h) {
4125 			RPanel *p = __get_cur_panel (panels);
4126 			__split_panel_horizontal (core, p, p->model->title, p->model->cmd);
4127 		} else if (x == w) {
4128 			RPanel *p = __get_cur_panel (panels);
4129 			__split_panel_vertical (core, p, p->model->title, p->model->cmd);
4130 		}
4131 	}
4132 	if (key && *key == INT8_MAX) {
4133 		*key = '"';
4134 		return false;
4135 	}
4136 	return false;
4137 }
4138 
__add_visual_mark(RCore * core)4139 static void __add_visual_mark(RCore *core) {
4140 	char *msg = r_str_newf (R_CONS_CLEAR_LINE"Set shortcut key for 0x%"PFMT64x": ", core->offset);
4141 	int ch = __show_status (core, msg);
4142 	free (msg);
4143 	r_core_visual_mark (core, ch);
4144 }
4145 
__handle_visual_mark(RCore * core)4146 static void __handle_visual_mark(RCore *core) {
4147 	RPanel *cur = __get_cur_panel (core->panels);
4148 	if (!__check_panel_type (cur, PANEL_CMD_DISASSEMBLY)) {
4149 		return;
4150 	}
4151 	int act = __show_status (core, "Visual Mark  s:set -:remove \':use: ");
4152 	switch (act) {
4153 	case 's':
4154 		__add_visual_mark (core);
4155 		break;
4156 	case '-':
4157 		r_cons_gotoxy (0, 0);
4158 		if (r_core_visual_mark_dump (core)) {
4159 			r_cons_printf (R_CONS_CLEAR_LINE"Remove a shortcut key from the list\n");
4160 			r_cons_flush ();
4161 			int ch = r_cons_readchar ();
4162 			r_core_visual_mark_del (core, ch);
4163 		}
4164 		break;
4165 	case '\'':
4166 		r_cons_gotoxy (0, 0);
4167 		if (r_core_visual_mark_dump (core)) {
4168 			r_cons_flush ();
4169 			int ch = r_cons_readchar ();
4170 			r_core_visual_mark_seek (core, ch);
4171 			__set_panel_addr (core, cur, core->offset);
4172 		}
4173 	}
4174 }
4175 
__move_panel_to_left(RCore * core,RPanel * panel,int src)4176 static void __move_panel_to_left(RCore *core, RPanel *panel, int src) {
4177 	RPanels *panels = core->panels;
4178 	__shrink_panels_backward (core, src);
4179 	panels->panel[0] = panel;
4180 	int h, w = r_cons_get_size (&h);
4181 	int p_w = w - panels->columnWidth;
4182 	p_w /= 2;
4183 	int new_w = w - p_w;
4184 	__set_geometry (&panel->view->pos, 0, 1, p_w + 1, h - 1);
4185 	int i = 1;
4186 	for (; i < panels->n_panels; i++) {
4187 		RPanel *tmp = __get_panel (panels, i);
4188 		int t_x = ((double)tmp->view->pos.x / (double)w) * (double)new_w + p_w;
4189 		int t_w = ((double)tmp->view->pos.w / (double)w) * (double)new_w + 1;
4190 		__set_geometry (&tmp->view->pos, t_x, tmp->view->pos.y, t_w, tmp->view->pos.h);
4191 	}
4192 	__fix_layout (core);
4193 	__set_curnode (core, 0);
4194 }
4195 
__move_panel_to_right(RCore * core,RPanel * panel,int src)4196 static void __move_panel_to_right(RCore *core, RPanel *panel, int src) {
4197 	RPanels *panels = core->panels;
4198 	__shrink_panels_forward (core, src);
4199 	panels->panel[panels->n_panels - 1] = panel;
4200 	int h, w = r_cons_get_size (&h);
4201 	int p_w = w - panels->columnWidth;
4202 	p_w /= 2;
4203 	int p_x = w - p_w;
4204 	__set_geometry (&panel->view->pos, p_x - 1, 1, p_w + 1, h - 1);
4205 	int new_w = w - p_w;
4206 	int i = 0;
4207 	for (; i < panels->n_panels - 1; i++) {
4208 		RPanel *tmp = __get_panel (panels, i);
4209 		int t_x = ((double)tmp->view->pos.x / (double)w) * (double)new_w;
4210 		int t_w = ((double)tmp->view->pos.w / (double)w) * (double)new_w + 1;
4211 		__set_geometry (&tmp->view->pos, t_x, tmp->view->pos.y, t_w, tmp->view->pos.h);
4212 	}
4213 	__fix_layout (core);
4214 	__set_curnode (core, panels->n_panels - 1);
4215 }
4216 
__move_panel_to_up(RCore * core,RPanel * panel,int src)4217 static void __move_panel_to_up(RCore *core, RPanel *panel, int src) {
4218 	RPanels *panels = core->panels;
4219 	__shrink_panels_backward (core, src);
4220 	panels->panel[0] = panel;
4221 	int h, w = r_cons_get_size (&h);
4222 	int p_h = h / 2;
4223 	int new_h = h - p_h;
4224 	__set_geometry (&panel->view->pos, 0, 1, w, p_h - 1);
4225 	int i = 1;
4226 	for (; i < panels->n_panels; i++) {
4227 		RPanel *tmp = __get_panel (panels, i);
4228 		int t_y = ((double)tmp->view->pos.y / (double)h) * (double)new_h + p_h;
4229 		int t_h = ((double)tmp->view->pos.h / (double)h) * (double)new_h + 1;
4230 		__set_geometry (&tmp->view->pos, tmp->view->pos.x, t_y, tmp->view->pos.w, t_h);
4231 	}
4232 	__fix_layout (core);
4233 	__set_curnode (core, 0);
4234 }
4235 
__move_panel_to_down(RCore * core,RPanel * panel,int src)4236 static void __move_panel_to_down(RCore *core, RPanel *panel, int src) {
4237 	RPanels *panels = core->panels;
4238 	__shrink_panels_forward (core, src);
4239 	panels->panel[panels->n_panels - 1] = panel;
4240 	int h, w = r_cons_get_size (&h);
4241 	int p_h = h / 2;
4242 	int new_h = h - p_h;
4243 	__set_geometry (&panel->view->pos, 0, new_h, w, p_h);
4244 	size_t i = 0;
4245 	for (; i < panels->n_panels - 1; i++) {
4246 		RPanel *tmp = __get_panel (panels, i);
4247 		const size_t t_y = (tmp->view->pos.y * new_h / h)  + 1;
4248 		const size_t t_h = (tmp->view->edge & (1 << PANEL_EDGE_BOTTOM)) ?  new_h - t_y : (tmp->view->pos.h * new_h / h) ;
4249 		__set_geometry (&tmp->view->pos, tmp->view->pos.x, t_y, tmp->view->pos.w, t_h);
4250 	}
4251 	__fix_layout (core);
4252 	__set_curnode (core, panels->n_panels - 1);
4253 }
4254 
__move_panel_to_dir(RCore * core,RPanel * panel,int src)4255 static void __move_panel_to_dir(RCore *core, RPanel *panel, int src) {
4256 	RPanels *panels = core->panels;
4257 	__dismantle_panel (panels, panel);
4258 	int key = __show_status (core, "Move the current panel to direction (h/j/k/l): ");
4259 	key = r_cons_arrow_to_hjkl (key);
4260 	__set_refresh_all (core, false, true);
4261 	switch (key) {
4262 	case 'h':
4263 		__move_panel_to_left (core, panel, src);
4264 		break;
4265 	case 'l':
4266 		__move_panel_to_right (core, panel, src);
4267 		break;
4268 	case 'k':
4269 		__move_panel_to_up (core, panel, src);
4270 		break;
4271 	case 'j':
4272 		__move_panel_to_down (core, panel, src);
4273 		break;
4274 	default:
4275 		break;
4276 	}
4277 }
4278 
__set_dcb(RCore * core,RPanel * p)4279 static void __set_dcb(RCore *core, RPanel *p) {
4280 	if (__is_abnormal_cursor_type (core, p)) {
4281 		p->model->cache = true;
4282 		p->model->directionCb = __direction_panels_cursor_cb;
4283 		return;
4284 	}
4285 	if ((p->model->cache && p->model->cmdStrCache) || p->model->readOnly) {
4286 		p->model->directionCb = __direction_default_cb;
4287 		return;
4288 	}
4289 	if (!p->model->cmd) {
4290 		return;
4291 	}
4292 	if (__check_panel_type (p, PANEL_CMD_GRAPH)) {
4293 		p->model->directionCb = __direction_graph_cb;
4294 		return;
4295 	}
4296 	if (__check_panel_type (p, PANEL_CMD_STACK)) {
4297 		p->model->directionCb = __direction_stack_cb;
4298 	} else if (__check_panel_type (p, PANEL_CMD_DISASSEMBLY)) {
4299 		p->model->directionCb = __direction_disassembly_cb;
4300 	} else if (__check_panel_type (p, PANEL_CMD_REGISTERS)) {
4301 		p->model->directionCb = __direction_register_cb;
4302 	} else if (__check_panel_type (p, PANEL_CMD_HEXDUMP)) {
4303 		p->model->directionCb = __direction_hexdump_cb;
4304 	} else {
4305 		p->model->directionCb = __direction_default_cb;
4306 	}
4307 }
4308 
__swap_panels(RPanels * panels,int p0,int p1)4309 static void __swap_panels(RPanels *panels, int p0, int p1) {
4310 	RPanel *panel0 = __get_panel (panels, p0);
4311 	RPanel *panel1 = __get_panel (panels, p1);
4312 	RPanelModel *tmp = panel0->model;
4313 
4314 	panel0->model = panel1->model;
4315 	panel1->model = tmp;
4316 }
4317 
__check_func(RCore * core)4318 static bool __check_func(RCore *core) {
4319 	RAnalFunction *fun = r_anal_get_fcn_in (core->anal, core->offset, R_ANAL_FCN_TYPE_NULL);
4320 	if (!fun) {
4321 		r_cons_message ("Not in a function. Type 'df' to define it here");
4322 		return false;
4323 	}
4324 	if (r_list_empty (fun->bbs)) {
4325 		r_cons_message ("No basic blocks in this function. You may want to use 'afb+'.");
4326 		return false;
4327 	}
4328 	return true;
4329 }
4330 
__call_visual_graph(RCore * core)4331 static void __call_visual_graph(RCore *core) {
4332 	if (__check_func (core)) {
4333 		RPanels *panels = core->panels;
4334 
4335 		r_cons_canvas_free (panels->can);
4336 		panels->can = NULL;
4337 
4338 		int ocolor = r_config_get_i (core->config, "scr.color");
4339 
4340 		r_core_visual_graph (core, NULL, NULL, true);
4341 		r_config_set_i (core->config, "scr.color", ocolor);
4342 
4343 		int h, w = r_cons_get_size (&h);
4344 		panels->can = __create_new_canvas (core, w, h);
4345 	}
4346 }
4347 
__check_func_diff(RCore * core,RPanel * p)4348 static bool __check_func_diff(RCore *core, RPanel *p) {
4349 	RAnalFunction *func = r_anal_get_fcn_in (core->anal, core->offset, R_ANAL_FCN_TYPE_NULL);
4350 	if (!func) {
4351 		if (R_STR_ISEMPTY (p->model->funcName)) {
4352 			return false;
4353 		}
4354 		p->model->funcName = NULL;
4355 		return true;
4356 	}
4357 	if (!p->model->funcName || strcmp (p->model->funcName, func->name)) {
4358 		p->model->funcName = r_str_dup (p->model->funcName, func->name);
4359 		return true;
4360 	}
4361 	return false;
4362 }
4363 
__print_default_cb(void * user,void * p)4364 static void __print_default_cb(void *user, void *p) {
4365 	RCore *core = (RCore *)user;
4366 	RPanel *panel = (RPanel *)p;
4367 	bool update = core->panels->autoUpdate && __check_func_diff (core, panel);
4368 	char *cmdstr = __find_cmd_str_cache (core, panel);
4369 	if (update || !cmdstr) {
4370 		cmdstr = __handle_cmd_str_cache (core, panel, false);
4371 		if (panel->model->cache && panel->model->cmdStrCache) {
4372 			__reset_scroll_pos (panel);
4373 		}
4374 	}
4375 	__update_panel_contents (core, panel, cmdstr);
4376 }
4377 
__print_decompiler_cb(void * user,void * p)4378 static void __print_decompiler_cb(void *user, void *p) {
4379 	//TODO: Refactoring
4380 	//TODO: Also, __check_func_diff should use addr not name
4381 	RCore *core = (RCore *)user;
4382 	RPanel *panel = (RPanel *)p;
4383 	bool update = core->panels->autoUpdate && __check_func_diff (core, panel);
4384 	char *cmdstr = NULL;
4385 	if (!update) {
4386 		cmdstr = __find_cmd_str_cache (core, panel);
4387 		if (cmdstr) {
4388 			__update_pdc_contents (core, panel, cmdstr);
4389 		}
4390 		return;
4391 	}
4392 	RAnalFunction *func = r_anal_get_fcn_in (core->anal, core->offset, R_ANAL_FCN_TYPE_NULL);
4393 	if (func && core->panels_root->cur_pdc_cache) {
4394 		cmdstr = r_str_new ((char *)sdb_ptr_get (core->panels_root->cur_pdc_cache,
4395 					r_num_as_string (NULL, func->addr, false), 0));
4396 		if (cmdstr) {
4397 			__set_cmd_str_cache (core, panel, cmdstr);
4398 			__reset_scroll_pos (panel);
4399 			__update_pdc_contents (core, panel, cmdstr);
4400 			return;
4401 		}
4402 	}
4403 	cmdstr = __handle_cmd_str_cache (core, panel, false);
4404 	if (cmdstr) {
4405 		__reset_scroll_pos (panel);
4406 		__set_decompiler_cache (core, cmdstr);
4407 		__update_pdc_contents (core, panel, cmdstr);
4408 	}
4409 }
4410 
__print_disasmsummary_cb(void * user,void * p)4411 static void __print_disasmsummary_cb (void *user, void *p) {
4412 	RCore *core = (RCore *)user;
4413 	RPanel *panel = (RPanel *)p;
4414 	bool update = core->panels->autoUpdate && __check_func_diff (core, panel);
4415 	char *cmdstr = __find_cmd_str_cache (core, panel);
4416 	if (update || !cmdstr) {
4417 		cmdstr = __handle_cmd_str_cache (core, panel, true);
4418 		if (panel->model->cache && panel->model->cmdStrCache) {
4419 			__reset_scroll_pos (panel);
4420 		}
4421 	}
4422 	__update_panel_contents (core, panel, cmdstr);
4423 }
4424 
__print_disassembly_cb(void * user,void * p)4425 static void __print_disassembly_cb(void *user, void *p) {
4426 	RCore *core = (RCore *)user;
4427 	RPanel *panel = (RPanel *)p;
4428 	core->print->screen_bounds = 1LL;
4429 	char *cmdstr = __find_cmd_str_cache (core, panel);
4430 	if (cmdstr) {
4431 		__update_panel_contents (core, panel, cmdstr);
4432 		return;
4433 	}
4434 	char *ocmd = panel->model->cmd;
4435 	panel->model->cmd = r_str_newf ("%s %d", panel->model->cmd, panel->view->pos.h - 3);
4436 	ut64 o_offset = core->offset;
4437 	core->offset = panel->model->addr;
4438 	r_core_seek (core, panel->model->addr, true);
4439 	if (r_config_get_i (core->config, "cfg.debug")) {
4440 		r_core_cmd (core, ".dr*", 0);
4441 	}
4442 	cmdstr = __handle_cmd_str_cache (core, panel, false);
4443 	core->offset = o_offset;
4444 	free (panel->model->cmd);
4445 	panel->model->cmd = ocmd;
4446 	__update_panel_contents (core, panel, cmdstr);
4447 }
4448 
__do_panels_refresh(RCore * core)4449 static void __do_panels_refresh(RCore *core) {
4450 	if (core->panels) {
4451 		__panel_all_clear (core->panels);
4452 		__panels_layout_refresh (core);
4453 	}
4454 }
4455 
__do_panels_resize(RCore * core)4456 static void __do_panels_resize(RCore *core) {
4457 	RPanels *panels = core->panels;
4458 	int i;
4459 	int h, w = r_cons_get_size (&h);
4460 	for (i = 0; i < panels->n_panels; i++) {
4461 		RPanel *panel = __get_panel (panels, i);
4462 		if ((panel->view->edge & (1 << PANEL_EDGE_BOTTOM))
4463 				&& (panel->view->pos.y + panel->view->pos.h < h)) {
4464 			panel->view->pos.h = h - panel->view->pos.y;
4465 		}
4466 		if ((panel->view->edge & (1 << PANEL_EDGE_RIGHT))
4467 				&& (panel->view->pos.x + panel->view->pos.w < w)) {
4468 			panel->view->pos.w = w - panel->view->pos.x;
4469 		}
4470 	}
4471 	__do_panels_refresh (core);
4472 }
4473 
__do_panels_refreshOneShot(RCore * core)4474 static void __do_panels_refreshOneShot(RCore *core) {
4475 	r_core_task_enqueue_oneshot (&core->tasks, (RCoreTaskOneShot) __do_panels_resize, core);
4476 }
4477 
__print_graph_cb(void * user,void * p)4478 static void __print_graph_cb(void *user, void *p) {
4479 	RCore *core = (RCore *)user;
4480 	RPanel *panel = (RPanel *)p;
4481 	bool update = core->panels->autoUpdate && __check_func_diff (core, panel);
4482 	char *cmdstr = __find_cmd_str_cache (core, panel);
4483 	if (update || !cmdstr) {
4484 		cmdstr = __handle_cmd_str_cache (core, panel, false);
4485 	}
4486 	core->cons->event_resize = NULL;
4487 	core->cons->event_data = core;
4488 	core->cons->event_resize = (RConsEvent) __do_panels_refreshOneShot;
4489 	__update_panel_contents (core, panel, cmdstr);
4490 }
4491 
__print_stack_cb(void * user,void * p)4492 static void __print_stack_cb(void *user, void *p) {
4493 	RCore *core = (RCore *)user;
4494 	RPanel *panel = (RPanel *)p;
4495 	const int delta = r_config_get_i (core->config, "stack.delta");
4496 	const int bits = r_config_get_i (core->config, "asm.bits");
4497 	const char sign = (delta < 0)? '+': '-';
4498 	const int absdelta = R_ABS (delta);
4499 	char *cmd = r_str_newf ("%s%s ", PANEL_CMD_STACK, bits == 32 ? "w" : "q");
4500 	int n = r_str_split (panel->model->cmd, ' ');
4501 	int i;
4502 	for (i = 0; i < n; i++) {
4503 		const char *s = r_str_word_get0 (panel->model->cmd, i);
4504 		if (!i) {
4505 			continue;
4506 		}
4507 		cmd = r_str_append (cmd, s);
4508 	}
4509 	panel->model->cmd = cmd;
4510 	const char *cmdstr = r_core_cmd_str (core, r_str_newf ("%s%c%d", cmd, sign, absdelta));
4511 	__update_panel_contents (core, panel, cmdstr);
4512 }
4513 
__print_hexdump_cb(void * user,void * p)4514 static void __print_hexdump_cb(void *user, void *p) {
4515 	RCore *core = (RCore *)user;
4516 	RPanel *panel = (RPanel *)p;
4517 	char *cmdstr = __find_cmd_str_cache (core, panel);
4518 	if (!cmdstr) {
4519 		ut64 o_offset = core->offset;
4520 		if (!panel->model->cache) {
4521 			core->offset = panel->model->addr;
4522 			r_core_seek (core, core->offset, true);
4523 			r_core_block_read (core);
4524 		}
4525 		char *base = hexdump_rotate[R_ABS(panel->model->rotate) % COUNT (hexdump_rotate)];
4526 		char *cmd = r_str_newf ("%s ", base);
4527 		int n = r_str_split (panel->model->cmd, ' ');
4528 		int i;
4529 		for (i = 0; i < n; i++) {
4530 			const char *s = r_str_word_get0 (panel->model->cmd, i);
4531 			if (!i) {
4532 				continue;
4533 			}
4534 			cmd = r_str_append (cmd, s);
4535 		}
4536 		panel->model->cmd = cmd;
4537 		cmdstr = __handle_cmd_str_cache (core, panel, false);
4538 		core->offset = o_offset;
4539 	}
4540 	__update_panel_contents (core, panel, cmdstr);
4541 }
4542 
__hudstuff(RCore * core)4543 static void __hudstuff(RCore *core) {
4544 	RPanels *panels = core->panels;
4545 	RPanel *cur = __get_cur_panel (panels);
4546 	r_core_visual_hudstuff (core);
4547 
4548 	if (__check_panel_type (cur, PANEL_CMD_DISASSEMBLY)) {
4549 		__set_panel_addr (core, cur, core->offset);
4550 	} else {
4551 		int i;
4552 		for (i = 0; i < panels->n_panels; i++) {
4553 			RPanel *panel = __get_panel (panels, i);
4554 			if (__check_panel_type (panel, PANEL_CMD_DISASSEMBLY)) {
4555 				__set_panel_addr (core, panel, core->offset);
4556 				break;
4557 			}
4558 		}
4559 	}
4560 }
4561 
__print_snow(RPanels * panels)4562 static void __print_snow(RPanels *panels) {
4563 	if (!panels->snows) {
4564 		panels->snows = r_list_newf (free);
4565 	}
4566 	RPanel *cur = __get_cur_panel (panels);
4567 	int i, amount = r_num_rand (4);
4568 	if (amount > 0) {
4569 		for (i = 0; i < amount; i++) {
4570 			RPanelsSnow *snow = R_NEW (RPanelsSnow);
4571 			snow->x = r_num_rand (cur->view->pos.w) + cur->view->pos.x;
4572 			snow->y = cur->view->pos.y;
4573 			r_list_append (panels->snows, snow);
4574 		}
4575 	}
4576 	RListIter *iter, *iter2;
4577 	RPanelsSnow *snow;
4578 	r_list_foreach_safe (panels->snows, iter, iter2, snow) {
4579 		int pos = r_num_rand (3) - 1;
4580 		snow->x += pos;
4581 		snow->y++;
4582 		if (snow->x >= cur->view->pos.w + cur->view->pos.x || snow->x <= cur->view->pos.x + 1) {
4583 			r_list_delete (panels->snows, iter);
4584 			continue;
4585 		}
4586 		if (snow->y >= cur->view->pos.h + cur->view->pos.y - 1) {
4587 			r_list_delete (panels->snows, iter);
4588 			continue;
4589 		}
4590 		if (r_cons_canvas_gotoxy (panels->can, snow->x, snow->y)) {
4591 			if (panels->fun == PANEL_FUN_SAKURA) {
4592 				r_cons_canvas_write (panels->can, Color_BMAGENTA","Color_RESET);
4593 			} else {
4594 				r_cons_canvas_write (panels->can, "*");
4595 			}
4596 		}
4597 	}
4598 }
4599 
__set_pcb(RPanel * p)4600 static void __set_pcb(RPanel *p) {
4601 	if (!p->model->cmd) {
4602 		return;
4603 	}
4604 	if (__check_panel_type (p, PANEL_CMD_DISASSEMBLY)) {
4605 		p->model->print_cb = __print_disassembly_cb;
4606 		return;
4607 	}
4608 	if (__check_panel_type (p, PANEL_CMD_STACK)) {
4609 		p->model->print_cb = __print_stack_cb;
4610 		return;
4611 	}
4612 	if (__check_panel_type (p, PANEL_CMD_HEXDUMP)) {
4613 		p->model->print_cb = __print_hexdump_cb;
4614 		return;
4615 	}
4616 	if (__check_panel_type (p, PANEL_CMD_DECOMPILER)) {
4617 		p->model->print_cb = __print_decompiler_cb;
4618 		return;
4619 	}
4620 	if (__check_panel_type (p, PANEL_CMD_GRAPH)) {
4621 		p->model->print_cb = __print_graph_cb;
4622 		return;
4623 	}
4624 	if (__check_panel_type (p, PANEL_CMD_TINYGRAPH)) {
4625 		p->model->print_cb = __print_graph_cb;
4626 		return;
4627 	}
4628 	if (__check_panel_type (p, PANEL_CMD_DISASMSUMMARY)) {
4629 		p->model->print_cb = __print_disasmsummary_cb;
4630 		return;
4631 	}
4632 	p->model->print_cb = __print_default_cb;
4633 }
4634 
__file_history_up(RLine * line)4635 static int __file_history_up(RLine *line) {
4636 	RCore *core = line->user;
4637 	RList *files = r_id_storage_list (core->io->files);
4638 	int num_files = r_list_length (files);
4639 	if (line->file_hist_index >= num_files || line->file_hist_index < 0) {
4640 		return false;
4641 	}
4642 	line->file_hist_index++;
4643 	RIODesc *desc = r_list_get_n (files, num_files - line->file_hist_index);
4644 	if (desc) {
4645 		strncpy (line->buffer.data, desc->name, R_LINE_BUFSIZE - 1);
4646 		line->buffer.index = line->buffer.length = strlen (line->buffer.data);
4647 	}
4648 	r_list_free (files);
4649 	return true;
4650 }
4651 
__file_history_down(RLine * line)4652 static int __file_history_down(RLine *line) {
4653 	RCore *core = line->user;
4654 	RList *files = r_id_storage_list (core->io->files);
4655 	int num_files = r_list_length (files);
4656 	if (line->file_hist_index <= 0 || line->file_hist_index > num_files) {
4657 		return false;
4658 	}
4659 	line->file_hist_index--;
4660 	if (line->file_hist_index <= 0) {
4661 		line->buffer.data[0] = '\0';
4662 		line->buffer.index = line->buffer.length = 0;
4663 		return false;
4664 	}
4665 	RIODesc *desc = r_list_get_n (files, num_files - line->file_hist_index);
4666 	if (desc) {
4667 		strncpy (line->buffer.data, desc->name, R_LINE_BUFSIZE - 1);
4668 		line->buffer.index = line->buffer.length = strlen (line->buffer.data);
4669 	}
4670 	r_list_free (files);
4671 	return true;
4672 }
4673 
4674 
__open_file_cb(void * user)4675 static int __open_file_cb(void *user) {
4676 	RCore *core = (RCore *)user;
4677 	core->cons->line->prompt_type = R_LINE_PROMPT_FILE;
4678 	r_line_set_hist_callback (core->cons->line, &__file_history_up, &__file_history_down);
4679 	__add_cmdf_panel (core, "open file: ", "o %s");
4680 	core->cons->line->prompt_type = R_LINE_PROMPT_DEFAULT;
4681 	r_line_set_hist_callback (core->cons->line, &r_line_hist_cmd_up, &r_line_hist_cmd_down);
4682 	return 0;
4683 }
4684 
__rw_cb(void * user)4685 static int __rw_cb(void *user) {
4686 	RCore *core = (RCore *)user;
4687 	r_core_cmd (core, "oo+", 0);
4688 	return 0;
4689 }
4690 
__debugger_cb(void * user)4691 static int __debugger_cb(void *user) {
4692 	RCore *core = (RCore *)user;
4693 	r_core_cmd (core, "oo", 0);
4694 	return 0;
4695 }
4696 
__settings_decompiler_cb(void * user)4697 static int __settings_decompiler_cb(void *user) {
4698 	RCore *core = (RCore *)user;
4699 	RPanelsRoot *root = core->panels_root;
4700 	RPanelsMenu *menu = core->panels->panels_menu;
4701 	RPanelsMenuItem *parent = menu->history[menu->depth - 1];
4702 	RPanelsMenuItem *child = parent->sub[parent->selectedIndex];
4703 	const char *pdc_next = child->name;
4704 	const char *pdc_now = r_config_get (core->config, "cmd.pdc");
4705 	if (!strcmp (pdc_next, pdc_now)) {
4706 		return 0;
4707 	}
4708 	root->cur_pdc_cache = sdb_ptr_get (root->pdc_caches, pdc_next, 0);
4709 	if (!root->cur_pdc_cache) {
4710 		Sdb *sdb = sdb_new0 ();
4711 		if (sdb) {
4712 			sdb_ptr_set (root->pdc_caches, pdc_next, sdb, 0);
4713 			root->cur_pdc_cache = sdb;
4714 		}
4715 	}
4716 	r_config_set (core->config, "cmd.pdc", pdc_next);
4717 	int j = 0;
4718 	for (j = 0; j < core->panels->n_panels; j++) {
4719 		RPanel *panel = __get_panel (core->panels, j);
4720 		if (!strncmp (panel->model->cmd, "pdc", 3)) {
4721 			char *cmdstr = r_core_cmd_strf (core, "pdc@0x%08"PFMT64x, panel->model->addr);
4722 			__update_panel_contents (core, panel, cmdstr);
4723 			__reset_scroll_pos (panel);
4724 			free (cmdstr);
4725 		}
4726 	}
4727 	__set_refresh_all (core, true, false);
4728 	__set_mode (core, PANEL_MODE_DEFAULT);
4729 	return 0;
4730 }
4731 
__create_default_panels(RCore * core)4732 static void __create_default_panels(RCore *core) {
4733 	RPanels *panels = core->panels;
4734 	panels->n_panels = 0;
4735 	__set_curnode (core, 0);
4736 	const char **panels_list = panels_static;
4737 	if (panels->layout == PANEL_LAYOUT_DEFAULT_DYNAMIC) {
4738 		panels_list = panels_dynamic;
4739 	}
4740 
4741 	int i = 0;
4742 	while (panels_list[i]) {
4743 		RPanel *p = __get_panel (panels, panels->n_panels);
4744 		if (!p) {
4745 			return;
4746 		}
4747 		const char *s = panels_list[i++];
4748 		char *db_val = __search_db (core, s);
4749 		__init_panel_param (core, p, s, db_val);
4750 		free (db_val);
4751 	}
4752 }
4753 
__load_layout_saved_cb(void * user)4754 static int __load_layout_saved_cb(void *user) {
4755 	RCore *core = (RCore *)user;
4756 	RPanelsMenu *menu = core->panels->panels_menu;
4757 	RPanelsMenuItem *parent = menu->history[menu->depth - 1];
4758 	RPanelsMenuItem *child = parent->sub[parent->selectedIndex];
4759 	if (!r_core_panels_load (core, child->name)) {
4760 		__create_default_panels (core);
4761 		__panels_layout (core->panels);
4762 	}
4763 	__set_curnode (core, 0);
4764 	core->panels->panels_menu->depth = 1;
4765 	__set_mode (core, PANEL_MODE_DEFAULT);
4766 	return 0;
4767 }
4768 
__load_layout_default_cb(void * user)4769 static int __load_layout_default_cb(void *user) {
4770 	RCore *core = (RCore *)user;
4771 	__init_panels (core, core->panels);
4772 	__create_default_panels (core);
4773 	__panels_layout (core->panels);
4774 	core->panels->panels_menu->depth = 1;
4775 	__set_mode (core, PANEL_MODE_DEFAULT);
4776 	return 0;
4777 }
4778 
__close_file_cb(void * user)4779 static int __close_file_cb(void *user) {
4780 	RCore *core = (RCore *)user;
4781 	r_core_cmd0 (core, "o-*");
4782 	return 0;
4783 }
4784 
__save_layout_cb(void * user)4785 static int __save_layout_cb(void *user) {
4786 	RCore *core = (RCore *)user;
4787 	r_core_panels_save (core, NULL);
4788 	__set_mode (core, PANEL_MODE_DEFAULT);
4789 	__clear_panels_menu (core);
4790 	__get_cur_panel (core->panels)->view->refresh = true;
4791 	return 0;
4792 }
4793 
__update_menu(RCore * core,const char * parent,R_NULLABLE RPanelMenuUpdateCallback cb)4794 static void __update_menu(RCore *core, const char *parent, R_NULLABLE RPanelMenuUpdateCallback cb) {
4795 	RPanels *panels = core->panels;
4796 	void *addr = ht_pp_find (panels->mht, parent, NULL);
4797 	RPanelsMenuItem *p_item = (RPanelsMenuItem *)addr;
4798 	int i;
4799 	for (i = 0; i < p_item->n_sub; i++) {
4800 		RPanelsMenuItem *sub = p_item->sub[i];
4801 		ht_pp_delete (core->panels->mht, sdb_fmt ("%s.%s", parent, sub->name));
4802 	}
4803 	p_item->sub = NULL;
4804 	p_item->n_sub = 0;
4805 	if (cb) {
4806 		cb (core, parent);
4807 	}
4808 	RPanelsMenu *menu = panels->panels_menu;
4809 	__update_menu_contents (core, menu, p_item);
4810 }
4811 
__get_panels_config_dir_path(void)4812 static char *__get_panels_config_dir_path(void) {
4813 	return r_str_home (R_JOIN_2_PATHS (R2_HOME_DATADIR, ".r2panels"));
4814 }
4815 
__add_menu(RCore * core,const char * parent,const char * name,RPanelsMenuCallback cb)4816 static void __add_menu(RCore *core, const char *parent, const char *name, RPanelsMenuCallback cb) {
4817 	RPanels *panels = core->panels;
4818 	RPanelsMenuItem *p_item, *item = R_NEW0 (RPanelsMenuItem);
4819 	if (!item) {
4820 		return;
4821 	}
4822 	if (parent) {
4823 		void *addr = ht_pp_find (panels->mht, parent, NULL);
4824 		p_item = (RPanelsMenuItem *)addr;
4825 		ht_pp_insert (panels->mht, sdb_fmt ("%s.%s", parent, name), item);
4826 	} else {
4827 		p_item = panels->panels_menu->root;
4828 		ht_pp_insert (panels->mht, sdb_fmt ("%s", name), item);
4829 	}
4830 	item->n_sub = 0;
4831 	item->selectedIndex = 0;
4832 	item->name = name ? r_str_new (name) : NULL;
4833 	item->sub = NULL;
4834 	item->cb = cb;
4835 	item->p = R_NEW0 (RPanel);
4836 	if (item->p) {
4837 		item->p->model = R_NEW0 (RPanelModel);
4838 		item->p->view = R_NEW0 (RPanelView);
4839 		if (item->p->model && item->p->view) {
4840 			p_item->n_sub++;
4841 			RPanelsMenuItem **sub = realloc (p_item->sub, sizeof (RPanelsMenuItem *) * p_item->n_sub);
4842 			if (sub) {
4843 				p_item->sub = sub;
4844 				p_item->sub[p_item->n_sub - 1] = item;
4845 				item = NULL;
4846 			}
4847 		}
4848 	}
4849 	__free_menu_item (item);
4850 }
4851 
__init_menu_saved_layout(void * _core,const char * parent)4852 static void __init_menu_saved_layout (void *_core, const char *parent) {
4853 	char *dir_path = __get_panels_config_dir_path ();
4854 	RList *dir = r_sys_dir (dir_path);
4855 	if (!dir) {
4856 		free (dir_path);
4857 		return;
4858 	}
4859 	RCore *core = (RCore *)_core;
4860 	RListIter *it;
4861 	char *entry;
4862 	r_list_foreach (dir, it, entry) {
4863 		if (strcmp (entry, ".") && strcmp (entry, "..")) {
4864 			__add_menu (core, parent, entry, __load_layout_saved_cb);
4865 		}
4866 	}
4867 	r_list_free (dir);
4868 	free (dir_path);
4869 }
4870 
__clear_layout_cb(void * user)4871 static int __clear_layout_cb(void *user) {
4872 	RCore *core = (RCore *)user;
4873 	if (!__show_status_yesno (core, 0, "Clear all the saved layouts?(y/n): ")) {
4874 		return 0;
4875 	}
4876 	char *dir_path = __get_panels_config_dir_path ();
4877 	RList *dir = r_sys_dir ((const char *)dir_path);
4878 	if (!dir) {
4879 		free (dir_path);
4880 		return 0;
4881 	}
4882 	RListIter *it;
4883 	char *entry;
4884 	r_list_foreach (dir, it, entry) {
4885 		char *tmp = r_str_newf ("%s%s%s", dir_path, R_SYS_DIR, entry);
4886 		r_file_rm (tmp);
4887 		free (tmp);
4888 	}
4889 	r_file_rm (dir_path);
4890 	r_list_free (dir);
4891 	free (dir_path);
4892 
4893 	__update_menu (core, "File.Load Layout.Saved", __init_menu_saved_layout);
4894 	return 0;
4895 }
4896 
__copy_cb(void * user)4897 static int __copy_cb(void *user) {
4898 	RCore *core = (RCore *)user;
4899 	__add_cmdf_panel (core, "How many bytes? ", "\"y %s\"");
4900 	return 0;
4901 }
4902 
__paste_cb(void * user)4903 static int __paste_cb(void *user) {
4904 	RCore *core = (RCore *)user;
4905 	r_core_cmd0 (core, "yy");
4906 	return 0;
4907 }
4908 
__write_str_cb(void * user)4909 static int __write_str_cb(void *user) {
4910 	RCore *core = (RCore *)user;
4911 	__add_cmdf_panel (core, "insert string: ", "\"w %s\"");
4912 	return 0;
4913 }
4914 
__write_hex_cb(void * user)4915 static int __write_hex_cb(void *user) {
4916 	RCore *core = (RCore *)user;
4917 	__add_cmdf_panel (core, "insert hexpairs: ", "\"wx %s\"");
4918 	return 0;
4919 }
4920 
__assemble_cb(void * user)4921 static int __assemble_cb(void *user) {
4922 	RCore *core = (RCore *)user;
4923 	r_core_visual_asm (core, core->offset);
4924 	return 0;
4925 }
4926 
__fill_cb(void * user)4927 static int __fill_cb(void *user) {
4928 	RCore *core = (RCore *)user;
4929 	__add_cmdf_panel (core, "Fill with: ", "wow %s");
4930 	return 0;
4931 }
4932 
__settings_colors_cb(void * user)4933 static int __settings_colors_cb(void *user) {
4934 	RCore *core = (RCore *)user;
4935 	RPanelsMenu *menu = core->panels->panels_menu;
4936 	RPanelsMenuItem *parent = menu->history[menu->depth - 1];
4937 	RPanelsMenuItem *child = parent->sub[parent->selectedIndex];
4938 	r_str_ansi_filter (child->name, NULL, NULL, -1);
4939 	r_core_cmdf (core, "eco %s", child->name);
4940 	int i;
4941 	for (i = 1; i < menu->depth; i++) {
4942 		RPanel *p = menu->history[i]->p;
4943 		p->view->refresh = true;
4944 		menu->refreshPanels[i - 1] = p;
4945 	}
4946 	__update_menu(core, "Settings.Colors", __init_menu_color_settings_layout);
4947 	return 0;
4948 }
4949 
__config_value_cb(void * user)4950 static int __config_value_cb(void *user) {
4951 	RCore *core = (RCore *)user;
4952 	RPanelsMenu *menu = core->panels->panels_menu;
4953 	RPanelsMenuItem *parent = menu->history[menu->depth - 1];
4954 	RPanelsMenuItem *child = parent->sub[parent->selectedIndex];
4955 	RStrBuf *tmp = r_strbuf_new (child->name);
4956 	(void)r_str_split (r_strbuf_get(tmp), ':');
4957 	const char *v = __show_status_input (core, "New value: ");
4958 	r_config_set (core->config, r_strbuf_get (tmp), v);
4959 	r_strbuf_free (tmp);
4960 	free (parent->p->model->title);
4961 	parent->p->model->title = r_strbuf_drain (__draw_menu (core, parent));
4962 	size_t i;
4963 	for (i = 1; i < menu->depth; i++) {
4964 		RPanel *p = menu->history[i]->p;
4965 		p->view->refresh = true;
4966 		menu->refreshPanels[i - 1] = p;
4967 	}
4968 	if (!strcmp (parent->name, "asm")) {
4969 		__update_menu (core, "Settings.Disassembly.asm", __init_menu_disasm_asm_settings_layout);
4970 	}
4971 	if (!strcmp (parent->name, "Screen")) {
4972 		__update_menu (core, "Settings.Screen", __init_menu_screen_settings_layout);
4973 	}
4974 	return 0;
4975 }
4976 
__config_toggle_cb(void * user)4977 static int __config_toggle_cb(void *user) {
4978 	RCore *core = (RCore *)user;
4979 	RPanelsMenu *menu = core->panels->panels_menu;
4980 	RPanelsMenuItem *parent = menu->history[menu->depth - 1];
4981 	RPanelsMenuItem *child = parent->sub[parent->selectedIndex];
4982 	RStrBuf *tmp = r_strbuf_new (child->name);
4983 	(void)r_str_split (r_strbuf_get (tmp), ':');
4984 	r_config_toggle (core->config, r_strbuf_get (tmp));
4985 	r_strbuf_free (tmp);
4986 	free (parent->p->model->title);
4987 	parent->p->model->title = r_strbuf_drain (__draw_menu (core, parent));
4988 	size_t i;
4989 	for (i = 1; i < menu->depth; i++) {
4990 		RPanel *p = menu->history[i]->p;
4991 		p->view->refresh = true;
4992 		menu->refreshPanels[i - 1] = p;
4993 	}
4994 	if (!strcmp (parent->name, "asm")) {
4995 		__update_menu (core, "Settings.Disassembly.asm", __init_menu_disasm_asm_settings_layout);
4996 	}
4997 	if (!strcmp (parent->name, "Screen")) {
4998 		__update_menu (core, "Settings.Screen", __init_menu_screen_settings_layout);
4999 	}
5000 	return 0;
5001 }
5002 
__init_menu_screen_settings_layout(void * _core,const char * parent)5003 static void __init_menu_screen_settings_layout(void *_core, const char *parent) {
5004 	RCore *core = (RCore *)_core;
5005 	RStrBuf *rsb = r_strbuf_new (NULL);
5006 	int i = 0;
5007 	while (menus_settings_screen[i]) {
5008 		const char *menu = menus_settings_screen[i];
5009 		r_strbuf_set (rsb, menu);
5010 		r_strbuf_append (rsb, ": ");
5011 		r_strbuf_append (rsb, r_config_get (core->config, menu));
5012 		if (!strcmp (menus_settings_screen[i], "scr.color")) {
5013 			__add_menu (core, parent, r_strbuf_get (rsb), __config_value_cb);
5014 		} else {
5015 			__add_menu (core, parent, r_strbuf_get (rsb), __config_toggle_cb);
5016 		}
5017 		i++;
5018 	}
5019 	r_strbuf_free (rsb);
5020 }
5021 
__calculator_cb(void * user)5022 static int __calculator_cb(void *user) {
5023 	RCore *core = (RCore *)user;
5024 	for (;;) {
5025 		char *s = __show_status_input (core, "> ");
5026 		if (!s || !*s) {
5027 			free (s);
5028 			break;
5029 		}
5030 		r_core_cmdf (core, "? %s", s);
5031 		r_cons_flush ();
5032 		free (s);
5033 	}
5034 	return 0;
5035 }
5036 
__r2_shell_cb(void * user)5037 static int __r2_shell_cb(void *user) {
5038 	RCore *core = (RCore *)user;
5039 	core->vmode = false;
5040 	r_core_visual_prompt_input (core);
5041 	core->vmode = true;
5042 	return 0;
5043 }
5044 
__system_shell_cb(void * user)5045 static int __system_shell_cb(void *user) {
5046 	r_cons_set_raw (0);
5047 	r_cons_flush ();
5048 	r_sys_cmd ("$SHELL");
5049 	return 0;
5050 }
5051 
__string_whole_bin_cb(void * user)5052 static int __string_whole_bin_cb(void *user) {
5053 	RCore *core = (RCore *)user;
5054 	__add_cmdf_panel (core, "search strings in the whole binary: ", "izzq~%s");
5055 	return 0;
5056 }
5057 
__string_data_sec_cb(void * user)5058 static int __string_data_sec_cb(void *user) {
5059 	RCore *core = (RCore *)user;
5060 	__add_cmdf_panel (core, "search string in data sections: ", "izq~%s");
5061 	return 0;
5062 }
5063 
__rop_cb(void * user)5064 static int __rop_cb(void *user) {
5065 	RCore *core = (RCore *)user;
5066 	__add_cmdf_panel (core, "rop grep: ", "\"/R %s\"");
5067 	return 0;
5068 }
5069 
__code_cb(void * user)5070 static int __code_cb(void *user) {
5071 	RCore *core = (RCore *)user;
5072 	__add_cmdf_panel (core, "search code: ", "\"/c %s\"");
5073 	return 0;
5074 }
5075 
__hexpairs_cb(void * user)5076 static int __hexpairs_cb(void *user) {
5077 	RCore *core = (RCore *)user;
5078 	__add_cmdf_panel (core, "search hexpairs: ", "\"/x %s\"");
5079 	return 0;
5080 }
5081 
__esil_init(RCore * core)5082 static void __esil_init(RCore *core) {
5083 	r_core_cmd (core, "aeim", 0);
5084 	r_core_cmd (core, "aeip", 0);
5085 }
5086 
__esil_step_to(RCore * core,ut64 end)5087 static void __esil_step_to(RCore *core, ut64 end) {
5088 	r_core_cmdf (core, "aesu 0x%08"PFMT64x, end);
5089 }
5090 
5091 
__esil_init_cb(void * user)5092 static int __esil_init_cb(void *user) {
5093 	RCore *core = (RCore *)user;
5094 	__esil_init (core);
5095 	return 0;
5096 }
5097 
__esil_step_to_cb(void * user)5098 static int __esil_step_to_cb(void *user) {
5099 	RCore *core = (RCore *)user;
5100 	char *end = __show_status_input (core, "target addr: ");
5101 	__esil_step_to (core, r_num_math (core->num, end));
5102 	return 0;
5103 }
5104 
__esil_step_range_cb(void * user)5105 static int __esil_step_range_cb(void *user) {
5106 	RStrBuf *rsb = r_strbuf_new (NULL);
5107 	RCore *core = (RCore *)user;
5108 	r_strbuf_append (rsb, "start addr: ");
5109 	char *s = __show_status_input (core, r_strbuf_get (rsb));
5110 	r_strbuf_append (rsb, s);
5111 	r_strbuf_append (rsb, " end addr: ");
5112 	char *d = __show_status_input (core, r_strbuf_get (rsb));
5113 	r_strbuf_free (rsb);
5114 	ut64 s_a = r_num_math (core->num, s);
5115 	ut64 d_a = r_num_math (core->num, d);
5116 	if (s_a >= d_a) {
5117 		return 0;
5118 	}
5119 	ut64 tmp = core->offset;
5120 	core->offset = s_a;
5121 	__esil_init (core);
5122 	__esil_step_to (core, d_a);
5123 	core->offset = tmp;
5124 	return 0;
5125 }
5126 
__io_cache_on_cb(void * user)5127 static int __io_cache_on_cb(void *user) {
5128 	RCore *core = (RCore *)user;
5129 	r_config_set_b (core->config, "io.cache", true);
5130 	(void)__show_status (core, "io.cache is on");
5131 	__set_mode (core, PANEL_MODE_DEFAULT);
5132 	return 0;
5133 }
5134 
__io_cache_off_cb(void * user)5135 static int __io_cache_off_cb(void *user) {
5136 	RCore *core = (RCore *)user;
5137 	r_config_set_b (core->config, "io.cache", false);
5138 	(void)__show_status (core, "io.cache is off");
5139 	__set_mode (core, PANEL_MODE_DEFAULT);
5140 	return 0;
5141 }
5142 
__reload_cb(void * user)5143 static int __reload_cb(void *user) {
5144 	RCore *core = (RCore *)user;
5145 	r_core_file_reopen_debug (core, "");
5146 	__update_disassembly_or_open (core);
5147 	return 0;
5148 }
5149 
__function_cb(void * user)5150 static int __function_cb(void *user) {
5151 	RCore *core = (RCore *)user;
5152 	r_core_cmdf (core, "af");
5153 	return 0;
5154 }
5155 
__symbols_cb(void * user)5156 static int __symbols_cb(void *user) {
5157 	RCore *core = (RCore *)user;
5158 	r_core_cmdf (core, "aa");
5159 	return 0;
5160 }
5161 
__program_cb(void * user)5162 static int __program_cb(void *user) {
5163 	RCore *core = (RCore *)user;
5164 	r_core_cmdf (core, "aaa");
5165 	return 0;
5166 }
5167 
__basic_blocks_cb(void * user)5168 static int __basic_blocks_cb(void *user) {
5169 	RCore *core = (RCore *)user;
5170 	r_core_cmdf (core, "aab");
5171 	return 0;
5172 }
5173 
__calls_cb(void * user)5174 static int __calls_cb(void *user) {
5175 	RCore *core = (RCore *)user;
5176 	r_core_cmdf (core, "aac");
5177 	return 0;
5178 }
5179 
__watch_points_cb(void * user)5180 static int __watch_points_cb(void *user) {
5181 	RCore *core = (RCore *)user;
5182 	char addrBuf[128], rw[128];
5183 	const char *addrPrompt = "addr: ", *rwPrompt = "<r/w/rw>: ";
5184 	__panel_prompt (addrPrompt, addrBuf, sizeof (addrBuf));
5185 	__panel_prompt (rwPrompt, rw, sizeof (rw));
5186 	ut64 addr = r_num_math (core->num, addrBuf);
5187 	r_core_cmdf (core, "dbw 0x%08"PFMT64x" %s", addr, rw);
5188 	return 0;
5189 }
5190 
__references_cb(void * user)5191 static int __references_cb(void *user) {
5192 	RCore *core = (RCore *)user;
5193 	r_core_cmdf (core, "aar");
5194 	return 0;
5195 }
5196 
__fortune_cb(void * user)5197 static int __fortune_cb(void *user) {
5198 	RCore *core = (RCore *)user;
5199 	char *s = r_core_cmd_str (core, "fo");
5200 	r_cons_message (s);
5201 	free (s);
5202 	return 0;
5203 }
5204 
__game_cb(void * user)5205 static int __game_cb(void *user) {
5206 	RCore *core = (RCore *)user;
5207 	r_cons_2048 (core->panels->can->color);
5208 	return 0;
5209 }
5210 
__help_cb(void * user)5211 static int __help_cb(void *user) {
5212 	RCore *core = (RCore *)user;
5213 	__toggle_help (core);
5214 	return 0;
5215 }
5216 
__license_cb(void * user)5217 static int __license_cb(void *user) {
5218 	r_cons_message ("Copyright 2006-2020 - pancake - LGPL");
5219 	return 0;
5220 }
5221 
__version_cb(void * user)5222 static int __version_cb(void *user) {
5223 	RCore *core = (RCore *)user;
5224 	char *s = r_core_cmd_str (core, "?V");
5225 	r_cons_message (s);
5226 	free (s);
5227 	return 0;
5228 }
5229 
__writeValueCb(void * user)5230 static int __writeValueCb(void *user) {
5231 	RCore *core = (RCore *)user;
5232 	char *res = __show_status_input (core, "insert number: ");
5233 	if (res) {
5234 		r_core_cmdf (core, "\"wv %s\"", res);
5235 		free (res);
5236 	}
5237 	return 0;
5238 }
5239 
__quit_cb(void * user)5240 static int __quit_cb(void *user) {
5241 	__set_root_state ((RCore *)user, QUIT);
5242 	return 0;
5243 }
5244 
__open_menu_cb(void * user)5245 static int __open_menu_cb (void *user) {
5246 	RCore* core = (RCore *)user;
5247 	RPanelsMenu *menu = core->panels->panels_menu;
5248 	RPanelsMenuItem *parent = menu->history[menu->depth - 1];
5249 	RPanelsMenuItem *child = parent->sub[parent->selectedIndex];
5250 	if (menu->depth < 2) {
5251 		__set_pos (&child->p->view->pos, menu->root->selectedIndex * 6, 1);
5252 	} else {
5253 		RPanelsMenuItem *p = menu->history[menu->depth - 2];
5254 		RPanelsMenuItem *parent2 = p->sub[p->selectedIndex];
5255 		__set_pos (&child->p->view->pos, parent2->p->view->pos.x + parent2->p->view->pos.w - 1,
5256 				menu->depth == 2 ? parent2->p->view->pos.y + parent2->selectedIndex : parent2->p->view->pos.y);
5257 	}
5258 	RStrBuf *buf = __draw_menu (core, child);
5259 	if (!buf) {
5260 		return 0;
5261 	}
5262 	free (child->p->model->title);
5263 	child->p->model->title = r_strbuf_drain (buf);
5264 	child->p->view->pos.w = r_str_bounds (child->p->model->title, &child->p->view->pos.h);
5265 	child->p->view->pos.h += 4;
5266 	child->p->model->type = PANEL_TYPE_MENU;
5267 	child->p->view->refresh = true;
5268 	menu->refreshPanels[menu->n_refresh++] = child->p;
5269 	menu->history[menu->depth++] = child;
5270 	return 0;
5271 }
5272 
cmpstr(const void * _a,const void * _b)5273 static int cmpstr(const void *_a, const void *_b) {
5274 	char *a = (char *)_a, *b = (char *)_b;
5275 	return strcmp (a, b);
5276 }
5277 
__sorted_list(RCore * core,const char * menu[],int count)5278 static RList *__sorted_list(RCore *core, const char *menu[], int count) {
5279 	RList *list = r_list_newf (NULL);
5280 	int i;
5281 	for (i = 0; i < count; i++) {
5282 		if (menu[i]) {
5283 			(void)r_list_append (list, (void *)menu[i]);
5284 		}
5285 	}
5286 	r_list_sort (list, cmpstr);
5287 	return list;
5288 }
5289 
__init_menu_color_settings_layout(void * _core,const char * parent)5290 static void __init_menu_color_settings_layout (void *_core, const char *parent) {
5291 	RCore *core = (RCore *)_core;
5292 	const char *color = core->cons->context->pal.graph_box2;
5293 	char *now = r_core_cmd_str (core, "eco.");
5294 	r_str_split (now, '\n');
5295 	parent = "Settings.Colors";
5296 	RList *list = __sorted_list (core, (const char **)menus_Colors, COUNT (menus_Colors));
5297 	char *pos;
5298 	RListIter* iter;
5299 	RStrBuf *buf = r_strbuf_new (NULL);
5300 	r_list_foreach (list, iter, pos) {
5301 		if (pos && !strcmp (now, pos)) {
5302 			r_strbuf_setf (buf, "%s%s", color, pos);
5303 			__add_menu (core, parent, r_strbuf_get (buf), __settings_colors_cb);
5304 			continue;
5305 		}
5306 		__add_menu (core, parent, pos, __settings_colors_cb);
5307 	}
5308 	free (now);
5309 	r_list_free (list);
5310 	r_strbuf_free (buf);
5311 }
5312 
__init_menu_disasm_settings_layout(void * _core,const char * parent)5313 static void __init_menu_disasm_settings_layout (void *_core, const char *parent) {
5314 	RCore *core = (RCore *)_core;
5315 	int i = 0;
5316 	RList *list = __sorted_list (core, menus_settings_disassembly, COUNT (menus_settings_disassembly));
5317 	char *pos;
5318 	RListIter* iter;
5319 	RStrBuf *rsb = r_strbuf_new (NULL);
5320 	r_list_foreach (list, iter, pos) {
5321 		if (!strcmp (pos, "asm")) {
5322 			__add_menu (core, parent, pos, __open_menu_cb);
5323 			__init_menu_disasm_asm_settings_layout (core, "Settings.Disassembly.asm");
5324 		} else {
5325 			r_strbuf_set (rsb, pos);
5326 			r_strbuf_append (rsb, ": ");
5327 			r_strbuf_append (rsb, r_config_get (core->config, pos));
5328 			__add_menu (core, parent, r_strbuf_get (rsb), __config_toggle_cb);
5329 		}
5330 		i++;
5331 	}
5332 	r_list_free (list);
5333 	r_strbuf_free (rsb);
5334 }
5335 
__init_menu_disasm_asm_settings_layout(void * _core,const char * parent)5336 static void __init_menu_disasm_asm_settings_layout(void *_core, const char *parent) {
5337 	RCore *core = (RCore *)_core;
5338 	RList *list = __sorted_list (core, menus_settings_disassembly_asm, COUNT (menus_settings_disassembly_asm));
5339 	char *pos;
5340 	RListIter* iter;
5341 	RStrBuf *rsb = r_strbuf_new (NULL);
5342 	r_list_foreach (list, iter, pos) {
5343 		r_strbuf_set (rsb, pos);
5344 		r_strbuf_append (rsb, ": ");
5345 		r_strbuf_append (rsb, r_config_get (core->config, pos));
5346 		if (!strcmp (pos, "asm.var.summary") ||
5347 				!strcmp (pos, "asm.arch") ||
5348 				!strcmp (pos, "asm.bits") ||
5349 				!strcmp (pos, "asm.cpu")) {
5350 			__add_menu (core, parent, r_strbuf_get (rsb), __config_value_cb);
5351 		} else {
5352 			__add_menu (core, parent, r_strbuf_get (rsb), __config_toggle_cb);
5353 		}
5354 	}
5355 	r_list_free (list);
5356 	r_strbuf_free (rsb);
5357 }
5358 
__load_config_menu(RCore * core)5359 static void __load_config_menu(RCore *core) {
5360 	RList *themes_list = r_core_list_themes (core);
5361 	RListIter *th_iter;
5362 	char *th;
5363 	int i = 0;
5364 	r_list_foreach (themes_list, th_iter, th) {
5365 		menus_Colors[i++] = th;
5366 	}
5367 }
5368 
__init_panels_menu(RCore * core)5369 static bool __init_panels_menu(RCore *core) {
5370 	RPanels *panels = core->panels;
5371 	RPanelsMenu *panels_menu = R_NEW0 (RPanelsMenu);
5372 	if (!panels_menu) {
5373 		return false;
5374 	}
5375 	RPanelsMenuItem *root = R_NEW0 (RPanelsMenuItem);
5376 	if (!root) {
5377 		R_FREE (panels_menu);
5378 		return false;
5379 	}
5380 	panels->panels_menu = panels_menu;
5381 	panels_menu->root = root;
5382 	root->n_sub = 0;
5383 	root->name = NULL;
5384 	root->sub = NULL;
5385 
5386 	__load_config_menu (core);
5387 
5388 	int i = 0;
5389 	while (menus[i]) {
5390 		__add_menu (core, NULL, menus[i], __open_menu_cb);
5391 		i++;
5392 	}
5393 	char *parent = "File";
5394 	i = 0;
5395 	while (menus_File[i]) {
5396 		if (!strcmp (menus_File[i], "Open")) {
5397 			__add_menu (core, parent, menus_File[i], __open_file_cb);
5398 		} else if (!strcmp (menus_File[i], "ReOpen")) {
5399 			__add_menu (core, parent, menus_File[i], __open_menu_cb);
5400 		} else if (!strcmp (menus_File[i], "Close")) {
5401 			__add_menu (core, parent, menus_File[i], __close_file_cb);
5402 		} else if (!strcmp (menus_File[i], "Save Layout")) {
5403 			__add_menu (core, parent, menus_File[i], __save_layout_cb);
5404 		} else if (!strcmp (menus_File[i], "Load Layout")) {
5405 			__add_menu (core, parent, menus_File[i], __open_menu_cb);
5406 		} else if (!strcmp (menus_File[i], "Clear Saved Layouts")) {
5407 			__add_menu (core, parent, menus_File[i], __clear_layout_cb);
5408 		} else if (!strcmp (menus_File[i], "Quit")) {
5409 			__add_menu (core, parent, menus_File[i], __quit_cb);
5410 		} else {
5411 			__add_menu (core, parent, menus_File[i], __add_cmd_panel);
5412 		}
5413 		i++;
5414 	}
5415 
5416 	parent = "Settings";
5417 	i = 0;
5418 	while (menus_Settings[i]) {
5419 		__add_menu (core, parent, menus_Settings[i++], __open_menu_cb);
5420 	}
5421 
5422 	parent = "Edit";
5423 	i = 0;
5424 	while (menus_Edit[i]) {
5425 		if (!strcmp (menus_Edit[i], "Copy")) {
5426 			__add_menu (core, parent, menus_Edit[i], __copy_cb);
5427 		} else if (!strcmp (menus_Edit[i], "Paste")) {
5428 			__add_menu (core, parent, menus_Edit[i], __paste_cb);
5429 		} else if (!strcmp (menus_Edit[i], "Write String")) {
5430 			__add_menu (core, parent, menus_Edit[i], __write_str_cb);
5431 		} else if (!strcmp (menus_Edit[i], "Write Hex")) {
5432 			__add_menu (core, parent, menus_Edit[i], __write_hex_cb);
5433 		} else if (!strcmp (menus_Edit[i], "Write Value")) {
5434 			__add_menu (core, parent, menus_Edit[i], __writeValueCb);
5435 		} else if (!strcmp (menus_Edit[i], "Assemble")) {
5436 			__add_menu (core, parent, menus_Edit[i], __assemble_cb);
5437 		} else if (!strcmp (menus_Edit[i], "Fill")) {
5438 			__add_menu (core, parent, menus_Edit[i], __fill_cb);
5439 		} else if (!strcmp (menus_Edit[i], "io.cache")) {
5440 			__add_menu (core, parent, menus_Edit[i], __open_menu_cb);
5441 		} else {
5442 			__add_menu (core, parent, menus_Edit[i], __add_cmd_panel);
5443 		}
5444 		i++;
5445 	}
5446 
5447 	{
5448 		parent = "View";
5449 		i = 0;
5450 		RList *list = __sorted_list (core, menus_View, COUNT (menus_View));
5451 		char *pos;
5452 		RListIter* iter;
5453 		r_list_foreach (list, iter, pos) {
5454 			if (!strcmp (pos, PANEL_TITLE_ALL_DECOMPILER)) {
5455 				__add_menu (core, parent, pos, __show_all_decompiler_cb);
5456 			} else {
5457 				__add_menu (core, parent, pos, __add_cmd_panel);
5458 			}
5459 		}
5460 	}
5461 
5462 	parent = "Tools";
5463 	i = 0;
5464 	while (menus_Tools[i]) {
5465 		if (!strcmp (menus_Tools[i], "Calculator")) {
5466 			__add_menu (core, parent, menus_Tools[i], __calculator_cb);
5467 		} else if (!strcmp (menus_Tools[i], "R2 Shell")) {
5468 			__add_menu (core, parent, menus_Tools[i], __r2_shell_cb);
5469 		} else if (!strcmp (menus_Tools[i], "System Shell")) {
5470 			__add_menu (core, parent, menus_Tools[i], __system_shell_cb);
5471 		}
5472 		i++;
5473 	}
5474 
5475 	parent = "Search";
5476 	i = 0;
5477 	while (menus_Search[i]) {
5478 		if (!strcmp (menus_Search[i], "String (Whole Bin)")) {
5479 			__add_menu (core, parent, menus_Search[i], __string_whole_bin_cb);
5480 		} else if (!strcmp (menus_Search[i], "String (Data Sections)")) {
5481 			__add_menu (core, parent, menus_Search[i], __string_data_sec_cb);
5482 		} else if (!strcmp (menus_Search[i], "ROP")) {
5483 			__add_menu (core, parent, menus_Search[i], __rop_cb);
5484 		} else if (!strcmp (menus_Search[i], "Code")) {
5485 			__add_menu (core, parent, menus_Search[i], __code_cb);
5486 		} else if (!strcmp (menus_Search[i], "Hexpairs")) {
5487 			__add_menu (core, parent, menus_Search[i], __hexpairs_cb);
5488 		}
5489 		i++;
5490 	}
5491 
5492 	parent = "Emulate";
5493 	i = 0;
5494 	while (menus_Emulate[i]) {
5495 		if (!strcmp (menus_Emulate[i], "Step From")) {
5496 			__add_menu (core, parent, menus_Emulate[i], __esil_init_cb);
5497 		} else if (!strcmp (menus_Emulate[i], "Step To")) {
5498 			__add_menu (core, parent, menus_Emulate[i], __esil_step_to_cb);
5499 		} else if (!strcmp (menus_Emulate[i], "Step Range")) {
5500 			__add_menu (core, parent, menus_Emulate[i], __esil_step_range_cb);
5501 		}
5502 		i++;
5503 	}
5504 
5505 	{
5506 		parent = "Debug";
5507 		i = 0;
5508 		RList *list = __sorted_list (core, menus_Debug, COUNT (menus_Debug));
5509 		char *pos;
5510 		RListIter* iter;
5511 		r_list_foreach (list, iter, pos) {
5512 			if (!strcmp (pos, "Breakpoints")) {
5513 				__add_menu (core, parent, pos, __break_points_cb);
5514 			} else if (!strcmp (pos, "Watchpoints")) {
5515 				__add_menu (core, parent, pos, __watch_points_cb);
5516 			} else if (!strcmp (pos, "Continue")) {
5517 				__add_menu (core, parent, pos, __continue_cb);
5518 			} else if (!strcmp (pos, "Step")) {
5519 				__add_menu (core, parent, pos, __step_cb);
5520 			} else if (!strcmp (pos, "Step Over")) {
5521 				__add_menu (core, parent, pos, __step_over_cb);
5522 			} else if (!strcmp (pos, "Reload")) {
5523 				__add_menu (core, parent, pos, __reload_cb);
5524 			} else {
5525 				__add_menu (core, parent, pos, __add_cmd_panel);
5526 			}
5527 		}
5528 	}
5529 
5530 	parent = "Analyze";
5531 	i = 0;
5532 	while (menus_Analyze[i]) {
5533 		if (!strcmp (menus_Analyze[i], "Function")) {
5534 			__add_menu (core, parent, menus_Analyze[i], __function_cb);
5535 		} else if (!strcmp (menus_Analyze[i], "Symbols")) {
5536 			__add_menu (core, parent, menus_Analyze[i], __symbols_cb);
5537 		} else if (!strcmp (menus_Analyze[i], "Program")) {
5538 			__add_menu (core, parent, menus_Analyze[i], __program_cb);
5539 		} else if (!strcmp (menus_Analyze[i], "BasicBlocks")) {
5540 			__add_menu (core, parent, menus_Analyze[i], __basic_blocks_cb);
5541 		} else if (!strcmp (menus_Analyze[i], "Calls")) {
5542 			__add_menu (core, parent, menus_Analyze[i], __calls_cb);
5543 		} else if (!strcmp (menus_Analyze[i], "References")) {
5544 			__add_menu (core, parent, menus_Analyze[i], __references_cb);
5545 		}
5546 		i++;
5547 	}
5548 	parent = "Help";
5549 	i = 0;
5550 	while (menus_Help[i]) {
5551 		if (!strcmp (menus_Help[i], "License")) {
5552 			__add_menu (core, parent, menus_Help[i], __license_cb);
5553 		} else if (!strcmp (menus_Help[i], "Version")) {
5554 			__add_menu (core, parent, menus_Help[i], __version_cb);
5555 		} else if (!strcmp (menus_Help[i], "Fortune")) {
5556 			__add_menu (core, parent, menus_Help[i], __fortune_cb);
5557 		} else if (!strcmp (menus_Help[i], "2048")) {
5558 			__add_menu (core, parent, menus_Help[i], __game_cb);
5559 		} else {
5560 			__add_menu (core, parent, menus_Help[i], __help_cb);
5561 		}
5562 		i++;
5563 	}
5564 
5565 	parent = "File.ReOpen";
5566 	i = 0;
5567 	while (menus_ReOpen[i]) {
5568 		if (!strcmp (menus_ReOpen[i], "In RW")) {
5569 			__add_menu (core, parent, menus_ReOpen[i], __rw_cb);
5570 		} else if (!strcmp (menus_ReOpen[i], "In Debugger")) {
5571 			__add_menu (core, parent, menus_ReOpen[i], __debugger_cb);
5572 		}
5573 		i++;
5574 	}
5575 
5576 	parent = "File.Load Layout";
5577 	i = 0;
5578 	while (menus_loadLayout[i]) {
5579 		if (!strcmp (menus_loadLayout[i], "Saved")) {
5580 			__add_menu (core, parent, menus_loadLayout[i], __open_menu_cb);
5581 		} else if (!strcmp (menus_loadLayout[i], "Default")) {
5582 			__add_menu (core, parent, menus_loadLayout[i], __load_layout_default_cb);
5583 		}
5584 		i++;
5585 	}
5586 
5587 	__init_menu_saved_layout (core, "File.Load Layout.Saved");
5588 
5589 	__init_menu_color_settings_layout (core, "Settings.Colors");
5590 
5591 	{
5592 		parent = "Settings.Decompiler";
5593 		char *opts = r_core_cmd_str (core, "e cmd.pdc=?");
5594 		RList *optl = r_str_split_list (opts, "\n", 0);
5595 		RListIter *iter;
5596 		char *opt;
5597 		r_list_foreach (optl, iter, opt) {
5598 			__add_menu (core, parent, strdup (opt), __settings_decompiler_cb);
5599 		}
5600 		r_list_free (optl);
5601 		free (opts);
5602 	}
5603 
5604 	__init_menu_disasm_settings_layout (core, "Settings.Disassembly");
5605 	__init_menu_screen_settings_layout (core, "Settings.Screen");
5606 
5607 	parent = "Edit.io.cache";
5608 	i = 0;
5609 	while (menus_iocache[i]) {
5610 		if (!strcmp (menus_iocache[i], "On")) {
5611 			__add_menu (core, parent, menus_iocache[i], __io_cache_on_cb);
5612 		} else if (!strcmp (menus_iocache[i], "Off")) {
5613 			__add_menu (core, parent, menus_iocache[i], __io_cache_off_cb);
5614 		}
5615 		i++;
5616 	}
5617 
5618 	panels_menu->history = calloc (8, sizeof (RPanelsMenuItem *));
5619 	__clear_panels_menu (core);
5620 	panels_menu->refreshPanels = calloc (8, sizeof (RPanel *));
5621 	return true;
5622 }
5623 
__init_panels(RCore * core,RPanels * panels)5624 static bool __init_panels(RCore *core, RPanels *panels) {
5625 	panels->panel = calloc (sizeof (RPanel *), PANEL_NUM_LIMIT);
5626 	if (!panels->panel) {
5627 		return false;
5628 	}
5629 	int i;
5630 	for (i = 0; i < PANEL_NUM_LIMIT; i++) {
5631 		panels->panel[i] = R_NEW0 (RPanel);
5632 		panels->panel[i]->model = R_NEW0 (RPanelModel);
5633 		__renew_filter (panels->panel[i], PANEL_NUM_LIMIT);
5634 		panels->panel[i]->view = R_NEW0 (RPanelView);
5635 		if (!panels->panel[i]->model || !panels->panel[i]->view) {
5636 			return false;
5637 		}
5638 	}
5639 	return true;
5640 }
5641 
__refresh_core_offset(RCore * core)5642 static void __refresh_core_offset (RCore *core) {
5643 	RPanels *panels = core->panels;
5644 	RPanel *cur = __get_cur_panel (panels);
5645 	if (__check_panel_type (cur, PANEL_CMD_DISASSEMBLY)) {
5646 		core->offset = cur->model->addr;
5647 	}
5648 }
5649 
demo_begin(RCore * core,RConsCanvas * can)5650 static void demo_begin(RCore *core, RConsCanvas *can) {
5651 	char *s = r_cons_canvas_to_string (can);
5652 	if (s) {
5653 		// TODO drop utf8!!
5654 		r_str_ansi_filter (s, NULL, NULL, -1);
5655 		int i, h, w = r_cons_get_size (&h);
5656 		for (i = 0; i < 40; i+= (1 + (i/30))) {
5657 			int H = i * ((double)h / 40);
5658 			char *r = r_str_scale (s, w, H);
5659 			r_cons_clear00 ();
5660 			r_cons_gotoxy (0, (h / 2) - (H / 2));
5661 			r_cons_strcat (r);
5662 			r_cons_flush ();
5663 			free (r);
5664 			r_sys_usleep (3000);
5665 		}
5666 		free (s);
5667 	}
5668 }
5669 
demo_end(RCore * core,RConsCanvas * can)5670 static void demo_end(RCore *core, RConsCanvas *can) {
5671 	bool utf8 = r_config_get_i (core->config, "scr.utf8");
5672 	r_config_set_b (core->config, "scr.utf8", false);
5673 	RPanel *cur = __get_cur_panel (core->panels);
5674 	cur->view->refresh = true;
5675 	firstRun= false;
5676 	__panels_refresh (core);
5677 	firstRun= true;
5678 	r_config_set_b (core->config, "scr.utf8", utf8);
5679 	char *s = r_cons_canvas_to_string (can);
5680 	if (s) {
5681 		// TODO drop utf8!!
5682 		r_str_ansi_filter (s, NULL, NULL, -1);
5683 		int i, h, w = r_cons_get_size (&h);
5684 		for (i = h; i > 0; i--) {
5685 			int H = i;
5686 			char *r = r_str_scale (s, w, H);
5687 			r_cons_clear00 ();
5688 			r_cons_gotoxy (0, (h / 2) - (H / 2)); // center
5689 			//r_cons_gotoxy (0, h-H); // bottom
5690 			r_cons_strcat (r);
5691 			r_cons_flush ();
5692 			free (r);
5693 			r_sys_usleep (3000);
5694 		}
5695 		r_sys_usleep (100000);
5696 		free (s);
5697 	}
5698 }
5699 
__default_panel_print(RCore * core,RPanel * panel)5700 static void __default_panel_print(RCore *core, RPanel *panel) {
5701 	bool o_cur = core->print->cur_enabled;
5702 	core->print->cur_enabled = o_cur & (__get_cur_panel (core->panels) == panel);
5703 	if (panel->model->readOnly) {
5704 		__update_help_contents (core, panel);
5705 		__update_help_title (core, panel);
5706 	} else if (panel->model->cmd) {
5707 		panel->model->print_cb (core, panel);
5708 		__update_panel_title (core, panel);
5709 	}
5710 	core->print->cur_enabled = o_cur;
5711 }
5712 
__panel_print(RCore * core,RConsCanvas * can,RPanel * panel,int color)5713 static void __panel_print(RCore *core, RConsCanvas *can, RPanel *panel, int color) {
5714 	if (!can || !panel|| !panel->view->refresh) {
5715 		return;
5716 	}
5717 	if (can->w <= panel->view->pos.x || can->h <= panel->view->pos.y) {
5718 		return;
5719 	}
5720 	panel->view->refresh = panel->model->type == PANEL_TYPE_MENU;
5721 	r_cons_canvas_fill (can, panel->view->pos.x, panel->view->pos.y, panel->view->pos.w, panel->view->pos.h, ' ');
5722 	if (panel->model->type == PANEL_TYPE_MENU) {
5723 		__menu_panel_print (can, panel, panel->view->sx, panel->view->sy, panel->view->pos.w, panel->view->pos.h);
5724 	} else {
5725 		__default_panel_print (core, panel);
5726 	}
5727 	int w, h;
5728 	w = R_MIN (panel->view->pos.w, can->w - panel->view->pos.x);
5729 	h = R_MIN (panel->view->pos.h, can->h - panel->view->pos.y);
5730 	if (color) {
5731 		r_cons_canvas_box (can, panel->view->pos.x, panel->view->pos.y, w, h, core->cons->context->pal.graph_box2);
5732 	} else {
5733 		r_cons_canvas_box (can, panel->view->pos.x, panel->view->pos.y, w, h, core->cons->context->pal.graph_box);
5734 	}
5735 }
5736 
__panels_refresh(RCore * core)5737 static void __panels_refresh(RCore *core) {
5738 	RPanels *panels = core->panels;
5739 	if (!panels) {
5740 		return;
5741 	}
5742 	RConsCanvas *can = panels->can;
5743 	if (!can) {
5744 		return;
5745 	}
5746 	r_cons_gotoxy (0, 0);
5747 	int i, h, w = r_cons_get_size (&h);
5748 	if (!r_cons_canvas_resize (can, w, h)) {
5749 		return;
5750 	}
5751 	RStrBuf *title = r_strbuf_new (" ");
5752 	bool utf8 = r_config_get_i (core->config, "scr.utf8");
5753 	if (firstRun) {
5754 		r_config_set_b (core->config, "scr.utf8", false);
5755 	}
5756 
5757 	__refresh_core_offset (core);
5758 	__set_refresh_all (core, false, false);
5759 
5760 	//TODO use getPanel
5761 	for (i = 0; i < panels->n_panels; i++) {
5762 		if (i != panels->curnode) {
5763 			__panel_print (core, can, __get_panel (panels, i), 0);
5764 		}
5765 	}
5766 	if (panels->mode == PANEL_MODE_MENU) {
5767 		__panel_print (core, can, __get_cur_panel (panels), 0);
5768 	} else {
5769 		__panel_print (core, can, __get_cur_panel (panels), 1);
5770 	}
5771 	for (i = 0; i < panels->panels_menu->n_refresh; i++) {
5772 		__panel_print (core, can, panels->panels_menu->refreshPanels[i], 1);
5773 	}
5774 	(void) r_cons_canvas_gotoxy (can, -can->sx, -can->sy);
5775 	r_cons_canvas_fill (can, -can->sx, -can->sy, w, 1, ' ');
5776 	const char *color = core->cons->context->pal.graph_box2;
5777 	if (panels->mode == PANEL_MODE_ZOOM) {
5778 		r_strbuf_appendf (title, "%s Zoom Mode | Press Enter or q to quit"Color_RESET, color);
5779 	} else if (panels->mode == PANEL_MODE_WINDOW) {
5780 		r_strbuf_appendf (title, "%s Window Mode | hjkl: move around the panels | q: quit the mode | Enter: Zoom mode"Color_RESET, color);
5781 	} else {
5782 		RPanelsMenuItem *parent = panels->panels_menu->root;
5783 		for (i = 0; i < parent->n_sub; i++) {
5784 			RPanelsMenuItem *item = parent->sub[i];
5785 			if (panels->mode == PANEL_MODE_MENU && i == parent->selectedIndex) {
5786 				r_strbuf_appendf (title, "%s[%s]"Color_RESET, color, item->name);
5787 			} else {
5788 				r_strbuf_appendf (title, " %s ", item->name);
5789 			}
5790 		}
5791 	}
5792 	if (panels->mode == PANEL_MODE_MENU) {
5793 		r_cons_canvas_write (can, Color_YELLOW);
5794 		r_cons_canvas_write (can, r_strbuf_get (title));
5795 		r_cons_canvas_write (can, Color_RESET);
5796 	} else {
5797 		r_cons_canvas_write (can, Color_RESET);
5798 		r_cons_canvas_write (can, r_strbuf_get (title));
5799 	}
5800 	r_strbuf_setf (title, "[0x%08"PFMT64x "]", core->offset);
5801 	i = -can->sx + w - r_strbuf_length (title);
5802 	(void) r_cons_canvas_gotoxy (can, i, -can->sy);
5803 	r_cons_canvas_write (can, r_strbuf_get (title));
5804 
5805 	int tab_pos = i;
5806 	for (i = core->panels_root->n_panels; i > 0; i--) {
5807 		RPanels *panels = core->panels_root->panels[i - 1];
5808 		char *name = NULL;
5809 		if (panels) {
5810 			name = panels->name;
5811 		}
5812 		if (i - 1 == core->panels_root->cur_panels) {
5813 			if (!name) {
5814 				r_strbuf_setf (title, "%s[%d] "Color_RESET, color, i);
5815 			} else {
5816 				r_strbuf_setf (title, "%s[%s] "Color_RESET, color, name);
5817 			}
5818 			tab_pos -= r_str_ansi_len (r_strbuf_get (title));
5819 		} else {
5820 			if (!name) {
5821 				r_strbuf_setf (title, "%d ", i);
5822 			} else {
5823 				r_strbuf_setf (title, "%s ", name);
5824 			}
5825 			tab_pos -= r_strbuf_length (title);
5826 		}
5827 		(void) r_cons_canvas_gotoxy (can, tab_pos, -can->sy);
5828 		r_cons_canvas_write (can, r_strbuf_get (title));
5829 	}
5830 	r_strbuf_set (title, "Tab ");
5831 	tab_pos -= r_strbuf_length (title);
5832 	(void) r_cons_canvas_gotoxy (can, tab_pos, -can->sy);
5833 	r_cons_canvas_write (can, r_strbuf_get (title));
5834 	r_strbuf_free (title);
5835 
5836 	if (panels->fun == PANEL_FUN_SNOW || panels->fun == PANEL_FUN_SAKURA) {
5837 		__print_snow (panels);
5838 	}
5839 
5840 	if (firstRun) {
5841 		if (core->panels_root->n_panels < 2) {
5842 			if (r_config_get_i (core->config, "scr.demo")) {
5843 				demo_begin (core, can);
5844 			}
5845 		}
5846 		firstRun = false;
5847 		r_config_set_b (core->config, "scr.utf8", utf8);
5848 		RPanel *cur = __get_cur_panel (core->panels);
5849 		cur->view->refresh = true;
5850 		__panels_refresh (core);
5851 		return;
5852 	}
5853 	r_cons_canvas_print (can);
5854 	if (core->scr_gadgets) {
5855 		r_core_cmd0 (core, "pg");
5856 	}
5857 	show_cursor (core);
5858 	r_cons_flush ();
5859 	if (r_cons_singleton ()->fps) {
5860 		r_cons_print_fps (40);
5861 	}
5862 }
5863 
__panel_breakpoint(RCore * core)5864 static void __panel_breakpoint(RCore *core) {
5865 	RPanel *cur = __get_cur_panel (core->panels);
5866 	if (__check_panel_type (cur, PANEL_CMD_DISASSEMBLY)) {
5867 		r_core_cmd (core, "dbs $$", 0);
5868 		cur->view->refresh = true;
5869 	}
5870 }
5871 
__panel_continue(RCore * core)5872 static void __panel_continue(RCore *core) {
5873 	r_core_cmd (core, "dc", 0);
5874 }
5875 
__handle_menu(RCore * core,const int key)5876 static void __handle_menu(RCore *core, const int key) {
5877 	RPanels *panels = core->panels;
5878 	RPanelsMenu *menu = panels->panels_menu;
5879 	RPanelsMenuItem *parent = menu->history[menu->depth - 1];
5880 	RPanelsMenuItem *child = parent->sub[parent->selectedIndex];
5881 	r_cons_switchbuf (false);
5882 	switch (key) {
5883 	case 'h':
5884 		if (menu->depth <= 2) {
5885 			menu->n_refresh = 0;
5886 			if (menu->root->selectedIndex > 0) {
5887 				menu->root->selectedIndex--;
5888 			} else {
5889 				menu->root->selectedIndex = menu->root->n_sub - 1;
5890 			}
5891 			if (menu->depth == 2) {
5892 				menu->depth = 1;
5893 				(void)(menu->root->sub[menu->root->selectedIndex]->cb (core));
5894 			}
5895 		} else {
5896 			__del_menu (core);
5897 		}
5898 		break;
5899 	case 'j':
5900 		if (r_config_get_i (core->config, "scr.cursor")) {
5901 			core->cons->cpos.y++;
5902 		} else {
5903 			if (menu->depth == 1) {
5904 				(void)(child->cb (core));
5905 			} else {
5906 				parent->selectedIndex = R_MIN (parent->n_sub - 1, parent->selectedIndex + 1);
5907 				__update_menu_contents (core, menu, parent);
5908 			}
5909 		}
5910 		break;
5911 	case 'k':
5912 		if (r_config_get_i (core->config, "scr.cursor")) {
5913 			core->cons->cpos.y--;
5914 		} else {
5915 			if (menu->depth < 2) {
5916 				break;
5917 			}
5918 			RPanelsMenuItem *parent = menu->history[menu->depth - 1];
5919 			if (parent->selectedIndex > 0) {
5920 				parent->selectedIndex--;
5921 				__update_menu_contents (core, menu, parent);
5922 			}
5923 		}
5924 		break;
5925 	case 'l':
5926 		{
5927 			if (menu->depth == 1) {
5928 				menu->root->selectedIndex++;
5929 				menu->root->selectedIndex %= menu->root->n_sub;
5930 				break;
5931 			}
5932 			if (parent->sub[parent->selectedIndex]->sub) {
5933 				(void)(parent->sub[parent->selectedIndex]->cb (core));
5934 			} else {
5935 				menu->n_refresh = 0;
5936 				menu->root->selectedIndex++;
5937 				menu->root->selectedIndex %= menu->root->n_sub;
5938 				menu->depth = 1;
5939 				(void)(menu->root->sub[menu->root->selectedIndex]->cb (core));
5940 			}
5941 		}
5942 		break;
5943 	case 'm':
5944 	case 'q':
5945 	case 'Q':
5946 	case -1:
5947 		if (panels->panels_menu->depth > 1) {
5948 			__del_menu (core);
5949 		} else {
5950 			menu->n_refresh = 0;
5951 			__set_mode (core, PANEL_MODE_DEFAULT);
5952 			__get_cur_panel (panels)->view->refresh = true;
5953 		}
5954 		break;
5955 	case '$':
5956 		r_core_cmd0 (core, "dr PC=$$");
5957 		break;
5958 	case ' ':
5959 	case '\r':
5960 	case '\n':
5961 		(void)(child->cb (core));
5962 		break;
5963 	case 9:
5964 		menu->n_refresh = 0;
5965 		__handle_tab_key (core, false);
5966 		break;
5967 	case 'Z':
5968 		menu->n_refresh = 0;
5969 		__handle_tab_key (core, true);
5970 		break;
5971 	case ':':
5972 		menu->n_refresh = 0;
5973 		__handlePrompt (core, panels);
5974 		break;
5975 	case '?':
5976 		menu->n_refresh = 0;
5977 		__toggle_help (core);
5978 		break;
5979 	case '"':
5980 		menu->n_refresh = 0;
5981 		__create_modal (core, __get_panel (panels, 0), panels->modal_db);
5982 		__set_mode (core, PANEL_MODE_DEFAULT);
5983 		break;
5984 	}
5985 }
5986 
__handle_console(RCore * core,RPanel * panel,const int key)5987 static bool __handle_console(RCore *core, RPanel *panel, const int key) {
5988 	if (!__check_panel_type (panel, PANEL_CMD_CONSOLE)) {
5989 		return false;
5990 	}
5991 	r_cons_switchbuf (false);
5992 	switch (key) {
5993 	case 'i':
5994 		{
5995 			char cmd[128] = {0};
5996 			char *prompt = r_str_newf ("[0x%08"PFMT64x"]) ", core->offset);
5997 			__panel_prompt (prompt, cmd, sizeof (cmd));
5998 			if (*cmd) {
5999 				if (!strcmp (cmd, "clear")) {
6000 					r_core_cmd0 (core, ":>$console");
6001 				} else {
6002 					r_core_cmdf (core, "?e %s %s>>$console", prompt, cmd);
6003 					r_core_cmdf (core, "%s >>$console", cmd);
6004 				}
6005 			}
6006 			panel->view->refresh = true;
6007 		}
6008 		return true;
6009 	case 'l':
6010 		r_core_cmd0 (core, ":>$console");
6011 		panel->view->refresh = true;
6012 		return true;
6013 	default:
6014 		// add more things later
6015 		break;
6016 	}
6017 	return false;
6018 }
6019 
__create_panels_config_path(const char * file)6020 static char *__create_panels_config_path(const char *file) {
6021 	char *dir_path = __get_panels_config_dir_path ();
6022 	r_sys_mkdirp (dir_path);
6023 	char *file_path = r_str_newf (R_JOIN_2_PATHS ("%s", "%s"), dir_path, file);
6024 	R_FREE (dir_path);
6025 	return file_path;
6026 }
6027 
__get_panels_config_file_from_dir(const char * file)6028 static char *__get_panels_config_file_from_dir(const char *file) {
6029 	char *dir_path = __get_panels_config_dir_path ();
6030 	RList *dir = r_sys_dir (dir_path);
6031 	if (!dir_path || !dir) {
6032 		free (dir_path);
6033 		return NULL;
6034 	}
6035 	char *tmp = NULL;
6036 	RListIter *it;
6037 	char *entry;
6038 	r_list_foreach (dir, it, entry) {
6039 		if (!strcmp (entry, file)) {
6040 			tmp = entry;
6041 			break;
6042 		}
6043 	}
6044 	if (!tmp) {
6045 		r_list_free (dir);
6046 		free (dir_path);
6047 		return NULL;
6048 	}
6049 	char *ret = r_str_newf (R_JOIN_2_PATHS ("%s", "%s"), dir_path, tmp);
6050 	r_list_free (dir);
6051 	free (dir_path);
6052 	return ret;
6053 }
6054 
r_core_panels_save(RCore * core,const char * oname)6055 R_API void r_core_panels_save(RCore *core, const char *oname) {
6056 	int i;
6057 	if (!core->panels) {
6058 		return;
6059 	}
6060 	const char *name = oname;
6061 	if (R_STR_ISEMPTY (name)) {
6062 		name = __show_status_input (core, "Name for the layout: ");
6063 		if (R_STR_ISEMPTY (name)) {
6064 			(void)__show_status (core, "Name can't be empty!");
6065 			return;
6066 		}
6067 	}
6068 	char *config_path = __create_panels_config_path (name);
6069 	RPanels *panels = core->panels;
6070 	PJ *pj = pj_new ();
6071 	for (i = 0; i < panels->n_panels; i++) {
6072 		RPanel *panel = __get_panel (panels, i);
6073 		pj_o (pj);
6074 		pj_ks (pj, "Title", panel->model->title);
6075 		pj_ks (pj, "Cmd", panel->model->cmd);
6076 		pj_kn (pj, "x", panel->view->pos.x);
6077 		pj_kn (pj, "y", panel->view->pos.y);
6078 		pj_kn (pj, "w", panel->view->pos.w);
6079 		pj_kn (pj, "h", panel->view->pos.h);
6080 		pj_end (pj);
6081 	}
6082 	FILE *fd = r_sandbox_fopen (config_path, "w");
6083 	if (fd) {
6084 		char *pjs = pj_drain (pj);
6085 		fprintf (fd, "%s\n", pjs);
6086 		free (pjs);
6087 		fclose (fd);
6088 		__update_menu (core, "File.Load Layout.Saved", __init_menu_saved_layout);
6089 		(void)__show_status (core, "Panels layout saved!");
6090 	}
6091 	free (config_path);
6092 }
6093 
__parse_panels_config(const char * cfg,int len)6094 static char *__parse_panels_config(const char *cfg, int len) {
6095 	if (R_STR_ISEMPTY (cfg) || len < 2) {
6096 		return NULL;
6097 	}
6098 	char *tmp = r_str_newlen (cfg, len + 1);
6099 	int i = 0;
6100 	for (; i < len; i++) {
6101 		if (tmp[i] == '}') {
6102 			if (i + 1 < len) {
6103 				if (tmp[i + 1] == ',') {
6104 					tmp[i + 1] = '\n';
6105 				}
6106 				continue;
6107 			}
6108 			tmp[i + 1] = '\n';
6109 		}
6110 	}
6111 	return tmp;
6112 }
6113 
r_core_panels_load(RCore * core,const char * _name)6114 R_API bool r_core_panels_load(RCore *core, const char *_name) {
6115 	if (!core->panels) {
6116 		return false;
6117 	}
6118 	char *config_path = __get_panels_config_file_from_dir (_name);
6119 	if (!config_path) {
6120 		char *tmp = r_str_newf ("No saved layout found for the name: %s", _name);
6121 		(void)__show_status (core, tmp);
6122 		free (tmp);
6123 		return false;
6124 	}
6125 	char *panels_config = r_file_slurp (config_path, NULL);
6126 	free (config_path);
6127 	if (!panels_config) {
6128 		char *tmp = r_str_newf ("Layout is empty: %s", _name);
6129 		(void)__show_status (core, tmp);
6130 		free (tmp);
6131 		return false;
6132 	}
6133 	RPanels *panels = core->panels;
6134 	__panel_all_clear (panels);
6135 	panels->n_panels = 0;
6136 	__set_curnode (core, 0);
6137 	char *title, *cmd, *x, *y, *w, *h, *p_cfg = panels_config, *tmp_cfg;
6138 	int i, tmp_count;
6139 	tmp_cfg = __parse_panels_config (p_cfg, strlen (p_cfg));
6140 	tmp_count = r_str_split (tmp_cfg, '\n');
6141 	for (i = 0; i < tmp_count; i++) {
6142 		if (R_STR_ISEMPTY (tmp_cfg)) {
6143 			break;
6144 		}
6145 		title = sdb_json_get_str (tmp_cfg, "Title");
6146 		cmd = sdb_json_get_str (tmp_cfg, "Cmd");
6147 		(void)r_str_arg_unescape (cmd);
6148 		x = sdb_json_get_str (tmp_cfg, "x");
6149 		y = sdb_json_get_str (tmp_cfg, "y");
6150 		w = sdb_json_get_str (tmp_cfg, "w");
6151 		h = sdb_json_get_str (tmp_cfg, "h");
6152 		RPanel *p = __get_panel (panels, panels->n_panels);
6153 		__set_geometry (&p->view->pos, atoi (x), atoi (y), atoi (w),atoi (h));
6154 		__init_panel_param (core, p, title, cmd);
6155 		// TODO: fix code duplication with __update_help
6156 		if (r_str_endswith (cmd, "Help")) {
6157 			p->model->title = r_str_dup (p->model->title, "Help");
6158 			p->model->cmd = r_str_dup (p->model->cmd, "Help");
6159 			RStrBuf *rsb = r_strbuf_new (NULL);
6160 			r_core_visual_append_help (rsb, "Panels Mode", help_msg_panels);
6161 			if (!rsb) {
6162 				return false;
6163 			}
6164 			__set_read_only (core, p, r_strbuf_drain (rsb));
6165 		}
6166 		tmp_cfg += strlen (tmp_cfg) + 1;
6167 	}
6168 	free (panels_config);
6169 	if (!panels->n_panels) {
6170 		free (tmp_cfg);
6171 		return false;
6172 	}
6173 	__set_refresh_all (core, true, false);
6174 	return true;
6175 }
6176 
__rotate_panels(RCore * core,bool rev)6177 static void __rotate_panels(RCore *core, bool rev) {
6178 	RPanels *panels = core->panels;
6179 	RPanel *first = __get_panel (panels, 0);
6180 	RPanel *last = __get_panel (panels, panels->n_panels - 1);
6181 	int i;
6182 	RPanelModel *tmp_model;
6183 	if (!rev) {
6184 		tmp_model = first->model;
6185 		for (i = 0; i < panels->n_panels - 1; i++) {
6186 			RPanel *p0 = __get_panel (panels, i);
6187 			RPanel *p1 = __get_panel (panels, i + 1);
6188 			p0->model = p1->model;
6189 		}
6190 		last->model = tmp_model;
6191 	} else {
6192 		tmp_model = last->model;
6193 		for (i = panels->n_panels - 1; i > 0; i--) {
6194 			RPanel *p0 = __get_panel (panels, i);
6195 			RPanel *p1 = __get_panel (panels, i - 1);
6196 			p0->model = p1->model;
6197 		}
6198 		first->model = tmp_model;
6199 	}
6200 	__set_refresh_all (core, false, true);
6201 }
6202 
__undo_seek(RCore * core)6203 static void __undo_seek(RCore *core) {
6204 	RPanel *cur = __get_cur_panel (core->panels);
6205 	if (!__check_panel_type (cur, PANEL_CMD_DISASSEMBLY)) {
6206 		return;
6207 	}
6208 	RIOUndos *undo = r_io_sundo (core->io, core->offset);
6209 	if (undo) {
6210 		r_core_visual_seek_animation (core, undo->off);
6211 		__set_panel_addr (core, cur, core->offset);
6212 	}
6213 }
6214 
__set_filter(RCore * core,RPanel * panel)6215 static void __set_filter(RCore *core, RPanel *panel) {
6216 	if (!panel->model->filter) {
6217 		return;
6218 	}
6219 	char *input = __show_status_input (core, "filter word: ");
6220 	if (input) {
6221 		panel->model->filter[panel->model->n_filter++] = input;
6222 		__set_cmd_str_cache (core, panel, NULL);
6223 		panel->view->refresh = true;
6224 	}
6225 	__reset_scroll_pos (panel);
6226 }
6227 
__redo_seek(RCore * core)6228 static void __redo_seek(RCore *core) {
6229 	RPanel *cur = __get_cur_panel (core->panels);
6230 	if (!__check_panel_type (cur, PANEL_CMD_DISASSEMBLY)) {
6231 		return;
6232 	}
6233 	RIOUndos *undo = r_io_sundo_redo (core->io);
6234 	if (undo) {
6235 		r_core_visual_seek_animation (core, undo->off);
6236 		__set_panel_addr (core, cur, core->offset);
6237 	}
6238 }
6239 
__handle_tab(RCore * core)6240 static void __handle_tab(RCore *core) {
6241 	r_cons_gotoxy (0, 0);
6242 	if (core->panels_root->n_panels <= 1) {
6243 		r_cons_printf (R_CONS_CLEAR_LINE"%s[Tab] t:new T:new with current panel -:del =:name"Color_RESET, core->cons->context->pal.graph_box2);
6244 	} else {
6245 		const int min = 1;
6246 		const int max = core->panels_root->n_panels;
6247 		r_cons_printf (R_CONS_CLEAR_LINE"%s[Tab] [%d..%d]:select; p:prev; n:next; t:new T:new with current panel -:del =:name"Color_RESET,
6248 			core->cons->context->pal.graph_box2, min, max);
6249 	}
6250 	r_cons_flush ();
6251 	int ch = r_cons_readchar ();
6252 
6253 	if (isdigit (ch)) {
6254 		__handle_tab_nth (core, ch);
6255 		return;
6256 	}
6257 
6258 	switch (ch) {
6259 	case 'n':
6260 		__handle_tab_next (core);
6261 		return;
6262 	case 'p':
6263 		__handle_tab_prev (core);
6264 		return;
6265 	case '-':
6266 		__set_root_state (core, DEL);
6267 		return;
6268 	case '=':
6269 		__handle_tab_name (core);
6270 		return;
6271 	case 't':
6272 		__handle_tab_new (core);
6273 		return;
6274 	case 'T':
6275 		__handle_tab_new_with_cur_panel (core);
6276 		return;
6277 	}
6278 }
6279 
6280 // copypasta from visual
prevOpcode(RCore * core)6281 static void prevOpcode(RCore *core) {
6282 	RPrint *p = core->print;
6283 	ut64 addr, oaddr = core->offset + core->print->cur;
6284 	if (r_core_prevop_addr (core, oaddr, 1, &addr)) {
6285 		const int delta = oaddr - addr;
6286 		p->cur -= delta;
6287 	} else {
6288 		p->cur -= 4;
6289 	}
6290 }
6291 
nextOpcode(RCore * core)6292 static void nextOpcode(RCore *core) {
6293 	RAnalOp *aop = r_core_anal_op (core, core->offset + core->print->cur, R_ANAL_OP_MASK_BASIC);
6294 	RPrint *p = core->print;
6295 	if (aop) {
6296 		p->cur += aop->size;
6297 		r_anal_op_free (aop);
6298 	} else {
6299 		p->cur += 4;
6300 	}
6301 }
6302 
__panels_process(RCore * core,RPanels * panels)6303 static void __panels_process(RCore *core, RPanels *panels) {
6304 	if (!panels) {
6305 		return;
6306 	}
6307 	int i, okey, key;
6308 	RPanelsRoot *panels_root = core->panels_root;
6309 	RPanels *prev;
6310 	prev = core->panels;
6311 	core->panels = panels;
6312 	panels->autoUpdate = true;
6313 	int h, w = r_cons_get_size (&h);
6314 	panels->can = __create_new_canvas (core, w, h);
6315 	__set_refresh_all (core, false, true);
6316 
6317 	r_cons_switchbuf (false);
6318 
6319 	int originCursor = core->print->cur;
6320 	core->print->cur = 0;
6321 	core->print->cur_enabled = false;
6322 	core->print->col = 0;
6323 
6324 	bool originVmode = core->vmode;
6325 	core->vmode = true;
6326 	{
6327 		const char *layout = r_config_get (core->config, "scr.layout");
6328 		if (R_STR_ISNOTEMPTY (layout)) {
6329 			r_core_panels_load (core, layout);
6330 		}
6331 	}
6332 
6333 	bool o_interactive = r_cons_is_interactive ();
6334 	r_cons_set_interactive (true);
6335 	r_core_visual_showcursor (core, false);
6336 
6337 	r_cons_enable_mouse (false);
6338 repeat:
6339 	r_cons_enable_mouse (r_config_get_i (core->config, "scr.wheel"));
6340 	core->panels = panels;
6341 	core->cons->event_resize = NULL; // avoid running old event with new data
6342 	core->cons->event_data = core;
6343 	core->cons->event_resize = (RConsEvent) __do_panels_refreshOneShot;
6344 	__panels_layout_refresh (core);
6345 	RPanel *cur = __get_cur_panel (panels);
6346 	if (panels->fun == PANEL_FUN_SNOW || panels->fun == PANEL_FUN_SAKURA) {
6347 		if (panels->mode == PANEL_MODE_MENU) {
6348 			panels->fun = PANEL_FUN_NOFUN;
6349 			__reset_snow (panels);
6350 			goto repeat;
6351 		}
6352 		okey = r_cons_readchar_timeout (300);
6353 		if (okey == -1) {
6354 			cur->view->refresh = true;
6355 			goto repeat;
6356 		}
6357 	} else {
6358 		okey = r_cons_readchar ();
6359 	}
6360 
6361 	key = r_cons_arrow_to_hjkl (okey);
6362 virtualmouse:
6363 	if (__handle_mouse (core, cur, &key)) {
6364 		if (panels_root->root_state != DEFAULT) {
6365 			goto exit;
6366 		}
6367 		goto repeat;
6368 	}
6369 
6370 	r_cons_switchbuf (true);
6371 
6372 	if (panels->mode == PANEL_MODE_MENU) {
6373 		__handle_menu (core, key);
6374 		if (__check_root_state (core, QUIT) ||
6375 				__check_root_state (core, ROTATE)) {
6376 			goto exit;
6377 		}
6378 		goto repeat;
6379 	}
6380 
6381 	if (core->print->cur_enabled) {
6382 		if (__handle_cursor_mode (core, key)) {
6383 			goto repeat;
6384 		}
6385 	}
6386 
6387 	if (panels->mode == PANEL_MODE_ZOOM) {
6388 		if (__handle_zoom_mode (core, key)) {
6389 			goto repeat;
6390 		}
6391 	}
6392 
6393 	if (panels->mode == PANEL_MODE_WINDOW) {
6394 		if (__handle_window_mode (core, key)) {
6395 			goto repeat;
6396 		}
6397 	}
6398 
6399 	if (__check_panel_type (cur, PANEL_CMD_DISASSEMBLY) && '0' < key && key <= '9') {
6400 		ut8 ch = key;
6401 		r_core_visual_jump (core, ch);
6402 		__set_panel_addr (core, cur, core->offset);
6403 		goto repeat;
6404 	}
6405 
6406 	const char *cmd;
6407 	RConsCanvas *can = panels->can;
6408 	if (__handle_console (core, cur, key)) {
6409 		goto repeat;
6410 	}
6411 	switch (key) {
6412 	case 'u':
6413 		__undo_seek (core);
6414 		break;
6415 	case 'U':
6416 		__redo_seek (core);
6417 		break;
6418 	case 'p':
6419 		__rotate_panels (core, false);
6420 		break;
6421 	case 'P':
6422 		__rotate_panels (core, true);
6423 		break;
6424 	case '.':
6425 		if (__check_panel_type (cur, PANEL_CMD_DISASSEMBLY)) {
6426 			ut64 addr = r_debug_reg_get (core->dbg, "PC");
6427 			if (addr && addr != UT64_MAX) {
6428 				r_core_seek (core, addr, true);
6429 			} else {
6430 				addr = r_num_get (core->num, "entry0");
6431 				if (addr && addr != UT64_MAX) {
6432 					r_core_seek (core, addr, true);
6433 				}
6434 			}
6435 			__set_panel_addr (core, cur, core->offset);
6436 		}
6437 		break;
6438 	case '?':
6439 		__toggle_help (core);
6440 		break;
6441 	case 'b':
6442 		r_core_visual_browse (core, NULL);
6443 		break;
6444 	case ';':
6445 		__handleComment (core);
6446 		break;
6447 	case '$':
6448 		if (core->print->cur_enabled) {
6449 			r_core_cmdf (core, "dr PC=$$+%d", core->print->cur);
6450 		} else {
6451 			r_core_cmd0 (core, "dr PC=$$");
6452 		}
6453 		break;
6454 	case 's':
6455 		__panel_single_step_in (core);
6456 		if (__check_panel_type (cur, PANEL_CMD_DISASSEMBLY)) {
6457 			__set_panel_addr (core, cur, core->offset);
6458 		}
6459 		break;
6460 	case 'S':
6461 		__panel_single_step_over (core);
6462 		if (__check_panel_type (cur, PANEL_CMD_DISASSEMBLY)) {
6463 			__set_panel_addr (core, cur, core->offset);
6464 		}
6465 		break;
6466 	case ' ':
6467 		if (r_config_get_i (core->config, "graph.web")) {
6468 			r_core_cmd0 (core, "agv $$");
6469 		} else {
6470 			__call_visual_graph (core);
6471 		}
6472 		break;
6473 	case ':':
6474 		r_core_visual_prompt_input (core);
6475 		__set_panel_addr (core, cur, core->offset);
6476 		break;
6477 	case 'c':
6478 		__activate_cursor (core);
6479 		break;
6480 	case 'C':
6481 		{
6482 			int color = r_config_get_i (core->config, "scr.color");
6483 			if (++color > 2) {
6484 				color = 0;
6485 			}
6486 			r_config_set_i (core->config, "scr.color", color);
6487 			can->color = color;
6488 			__set_refresh_all (core, true, false);
6489 		}
6490 		break;
6491 	case 'r':
6492 		if (r_config_get_i (core->config, "asm.hint.call")) {
6493 			r_config_toggle (core->config, "asm.hint.call");
6494 			r_config_set_b (core->config, "asm.hint.jmp", true);
6495 		} else if (r_config_get_i (core->config, "asm.hint.jmp")) {
6496 			r_config_toggle (core->config, "asm.hint.jmp");
6497 			r_config_set_b (core->config, "asm.hint.emu", true);
6498 		} else if (r_config_get_i (core->config, "asm.hint.emu")) {
6499 			r_config_toggle (core->config, "asm.hint.emu");
6500 			r_config_set_b (core->config, "asm.hint.lea", true);
6501 		} else if (r_config_get_i (core->config, "asm.hint.lea")) {
6502 			r_config_toggle (core->config, "asm.hint.lea");
6503 			r_config_set_b (core->config, "asm.hint.call", true);
6504 		} else {
6505 			r_config_set_b (core->config, "asm.hint.call", true);
6506 		}
6507 		break;
6508 	case 'R':
6509 		if (r_config_get_i (core->config, "scr.randpal")) {
6510 			r_core_cmd0 (core, "ecr");
6511 		} else {
6512 			r_core_cmd0 (core, "ecn");
6513 		}
6514 		__do_panels_refresh (core);
6515 		break;
6516 	case 'a':
6517 		panels->autoUpdate = __show_status_yesno (core, 1, "Auto update On? (Y/n)");
6518 		break;
6519 	case 'A':
6520 		{
6521 			const int ocur = core->print->cur_enabled;
6522 			r_core_visual_asm (core, core->offset);
6523 			core->print->cur_enabled = ocur;
6524 		}
6525 		break;
6526 	case 'd':
6527 		r_core_visual_define (core, "", 0);
6528 		break;
6529 	case 'D':
6530 		__replace_cmd (core, PANEL_TITLE_DISASSEMBLY, PANEL_CMD_DISASSEMBLY);
6531 		break;
6532 	case 'j':
6533 		if (r_config_get_i (core->config, "scr.cursor")) {
6534 			core->cons->cpos.y++;
6535 		} else {
6536 			if (core->print->cur_enabled) {
6537 				nextOpcode (core);
6538 			} else {
6539 				r_cons_switchbuf (false);
6540 				if (cur->model->directionCb) {
6541 					cur->model->directionCb (core, (int)DOWN);
6542 				}
6543 			}
6544 		}
6545 		break;
6546 	case 'k':
6547 		if (r_config_get_i (core->config, "scr.cursor")) {
6548 			core->cons->cpos.y--;
6549 		} else {
6550 			if (core->print->cur_enabled) {
6551 				prevOpcode (core);
6552 			} else {
6553 				r_cons_switchbuf (false);
6554 				if (cur->model->directionCb) {
6555 					cur->model->directionCb (core, (int)UP);
6556 				}
6557 			}
6558 		}
6559 		break;
6560 	case 'K':
6561 		if (r_config_get_i (core->config, "scr.cursor")) {
6562 			core->cons->cpos.y -= 5;
6563 		} else {
6564 			if (core->print->cur_enabled) {
6565 				size_t i;
6566 				for (i = 0; i < 4; i++) {
6567 					prevOpcode (core);
6568 				}
6569 			} else {
6570 				r_cons_switchbuf (false);
6571 				if (cur->model->directionCb) {
6572 					for (i = 0; i < __get_cur_panel (panels)->view->pos.h / 2 - 6; i++) {
6573 						cur->model->directionCb (core, (int)UP);
6574 					}
6575 				}
6576 			}
6577 		}
6578 		break;
6579 	case 'J':
6580 		if (r_config_get_i (core->config, "scr.cursor")) {
6581 			core->cons->cpos.y += 5;
6582 		} else {
6583 			if (core->print->cur_enabled) {
6584 				size_t i;
6585 				for (i = 0; i < 4; i++) {
6586 					nextOpcode (core);
6587 				}
6588 			} else {
6589 				r_cons_switchbuf (false);
6590 				if (cur->model->directionCb) {
6591 					for (i = 0; i < __get_cur_panel (panels)->view->pos.h / 2 - 6; i++) {
6592 						cur->model->directionCb (core, (int)DOWN);
6593 					}
6594 				}
6595 			}
6596 		}
6597 		break;
6598 	case 'H':
6599 		if (r_config_get_i (core->config, "scr.cursor")) {
6600 			core->cons->cpos.x -= 5;
6601 		} else {
6602 			r_cons_switchbuf (false);
6603 			if (cur->model->directionCb) {
6604 				for (i = 0; i < __get_cur_panel (panels)->view->pos.w / 3; i++) {
6605 					cur->model->directionCb (core, (int)LEFT);
6606 				}
6607 			}
6608 		}
6609 		break;
6610 	case 'L':
6611 		if (r_config_get_i (core->config, "scr.cursor")) {
6612 			core->cons->cpos.x += 5;
6613 		} else {
6614 			r_cons_switchbuf (false);
6615 			if (cur->model->directionCb) {
6616 				for (i = 0; i < __get_cur_panel (panels)->view->pos.w / 3; i++) {
6617 					cur->model->directionCb (core, (int)RIGHT);
6618 				}
6619 			}
6620 		}
6621 		break;
6622 	case 'f':
6623 		__set_filter (core, cur);
6624 		break;
6625 	case 'F':
6626 		__reset_filter (core, cur);
6627 		break;
6628 	case '_':
6629 		__hudstuff (core);
6630 		break;
6631 	case '\\':
6632 		r_core_visual_hud (core);
6633 		break;
6634 	case '"':
6635 		r_cons_switchbuf (false);
6636 		__create_modal (core, cur, panels->modal_db);
6637 		if (__check_root_state (core, ROTATE)) {
6638 			goto exit;
6639 		}
6640 		// all panels containing decompiler data should be cached
6641 		cur->model->cache = strstr (cur->model->title, "Decomp") != NULL;
6642 		break;
6643 	case 'O':
6644 		__handle_print_rotate (core);
6645 		break;
6646 	case 'n':
6647 		if (__check_panel_type (cur, PANEL_CMD_DISASSEMBLY)) {
6648 			r_core_seek_next (core, r_config_get (core->config, "scr.nkey"));
6649 			__set_panel_addr (core, cur, core->offset);
6650 		}
6651 		break;
6652 	case 'N':
6653 		if (__check_panel_type (cur, PANEL_CMD_DISASSEMBLY)) {
6654 			r_core_seek_previous (core, r_config_get (core->config, "scr.nkey"));
6655 			__set_panel_addr (core, cur, core->offset);
6656 		}
6657 		break;
6658 	case 'x':
6659 		__handle_refs (core, cur, UT64_MAX);
6660 		break;
6661 	case 'X':
6662 #if 0
6663 // already accessible via xX
6664 		r_core_visual_refs (core, false, true);
6665 		cur->model->addr = core->offset;
6666 		set_refresh_all (panels, false);
6667 #endif
6668 		__dismantle_del_panel (core, cur, panels->curnode);
6669 		break;
6670 	case 9: // TAB
6671 		__handle_tab_key (core, false);
6672 		break;
6673 	case 'Z': // SHIFT-TAB
6674 		__handle_tab_key (core, true);
6675 		break;
6676 	case 'M':
6677 		__handle_visual_mark (core);
6678 		break;
6679 	case 'e':
6680 	{
6681 		char *cmd = __show_status_input (core, "New command: ");
6682 		if (R_STR_ISNOTEMPTY (cmd)) {
6683 			__replace_cmd (core, cmd, cmd);
6684 		}
6685 		free (cmd);
6686 	}
6687 		break;
6688 	case 'm':
6689 		__set_mode (core, PANEL_MODE_MENU);
6690 		__clear_panels_menu (core);
6691 		__get_cur_panel (panels)->view->refresh = true;
6692 		break;
6693 	case 'g':
6694 		r_core_visual_showcursor (core, true);
6695 		r_core_visual_offset (core);
6696 		r_core_visual_showcursor (core, false);
6697 		__set_panel_addr (core, cur, core->offset);
6698 		break;
6699 	case 'G':
6700 		{
6701 			const char *hl = r_config_get (core->config, "scr.highlight");
6702 			if (hl) {
6703 				ut64 addr = r_num_math (core->num, hl);
6704 				__set_panel_addr (core, cur, addr);
6705 				// r_io_sundo_push (core->io, addr, false); // doesnt seems to work
6706 			}
6707 		}
6708 		break;
6709 	case 'h':
6710 		if (r_config_get_i (core->config, "scr.cursor")) {
6711 			core->cons->cpos.x--;
6712 		} else {
6713 			if (core->print->cur_enabled) {
6714 				core->print->cur--;
6715 			} else {
6716 				r_cons_switchbuf (false);
6717 				if (cur->model->directionCb) {
6718 					cur->model->directionCb (core, (int)LEFT);
6719 				}
6720 			}
6721 		}
6722 		break;
6723 	case 'l':
6724 		if (r_config_get_i (core->config, "scr.cursor")) {
6725 			core->cons->cpos.x++;
6726 		} else {
6727 			if (core->print->cur_enabled) {
6728 				core->print->cur++;
6729 			} else {
6730 				r_cons_switchbuf (false);
6731 				if (cur->model->directionCb) {
6732 					cur->model->directionCb (core, (int)RIGHT);
6733 				}
6734 			}
6735 		}
6736 		break;
6737 	case 'V':
6738 		if (r_config_get_i (core->config, "graph.web")) {
6739 			r_core_cmd0 (core, "agv $$");
6740 		} else {
6741 			__call_visual_graph (core);
6742 		}
6743 		break;
6744 	case ']':
6745 		if (__check_panel_type (cur, PANEL_CMD_HEXDUMP)) {
6746 			r_config_set_i (core->config, "hex.cols", r_config_get_i (core->config, "hex.cols") + 1);
6747 		} else {
6748 			int cmtcol = r_config_get_i (core->config, "asm.cmt.col");
6749 			r_config_set_i (core->config, "asm.cmt.col", cmtcol + 2);
6750 		}
6751 		cur->view->refresh = true;
6752 		break;
6753 	case '[':
6754 		if (__check_panel_type (cur, PANEL_CMD_HEXDUMP)) {
6755 			r_config_set_i (core->config, "hex.cols", r_config_get_i (core->config, "hex.cols") - 1);
6756 		} else {
6757 			int cmtcol = r_config_get_i (core->config, "asm.cmt.col");
6758 			if (cmtcol > 2) {
6759 				r_config_set_i (core->config, "asm.cmt.col", cmtcol - 2);
6760 			}
6761 		}
6762 		cur->view->refresh = true;
6763 		break;
6764 	case '/':
6765 		r_core_cmd0 (core, "?i highlight;e scr.highlight=`yp`");
6766 		break;
6767 	case 'z':
6768 		if (panels->curnode > 0) {
6769 			__swap_panels (panels, 0, panels->curnode);
6770 			__set_curnode (core, 0);
6771 		}
6772 		break;
6773 	case 'i':
6774 		if (cur->model->rotateCb) {
6775 			cur->model->rotateCb (core, false);
6776 			cur->view->refresh = true;
6777 		}
6778 		break;
6779 	case 'I':
6780 		if (cur->model->rotateCb) {
6781 			cur->model->rotateCb (core, true);
6782 			cur->view->refresh = true;
6783 		}
6784 		break;
6785 	case 't':
6786 		__handle_tab (core);
6787 		if (panels_root->root_state != DEFAULT) {
6788 			goto exit;
6789 		}
6790 		break;
6791 	case 'T':
6792 		if (panels_root->n_panels > 1) {
6793 			__set_root_state (core, DEL);
6794 			goto exit;
6795 		}
6796 		break;
6797 	case 'w':
6798 		__toggle_window_mode (core);
6799 		break;
6800 	case 'W':
6801 		__move_panel_to_dir (core, cur, panels->curnode);
6802 		break;
6803 	case 0x0d: // "\\n"
6804 		if (r_config_get_i (core->config, "scr.cursor")) {
6805 			key = 0;
6806 			r_cons_set_click (core->cons->cpos.x, core->cons->cpos.y);
6807 			goto virtualmouse;
6808 		} else {
6809 			__toggle_zoom_mode (core);
6810 		}
6811 		break;
6812 	case '|':
6813 		{
6814 			RPanel *p = __get_cur_panel (panels);
6815 			__split_panel_vertical (core, p, p->model->title, p->model->cmd);
6816 			break;
6817 		}
6818 	case '-':
6819 		{
6820 			RPanel *p = __get_cur_panel (panels);
6821 			__split_panel_horizontal (core, p, p->model->title, p->model->cmd);
6822 			break;
6823 		}
6824 	case '*':
6825 		if (__check_func (core)) {
6826 			r_cons_canvas_free (can);
6827 			panels->can = NULL;
6828 
6829 			__replace_cmd (core, PANEL_TITLE_DECOMPILER, PANEL_CMD_DECOMPILER);
6830 
6831 			int h, w = r_cons_get_size (&h);
6832 			panels->can = __create_new_canvas (core, w, h);
6833 		}
6834 		break;
6835 	case '(':
6836 		if (panels->fun != PANEL_FUN_SNOW && panels->fun != PANEL_FUN_SAKURA) {
6837 			//TODO: Refactoring the FUN if bored af
6838 			//panels->fun = PANEL_FUN_SNOW;
6839 			panels->fun = PANEL_FUN_SAKURA;
6840 		} else {
6841 			panels->fun = PANEL_FUN_NOFUN;
6842 			__reset_snow (panels);
6843 		}
6844 		break;
6845 	case ')':
6846 		__rotate_asmemu (core, __get_cur_panel (panels));
6847 		break;
6848 	case '&':
6849 		__toggle_cache (core, __get_cur_panel (panels));
6850 		break;
6851 	case R_CONS_KEY_F1:
6852 		cmd = r_config_get (core->config, "key.f1");
6853 		if (cmd && *cmd) {
6854 			(void)r_core_cmd0 (core, cmd);
6855 		}
6856 		break;
6857 	case R_CONS_KEY_F2:
6858 		cmd = r_config_get (core->config, "key.f2");
6859 		if (cmd && *cmd) {
6860 			(void)r_core_cmd0 (core, cmd);
6861 		} else {
6862 			__panel_breakpoint (core);
6863 		}
6864 		break;
6865 	case R_CONS_KEY_F3:
6866 		cmd = r_config_get (core->config, "key.f3");
6867 		if (cmd && *cmd) {
6868 			(void)r_core_cmd0 (core, cmd);
6869 		}
6870 		break;
6871 	case R_CONS_KEY_F4:
6872 		cmd = r_config_get (core->config, "key.f4");
6873 		if (cmd && *cmd) {
6874 			(void)r_core_cmd0 (core, cmd);
6875 		}
6876 		break;
6877 	case R_CONS_KEY_F5:
6878 		cmd = r_config_get (core->config, "key.f5");
6879 		if (cmd && *cmd) {
6880 			(void)r_core_cmd0 (core, cmd);
6881 		}
6882 		break;
6883 	case R_CONS_KEY_F6:
6884 		cmd = r_config_get (core->config, "key.f6");
6885 		if (cmd && *cmd) {
6886 			(void)r_core_cmd0 (core, cmd);
6887 		}
6888 		break;
6889 	case R_CONS_KEY_F7:
6890 		cmd = r_config_get (core->config, "key.f7");
6891 		if (cmd && *cmd) {
6892 			(void)r_core_cmd0 (core, cmd);
6893 		} else {
6894 			__panel_single_step_in (core);
6895 			if (__check_panel_type (cur, PANEL_CMD_DISASSEMBLY)) {
6896 				__set_panel_addr (core, cur, core->offset);
6897 			}
6898 		}
6899 		break;
6900 	case R_CONS_KEY_F8:
6901 		cmd = r_config_get (core->config, "key.f8");
6902 		if (cmd && *cmd) {
6903 			(void)r_core_cmd0 (core, cmd);
6904 		} else {
6905 			__panel_single_step_over (core);
6906 			if (__check_panel_type (cur, PANEL_CMD_DISASSEMBLY)) {
6907 				__set_panel_addr (core, cur, core->offset);
6908 			}
6909 		}
6910 		break;
6911 	case R_CONS_KEY_F9:
6912 		cmd = r_config_get (core->config, "key.f9");
6913 		if (cmd && *cmd) {
6914 			(void)r_core_cmd0 (core, cmd);
6915 		} else {
6916 			if (__check_panel_type (cur, PANEL_CMD_DISASSEMBLY)) {
6917 				__panel_continue (core);
6918 				__set_panel_addr (core, cur, core->offset);
6919 			}
6920 		}
6921 		break;
6922 	case R_CONS_KEY_F10:
6923 		cmd = r_config_get (core->config, "key.f10");
6924 		if (cmd && *cmd) {
6925 			(void)r_core_cmd0 (core, cmd);
6926 		}
6927 		break;
6928 	case R_CONS_KEY_F11:
6929 		cmd = r_config_get (core->config, "key.f11");
6930 		if (cmd && *cmd) {
6931 			(void)r_core_cmd0 (core, cmd);
6932 		}
6933 		break;
6934 	case R_CONS_KEY_F12:
6935 		cmd = r_config_get (core->config, "key.f12");
6936 		if (cmd && *cmd) {
6937 			(void)r_core_cmd0 (core, cmd);
6938 		}
6939 		break;
6940 	case 'Q':
6941 		__set_root_state (core, QUIT);
6942 		goto exit;
6943 	case '!':
6944 		fromVisual = true;
6945 	case 'q':
6946 	case -1: // EOF
6947 		__set_root_state (core, DEL);
6948 		if (core->panels_root->n_panels < 2) {
6949 			if (r_config_get_i (core->config, "scr.demo")) {
6950 				demo_end (core, can);
6951 			}
6952 		}
6953 		goto exit;
6954 #if 0
6955 	case 27: // ESC
6956 		if (r_cons_readchar () == 91) {
6957 			if (r_cons_readchar () == 90) {}
6958 		}
6959 		break;
6960 #endif
6961 	default:
6962 		// eprintf ("Key %d\n", key);
6963 		// sleep (1);
6964 		break;
6965 	}
6966 	goto repeat;
6967 exit:
6968 	if (!originVmode) {
6969 		r_core_visual_showcursor (core, true);
6970 	}
6971 	core->cons->event_resize = NULL;
6972 	core->cons->event_data = NULL;
6973 	core->print->cur = originCursor;
6974 	core->print->cur_enabled = false;
6975 	core->print->col = 0;
6976 	core->vmode = originVmode;
6977 	core->panels = prev;
6978 	r_cons_set_interactive (o_interactive);
6979 }
6980 
__del_panels(RCore * core)6981 static void __del_panels(RCore *core) {
6982 	RPanelsRoot *panels_root = core->panels_root;
6983 	if (panels_root->n_panels <= 1) {
6984 		core->panels_root->root_state = QUIT;
6985 		return;
6986 	}
6987 	int i;
6988 	for (i = panels_root->cur_panels; i < panels_root->n_panels - 1; i++) {
6989 		panels_root->panels[i] = panels_root->panels[i + 1];
6990 	}
6991 	panels_root->n_panels--;
6992 	if (panels_root->cur_panels >= panels_root->n_panels) {
6993 		panels_root->cur_panels = panels_root->n_panels - 1;
6994 	}
6995 }
6996 
r_core_panels_root(RCore * core,RPanelsRoot * panels_root)6997 R_API bool r_core_panels_root(RCore *core, RPanelsRoot *panels_root) {
6998 	fromVisual = core->vmode;
6999 	if (!panels_root) {
7000 		panels_root = R_NEW0 (RPanelsRoot);
7001 		if (!panels_root) {
7002 			return false;
7003 		}
7004 		core->panels_root = panels_root;
7005 		panels_root->panels = calloc (sizeof (RPanels *), PANEL_NUM_LIMIT);
7006 		panels_root->n_panels = 0;
7007 		panels_root->cur_panels = 0;
7008 		panels_root->pdc_caches = sdb_new0 ();
7009 		panels_root->cur_pdc_cache = NULL;
7010 		__set_root_state (core, DEFAULT);
7011 		__init_new_panels_root (core);
7012 	} else {
7013 		if (!panels_root->n_panels) {
7014 			panels_root->n_panels = 0;
7015 			panels_root->cur_panels = 0;
7016 			__init_new_panels_root (core);
7017 		}
7018 		const char *pdc_now = r_config_get (core->config, "cmd.pdc");
7019 		if (sdb_exists (panels_root->pdc_caches, pdc_now)) {
7020 			panels_root->cur_pdc_cache = sdb_ptr_get (panels_root->pdc_caches, r_str_new (pdc_now), 0);
7021 		} else {
7022 			Sdb *sdb = sdb_new0();
7023 			sdb_ptr_set (panels_root->pdc_caches, r_str_new (pdc_now), sdb, 0);
7024 			panels_root->cur_pdc_cache = sdb;
7025 		}
7026 	}
7027 	const char *layout = r_config_get (core->config, "scr.layout");
7028 	if (!R_STR_ISEMPTY (layout)) {
7029 		r_core_cmdf (core, "v %s", layout);
7030 	}
7031 	RPanels *panels = panels_root->panels[panels_root->cur_panels];
7032 	if (panels) {
7033 		size_t i = 0;
7034 		for (; i < panels->n_panels; i++) {
7035 			RPanel *cur = __get_panel (panels, i);
7036 			if (cur) {
7037 				cur->model->addr = core->offset;
7038 			}
7039 		}
7040 	}
7041 	while (panels_root->n_panels) {
7042 		__set_root_state (core, DEFAULT);
7043 		__panels_process (core, panels_root->panels[panels_root->cur_panels]);
7044 		if (__check_root_state (core, DEL)) {
7045 			__del_panels (core);
7046 		}
7047 		if (__check_root_state (core, QUIT)) {
7048 			break;
7049 		}
7050 	}
7051 	if (fromVisual) {
7052 		r_core_cmdf (core, "V");
7053 	} else {
7054 		r_cons_enable_mouse (false);
7055 	}
7056 	return true;
7057 }
7058 
__init_new_panels_root(RCore * core)7059 static void __init_new_panels_root(RCore *core) {
7060 	RPanelsRoot *panels_root = core->panels_root;
7061 	RPanels *panels = __panels_new (core);
7062 	if (!panels) {
7063 		return;
7064 	}
7065 	RPanels *prev = core->panels;
7066 	core->panels = panels;
7067 	panels_root->panels[panels_root->n_panels++] = panels;
7068 	if (!__init_panels_menu (core)) {
7069 		core->panels = prev;
7070 		return;
7071 	}
7072 	if (!__init_panels (core, panels)) {
7073 		core->panels = prev;
7074 		return;
7075 	}
7076 	__init_all_dbs (core);
7077 	__set_mode (core, PANEL_MODE_DEFAULT);
7078 	__create_default_panels (core);
7079 	__panels_layout (panels);
7080 	core->panels = prev;
7081 }
7082