1 /* radare - LGPL - Copyright 2009-2021 - nibble, pancake */
2 
3 #define INTERACTIVE_MAX_REP 1024
4 
5 #include <r_core.h>
6 #include <r_anal.h>
7 #include <r_cons.h>
8 #include <r_cmd.h>
9 #include <stdint.h>
10 #include <sys/types.h>
11 #include <ctype.h>
12 #include <stdarg.h>
13 #include "cmd_helps.h"
14 #if __UNIX__
15 #include <sys/utsname.h>
16 #endif
17 
18 #include <tree_sitter/api.h>
19 TSLanguage *tree_sitter_r2cmd ();
20 
21 // NOTE: this should be in sync with SPECIAL_CHARACTERS in
22 //       radare2-shell-parser grammar, except for ", ' and
23 //       whitespaces, because we let cmd_substitution_arg create
24 //       new arguments
25 static const char *SPECIAL_CHARS_REGULAR = "@;~$#|`\"'()<>";
26 static const char *SPECIAL_CHARS_PF = "@;~$#|`\"'<>";
27 static const char *SPECIAL_CHARS_DOUBLE_QUOTED = "\"";
28 static const char *SPECIAL_CHARS_SINGLE_QUOTED = "'";
29 
cmd_descriptor(const char * cmd,const char * help[])30 static RCmdDescriptor *cmd_descriptor(const char *cmd, const char *help[]) {
31 	RCmdDescriptor *d = R_NEW0 (RCmdDescriptor);
32 	if (d) {
33 		d->cmd = cmd;
34 		d->help_msg = help;
35 	}
36 	return d;
37 }
38 
39 #define DEFINE_CMD_DESCRIPTOR(core, cmd_) \
40 	{ \
41 		RCmdDescriptor *d = cmd_descriptor (#cmd_, help_msg_##cmd_); \
42 		if (d) { \
43 			r_list_append ((core)->cmd_descriptors, d); \
44 		} \
45 	}
46 
47 #define DEFINE_CMD_DESCRIPTOR_WITH_DETAIL(core, cmd_) \
48 	{ \
49 		RCmdDescriptor *d = cmd_descriptor (#cmd_, help_msg##cmd_); \
50 		if (d) { \
51 			d->help_detail = help_detail_##cmd_; \
52 			r_list_append ((core)->cmd_descriptors, d); \
53 		} \
54 	}
55 
56 #define DEFINE_CMD_DESCRIPTOR_WITH_DETAIL2(core, cmd_) \
57 	{ \
58 		RCmdDescriptor *d = cmd_descriptor (#cmd_, help_msg_##cmd_); \
59 		if (d) { \
60 			d->help_detail = help_detail_##cmd_; \
61 			d->help_detail2 = help_detail2_##cmd_; \
62 			r_list_append ((core)->cmd_descriptors, d); \
63 		} \
64 	}
65 
66 #define DEFINE_CMD_DESCRIPTOR_SPECIAL(core, cmd_, named_cmd) \
67 	{ \
68 		RCmdDescriptor *d = R_NEW0 (RCmdDescriptor); \
69 		if (d) { \
70 			d->cmd = #cmd_; \
71 			d->help_msg = help_msg_##named_cmd; \
72 			r_list_append ((core)->cmd_descriptors, d); \
73 		} \
74 	}
75 
76 static int r_core_cmd_subst_i(RCore *core, char *cmd, char* colon, bool *tmpseek);
77 
bb_cmpaddr(const void * _a,const void * _b)78 static int bb_cmpaddr(const void *_a, const void *_b) {
79 	const RAnalBlock *a = _a, *b = _b;
80 	return a->addr > b->addr ? 1 : (a->addr < b->addr ? -1 : 0);
81 }
82 
83 static void cmd_debug_reg(RCore *core, const char *str);
84 
85 #include "cmd_quit.c"
86 #include "cmd_hash.c"
87 #include "cmd_debug.c"
88 #include "cmd_log.c"
89 #include "cmd_flag.c"
90 #include "cmd_zign.c"
91 #include "cmd_project.c"
92 #include "cmd_write.c"
93 #include "cmd_cmp.c"
94 #include "cmd_eval.c"
95 #include "cmd_type.c"
96 #include "cmd_anal.c"
97 #include "cmd_open.c"
98 #include "cmd_meta.c"
99 #include "cmd_egg.c"
100 #include "cmd_info.c"
101 #include "cmd_macro.c"
102 #include "cmd_magic.c"
103 #include "cmd_mount.c"
104 #include "cmd_seek.c"
105 #include "cmd_search.c" // defines incDigitBuffer... used by cmd_print
106 #include "cmd_print.c"
107 #include "cmd_help.c"
108 #include "cmd_colon.c"
109 
110 static const char *help_msg_dollar[] = {
111 	"Usage:", "$alias[=cmd] [args...]", "Alias commands and strings (See ?$? for help on $variables)",
112 	"$", "", "list all defined aliases",
113 	"$*", "", "list all the aliases as r2 commands in base64",
114 	"$**", "", "same as above, but using plain text",
115 	"$", "foo:=123", "alias for 'f foo=123'",
116 	"$", "foo-=4", "alias for 'f foo-=4'",
117 	"$", "foo+=4", "alias for 'f foo+=4'",
118 	"$", "foo", "alias for 's foo' (note that command aliases can override flag resolution)",
119 	"$", "dis=base64:AAA==", "alias this base64 encoded text to be printed when $dis is called",
120 	"$", "dis=$hello world", "alias this text to be printed when $dis is called",
121 	"$", "dis=-", "open cfg.editor to set the new value for dis alias",
122 	"$", "dis=af;pdf", "create command - analyze to show function",
123 	"$", "test=#!pipe node /tmp/test.js", "create command - rlangpipe script",
124 	"$", "dis=", "undefine alias",
125 	"$", "dis", "execute the previously defined alias",
126 	"$", "dis?", "show commands aliased by $dis",
127 	"$", "dis?n", "show commands aliased by $dis, without a new line",
128 	NULL
129 };
130 
131 static const char *help_msg_star[] = {
132 	"Usage:", "*<addr>[=[0x]value]", "Pointer read/write data/values",
133 	"*", "entry0=cc", "write trap in entrypoint",
134 	"*", "entry0+10=0x804800", "write value in delta address",
135 	"*", "entry0", "read byte at given address",
136 	"*", "/", "end multiline comment. (use '/*' to start mulitiline comment",
137 	"TODO: last command should honor asm.bits", "", "",
138 	NULL
139 };
140 
141 static const char *cmd_table_help[] = {
142 	"Usage:", ",[,.-/*jhr] [file]", "# load table data",
143 	",", "", "display table",
144 	", ", "[table-query]", "filter and print table. See ,? for more details",
145 	",.", " file.csv", "load table from CSV file (comma dot)",
146 	",,", "", "print table in csv format (comma comma)",
147 	",-", "", "reset table",
148 	",/", "?", "query/filter current table (non-destructive)",
149 	",*", ">$foo", "print table as r2 commands",
150 	",j", "", "print table in json format",
151 	",h", " xxd foo bar cow", "define header column names and types",
152 	",r", " 1 2 foo", "adds a row using the given format string",
153 	NULL
154 };
155 
156 static const char *help_msg_dot[] = {
157 	"Usage:", ".[r2cmd] | [file] | [!command] | [(macro)]", "# define macro or interpret r2, r_lang,\n"
158 	"    cparse, d, es6, exe, go, js, lsp, pl, py, rb, sh, vala or zig file",
159 	".", "", "repeat last command backward",
160 	".", "r2cmd", "interpret the output of the command as r2 commands",
161 	"..", " [file]", "run the output of the execution of a script as r2 commands",
162 	"...", "", "repeat last command forward (same as \\n)",
163 	".:", "8080", "listen for commands on given tcp port",
164 	".--", "", "terminate tcp server for remote commands",
165 	".", " foo.r2", "interpret script",
166 	".-", "", "open cfg.editor and interpret tmp file",
167 	".*", " file ...", "same as #!pipe open cfg.editor and interpret tmp file",
168 	".!", "rabin -ri $FILE", "interpret output of command",
169 	".", "(foo 1 2 3)", "run macro 'foo' with args 1, 2, 3",
170 	"./", " ELF", "interpret output of command /m ELF as r. commands",
171 	NULL
172 };
173 
174 static const char *help_msg_equal[] = {
175 	"Usage:", " =[:!+-=ghH] [...]", " # connect with other instances of r2",
176 	"\nremote commands:", "", "",
177 	"=", "", "list all open connections",
178 	"=<", "[fd] cmd", "send output of local command to remote fd", // XXX may not be a special char
179 	"=", "[fd] cmd", "exec cmd at remote 'fd' (last open is default one)",
180 	"=!", " cmd", "run command via r_io_system",
181 	"=+", " [proto://]host:port", "connect to remote host:port (*rap://, raps://, tcp://, udp://, http://)",
182 	"=-", "[fd]", "remove all hosts or host 'fd'",
183 	"==", "[fd]", "open remote session with host 'fd', 'q' to quit",
184 	"=!=", "", "disable remote cmd mode",
185 	"!=!", "", "enable remote cmd mode",
186 	"\nservers:","","",
187 	".:", "9000", "start the tcp server (echo x|nc ::1 9090 or curl ::1:9090/cmd/x)",
188 	"=:", "port", "start the rap server (o rap://9999)",
189 	"=g", "[?]", "start the gdbserver",
190 	"=h", "[?]", "start the http webserver",
191 	"=H", "[?]", "start the http webserver (and launch the web browser)",
192 	"\nother:","","",
193 	"=&", ":port", "start rap server in background (same as '&_=h')",
194 	"=", ":host:port cmd", "run 'cmd' command on remote server",
195 	"\nexamples:","","",
196 	"=+", "tcp://localhost:9090/", "connect to: r2 -c.:9090 ./bin",
197 	// "=+", "udp://localhost:9090/", "connect to: r2 -c.:9090 ./bin",
198 	"=+", "rap://localhost:9090/", "connect to: r2 rap://:9090",
199 	"=+", "http://localhost:9090/cmd/", "connect to: r2 -c'=h 9090' bin",
200 	"o ", "rap://:9090/", "start the rap server on tcp port 9090",
201 	NULL
202 };
203 
204 static const char *help_msg_equalh[] = {
205 	"Usage:", " =[hH] [...]", " # http server",
206 	"http server:", "", "",
207 	"=h", " port", "listen for http connections (r2 -qc=H /bin/ls)",
208 	"=h-", "", "stop background webserver",
209 	"=h--", "", "stop foreground webserver",
210 	"=h*", "", "restart current webserver",
211 	"=h&", " port", "start http server in background",
212 	"=H", " port", "launch browser and listen for http",
213 	"=H&", " port", "launch browser and listen for http in background",
214 	NULL
215 };
216 
217 static const char *help_msg_equalg[] = {
218 	"Usage:", " =[g] [...]", " # gdb server",
219 	"gdbserver:", "", "",
220 	"=g", " port file [args]", "listen on 'port' debugging 'file' using gdbserver",
221 	"=g!", " port file [args]", "same as above, but debug protocol messages (like gdbserver --remote-debug)",
222 	NULL
223 };
224 
225 static const char *help_msg_b[] = {
226 	"Usage:",  "b[f] [arg]\n", "Get/Set block size",
227 	"b", " 33", "set block size to 33",
228 	"b", " eip+4", "numeric argument can be an expression",
229 	"b", "", "display current block size",
230 	"b", "+3", "increase blocksize by 3",
231 	"b", "-16", "decrease blocksize by 16",
232 	"b*", "", "display current block size in r2 command",
233 	"bf", " foo", "set block size to flag size",
234 	"bj", "", "display block size information in JSON",
235 	"bm", " 1M", "set max block size",
236 	NULL
237 };
238 
239 static const char *help_msg_k[] = {
240 	"Usage:", "k[s] [key[=value]]", "Sdb Query",
241 	"k", " anal/**", "list namespaces under anal",
242 	"k", " anal/meta/*", "list kv from anal > meta namespaces",
243 	"k", " anal/meta/meta.0x80404", "get value for meta.0x80404 key",
244 	"k", " foo", "show value",
245 	"k", " foo=bar", "set value",
246 	"k", "", "list keys",
247 	"kd", " [file.sdb] [ns]", "dump namespace to disk",
248 	"kj", "", "List all namespaces and sdb databases in JSON format",
249 	"ko", " [file.sdb] [ns]", "open file into namespace",
250 	"ks", " [ns]", "enter the sdb query shell",
251 	//"kl", " ha.sdb", "load keyvalue from ha.sdb",
252 	//"ks", " ha.sdb", "save keyvalue to ha.sdb",
253 	NULL,
254 };
255 
256 static const char *help_msg_r[] = {
257 	"Usage:", "r[+-][ size]", "Resize file",
258 	"r", "", "display file size",
259 	"rj", "", "display the file size in JSON format",
260 	"r", " size", "expand or truncate file to given size",
261 	"r-", "num", "remove num bytes, move following data down",
262 	"r+", "num", "insert num bytes, move following data up",
263 	"rb", "oldbase @ newbase", "rebase all flags, bin.info, breakpoints and analysis",
264 	"rm" ," [file]", "remove file",
265 	"rh" ,"", "show size in human format",
266 	"r2" ," [file]", "launch r2 (same for rax2, rasm2, ...)",
267 	"reset" ,"", "reset console settings (clear --hard)",
268 	NULL
269 };
270 
271 static const char *help_msg_u[] = {
272 	"Usage:", "u", "uname or undo write/seek",
273 	"u", "", "show system uname",
274 	"uw", "", "alias for wc (requires: e io.cache=true)",
275 	"us", "", "alias for s- (seek history)",
276 	"uc", "[?]", "undo core commands (uc?, ucl, uc*, ..)",
277 	"uniq", "", "filter rows to avoid duplicates",
278 	"uname", "", "uname - show system information",
279 	NULL
280 };
281 
282 static const char *help_msg_uc[] = {
283 	"Usage:", "uc [cmd] [revert-cmd]", "undo core commands",
284 	"uc", "", "list all core undos",
285 	"uc*", "", "list all core undos as r2 commands",
286 	"uc-", "", "undo last action",
287 	"uc.", "", "list all reverts in current",
288 	NULL
289 };
290 
291 static const char *help_msg_y[] = {
292 	"Usage:", "y[ptxy] [len] [[@]addr]", " # See wd? for memcpy, same as 'yf'.",
293 	"y!", "", "open cfg.editor to edit the clipboard",
294 	"y", " 16 @ 0x200", "copy 16 bytes into clipboard from 0x200",
295 	"y", " 16 0x200", "copy 16 bytes into clipboard from 0x200",
296 	"y", " 16", "copy 16 bytes into clipboard",
297 	"y", "", "show yank buffer information (origin len bytes)",
298 	"y*", "", "print in r2 commands what's been yanked",
299 	"yf", " 64 0x200", "copy file 64 bytes from 0x200 from file",
300 	"yfa", " file copy", "copy all bytes from file (opens w/ io)",
301 	"yfx", " 10203040", "yank from hexpairs (same as ywx)",
302 	"yj", "", "print in JSON commands what's been yanked",
303 	"yp", "", "print contents of clipboard",
304 	"yq", "", "print contents of clipboard in hexpairs",
305 	"ys", "", "print contents of clipboard as string",
306 	"yt", " 64 0x200", "copy 64 bytes from current seek to 0x200",
307 	"ytf", " file", "dump the clipboard to given file",
308 	"yw", " hello world", "yank from string",
309 	"ywx", " 10203040", "yank from hexpairs (same as yfx)",
310 	"yx", "", "print contents of clipboard in hexadecimal",
311 	"yy", " @ 0x3344", "paste contents of clipboard to 0x3344",
312 	"yy", " 0x3344", "paste contents of clipboard to 0x3344",
313 	"yy", "", "paste contents of clipboard at current seek",
314 	"yz", " [len]", "copy nul-terminated string (up to blocksize) into clipboard",
315 	NULL
316 };
317 
318 static const char *help_msg_triple_exclamation[] = {
319 	"Usage:", "!!![-*][cmd] [arg|$type...]", " # user-defined autocompletion for commands",
320 	"!!!", "", "list all autocompletions",
321 	"!!!?", "", "show this help",
322 	"!!!", "-*", "remove all user-defined autocompletions",
323 	"!!!", "-\\*", "remove autocompletions matching this glob expression",
324 	"!!!", "-foo", "remove autocompletion named 'foo'",
325 	"!!!", "foo", "add 'foo' for autocompletion",
326 	"!!!", "bar $flag", "add 'bar' for autocompletion with $flag as argument",
327 	"Types:", "", "",
328 	NULL
329 };
330 
331 static const char *help_msg_vertical_bar[] = {
332 	"Usage:", "[cmd] | [program|H|T|.|]", "",
333 	"", "[cmd] |?", "show this help",
334 	"", "[cmd] |", "disable scr.html and scr.color",
335 	"", "[cmd] |H", "enable scr.html, respect scr.color",
336 	"", "[cmd] |T", "use scr.tts to speak out the stdout",
337 	"", "[cmd] | [program]", "pipe output of command to program",
338 	"", "[cmd] |.", "alias for .[cmd]",
339 	NULL
340 };
341 
342 static const char *help_msg_v[] = {
343 	"Usage:", "v[*i]", "",
344 	"v", "", "open visual panels",
345 	"v", " test", "load saved layout with name test",
346 	"v=", " test", "save current layout with name test",
347 	"vi", " test", "open the file test in 'cfg.editor'",
348 	NULL
349 };
350 
r_core_cmd_help(const RCore * core,const char * help[])351 R_API void r_core_cmd_help(const RCore *core, const char *help[]) {
352 	r_cons_cmd_help (help, core->print->flags & R_PRINT_FLAGS_COLOR);
353 }
354 
355 struct duplicate_flag_t {
356 	RList *ret;
357 	const char *word;
358 };
359 
duplicate_flag(RFlagItem * flag,void * u)360 static bool duplicate_flag(RFlagItem *flag, void *u) {
361 	struct duplicate_flag_t *user = (struct duplicate_flag_t *)u;
362 	/* filter per flag spaces */
363 	if (r_str_glob (flag->name, user->word)) {
364 		RFlagItem *cloned_item = r_flag_item_clone (flag);
365 		if (!cloned_item) {
366 			return false;
367 		}
368 		r_list_append (user->ret, cloned_item);
369 	}
370 	return true;
371 }
372 
recursive_help_go(RCore * core,int detail,RCmdDescriptor * desc)373 static void recursive_help_go(RCore *core, int detail, RCmdDescriptor *desc) {
374 	int i;
375 	if (desc->help_msg) {
376 		r_core_cmd_help (core, desc->help_msg);
377 	}
378 	if (detail >= 1) {
379 		if (desc->help_detail) {
380 			r_core_cmd_help (core, desc->help_detail);
381 		}
382 		if (detail >= 2 && desc->help_detail2) {
383 			r_core_cmd_help (core, desc->help_detail2);
384 		}
385 	}
386 	for (i = 32; i < R_ARRAY_SIZE (desc->sub); i++) {
387 		if (desc->sub[i]) {
388 			recursive_help_go (core, detail, desc->sub[i]);
389 		}
390 	}
391 }
392 
recursive_help(RCore * core,int detail,const char * cmd_prefix)393 static void recursive_help(RCore *core, int detail, const char *cmd_prefix) {
394 	const ut8 *p;
395 	RCmdDescriptor *desc = &core->root_cmd_descriptor;
396 	for (p = (const ut8 *)cmd_prefix; *p && *p < R_ARRAY_SIZE (desc->sub); p++) {
397 		if (!(desc = desc->sub[*p])) {
398 			return;
399 		}
400 	}
401 	recursive_help_go (core, detail, desc);
402 }
403 
lastcmd_repeat(RCore * core,int next)404 static bool lastcmd_repeat(RCore *core, int next) {
405 	int res = -1;
406 	// Fix for backtickbug px`~`
407 	if (!core->lastcmd || core->cons->context->cmd_depth < 1) {
408 		return false;
409 	}
410 	switch (*core->lastcmd) {
411 	case '.':
412 		if (core->lastcmd[1] == '(') { // macro call
413 			res = r_core_cmd0 (core, core->lastcmd);
414 		}
415 		break;
416 	case 'd': // debug
417 		res = r_core_cmd0 (core, core->lastcmd);
418 		switch (core->lastcmd[1]) {
419 		case 's':
420 		case 'c':
421 			r_core_cmd0 (core, "sr PC;pd 1");
422 		}
423 		break;
424 	case 'p': // print
425 	case 'x':
426 	case '$':
427 		if (!strncmp (core->lastcmd, "pd", 2)) {
428 			if (core->lastcmd[2]== ' ') {
429 				r_core_cmdf (core, "so %s", core->lastcmd + 3);
430 			} else {
431 				r_core_cmd0 (core, "so `pi~?`");
432 			}
433 		} else {
434 			if (next) {
435 				r_core_seek (core, core->offset + core->blocksize, true);
436 			} else {
437 				if (core->blocksize > core->offset) {
438 					r_core_seek (core, 0, true);
439 				} else {
440 					r_core_seek (core, core->offset - core->blocksize, true);
441 				}
442 			}
443 		}
444 		res = r_core_cmd0 (core, core->lastcmd);
445 		break;
446 	}
447 	return res != -1;
448 }
449 
r_core_cmd_nullcallback(void * data)450 static int r_core_cmd_nullcallback(void *data) {
451 	RCore *core = (RCore*) data;
452 	if (core->cons->context->breaked) {
453 		core->cons->context->breaked = false;
454 		return 0;
455 	}
456 	if (!core->cmdrepeat) {
457 		return 0;
458 	}
459 	lastcmd_repeat (core, true);
460 	return 1;
461 }
462 
cmd_uname(void * data,const char * input)463 static int cmd_uname(void *data, const char *input) { // "uniq"
464 	RSysInfo *si = r_sys_info();
465 	if (si) {
466 		r_cons_printf ("%s", si->sysname);
467 		if (strstr (input, "-r")) {
468 			r_cons_printf (" %s", si->release);
469 		}
470 		r_cons_newline ();
471 		r_sys_info_free (si);
472 	}
473 	return 0;
474 }
475 
cmd_uniq(void * data,const char * input)476 static int cmd_uniq(void *data, const char *input) { // "uniq"
477 	RCore *core = (RCore *)data;
478 	const char *arg = strchr (input, ' ');
479 	if (arg) {
480 		arg = r_str_trim_head_ro (arg + 1);
481 	}
482 	switch (*input) {
483 	case '?': // "uniq?"
484 		eprintf ("Usage: uniq # uniq to list unique strings in file\n");
485 		break;
486 	default: // "uniq"
487 		if (!arg) {
488 			arg = "";
489 		}
490 		if (r_fs_check (core->fs, arg)) {
491 			r_core_cmdf (core, "md %s", arg);
492 		} else {
493 			char *res = r_syscmd_uniq (arg);
494 			if (res) {
495 				r_cons_print (res);
496 				free (res);
497 			}
498 		}
499 		break;
500 	}
501 	return 0;
502 }
503 
cmd_head(void * data,const char * _input)504 static int cmd_head (void *data, const char *_input) { // "head"
505 	RCore *core = (RCore *)data;
506 	int lines = 5;
507 	char *input = strdup (_input);
508 	char *arg = strchr (input, ' ');
509 	char *tmp, *count;
510 	if (arg) {
511 		arg = (char *)r_str_trim_head_ro (arg + 1); 	// contains "count filename"
512 		count = strchr (arg, ' ');
513 		if (count) {
514 			*count = 0;	// split the count and file name
515 			tmp = (char *)r_str_trim_head_ro (count + 1);
516 			lines = atoi (arg);
517 			arg = tmp;
518 		}
519 	}
520 	switch (*input) {
521 	case '?': // "head?"
522 		eprintf ("Usage: head [file] # to list first n lines in file\n");
523 		break;
524 	default: // "head"
525 		if (!arg) {
526 			arg = "";
527 		}
528 		if (r_fs_check (core->fs, arg)) {
529 			r_core_cmdf (core, "md %s", arg);
530 		} else {
531 			char *res = r_syscmd_head (arg, lines);
532 			if (res) {
533 				r_cons_print (res);
534 				free (res);
535 			}
536 		}
537 		break;
538 	}
539 	free (input);
540 	return 0;
541 }
542 
cmd_undo(void * data,const char * input)543 static int cmd_undo(void *data, const char *input) {
544 	RCore *core = (RCore *)data;
545 	switch (input[0]) {
546 	case '?': // "u?"
547 		r_core_cmd_help (data, help_msg_u);
548 		return 1;
549 	case 'c': // "uc"
550 		switch (input[1]) {
551 		case ' ': {
552 			char *cmd = strdup (input + 2);
553 			char *rcmd = strchr (cmd, ',');
554 			if (rcmd) {
555 				*rcmd++ = 0;
556 				RCoreUndo *undo = r_core_undo_new (core->offset, cmd, rcmd);
557 				r_core_undo_push (core, undo);
558 			} else {
559 				eprintf ("Usage: uc [cmd] [revert-cmd]");
560 			}
561 			free (cmd);
562 			}
563 			break;
564 		case '?': // "uc?"
565 			r_core_cmd_help (core, help_msg_uc);
566 			break;
567 		case '.': { // "uc."
568 			RCoreUndoCondition cond = {
569 				.addr = core->offset,
570 				.minstamp = 0,
571 				.glob = NULL
572 			};
573 			r_core_undo_print (core, 1, &cond);
574 			break;
575 		}
576 		case '*': // "uc*"
577 			r_core_undo_print (core, 1, NULL);
578 			break;
579 		case '-': // "uc-"
580 			r_core_undo_pop (core);
581 			break;
582 		default:
583 			r_core_undo_print (core, 0, NULL);
584 			break;
585 		}
586 		return 1;
587 	case 's': // "us"
588 		r_core_cmdf (data, "s-%s", input + 1);
589 		return 1;
590 	case 'w': // "uw"
591 		r_core_cmdf (data, "wc%s", input + 1);
592 		return 1;
593 	case 'n': // "un"
594 		if (input[1] == 'a') { // "uname"
595 			(void)cmd_uname (core, input);
596 		} else if (input[1] == 'i' && input[2] == 'q') {
597 			(void)cmd_uniq (core, input);
598 		}
599 		return 1;
600 	}
601 #if __UNIX__
602 	struct utsname un;
603 	uname (&un);
604 	r_cons_printf ("%s %s %s %s\n", un.sysname,
605 		un.nodename, un.release, un.machine);
606 #elif __WINDOWS__
607 	r_cons_printf ("windows\n");
608 #else
609 	r_cons_printf ("unknown\n");
610 #endif
611 	return 0;
612 }
613 
cmd_alias(void * data,const char * input)614 static int cmd_alias(void *data, const char *input) {
615 	RCore *core = (RCore *)data;
616 	if (*input == '?') {
617 		r_core_cmd_help (core, help_msg_dollar);
618 		return 0;
619 	}
620 	int i = strlen (input);
621 	char *buf = malloc (i + 2);
622 	if (!buf) {
623 		return 0;
624 	}
625 	*buf = '$'; // prefix aliases with a dollar
626 	memcpy (buf + 1, input, i + 1);
627 	char *q = strchr (buf, ' ');
628 	char *def = strchr (buf, '=');
629 	char *desc = strchr (buf, '?');
630 	char *nonl = strchr (buf, 'n');
631 
632 	int defmode = 0;
633 	if (def && def > buf) {
634 		char *prev = def - 1;
635 		switch (*prev) {
636 		case ':':
637 			defmode = *prev;
638 			*prev = 0;
639 			break;
640 		case '+':
641 			defmode = *prev;
642 			*prev = 0;
643 			break;
644 		case '-':
645 			defmode = *prev;
646 			*prev = 0;
647 			break;
648 		}
649 	}
650 
651 	/* create alias */
652 	if ((def && q && (def < q)) || (def && !q)) {
653 		*def++ = 0;
654 		size_t len = strlen (def);
655 		if (defmode) {
656 			ut64 at = r_num_math (core->num, def);
657 			switch (defmode) {
658 			case ':':
659 				r_flag_set (core->flags, buf + 1, at, 1);
660 				return 1;
661 			case '+':
662 				at = r_num_get (core->num, buf + 1) + at;
663 				r_flag_set (core->flags, buf + 1, at, 1);
664 				return 1;
665 			case '-':
666 				at = r_num_get (core->num, buf + 1) - at;
667 				r_flag_set (core->flags, buf + 1, at, 1);
668 				return 1;
669 			}
670 		}
671 		/* Remove quotes */
672 		if (len > 0 && (def[0] == '\'') && (def[len - 1] == '\'')) {
673 			def[len - 1] = 0x00;
674 			def++;
675 		}
676 		if (!q || (q && q > def)) {
677 			if (*def) {
678 				if (!strcmp (def, "-")) {
679 					const char *v = r_cmd_alias_get (core->rcmd, buf, 0);
680 					char *n = r_cons_editor (NULL, v);
681 					if (n) {
682 						r_cmd_alias_set (core->rcmd, buf, n, 0);
683 						free (n);
684 					}
685 				} else {
686 					r_cmd_alias_set (core->rcmd, buf, def, 0);
687 				}
688 			} else {
689 				r_cmd_alias_del (core->rcmd, buf);
690 			}
691 		}
692 	/* Show command for alias */
693 	} else if (desc && !q) {
694 		*desc = 0;
695 		const char *v = r_cmd_alias_get (core->rcmd, buf, 0);
696 		if (v) {
697 			if (nonl == desc + 1) {
698 				r_cons_print (v);
699 			} else {
700 				r_cons_println (v);
701 			}
702 			free (buf);
703 			return 1;
704 		} else {
705 			eprintf ("unknown key '%s'\n", buf);
706 		}
707 	} else if (buf[1] == '*') {
708 		/* Show aliases */
709 		int i, count = 0;
710 		char **keys = r_cmd_alias_keys (core->rcmd, &count);
711 		for (i = 0; i < count; i++) {
712 			const char *v = r_cmd_alias_get (core->rcmd, keys[i], 0);
713 			char *q = r_base64_encode_dyn (v, -1);
714 			if (buf[2] == '*') {
715 				r_cons_printf ("%s=%s\n", keys[i], v);
716 			} else {
717 				r_cons_printf ("%s=base64:%s\n", keys[i], q);
718 			}
719 			free (q);
720 		}
721 	} else if (!buf[1]) {
722 		int i, count = 0;
723 		char **keys = r_cmd_alias_keys (core->rcmd, &count);
724 		for (i = 0; i < count; i++) {
725 			r_cons_println (keys[i]);
726 		}
727 	} else {
728 		/* Execute alias */
729 		if (q) {
730 			*q = 0;
731 		}
732 		const char *v = r_cmd_alias_get (core->rcmd, buf, 0);
733 		if (v) {
734 			if (*v == '$') {
735 				r_cons_strcat (v + 1);
736 				r_cons_newline ();
737 			} else if (q) {
738 				char *out = r_str_newf ("%s %s", v, q + 1);
739 				r_core_cmd0 (core, out);
740 				free (out);
741 			} else {
742 				r_core_cmd0 (core, v);
743 			}
744 		} else {
745 			ut64 at = r_num_get (core->num, buf + 1);
746 			if (at != UT64_MAX) {
747 				r_core_seek (core, at, true);
748 			} else {
749 				eprintf ("Unknown alias '%s'\n", buf + 1);
750 			}
751 		}
752 	}
753 	free (buf);
754 	return 0;
755 }
756 
getArg(char ch,int def)757 static int getArg(char ch, int def) {
758 	switch (ch) {
759 	case '&':
760 	case '-':
761 		return ch;
762 	}
763 	return def;
764 }
765 
766 // wtf dupe for local vs remote?
aliascmd(RCore * core,const char * str)767 static void aliascmd(RCore *core, const char *str) {
768 	switch (str[0]) {
769 	case '\0': // "=$"
770 		r_core_cmd0 (core, "$");
771 		break;
772 	case '-': // "=$-"
773 		if (str[1]) {
774 			r_cmd_alias_del (core->rcmd, str + 2);
775 		} else {
776 			r_cmd_alias_del (core->rcmd, NULL);
777 		//	r_cmd_alias_reset (core->rcmd);
778 		}
779 		break;
780 	case '?': // "=$?"
781 		eprintf ("Usage: =$[-][remotecmd]  # remote command alias\n");
782 		eprintf (" =$dr   # makes 'dr' alias for =!dr\n");
783 		eprintf (" =$-dr  # unset 'dr' alias\n");
784 		break;
785 	default:
786 		r_cmd_alias_set (core->rcmd, str, "", 1);
787 		break;
788 	}
789 }
790 
cmd_remote(RCore * core,const char * input,bool retry)791 static void cmd_remote(RCore *core, const char *input, bool retry) {
792 	if (!*input) {
793 		return;
794 	}
795 	if (*input == '?') {
796 		r_cons_printf ("Usage: =r localhost:9999\n");
797 		return;
798 	}
799 	char *host = strdup (input);
800 	char *port = strchr (host, ':');
801 	if (port) {
802 		*port++ = 0;
803 	}
804 	RSocket *s = r_socket_new (false);
805 repeat:
806 	if (r_socket_connect (s, host, port, R_SOCKET_PROTO_TCP, 1500)) {
807 		char buf[1024];
808 		void *bed = r_cons_sleep_begin ();
809 		r_cons_break_push (NULL, NULL);
810 		for (;;) {
811 			if (r_cons_is_breaked ()) {
812 				break;
813 			}
814 			r_socket_printf (s, "[0x%08"PFMT64x"]> ", core->offset);
815 			r_socket_flush (s);
816 			memset (buf, 0, sizeof (buf));
817 			r_socket_block_time (s, true, 99999, 0);
818 			if (r_socket_read (s, (ut8*)buf, sizeof (buf) - 1) < 1) {
819 				break;
820 			}
821 			if (*buf == 'q') {
822 				break;
823 			}
824 			const bool orig = r_config_get_b (core->config, "scr.interactive");
825 			r_config_set_b (core->config, "scr.interactive", false);
826 			char *res = r_core_cmd_str (core, buf);
827 			r_config_set_b (core->config, "scr.interactive", orig);
828 			r_socket_printf (s, "%s\n", res);
829 			r_socket_flush (s);
830 			free (res);
831 		}
832 		r_cons_break_pop ();
833 		r_cons_sleep_end (bed);
834 	} else {
835 		if (retry) {
836 			r_sys_sleep (1);
837 			goto repeat;
838 		}
839 	}
840 	r_socket_close (s);
841 	r_socket_free (s);
842 	free (host);
843 }
844 
cmd_rap(void * data,const char * input)845 static int cmd_rap(void *data, const char *input) {
846 	RCore *core = (RCore *)data;
847 	switch (*input) {
848 	case '\0': // "="
849 		r_core_rtr_list (core);
850 		break;
851 	case 'r': // "=r"
852 		cmd_remote (core, r_str_trim_head_ro (input + 1), false);
853 		break;
854 	case 'R': // "=R"
855 		cmd_remote (core, r_str_trim_head_ro (input + 1), true);
856 		break;
857 	case 'j': // "=j"
858 		eprintf ("TODO: list connections in json\n");
859 		break;
860 	case '!': // "=!"
861 		if (input[1] == 'q') {
862 			R_FREE (core->cmdremote);
863 		} else if (input[1] == '=') { // =!=0 or =!= for iosystem
864 			R_FREE (core->cmdremote);
865 			core->cmdremote = r_str_trim_dup (input + 2);
866 		} else {
867 			char *res = r_io_system (core->io, input + 1);
868 			if (res) {
869 				r_cons_printf ("%s\n", res);
870 				free (res);
871 			}
872 		}
873 		break;
874 	case '$': // "=$"
875 		// XXX deprecate?
876 		aliascmd (core, input + 1);
877 		break;
878 	case '+': // "=+"
879 		r_core_rtr_add (core, input + 1);
880 		break;
881 	case '-': // "=-"
882 		r_core_rtr_remove (core, input + 1);
883 		break;
884 	//case ':': r_core_rtr_cmds (core, input + 1); break;
885 	case '<': // "=<"
886 		r_core_rtr_pushout (core, input + 1);
887 		break;
888 	case '=': // "=="
889 		r_core_rtr_session (core, input + 1);
890 		break;
891 	case 'g': // "=g"
892 		if (input[1] == '?') {
893 			r_core_cmd_help (core, help_msg_equalg);
894 		} else {
895 			r_core_rtr_gdb (core, getArg (input[1], 'g'), input + 1);
896 		}
897 		break;
898 	case 'h': // "=h"
899 		if (input[1] == '?') {
900 			r_core_cmd_help (core, help_msg_equalh);
901 		} else {
902 			r_core_rtr_http (core, getArg (input[1], 'h'), 'h', input + 1);
903 		}
904 		break;
905 	case 'H': // "=H"
906 		if (input[1] == '?') {
907 			r_core_cmd_help (core, help_msg_equalh);
908 		} else {
909 			const char *arg = r_str_trim_head_ro (input + 1);
910 			r_core_rtr_http (core, getArg (input[1], 'H'), 'H', arg);
911 		}
912 		break;
913 	case '?': // "=?"
914 		r_core_cmd_help (core, help_msg_equal);
915 		break;
916 	default:
917 		r_core_rtr_cmd (core, input);
918 		break;
919 	}
920 	return 0;
921 }
922 
cmd_rap_run(void * data,const char * input)923 static int cmd_rap_run(void *data, const char *input) {
924 	RCore *core = (RCore *)data;
925 	char *res = r_io_system (core->io, input);
926 	if (res) {
927 		int ret = atoi (res);
928 		free (res);
929 		return ret;
930 	}
931 	return false;
932 }
933 
cmd_yank(void * data,const char * input)934 static int cmd_yank(void *data, const char *input) {
935 	ut64 n;
936 	RCore *core = (RCore *)data;
937 	switch (input[0]) {
938 	case ' ': // "y "
939 		r_core_yank (core, core->offset, r_num_math (core->num, input + 1));
940 		break;
941 	case 'l': // "yl"
942 		core->num->value = r_buf_size (core->yank_buf);
943 		break;
944 	case 'y': // "yy"
945 		while (input[1] == ' ') {
946 			input++;
947 		}
948 		n = input[1]? r_num_math (core->num, input + 1): core->offset;
949 		r_core_yank_paste (core, n, 0);
950 		break;
951 	case 'x': // "yx"
952 		r_core_yank_hexdump (core, r_num_math (core->num, input + 1));
953 		break;
954 	case 'z': // "yz"
955 		r_core_yank_string (core, core->offset, r_num_math (core->num, input + 1));
956 		break;
957 	case 'w': // "yw" ... we have yf which makes more sense than 'w'
958 		switch (input[1]) {
959 		case ' ':
960 			r_core_yank_set (core, 0, (const ut8*)input + 2, strlen (input + 2));
961 			break;
962 		case 'x':
963 			if (input[2] == ' ') {
964 				char *out = strdup (input + 3);
965 				int len = r_hex_str2bin (input + 3, (ut8*)out);
966 				if (len > 0) {
967 					r_core_yank_set (core, core->offset, (const ut8*)out, len);
968 				} else {
969 					eprintf ("Invalid length\n");
970 				}
971 				free (out);
972 			} else {
973 				eprintf ("Usage: ywx [hexpairs]\n");
974 			}
975 			// r_core_yank_write_hex (core, input + 2);
976 			break;
977 		default:
978 			eprintf ("Usage: ywx [hexpairs]\n");
979 			break;
980 		}
981 		break;
982 	case 'p': // "yp"
983 		r_core_yank_cat (core, r_num_math (core->num, input + 1));
984 		break;
985 	case 's': // "ys"
986 		r_core_yank_cat_string (core, r_num_math (core->num, input + 1));
987 		break;
988 	case 't': // "wt"
989 		if (input[1] == 'f') { // "wtf"
990 			ut64 tmpsz;
991 			const char *file = r_str_trim_head_ro (input + 2);
992 			const ut8 *tmp = r_buf_data (core->yank_buf, &tmpsz);
993 			if (!r_file_dump (file, tmp, tmpsz, false)) {
994 				eprintf ("Cannot dump to '%s'\n", file);
995 			}
996 		} else if (input[1] == ' ') {
997 			r_core_yank_to (core, input + 1);
998 		} else {
999 			eprintf ("Usage: wt[f] [arg] ..\n");
1000 		}
1001 		break;
1002 	case 'f': // "yf"
1003 		switch (input[1]) {
1004 		case ' ': // "yf"
1005 			r_core_yank_file_ex (core, input + 1);
1006 			break;
1007 		case 'x': // "yfx"
1008 			r_core_yank_hexpair (core, input + 2);
1009 			break;
1010 		case 'a': // "yfa"
1011 			r_core_yank_file_all (core, input + 2);
1012 			break;
1013 		default:
1014 			eprintf ("Usage: yf[xa] [arg]\n");
1015 			eprintf ("yf [file]     - copy blocksize from file into the clipboard\n");
1016 			eprintf ("yfa [path]    - yank the whole file\n");
1017 			eprintf ("yfx [hexpair] - yank from hexpair string\n");
1018 			break;
1019 		}
1020 		break;
1021 	case '!': // "y!"
1022 		{
1023 			char *sig = r_core_cmd_str (core, "y*");
1024 			if (!sig || !*sig) {
1025 				free (sig);
1026 				sig = strdup ("wx 10203040");
1027 			}
1028 			char *data = r_core_editor (core, NULL, sig);
1029 			(void) strtok (data, ";\n");
1030 			r_core_cmdf (core, "y%s", data);
1031 			free (sig);
1032 			free (data);
1033 		}
1034 		break;
1035 	case '*': // "y*"
1036 	case 'j': // "yj"
1037 	case 'q': // "yq"
1038 	case '\0': // "y"
1039 		r_core_yank_dump (core, 0, input[0]);
1040 		break;
1041 	default:
1042 		r_core_cmd_help (core, help_msg_y);
1043 		break;
1044 	}
1045 	return true;
1046 }
1047 
lang_run_file(RCore * core,RLang * lang,const char * file)1048 static int lang_run_file(RCore *core, RLang *lang, const char *file) {
1049 	r_core_sysenv_begin (core, NULL);
1050 	return r_lang_run_file (core->lang, file);
1051 }
1052 
langFromHashbang(RCore * core,const char * file)1053 static char *langFromHashbang(RCore *core, const char *file) {
1054 	int fd = r_sandbox_open (file, O_RDONLY, 0);
1055 	if (fd != -1) {
1056 		char firstLine[128] = {0};
1057 		int len = r_sandbox_read (fd, (ut8*)firstLine, sizeof (firstLine) - 1);
1058 		firstLine[len] = 0;
1059 		if (!strncmp (firstLine, "#!/", 3)) {
1060 			// I CAN HAS A HASHBANG
1061 			char *nl = strchr (firstLine, '\n');
1062 			if (nl) {
1063 				*nl = 0;
1064 			}
1065 			nl = strchr (firstLine, ' ');
1066 			if (nl) {
1067 				*nl = 0;
1068 			}
1069 			nl = strdup (firstLine + 2);
1070 			r_sandbox_close (fd);
1071 			return nl;
1072 		}
1073 		r_sandbox_close (fd);
1074 	}
1075 	return NULL;
1076 }
1077 
r_core_run_script(RCore * core,const char * file)1078 R_API bool r_core_run_script(RCore *core, const char *file) {
1079 	bool ret = false;
1080 	RListIter *iter;
1081 	RLangPlugin *p;
1082 	char *name;
1083 
1084 	r_list_foreach (core->scriptstack, iter, name) {
1085 		if (!strcmp (file, name)) {
1086 			eprintf ("WARNING: ignored nested source: %s\n", file);
1087 			return false;
1088 		}
1089 	}
1090 	r_list_push (core->scriptstack, strdup (file));
1091 
1092 	if (!strcmp (file, "-")) {
1093 		char *out = r_core_editor (core, NULL, NULL);
1094 		if (out) {
1095 			ret = r_core_cmd_lines (core, out);
1096 			free (out);
1097 		}
1098 	} else if (r_str_endswith (file, ".html")) {
1099 		const bool httpSandbox = r_config_get_i (core->config, "http.sandbox");
1100 		char *httpIndex = strdup (r_config_get (core->config, "http.index"));
1101 		r_config_set_b (core->config, "http.sandbox", false);
1102 		char *absfile = r_file_abspath (file);
1103 		r_config_set (core->config, "http.index", absfile);
1104 		free (absfile);
1105 		r_core_cmdf (core, "=H");
1106 		r_config_set_b (core->config, "http.sandbox", httpSandbox);
1107 		r_config_set (core->config, "http.index", httpIndex);
1108 		free (httpIndex);
1109 		ret = true;
1110 	} else if (r_str_endswith (file, ".c")) {
1111 		r_core_cmd_strf (core, "#!c %s", file);
1112 		ret = true;
1113 	} else if (r_file_is_c (file)) {
1114 		const char *dir = r_config_get (core->config, "dir.types");
1115 		char *out = r_parse_c_file (core->anal, file, dir, NULL);
1116 		if (out) {
1117 			r_cons_strcat (out);
1118 			sdb_query_lines (core->anal->sdb_types, out);
1119 			free (out);
1120 		}
1121 		ret = out != NULL;
1122 	} else {
1123 		p = r_lang_get_by_extension (core->lang, file);
1124 		if (p) {
1125 			r_lang_use (core->lang, p->name);
1126 			ret = lang_run_file (core, core->lang, file);
1127 		} else {
1128 // XXX this is an ugly hack, we need to use execve here and specify args properly
1129 #if __WINDOWS__
1130 #define cmdstr(x) r_str_newf (x" %s", file);
1131 #else
1132 #define cmdstr(x) r_str_newf (x" '%s'", file);
1133 #endif
1134 			const char *p = r_str_lchr (file, '.');
1135 			if (p) {
1136 				const char *ext = p + 1;
1137 				/* TODO: handle this inside r_lang_pipe with new APIs */
1138 				if (!strcmp (ext, "js")) {
1139 					char *cmd = cmdstr ("node");
1140 					r_lang_use (core->lang, "pipe");
1141 					lang_run_file (core, core->lang, cmd);
1142 					free (cmd);
1143 					ret = 1;
1144 				} else if (!strcmp (ext, "exe")) {
1145 #if __WINDOWS__
1146 					char *cmd = r_str_newf ("%s", file);
1147 #else
1148 					char *cmd = cmdstr ("wine");
1149 #endif
1150 					r_lang_use (core->lang, "pipe");
1151 					lang_run_file (core, core->lang, cmd);
1152 					free (cmd);
1153 					ret = 1;
1154 				} else if (!strcmp (ext, "zig")) {
1155 					char *cmd = cmdstr ("zig run");
1156 					r_lang_use (core->lang, "pipe");
1157 					lang_run_file (core, core->lang, cmd);
1158 					free (cmd);
1159 					ret = 1;
1160 				} else if (!strcmp (ext, "d")) {
1161 					char *cmd = cmdstr ("dmd -run");
1162 					r_lang_use (core->lang, "pipe");
1163 					lang_run_file (core, core->lang, cmd);
1164 					free (cmd);
1165 					ret = 1;
1166 				} else if (!strcmp (ext, "lsp")) {
1167 					char *cmd = cmdstr ("newlisp -n");
1168 					r_lang_use (core->lang, "pipe");
1169 					lang_run_file (core, core->lang, cmd);
1170 					free (cmd);
1171 					ret = 1;
1172 				} else if (!strcmp (ext, "go")) {
1173 					char *cmd = cmdstr ("go run");
1174 					r_lang_use (core->lang, "pipe");
1175 					lang_run_file (core, core->lang, cmd);
1176 					free (cmd);
1177 					ret = 1;
1178 				} else if (!strcmp (ext, "es6")) {
1179 					char *cmd = cmdstr ("babel-node");
1180 					r_lang_use (core->lang, "pipe");
1181 					lang_run_file (core, core->lang, cmd);
1182 					free (cmd);
1183 					ret = 1;
1184 				} else if (!strcmp (ext, "rb")) {
1185 					char *cmd = cmdstr ("ruby");
1186 					r_lang_use (core->lang, "pipe");
1187 					lang_run_file (core, core->lang, cmd);
1188 					free (cmd);
1189 					ret = 1;
1190 				} else if (!strcmp (ext, "vala")) {
1191 					r_lang_use (core->lang, "vala");
1192 					lang_run_file (core, core->lang, file);
1193 					ret = 1;
1194 				} else if (!strcmp (ext, "sh")) {
1195 					char *shell = r_sys_getenv ("SHELL");
1196 					if (!shell) {
1197 						shell = strdup ("sh");
1198 					}
1199 					if (shell) {
1200 						r_lang_use (core->lang, "pipe");
1201 						char *cmd = r_str_newf ("%s '%s'", shell, file);
1202 						if (cmd) {
1203 							lang_run_file (core, core->lang, cmd);
1204 							free (cmd);
1205 						}
1206 						free (shell);
1207 					}
1208 					ret = 1;
1209 				} else if (!strcmp (ext, "pl")) {
1210 					char *cmd = cmdstr ("perl");
1211 					r_lang_use (core->lang, "pipe");
1212 					lang_run_file (core, core->lang, cmd);
1213 					free (cmd);
1214 					ret = 1;
1215 				} else if (!strcmp (ext, "py")) {
1216 					char *cmd = cmdstr ("python");
1217 					r_lang_use (core->lang, "pipe");
1218 					lang_run_file (core, core->lang, cmd);
1219 					free (cmd);
1220 					ret = 1;
1221 				}
1222 			} else {
1223 				char *abspath = r_file_path (file);
1224 				char *lang = langFromHashbang (core, file);
1225 				if (lang) {
1226 					r_lang_use (core->lang, "pipe");
1227 					char *cmd = r_str_newf ("%s '%s'", lang, file);
1228 					lang_run_file (core, core->lang, cmd);
1229 					free (lang);
1230 					free (cmd);
1231 					ret = 1;
1232 				}
1233 				free (abspath);
1234 			}
1235 			if (!ret) {
1236 				ret = r_core_cmd_file (core, file);
1237 			}
1238 		}
1239 	}
1240 	free (r_list_pop (core->scriptstack));
1241 	return ret;
1242 }
1243 
cmd_ls(void * data,const char * input)1244 static int cmd_ls(void *data, const char *input) { // "ls"
1245 	RCore *core = (RCore *)data;
1246 	const char *arg = strchr (input, ' ');
1247 	if (arg) {
1248 		arg = r_str_trim_head_ro (arg + 1);
1249 	}
1250 	switch (*input) {
1251 	case '?': // "l?"
1252 		eprintf ("Usage: l[es] # ls to list files, le[ss] to less a file\n");
1253 		break;
1254 	case 'e': // "le"
1255 		if (arg) {
1256 			r_core_cmdf (core, "cat %s~..", arg);
1257 		} else {
1258 			eprintf ("Usage: less [file]\n");
1259 		}
1260 		break;
1261 	default: // "ls"
1262 		if (!arg) {
1263 			arg = "";
1264 		}
1265 		if (r_fs_check (core->fs, arg)) {
1266 			r_core_cmdf (core, "md %s", arg);
1267 		} else {
1268 			char *res = r_syscmd_ls (arg);
1269 			if (res) {
1270 				r_cons_print (res);
1271 				free (res);
1272 			}
1273 		}
1274 		break;
1275 	}
1276 	return 0;
1277 }
1278 
cmd_join(void * data,const char * input)1279 static int cmd_join(void *data, const char *input) { // "join"
1280 	RCore *core = (RCore *)data;
1281 	char *tmp = strdup (input);
1282 	const char *arg1 = strchr (tmp, ' ');
1283 	if (!arg1) {
1284 		goto beach;
1285 	}
1286 	arg1 = r_str_trim_head_ro (arg1);
1287 	if (!arg1) {
1288 		goto beach;
1289 	}
1290 	char *end = strchr (arg1, ' ');
1291 	if (!end) {
1292 		goto beach;
1293 	}
1294 	*end = '\0';
1295 	const char *arg2 = end+1;
1296 	if (!arg2) {
1297 		goto beach;
1298 	}
1299 	arg2 = r_str_trim_head_ro (arg2);
1300 	switch (*input) {
1301 	case '?': // "join?"
1302 		goto beach;
1303 	default: // "join"
1304 		if (!arg1) {
1305 			arg1 = "";
1306 		}
1307 		if (!arg2) {
1308 			arg2 = "";
1309 		}
1310 		if (!r_fs_check (core->fs, arg1) && !r_fs_check (core->fs, arg2)) {
1311 			char *res = r_syscmd_join (arg1, arg2);
1312 			if (res) {
1313 				r_cons_print (res);
1314 				free (res);
1315 			}
1316 		}
1317 		break;
1318 	}
1319 	free (tmp);
1320 	return 0;
1321 beach:
1322 	eprintf ("Usage: join [file1] [file2] # join the contents of the two files\n");
1323 	free (tmp);
1324 	return 0;
1325 }
1326 
cmd_stdin(void * data,const char * input)1327 static int cmd_stdin(void *data, const char *input) {
1328 	RCore *core = (RCore *)data;
1329 	if (input[0] == '?') {
1330 		r_cons_printf ("Usage: '-' '.-' '. -' do the same\n");
1331 		return false;
1332 	}
1333 	return r_core_run_script (core, "-");
1334 }
1335 
load_table_json(RCore * core,RTable * t,char * data)1336 static void load_table_json(RCore *core, RTable *t, char *data) {
1337 	// parse json file and iterate over all the entries
1338 	// RTableRow *row = r_table_row_new (items);
1339 	// r_list_append (t->rows, row);
1340 	eprintf ("TODO: Loading tables from JSON is not yet implemented\n");
1341 }
1342 
get_type_string(const char * s)1343 static const char *get_type_string(const char *s) {
1344 	if (!strncmp (s, "0x", 2)) {
1345 		return "x";
1346 	}
1347 	if (*s == '0' || atoi (s)) {
1348 		return "d";
1349 	}
1350 	return "s";
1351 }
1352 
load_table_csv(RCore * core,RTable * t,RList * lines)1353 static void load_table_csv(RCore *core, RTable *t, RList *lines) {
1354 	RListIter *iter;
1355 	char *line;
1356 	int row = 0;
1357 
1358 	RList *cols = NULL;
1359 	r_list_foreach (lines, iter, line) {
1360 		char *word;
1361 		RListIter *iter2;
1362 		RList *words = r_str_split_list (line, ",", 0);
1363 		if (r_list_length (words) > 0) {
1364 			switch (row) {
1365 			case 0:
1366 				cols = words;
1367 				words = NULL;
1368 				break;
1369 			case 1:
1370 				{
1371 				RStrBuf *b = r_strbuf_new (",h ");
1372 				RStrBuf *args = r_strbuf_new ("");
1373 				r_list_foreach (words, iter2, word) {
1374 					const char *type = get_type_string (word);
1375 					r_strbuf_append (b, type);
1376 				}
1377 				r_list_foreach (cols, iter2, word) {
1378 					r_strbuf_append (b , " ");
1379 					r_strbuf_append (b, word);
1380 				}
1381 				r_core_cmd0 (core, r_strbuf_get (b));
1382 				r_strbuf_free (args);
1383 				r_strbuf_free (b);
1384 				}
1385 				/* fallthrough */
1386 			default:
1387 				{
1388 				RStrBuf *b = r_strbuf_new (",r ");
1389 				r_list_foreach (words, iter2, word) {
1390 					r_strbuf_append (b, " ");
1391 					r_strbuf_append (b, word);
1392 				}
1393 				r_core_cmd0 (core, r_strbuf_get (b));
1394 				r_strbuf_free (b);
1395 				}
1396 				break;
1397 			}
1398 		}
1399 		r_list_free (words);
1400 		row++;
1401 	}
1402 }
1403 
load_table_asciiart(RCore * core,RTable * t,RList * lines)1404 static void load_table_asciiart(RCore *core, RTable *t, RList *lines) {
1405 	RListIter *iter;
1406 	char *line;
1407 	const char *separator = "|";
1408 	int ncols = 0;
1409 	bool expect_header = false;
1410 	bool expect_rows = false;
1411 	r_list_foreach (lines, iter, line) {
1412 		if (!expect_rows) {
1413 			if (r_str_startswith (line, ".--")) {
1414 				expect_header = true;
1415 				separator = "|";
1416 				continue;
1417 			}
1418 			if (r_str_startswith (line, "┌")) {
1419 				expect_header = true;
1420 				separator = "│";
1421 				continue;
1422 			}
1423 			if (r_str_startswith (line, ")-")) {
1424 				expect_rows = true;
1425 				separator = "|";
1426 				continue;
1427 			}
1428 			if (r_str_startswith (line, "│─")) {
1429 				expect_rows = true;
1430 				separator = "│";
1431 				continue;
1432 			}
1433 		}
1434 
1435 		RTableColumnType *typeString = r_table_type ("string");
1436 		RTableColumnType *typeNumber = r_table_type ("number");
1437 		if (expect_header) {
1438 			char *arg;
1439 			RList *args = r_str_split_list (line + strlen (separator), separator, 0);
1440 			RListIter *iter2;
1441 			ncols = 0;
1442 			if (r_list_length (t->cols) > 0) {
1443 				eprintf ("Warning: Not re-adding headers. Use ,- to reset the table.\n");
1444 				continue;
1445 			}
1446 			r_list_foreach (args, iter2, arg) {
1447 				char *s = strchr (arg, ' ');
1448 				char *ss = r_str_trim_dup (s? s + 1: arg);
1449 				if (!*ss) {
1450 					free (ss);
1451 					continue;
1452 				}
1453 				r_table_add_column (t, typeString, ss, 0);
1454 				ncols ++;
1455 			}
1456 			expect_header = false;
1457 		} else if (expect_rows) {
1458 			char *arg;
1459 			size_t line_len = strlen (line);
1460 			size_t separator_len = strlen (separator);
1461 			size_t pos = (line_len < separator_len)? line_len: separator_len;
1462 			RList *args = r_str_split_list (line + pos, separator, 0);
1463 			RList *items = r_list_newf (free);
1464 			RListIter *iter2;
1465 			if (r_list_length (args) < ncols) {
1466 				// dowarn?
1467 				continue;
1468 			}
1469 			r_list_foreach (args, iter2, arg) {
1470 				char *ss = r_str_trim_dup (arg);
1471 				if (!*ss) {
1472 					free (ss);
1473 					continue;
1474 				}
1475 				if (isdigit ((unsigned char)*ss)) {
1476 					int col = r_list_length (items);
1477 					RTableColumn *c = r_list_get_n (t->cols, col);
1478 					if (c) {
1479 						c->type = typeNumber;
1480 					}
1481 				}
1482 				r_list_append (items, ss);
1483 			}
1484 			RTableRow *row = r_table_row_new (items);
1485 			r_list_append (t->rows, row);
1486 		}
1487 	}
1488 }
1489 
load_table(RCore * core,RTable * t,char * data)1490 static void load_table(RCore *core, RTable *t, char *data) {
1491 	r_return_if_fail (core && t && data);
1492 	if (*data == '[') {
1493 		load_table_json (core, t, data);
1494 	} else {
1495 		RList *lines = r_str_split_list (data, "\n", 0);
1496 		if (strchr (data, ',')) {
1497 			load_table_csv (core, t, lines);
1498 		} else {
1499 			load_table_asciiart (core, t, lines);
1500 		}
1501 		r_list_free (lines);
1502 	}
1503 	free (data);
1504 }
1505 
display_table(char * ts)1506 static void display_table(char *ts) {
1507 	if (ts) {
1508 		r_cons_printf ("%s\n", ts);
1509 		free (ts);
1510 	}
1511 }
1512 
cmd_table_header(RCore * core,char * s)1513 static void cmd_table_header(RCore *core, char *s) {
1514 	RList *list = r_str_split_list (s, " ", 0); // owns *s
1515 	RListIter *iter;
1516 	char *format = r_list_pop_head (list);
1517 	if (!format) {
1518 		return;
1519 	}
1520 	if (!core->table) {
1521 		core->table = r_core_table (core, "header");
1522 	}
1523 	size_t i = 0;
1524 	r_list_foreach (list, iter, s) {
1525 		const char type_char = format[i];
1526 		if (!type_char) {
1527 			break;
1528 		}
1529 		const char *type_name = (type_char == 's')
1530 			? "string": "number";
1531 		RTableColumnType *typeString = r_table_type (type_name);
1532 		r_table_add_column (core->table, typeString, s, 0);
1533 		i++;
1534 	}
1535 	r_list_free (list);
1536 	free (format);
1537 }
1538 
display_table_filter(RCore * core,const char * input)1539 static bool display_table_filter(RCore *core, const char *input) {
1540 	r_return_val_if_fail (core && input, false);
1541 	if (!core->table) {
1542 		return false;
1543 	}
1544 	int skip = (*input == ' ')? 1: (*input&&input[1])? 2: 0;
1545 	if (skip) {
1546 		const char *q = r_str_trim_head_ro (input + skip);
1547 		return r_table_query (core->table, q);
1548 	}
1549 	return true;
1550 }
1551 
cmd_table(void * data,const char * input)1552 static int cmd_table(void *data, const char *input) {
1553 	RCore *core = (RCore*)data;
1554 	if (!core->table) {
1555 		core->table = r_table_new ("table");
1556 	}
1557 	switch (*input) {
1558 	case 'h': // table header columns
1559 	case 'c': // table columns
1560 		cmd_table_header (core, r_str_trim_dup (input + 1));
1561 		break;
1562 	case 'r': // add row
1563 		{
1564 			if (!core->table) {
1565 				core->table = r_table_new ("table");
1566 			}
1567 			char *args = r_str_trim_dup (input + 1);
1568 			if (*args) {
1569 				RList *list = r_str_split_list (args, " ", 0);
1570 				if (list) {
1571 					r_table_add_row_list (core->table, list);
1572 				}
1573 			}
1574 		}
1575 		break;
1576 	case '-':
1577 		r_table_free (core->table);
1578 		core->table = r_table_new ("table");
1579 		break;
1580 	case '/':
1581 		// query here
1582 		{
1583 			RTable *ot = r_table_clone (core->table);
1584 			if (display_table_filter (core, input)) {
1585 				display_table (r_table_tostring (core->table));
1586 			}
1587 			r_table_free (core->table);
1588 			core->table = ot;
1589 		}
1590 		break;
1591 	case '.': // ",."
1592 		if (R_STR_ISEMPTY (input + 1)) {
1593 			eprintf ("Usage: ,. [file | $alias]\n");
1594 		} else {
1595 			const char *file = r_str_trim_head_ro (input + 1);
1596 			if (*file == '$') {
1597 				const char *file_data = r_cmd_alias_get (core->rcmd, file, 1);
1598 				if (file_data) {
1599 					load_table (core, core->table, strdup (file_data + 1));
1600 				}
1601 			} else {
1602 				char *file_data = r_file_slurp (file, NULL);
1603 				if (file_data) {
1604 					load_table (core, core->table, file_data);
1605 				} else {
1606 					eprintf ("Cannot open file.\n");
1607 				}
1608 			}
1609 		}
1610 		break;
1611 	case ' ':
1612 		if (display_table_filter (core, input)) {
1613 			display_table (r_table_tostring (core->table));
1614 		}
1615 		break;
1616 	case ',':
1617 		if (display_table_filter (core, input)) {
1618 			display_table (r_table_tocsv (core->table));
1619 		}
1620 		break;
1621 	case '*':
1622 		if (display_table_filter (core, input)) {
1623 			display_table (r_table_tor2cmds (core->table));
1624 		}
1625 		break;
1626 	case 'j':
1627 		if (display_table_filter (core, input)) {
1628 			display_table (r_table_tojson (core->table));
1629 		}
1630 		break;
1631 	case 0:
1632 		if (core->table) {
1633 			display_table (r_table_tofancystring (core->table));
1634 		}
1635 		break;
1636 	case '?':
1637 		r_core_cmd_help (core, cmd_table_help);
1638 		r_cons_printf ("%s\n", r_table_help ());
1639 		break;
1640 	default:
1641 		r_core_cmd_help (core, cmd_table_help);
1642 		break;
1643 	}
1644 	return 0;
1645 }
1646 
cmd_interpret(void * data,const char * input)1647 static int cmd_interpret(void *data, const char *input) {
1648 	char *str, *ptr, *eol, *rbuf, *filter, *inp;
1649 	const char *host, *port, *cmd;
1650 	RCore *core = (RCore *)data;
1651 
1652 	if (!strcmp (input, "?")) {
1653 		r_core_cmd_help (core, help_msg_dot);
1654 		return 0;
1655 	}
1656 	switch (*input) {
1657 	case '\0': // "."
1658 		lastcmd_repeat (core, 0);
1659 		break;
1660 	case ':': // ".:"
1661 		if ((ptr = strchr (input + 1, ' '))) {
1662 			/* .:port cmd */
1663 			/* .:host:port cmd */
1664 			cmd = ptr + 1;
1665 			*ptr = 0;
1666 			eol = strchr (input + 1, ':');
1667 			if (eol) {
1668 				*eol = 0;
1669 				host = input + 1;
1670 				port = eol + 1;
1671 			} else {
1672 				host = "localhost";
1673 				port = input + ((input[1] == ':')? 2: 1);
1674 			}
1675 			rbuf = r_core_rtr_cmds_query (core, host, port, cmd);
1676 			if (rbuf) {
1677 				r_cons_print (rbuf);
1678 				free (rbuf);
1679 			}
1680 		} else {
1681 			r_core_rtr_cmds (core, input + 1);
1682 		}
1683 		break;
1684 	case '.': // ".." same as \n
1685 		if (input[1] == '.') { // "..." run the last command repeated
1686 			// same as \n with e cmd.repeat=true
1687 			lastcmd_repeat (core, 1);
1688 		} else if (input[1]) {
1689 			char *str = r_core_cmd_str_pipe (core, r_str_trim_head_ro (input));
1690 			if (str) {
1691 				r_core_cmd (core, str, 0);
1692 				free (str);
1693 			}
1694 		} else {
1695 			eprintf ("Usage: .. ([file])\n");
1696 		}
1697 		break;
1698 	case '*': // ".*"
1699 		{
1700 			const char *a = r_str_trim_head_ro (input + 1);
1701 			char *s = strdup (a);
1702 			char *sp = strchr (s, ' ');
1703 			if (sp) {
1704 				*sp = 0;
1705 			}
1706 			if (R_STR_ISNOTEMPTY (s)) {
1707 				r_core_run_script (core, s);
1708 			}
1709 			free (s);
1710 		}
1711 		break;
1712 	case '-': // ".-"
1713 		if (input[1] == '?') {
1714 			r_cons_printf ("Usage: '-' '.-' '. -' do the same\n");
1715 		} else {
1716 			r_core_run_script (core, "-");
1717 		}
1718 		break;
1719 	case ' ': // ". "
1720 		{
1721 			const char *script_file = r_str_trim_head_ro (input + 1);
1722 			if (*script_file == '$') {
1723 				const char *oldText = r_cmd_alias_get (core->rcmd, script_file, 1);
1724 				r_core_cmd0 (core, oldText); // script_file);
1725 			} else {
1726 				if (!r_core_run_script (core, script_file)) {
1727 					eprintf ("Cannot find script '%s'\n", script_file);
1728 					core->num->value = 1;
1729 				} else {
1730 					core->num->value = 0;
1731 				}
1732 			}
1733 		}
1734 		break;
1735 	case '!': // ".!"
1736 		/* from command */
1737 		r_core_cmd_command (core, input + 1);
1738 		break;
1739 	case '(': // ".("
1740 		r_cmd_macro_call (&core->rcmd->macro, input + 1);
1741 		break;
1742 	default:
1743 		if (*input >= 0 && *input <= 9) {
1744 			eprintf ("|ERROR| No .[0..9] to avoid infinite loops\n");
1745 			break;
1746 		}
1747 		inp = strdup (input);
1748 		filter = strchr (inp, '~');
1749 		if (filter) {
1750 			*filter = 0;
1751 		}
1752 		int tmp_html = r_cons_singleton ()->is_html;
1753 		r_cons_singleton ()->is_html = false;
1754 		ptr = str = r_core_cmd_str (core, inp);
1755 		r_cons_singleton ()->is_html = tmp_html;
1756 
1757 		if (filter) {
1758 			*filter = '~';
1759 		}
1760 		r_cons_break_push (NULL, NULL);
1761 		if (ptr) {
1762 			for (;;) {
1763 				if (r_cons_is_breaked ()) {
1764 					break;
1765 				}
1766 				eol = strchr (ptr, '\n');
1767 				if (eol) {
1768 					*eol = '\0';
1769 				}
1770 				if (*ptr) {
1771 					char *p = r_str_append (strdup (ptr), filter);
1772 					r_core_cmd0 (core, p);
1773 					free (p);
1774 				}
1775 				if (!eol) {
1776 					break;
1777 				}
1778 				ptr = eol + 1;
1779 			}
1780 		}
1781 		r_cons_break_pop ();
1782 		free (str);
1783 		free (inp);
1784 		break;
1785 	}
1786 	return 0;
1787 }
1788 
callback_foreach_kv(void * user,const char * k,const char * v)1789 static bool callback_foreach_kv(void *user, const char *k, const char *v) {
1790 	r_cons_printf ("%s=%s\n", k, v);
1791 	return true;
1792 }
1793 
r_line_hist_sdb_up(RLine * line)1794 R_API int r_line_hist_sdb_up(RLine *line) {
1795 	if (!line->sdbshell_hist_iter || !line->sdbshell_hist_iter->n) {
1796 		return false;
1797 	}
1798 	line->sdbshell_hist_iter = line->sdbshell_hist_iter->n;
1799 	strncpy (line->buffer.data, line->sdbshell_hist_iter->data, R_LINE_BUFSIZE - 1);
1800 	line->buffer.index = line->buffer.length = strlen (line->buffer.data);
1801 	return true;
1802 }
1803 
r_line_hist_sdb_down(RLine * line)1804 R_API int r_line_hist_sdb_down(RLine *line) {
1805 	if (!line->sdbshell_hist_iter || !line->sdbshell_hist_iter->p) {
1806 		return false;
1807 	}
1808 	line->sdbshell_hist_iter = line->sdbshell_hist_iter->p;
1809 	strncpy (line->buffer.data, line->sdbshell_hist_iter->data, R_LINE_BUFSIZE - 1);
1810 	line->buffer.index = line->buffer.length = strlen (line->buffer.data);
1811 	return true;
1812 }
1813 
cmd_kuery(void * data,const char * input)1814 static int cmd_kuery(void *data, const char *input) {
1815 	char buf[1024], *out;
1816 	RCore *core = (RCore*)data;
1817 	const char *sp, *p = "[sdb]> ";
1818 	Sdb *s = core->sdb;
1819 
1820 	char *cur_pos = NULL, *cur_cmd = NULL, *next_cmd = NULL;
1821 	char *temp_pos = NULL, *temp_cmd = NULL;
1822 
1823 	switch (input[0]) {
1824 	case 'j':
1825 		out = sdb_querys (s, NULL, 0, "anal/**");
1826 		if (!out) {
1827 			r_cons_println ("No Output from sdb");
1828 			break;
1829 		}
1830 		PJ * pj = pj_new ();
1831 		if (!pj) {
1832   			free (out);
1833   			break;
1834 		}
1835 		pj_o (pj);
1836 		pj_ko (pj, "anal");
1837 		pj_ka (pj, "cur_cmd");
1838 
1839 		while (*out) {
1840 			cur_pos = strchr (out, '\n');
1841 			if (!cur_pos) {
1842 					break;
1843 			}
1844 			cur_cmd = r_str_ndup (out, cur_pos - out);
1845 			pj_s (pj, cur_cmd);
1846 
1847 			free (next_cmd);
1848 			next_cmd = r_str_newf ("anal/%s/*", cur_cmd);
1849 			char *query_result = sdb_querys (s, NULL, 0, next_cmd);
1850 
1851 			if (!query_result) {
1852 				out = cur_pos + 1;
1853 				continue;
1854 			}
1855 
1856 			char *temp = query_result;
1857 			while (*temp) {
1858 				temp_pos = strchr (temp, '\n');
1859 				if (!temp_pos) {
1860 					break;
1861 				}
1862 				temp_cmd = r_str_ndup (temp, temp_pos - temp);
1863 				pj_s (pj, temp_cmd);
1864 				temp = temp_pos + 1;
1865 			}
1866 			out = cur_pos + 1;
1867 			free (query_result);
1868 		}
1869 		pj_end (pj);
1870 		pj_end (pj);
1871 		pj_end (pj);
1872 		r_cons_println (pj_string (pj));
1873 		pj_free (pj);
1874 		R_FREE (next_cmd);
1875 		free (next_cmd);
1876 		free (cur_cmd);
1877 		break;
1878 	case ' ':
1879 		if (s) {
1880 			out = sdb_querys (s, NULL, 0, input + 1);
1881 			if (out) {
1882 				r_cons_print (out);
1883 			}
1884 			R_FREE (out);
1885 		}
1886 		break;
1887 	//case 's': r_pair_save (s, input + 3); break;
1888 	//case 'l': r_pair_load (sdb, input + 3); break;
1889 	case '\0':
1890 		sdb_foreach (s, callback_foreach_kv, NULL);
1891 		break;
1892 	// TODO: add command to list all namespaces // sdb_ns_foreach ?
1893 	case 's': // "ks"
1894 		if (core->http_up) {
1895 			return false;
1896 		}
1897 		if (!r_cons_is_interactive ()) {
1898 			return false;
1899 		}
1900 		if (input[1] == ' ') {
1901 			char *n, *o, *p = strdup (input + 2);
1902 			// TODO: slash split here? or inside sdb_ns ?
1903 			for (n = o = p; n; o = n) {
1904 				n = strchr (o, '/'); // SDB_NS_SEPARATOR NAMESPACE
1905 				if (n) {
1906 					*n++ = 0;
1907 				}
1908 				s = sdb_ns (s, o, 1);
1909 			}
1910 			free (p);
1911 		}
1912 		if (!s) {
1913 			s = core->sdb;
1914 		}
1915 		RLine *line = core->cons->line;
1916 		if (!line->sdbshell_hist) {
1917 			line->sdbshell_hist = r_list_newf (free);
1918 			r_list_append (line->sdbshell_hist, r_str_new ("\0"));
1919 		}
1920 		RList *sdb_hist = line->sdbshell_hist;
1921 		r_line_set_hist_callback (line, &r_line_hist_sdb_up, &r_line_hist_sdb_down);
1922 		for (;;) {
1923 			r_line_set_prompt (p);
1924 			if (r_cons_fgets (buf, sizeof (buf), 0, NULL) < 1) {
1925 				break;
1926 			}
1927 			if (!*buf) {
1928 				break;
1929 			}
1930 			if (sdb_hist) {
1931 				if ((r_list_length (sdb_hist) == 1) || (r_list_length (sdb_hist) > 1 && strcmp (r_list_get_n (sdb_hist, 1), buf))) {
1932 					r_list_insert (sdb_hist, 1, strdup (buf));
1933 				}
1934 				line->sdbshell_hist_iter = sdb_hist->head;
1935 			}
1936 			out = sdb_querys (s, NULL, 0, buf);
1937 			if (out) {
1938 				r_cons_println (out);
1939 				r_cons_flush ();
1940 			}
1941 		}
1942 		r_line_set_hist_callback (core->cons->line, &r_line_hist_cmd_up, &r_line_hist_cmd_down);
1943 		break;
1944 	case 'o': // "ko"
1945 		if (r_sandbox_enable (0)) {
1946 			eprintf ("This command is disabled in sandbox mode\n");
1947 			return 0;
1948 		}
1949 		if (input[1] == ' ') {
1950 			char *fn = strdup (input + 2);
1951 			if (!fn) {
1952 				eprintf("Unable to allocate memory\n");
1953 				return 0;
1954 			}
1955 			char *ns = strchr (fn, ' ');
1956 			if (ns) {
1957 				Sdb *db;
1958 				*ns++ = 0;
1959 				if (r_file_exists (fn)) {
1960 					db = sdb_ns_path (core->sdb, ns, 1);
1961 					if (db) {
1962 						Sdb *newdb = sdb_new (NULL, fn, 0);
1963 						if (newdb) {
1964 							sdb_drain  (db, newdb);
1965 						} else {
1966 							eprintf ("Cannot open sdb '%s'\n", fn);
1967 						}
1968 					} else {
1969 						eprintf ("Cannot find sdb '%s'\n", ns);
1970 					}
1971 				} else {
1972 					eprintf ("Cannot open file\n");
1973 				}
1974 			} else {
1975 				eprintf ("Missing sdb namespace\n");
1976 			}
1977 			free (fn);
1978 		} else {
1979 			eprintf ("Usage: ko [file] [namespace]\n");
1980 		}
1981 		break;
1982 	case 'd': // "kd"
1983 		if (r_sandbox_enable (0)) {
1984 			eprintf ("This command is disabled in sandbox mode\n");
1985 			return 0;
1986 		}
1987 		if (input[1] == ' ') {
1988 			char *fn = strdup (input + 2);
1989 			char *ns = strchr (fn, ' ');
1990 			if (ns) {
1991 				*ns++ = 0;
1992 				Sdb *db = sdb_ns_path (core->sdb, ns, 0);
1993 				if (db) {
1994 					sdb_file (db, fn);
1995 					sdb_sync (db);
1996 				} else {
1997 					eprintf ("Cannot find sdb '%s'\n", ns);
1998 				}
1999 			} else {
2000 				eprintf ("Missing sdb namespace\n");
2001 			}
2002 			free (fn);
2003 		} else {
2004 			eprintf ("Usage: kd [file] [namespace]\n");
2005 		}
2006 		break;
2007 	case '?':
2008 		r_core_cmd_help (core, help_msg_k);
2009 		break;
2010 	}
2011 
2012 	if (input[0] == '\0') {
2013 		/* nothing more to do, the command has been parsed. */
2014 		return 0;
2015 	}
2016 
2017 	sp = strchr (input + 1, ' ');
2018 	if (sp) {
2019 		char *inp = strdup (input);
2020 		inp [(size_t)(sp - input)] = 0;
2021 		s = sdb_ns (core->sdb, inp + 1, 1);
2022 		out = sdb_querys (s, NULL, 0, sp + 1);
2023 		if (out) {
2024 			r_cons_println (out);
2025 			free (out);
2026 		}
2027 		free (inp);
2028 		return 0;
2029 	}
2030 	return 0;
2031 }
2032 
cmd_bsize(void * data,const char * input)2033 static int cmd_bsize(void *data, const char *input) {
2034 	ut64 n;
2035 	RFlagItem *flag;
2036 	RCore *core = (RCore *)data;
2037 	switch (input[0]) {
2038 	case 'm': // "bm"
2039 		n = r_num_math (core->num, input + 1);
2040 		if (n > 1) {
2041 			core->blocksize_max = n;
2042 		} else {
2043 			r_cons_printf ("0x%x\n", (ut32)core->blocksize_max);
2044 		}
2045 		break;
2046 	case '+': // "b+"
2047 		n = r_num_math (core->num, input + 1);
2048 		r_core_block_size (core, core->blocksize + n);
2049 		break;
2050 	case '-': // "b-"
2051 		n = r_num_math (core->num, input + 1);
2052 		r_core_block_size (core, core->blocksize - n);
2053 		break;
2054 	case 'f': // "bf"
2055 		if (input[1] == ' ') {
2056 			flag = r_flag_get (core->flags, input + 2);
2057 			if (flag) {
2058 				r_core_block_size (core, flag->size);
2059 			} else {
2060 				eprintf ("bf: cannot find flag named '%s'\n", input + 2);
2061 			}
2062 		} else {
2063 			eprintf ("Usage: bf [flagname]\n");
2064 		}
2065 		break;
2066 	case 'j': { // "bj"
2067 		PJ * pj = pj_new ();
2068 		if (!pj) {
2069 			break;
2070 		}
2071 		pj_o (pj);
2072 		pj_ki (pj, "blocksize", core->blocksize);
2073 		pj_ki (pj, "blocksize_limit", core->blocksize_max);
2074 		pj_end (pj);
2075 		r_cons_println (pj_string (pj));
2076 		pj_free (pj);
2077 		break;
2078 	}
2079 	case '*': // "b*"
2080 		r_cons_printf ("b 0x%x\n", core->blocksize);
2081 		break;
2082 	case '\0': // "b"
2083 		r_cons_printf ("0x%x\n", core->blocksize);
2084 		break;
2085 	case ' ':
2086 		r_core_block_size (core, r_num_math (core->num, input));
2087 		break;
2088 	default:
2089 	case '?': // "b?"
2090 		r_core_cmd_help (core, help_msg_b);
2091 		break;
2092 	}
2093 	return 0;
2094 }
2095 
__runMain(RMainCallback cb,const char * arg)2096 static int __runMain(RMainCallback cb, const char *arg) {
2097 	char *a = r_str_trim_dup (arg);
2098 	int argc = 0;
2099 	char **args = r_str_argv (a, &argc);
2100 	int res = cb (argc, (const char **)args);
2101 	free (args);
2102 	free (a);
2103 	return res;
2104 }
2105 
cmd_r2cmd(RCore * core,const char * _input)2106 static bool cmd_r2cmd(RCore *core, const char *_input) {
2107 	char *input = r_str_newf ("r%s", _input);
2108 	int rc = 0;
2109 	if (r_str_startswith (input, "rax2")) {
2110 		rc = __runMain (core->r_main_rax2, input);
2111 	} else if (r_str_startswith (input, "r2")) {
2112 		r_sys_cmdf ("%s", input);
2113 		// rc = __runMain (core->r_main_radare2, input);
2114 	} else if (r_str_startswith (input, "radare2")) {
2115 		r_sys_cmdf ("%s", input);
2116 		// rc = __runMain (core->r_main_radare2, input);
2117 	} else if (r_str_startswith (input, "rasm2")) {
2118 		r_sys_cmdf ("%s", input);
2119 		// rc = __runMain (core->r_main_rasm2, input);
2120 	} else if (r_str_startswith (input, "rabin2")) {
2121 		r_sys_cmdf ("%s", input);
2122 		// rc = __runMain (core->r_main_rabin2, input);
2123 	} else if (r_str_startswith (input, "ragg2")) {
2124 		r_sys_cmdf ("%s", input);
2125 		// rc = __runMain (core->r_main_ragg2, input);
2126 	} else if (r_str_startswith (input, "r2pm")) {
2127 		r_sys_cmdf ("%s", input);
2128 		// rc = __runMain (core->r_main_r2pm, input);
2129 	} else if (r_str_startswith (input, "radiff2")) {
2130 		rc = __runMain (core->r_main_radiff2, input);
2131 	} else {
2132 		const char *r2cmds[] = {
2133 			"rax2", "r2pm", "rasm2", "rabin2", "rahash2", "rafind2", "rarun2", "ragg2", "radare2", "r2", NULL
2134 		};
2135 		int i;
2136 		for (i = 0; r2cmds[i]; i++) {
2137 			if (r_str_startswith (input, r2cmds[i])) {
2138 				free (input);
2139 				return true;
2140 			}
2141 		}
2142 		free (input);
2143 		return false;
2144 	}
2145 	free (input);
2146 	core->num->value = rc;
2147 	return true;
2148 }
2149 
cmd_rebase(RCore * core,const char * input)2150 static int cmd_rebase(RCore *core, const char *input) {
2151 	ut64 addr = r_num_math (core->num, input);
2152 	if (!addr) {
2153 		r_cons_printf ("Usage: rb oldbase @ newbase\n");
2154 		return 0;
2155 	}
2156 	// old base = addr
2157 	// new base = core->offset
2158 	r_debug_bp_rebase (core->dbg, addr, core->offset);
2159 	r_bin_set_baddr (core->bin, core->offset);
2160 	r_flag_move (core->flags, addr, core->offset);
2161 	r_core_cmd0 (core, ".is*");
2162 	r_core_cmd0 (core, ".iM*");
2163 	r_core_cmd0 (core, ".ii*");
2164 	r_core_cmd0 (core, ".iz*");
2165 	// TODO: r_anal_move :??
2166 	// TODO: differentiate analysis by map ranges (associated with files or memory maps)
2167 	return 0;
2168 }
2169 
cmd_resize(void * data,const char * input)2170 static int cmd_resize(void *data, const char *input) {
2171 	RCore *core = (RCore *)data;
2172 	ut64 newsize = 0;
2173 	st64 delta = 0;
2174 	int grow, ret;
2175 
2176 	if (cmd_r2cmd (core, input)) {
2177 		return true;
2178 	}
2179 
2180 	ut64 oldsize = (core->io->desc) ? r_io_fd_size (core->io, core->io->desc->fd): 0;
2181 	switch (*input) {
2182 	case 'a': // "r..."
2183 		if (r_str_startswith (input, "adare2")) {
2184 			__runMain (core->r_main_radare2, input - 1);
2185 		}
2186 		return true;
2187 	case 'b': // "rb" rebase
2188 		return cmd_rebase (core, input + 1);
2189 	case '2': // "r2" // XXX should be handled already in cmd_r2cmd()
2190 		// TODO: use argv[0] instead of 'radare2'
2191 		// TODO: { char **argv = { "r2", NULL }; r_main_radare2 (1, argv); }
2192 		r_sys_cmdf ("radare%s", input);
2193 		return true;
2194 	case 'm': // "rm"
2195 		if (input[1] == ' ') {
2196 			const char *file = r_str_trim_head_ro (input + 2);
2197 			if (*file == '$') {
2198 				r_cmd_alias_del (core->rcmd, file);
2199 			} else {
2200 				r_file_rm (file);
2201 			}
2202 		} else {
2203 			eprintf ("Usage: rm [file]   # removes a file\n");
2204 		}
2205 		return true;
2206 	case '\0':
2207 		if (core->io->desc) {
2208 			if (oldsize != -1) {
2209 				r_cons_printf ("%"PFMT64d"\n", oldsize);
2210 			}
2211 		}
2212 		return true;
2213 	case 'j': { // "rj"
2214 			PJ * pj = pj_new ();
2215 			pj_o (pj);
2216 			if (oldsize != -1) {
2217 				pj_kn (pj, "size", oldsize);
2218 			}
2219 			pj_end (pj);
2220 			char *s = pj_drain (pj);
2221 			r_cons_println (s);
2222 			free (s);
2223 			return true;
2224 		}
2225 	case 'h':
2226 		if (core->io->desc) {
2227 			if (oldsize != -1) {
2228 				char humansz[8];
2229 				r_num_units (humansz, sizeof (humansz), oldsize);
2230 				r_cons_printf ("%s\n", humansz);
2231 			}
2232 		}
2233 		return true;
2234 	case '+': // "r+"
2235 	case '-': // "r-"
2236 		delta = (st64)r_num_math (core->num, input);
2237 		newsize = oldsize + delta;
2238 		break;
2239 	case ' ': // "r "
2240 		newsize = r_num_math (core->num, input + 1);
2241 		if (newsize == 0) {
2242 			if (input[1] == '0') {
2243 				eprintf ("Invalid size\n");
2244 			}
2245 			return false;
2246 		}
2247 		break;
2248 	case 'e':
2249 		{
2250 			int rc = write (1, Color_RESET_TERMINAL, strlen (Color_RESET_TERMINAL));
2251 			if (rc == -1) {
2252 				return false;
2253 			}
2254 		}
2255 		return true;
2256 	case '?': // "r?"
2257 	default:
2258 		r_core_cmd_help (core, help_msg_r);
2259 		return true;
2260 	}
2261 
2262 	grow = (newsize > oldsize);
2263 	if (grow) {
2264 		ret = r_io_resize (core->io, newsize);
2265 		if (ret < 1) {
2266 			eprintf ("r_io_resize: cannot resize\n");
2267 		}
2268 	}
2269 	if (delta && core->offset < newsize) {
2270 		r_io_shift (core->io, core->offset, grow?newsize:oldsize, delta);
2271 	}
2272 	if (!grow) {
2273 		ret = r_io_resize (core->io, newsize);
2274 		if (ret < 1) {
2275 			eprintf ("r_io_resize: cannot resize\n");
2276 		}
2277 	}
2278 	if (newsize < core->offset+core->blocksize || oldsize < core->offset + core->blocksize) {
2279 		r_core_block_read (core);
2280 	}
2281 	return true;
2282 }
2283 
cmd_panels(void * data,const char * input)2284 static int cmd_panels(void *data, const char *input) {
2285 	RCore *core = (RCore*) data;
2286 	if (core->vmode) {
2287 		return false;
2288 	}
2289 	if (*input == '?') {
2290 		r_core_cmd_help (core, help_msg_v);
2291 		return false;
2292 	}
2293 	if (!r_cons_is_interactive ()) {
2294 		eprintf ("Panel mode requires scr.interactive=true.\n");
2295 		return false;
2296 	}
2297 	if (*input == ' ') {
2298 		if (core->panels) {
2299 			r_core_panels_load (core, input + 1);
2300 		}
2301 		r_config_set (core->config, "scr.layout", input + 1);
2302 		return true;
2303 	}
2304 	if (*input == '=') {
2305 		r_core_panels_save (core, input + 1);
2306 		r_config_set (core->config, "scr.layout", input + 1);
2307 		return true;
2308 	}
2309 	if (*input == 'i') {
2310 		char *sp = strchr (input, ' ');
2311 		if (sp) {
2312 			char *r = r_core_editor (core, sp + 1, NULL);
2313 			if (r) {
2314 				free (r);
2315 			} else {
2316 				eprintf ("Cannot open file (%s)\n", sp + 1);
2317 			}
2318 		}
2319 		////r_sys_cmdf ("v%s", input);
2320 		return false;
2321 	}
2322 	r_core_panels_root (core, core->panels_root);
2323 	return true;
2324 }
2325 
cmd_visual(void * data,const char * input)2326 static int cmd_visual(void *data, const char *input) {
2327 	RCore *core = (RCore*) data;
2328 	if (core->http_up) {
2329 		return false;
2330 	}
2331 	if (!r_cons_is_interactive ()) {
2332 		eprintf ("Visual mode requires scr.interactive=true.\n");
2333 		return false;
2334 	}
2335 	return r_core_visual ((RCore *)data, input);
2336 }
2337 
cmd_pipein(void * user,const char * input)2338 static int cmd_pipein(void *user, const char *input) {
2339 	char *buf = strdup (input);
2340 	int len = r_str_unescape (buf);
2341 	r_cons_readpush (buf, len);
2342 	free (buf);
2343 	return 0;
2344 }
2345 
cmd_tasks(void * data,const char * input)2346 static int cmd_tasks(void *data, const char *input) {
2347 	RCore *core = (RCore*) data;
2348 	switch (input[0]) {
2349 	case '\0': // "&"
2350 	case 'j': // "&j"
2351 		r_core_task_list (core, *input);
2352 		break;
2353 	case 'b': { // "&b"
2354 		if (r_sandbox_enable (0)) {
2355 			eprintf ("This command is disabled in sandbox mode\n");
2356 			return 0;
2357 		}
2358 		int tid = r_num_math (core->num, input + 1);
2359 		if (tid) {
2360 			r_core_task_break (&core->tasks, tid);
2361 		}
2362 		break;
2363 	}
2364 	case '&': { // "&&"
2365 		if (r_sandbox_enable (0)) {
2366 			eprintf ("This command is disabled in sandbox mode\n");
2367 			return 0;
2368 		}
2369 		int tid = r_num_math (core->num, input + 1);
2370 		r_core_task_join (&core->tasks, core->tasks.current_task, tid ? tid : -1);
2371 		break;
2372 	}
2373 	case '=': { // "&="
2374 		// r_core_task_list (core, '=');
2375 		int tid = r_num_math (core->num, input + 1);
2376 		if (tid) {
2377 			RCoreTask *task = r_core_task_get_incref (&core->tasks, tid);
2378 			if (task) {
2379 				if (task->res) {
2380 					r_cons_println (task->res);
2381 				}
2382 				r_core_task_decref (task);
2383 			} else {
2384 				eprintf ("Cannot find task\n");
2385 			}
2386 		}
2387 		break;
2388 	}
2389 	case '-': // "&-"
2390 		if (r_sandbox_enable (0)) {
2391 			eprintf ("This command is disabled in sandbox mode\n");
2392 			return 0;
2393 		}
2394 		if (input[1] == '*') {
2395 			r_core_task_del_all_done (&core->tasks);
2396 		} else {
2397 			r_core_task_del (&core->tasks, r_num_math (core->num, input + 1));
2398 		}
2399 		break;
2400 	case '?': // "&?"
2401 	default:
2402 		helpCmdTasks (core);
2403 		break;
2404 	case ' ': // "& "
2405 	case '_': // "&_"
2406 	case 't': { // "&t"
2407 		if (r_sandbox_enable (0)) {
2408 			eprintf ("This command is disabled in sandbox mode\n");
2409 			return 0;
2410 		}
2411 		RCoreTask *task = r_core_task_new (core, true, input + 1, NULL, core);
2412 		if (!task) {
2413 			break;
2414 		}
2415 		task->transient = input[0] == 't';
2416 		r_core_task_enqueue (&core->tasks, task);
2417 		break;
2418 	}
2419 	}
2420 	return 0;
2421 }
2422 
cmd_pointer(void * data,const char * input)2423 static int cmd_pointer(void *data, const char *input) {
2424 	RCore *core = (RCore*) data;
2425 	int ret = true;
2426 	char *str, *eq;
2427 	input = r_str_trim_head_ro (input);
2428 	while (*input == ' ') {
2429 		input++;
2430 	}
2431 	if (!*input || *input == '?') {
2432 		r_core_cmd_help (core, help_msg_star);
2433 		return ret;
2434 	}
2435 	str = strdup (input);
2436 	eq = strchr (str, '=');
2437 	if (eq) {
2438 		*eq++ = 0;
2439 		if (!strncmp (eq, "0x", 2)) {
2440 			ret = r_core_cmdf (core, "wv %s@%s", eq, str);
2441 		} else {
2442 			ret = r_core_cmdf (core, "wx %s@%s", eq, str);
2443 		}
2444 	} else {
2445 		ret = r_core_cmdf (core, "?v [%s]", input);
2446 	}
2447 	free (str);
2448 	return ret;
2449 }
2450 
cmd_env(void * data,const char * input)2451 static int cmd_env(void *data, const char *input) {
2452 	RCore *core = (RCore*)data;
2453 	int ret = true;
2454 	switch (*input) {
2455 	case '?':
2456 		cmd_help_percent (core);
2457 		break;
2458 	default:
2459 		ret = r_core_cmdf (core, "env %s", input);
2460 	}
2461 	return ret;
2462 }
2463 
2464 static struct autocomplete_flag_map_t {
2465 	const char* name;
2466 	const char* desc;
2467 	int type;
2468 } autocomplete_flags [] = {
2469 	{ "$dflt", "default autocomplete flag", R_CORE_AUTOCMPLT_DFLT },
2470 	{ "$flag", "shows known flag hints", R_CORE_AUTOCMPLT_FLAG },
2471 	{ "$flsp", "shows known flag-spaces hints", R_CORE_AUTOCMPLT_FLSP },
2472 	{ "$seek", "shows the seek hints", R_CORE_AUTOCMPLT_SEEK },
2473 	{ "$fcn", "shows the functions hints", R_CORE_AUTOCMPLT_FCN },
2474 	{ "$zign", "shows known zignatures hints", R_CORE_AUTOCMPLT_ZIGN },
2475 	{ "$eval", "shows known evals hints", R_CORE_AUTOCMPLT_EVAL },
2476 	{ "$prjt", "shows known projects hints", R_CORE_AUTOCMPLT_PRJT },
2477 	{ "$mins", NULL, R_CORE_AUTOCMPLT_MINS },
2478 	{ "$brkp", "shows known breakpoints hints", R_CORE_AUTOCMPLT_BRKP },
2479 	{ "$macro", NULL, R_CORE_AUTOCMPLT_MACR },
2480 	{ "$file", "hints file paths", R_CORE_AUTOCMPLT_FILE },
2481 	{ "$thme", "shows known themes hints", R_CORE_AUTOCMPLT_THME },
2482 	{ "$optn", "allows the selection for multiple options", R_CORE_AUTOCMPLT_OPTN },
2483 	{ "$ms", "shows mount hints", R_CORE_AUTOCMPLT_MS},
2484 	{ "$sdb", "shows sdb hints", R_CORE_AUTOCMPLT_SDB},
2485 	{ NULL, NULL, 0 }
2486 };
2487 
print_dict(RCoreAutocomplete * a,int sub)2488 static inline void print_dict(RCoreAutocomplete* a, int sub) {
2489 	if (!a) {
2490 		return;
2491 	}
2492 	int i, j;
2493 	const char* name = "unknown";
2494 	for (i = 0; i < a->n_subcmds; i++) {
2495 		RCoreAutocomplete* b = a->subcmds[i];
2496 		if (b->locked) {
2497 			continue;
2498 		}
2499 		for (j = 0; j < R_CORE_AUTOCMPLT_END; j++) {
2500 			if (b->type == autocomplete_flags[j].type) {
2501 				name = autocomplete_flags[j].name;
2502 				break;
2503 			}
2504 		}
2505 		eprintf ("[%3d] %s: '%s'\n", sub, name, b->cmd);
2506 		print_dict (a->subcmds[i], sub + 1);
2507 	}
2508 }
2509 
autocomplete_type(const char * strflag)2510 static int autocomplete_type(const char* strflag) {
2511 	int i;
2512 	for (i = 0; i < R_CORE_AUTOCMPLT_END; i++) {
2513 		if (autocomplete_flags[i].desc && !strncmp (strflag, autocomplete_flags[i].name, 5)) {
2514 			return autocomplete_flags[i].type;
2515 		}
2516 	}
2517 	eprintf ("Invalid flag '%s'\n", strflag);
2518 	return R_CORE_AUTOCMPLT_END;
2519 }
2520 
cmd_autocomplete_help(RCore * core)2521 static void cmd_autocomplete_help(RCore *core) {
2522 	r_core_cmd_help (core, help_msg_triple_exclamation);
2523 	// non-zero-cost survival without iterators 101
2524 	const char **help = calloc (R_CORE_AUTOCMPLT_END + 1, 3 * sizeof (char *));
2525 	int i;
2526 	size_t n;
2527 	for (i = 0, n = 0; i < R_CORE_AUTOCMPLT_END; i++) {
2528 		if (autocomplete_flags[i].desc) {
2529 			// highlight "$" as cmd and the rest of the name as args
2530 			help[n + 0] = "$";
2531 			help[n + 1] = autocomplete_flags[i].name + 1;
2532 			help[n + 2] = autocomplete_flags[i].desc;
2533 			n += 3;
2534 		}
2535 	}
2536 	r_core_cmd_help (core, help);
2537 	free (help);
2538 }
2539 
cmd_autocomplete(RCore * core,const char * input)2540 static void cmd_autocomplete(RCore *core, const char *input) {
2541 	RCoreAutocomplete* b = core->autocomplete;
2542 	input = r_str_trim_head_ro (input);
2543 	char arg[256];
2544 	if (!*input) {
2545 		print_dict (core->autocomplete, 0);
2546 		return;
2547 	}
2548 	if (*input == '?') {
2549 		cmd_autocomplete_help (core);
2550 		return;
2551 	}
2552 	if (*input == '-') {
2553 		const char *arg = input + 1;
2554 		if (!*input) {
2555 			eprintf ("Use !!!-* or !!!-<cmd>\n");
2556 			return;
2557 		}
2558 		r_core_autocomplete_remove (b, arg);
2559 		return;
2560 	}
2561 	while (b) {
2562 		const char* end = r_str_trim_head_wp (input);
2563 		if (!end) {
2564 			break;
2565 		}
2566 		if ((end - input) >= sizeof (arg)) {
2567 			// wtf?
2568 			eprintf ("Exceeded the max arg length (255).\n");
2569 			return;
2570 		}
2571 		if (end == input) {
2572 			break;
2573 		}
2574 		memcpy (arg, input, end - input);
2575 		arg[end - input] = 0;
2576 		RCoreAutocomplete* a = r_core_autocomplete_find (b, arg, true);
2577 		input = r_str_trim_head_ro (end);
2578 		if (input && *input && !a) {
2579 			if (b->type == R_CORE_AUTOCMPLT_DFLT && !(b = r_core_autocomplete_add (b, arg, R_CORE_AUTOCMPLT_DFLT, false))) {
2580 				eprintf ("ENOMEM\n");
2581 				return;
2582 			} else if (b->type != R_CORE_AUTOCMPLT_DFLT) {
2583 				eprintf ("Cannot add autocomplete to '%s'. type not $dflt\n", b->cmd);
2584 				return;
2585 			}
2586 		} else if ((!input || !*input) && !a) {
2587 			if (arg[0] == '$') {
2588 				int type = autocomplete_type (arg);
2589 				if (type != R_CORE_AUTOCMPLT_END && !b->locked && !b->n_subcmds) {
2590 					b->type = type;
2591 				} else if (b->locked || b->n_subcmds) {
2592 					if (!b->cmd) {
2593 						return;
2594 					}
2595 					eprintf ("Changing type of '%s' is forbidden.\n", b->cmd);
2596 				}
2597 			} else {
2598 				if (!r_core_autocomplete_add (b, arg, R_CORE_AUTOCMPLT_DFLT, false)) {
2599 					eprintf ("ENOMEM\n");
2600 					return;
2601 				}
2602 			}
2603 			return;
2604 		} else if ((!input || !*input) && a) {
2605 			// eprintf ("Cannot add '%s'. Already exists.\n", arg);
2606 			return;
2607 		} else {
2608 			b = a;
2609 		}
2610 	}
2611 	eprintf ("Invalid usage of !!!\n");
2612 }
2613 
cmd_last(void * data,const char * input)2614 static int cmd_last(void *data, const char *input) {
2615 	switch (*input) {
2616 	case 0:
2617 		r_cons_last ();
2618 		break;
2619 	default:
2620 		eprintf ("Usage: _  print last output\n");
2621 	}
2622 	return 0;
2623 }
2624 
cmd_system(void * data,const char * input)2625 static int cmd_system(void *data, const char *input) {
2626 	RCore *core = (RCore*)data;
2627 	ut64 n;
2628 	int ret = 0;
2629 	switch (*input) {
2630 	case '-': //!-
2631 		if (input[1]) {
2632 			r_line_hist_free();
2633 			r_line_hist_save (R2_HOME_HISTORY);
2634 		} else {
2635 			r_line_hist_free();
2636 		}
2637 		break;
2638 	case '=': //!=
2639 		if (input[1] == '?') {
2640 			r_cons_printf ("Usage: !=[!]  - enable/disable remote commands\n");
2641 		} else {
2642 			if (!r_sandbox_enable (0)) {
2643 				R_FREE (core->cmdremote);
2644 			}
2645 		}
2646 		break;
2647 	case '!': //!!
2648 		if (input[1] == '!') { // !!! & !!!-
2649 			cmd_autocomplete (core, input + 2);
2650 		} else if (input[1] == '?') {
2651 			cmd_help_exclamation (core);
2652 		} else if (input[1] == '*') {
2653 			char *cmd = r_str_trim_dup (input + 1);
2654 			(void)r_core_cmdf (core, "\"#!pipe %s\"", cmd);
2655 			free (cmd);
2656 		} else {
2657 			if (r_sandbox_enable (0)) {
2658 				eprintf ("This command is disabled in sandbox mode\n");
2659 				return 0;
2660 			}
2661 			if (input[1]) {
2662 				int olen;
2663 				char *out = NULL;
2664 				char *cmd = r_core_sysenv_begin (core, input);
2665 				if (cmd) {
2666 					void *bed = r_cons_sleep_begin ();
2667 					ret = r_sys_cmd_str_full (cmd + 1, NULL, &out, &olen, NULL);
2668 					r_cons_sleep_end (bed);
2669 					r_core_sysenv_end (core, input);
2670 					r_cons_memcat (out, olen);
2671 					free (out);
2672 					free (cmd);
2673 				} //else eprintf ("Error setting up system environment\n");
2674 			} else {
2675 				eprintf ("History saved to "R2_HOME_HISTORY"\n");
2676 				r_line_hist_save (R2_HOME_HISTORY);
2677 			}
2678 		}
2679 		break;
2680 	case '\0':
2681 		r_line_hist_list ();
2682 		break;
2683 	case '?': //!?
2684 		cmd_help_exclamation (core);
2685 		break;
2686 	case '*':
2687 		// TODO: use the api
2688 		{
2689 		char *cmd = r_str_trim_dup (input + 1);
2690 		cmd = r_str_replace (cmd, " ", "\\ ", true);
2691 		cmd = r_str_replace (cmd, "\\ ", " ", false);
2692 		cmd = r_str_replace (cmd, "\"", "'", false);
2693 		ret = r_core_cmdf (core, "\"#!pipe %s\"", cmd);
2694 		free (cmd);
2695 		}
2696 		break;
2697 	default:
2698 		n = atoi (input);
2699 		if (*input == '0' || n > 0) {
2700 			const char *cmd = r_line_hist_get (n);
2701 			if (cmd) {
2702 				r_core_cmd0 (core, cmd);
2703 			}
2704 			//else eprintf ("Error setting up system environment\n");
2705 		} else {
2706 			char *cmd = r_core_sysenv_begin (core, input);
2707 			if (cmd) {
2708 				void *bed = r_cons_sleep_begin ();
2709 				ret = r_sys_cmd (cmd);
2710 				r_cons_sleep_end (bed);
2711 				r_core_sysenv_end (core, input);
2712 				free (cmd);
2713 			} else {
2714 				eprintf ("Error setting up system environment\n");
2715 			}
2716 		}
2717 		break;
2718 	}
2719 	return ret;
2720 }
2721 
unescape_special_chars(const char * s,const char * special_chars)2722 static char *unescape_special_chars(const char *s, const char *special_chars) {
2723 	char *dst = R_NEWS (char, strlen (s) + 1);
2724 	int i, j = 0;
2725 
2726 	for (i = 0; s[i]; i++) {
2727 		if (s[i] != '\\' || !strchr (special_chars, s[i + 1])) {
2728 			dst[j++] = s[i];
2729 			continue;
2730 		}
2731 		dst[j++] = s[i + 1];
2732 		i++;
2733 	}
2734 	dst[j++] = '\0';
2735 	return dst;
2736 }
2737 
2738 #if __WINDOWS__
2739 #include <tchar.h>
2740 #define __CLOSE_DUPPED_PIPES() \
2741 		close (1);             \
2742 		close (fd_out);        \
2743 		fd_out = -1;
2744 
r_w32_cmd_pipe(RCore * core,char * radare_cmd,char * shell_cmd)2745 static void r_w32_cmd_pipe(RCore *core, char *radare_cmd, char *shell_cmd) {
2746 	STARTUPINFO si = {0};
2747 	PROCESS_INFORMATION pi = {0};
2748 	SECURITY_ATTRIBUTES sa;
2749 	HANDLE pipe[2] = {NULL, NULL};
2750 	int fd_out = -1, cons_out = -1;
2751 	char *_shell_cmd = NULL;
2752 	LPTSTR _shell_cmd_ = NULL;
2753 	DWORD mode;
2754 	TCHAR *systemdir = NULL;
2755 	GetConsoleMode (GetStdHandle (STD_OUTPUT_HANDLE), &mode);
2756 
2757 	sa.nLength = sizeof (SECURITY_ATTRIBUTES);
2758 	sa.bInheritHandle = TRUE;
2759 	sa.lpSecurityDescriptor = NULL;
2760 	if (!CreatePipe (&pipe[0], &pipe[1], &sa, 0)) {
2761 		r_sys_perror ("r_w32_cmd_pipe/CreatePipe");
2762 		goto err_r_w32_cmd_pipe;
2763 	}
2764 	if (!SetHandleInformation (pipe[1], HANDLE_FLAG_INHERIT, 0)) {
2765 		r_sys_perror ("r_w32_cmd_pipe/SetHandleInformation");
2766 		goto err_r_w32_cmd_pipe;
2767 	}
2768 	si.hStdError = GetStdHandle (STD_ERROR_HANDLE);
2769 	si.hStdOutput = GetStdHandle (STD_OUTPUT_HANDLE);
2770 	si.hStdInput = pipe[0];
2771 	si.dwFlags |= STARTF_USESTDHANDLES;
2772 	si.cb = sizeof (si);
2773 	_shell_cmd = shell_cmd;
2774 	while (*_shell_cmd && isspace ((ut8)*_shell_cmd)) {
2775 		_shell_cmd++;
2776 	}
2777 	char *tmp = r_str_newf ("/Q /c \"%s\"", _shell_cmd);
2778 	if (!tmp) {
2779 		goto err_r_w32_cmd_pipe;
2780 	}
2781 	_shell_cmd = tmp;
2782 	_shell_cmd_ = r_sys_conv_utf8_to_win (_shell_cmd);
2783 	free (tmp);
2784 	if (!_shell_cmd_) {
2785 		goto err_r_w32_cmd_pipe;
2786 	}
2787 	systemdir = calloc (MAX_PATH, sizeof (TCHAR));
2788 	if (!systemdir) {
2789 		goto err_r_w32_cmd_pipe;
2790 	}
2791 	int ret = GetSystemDirectory (systemdir, MAX_PATH);
2792 	if (!ret) {
2793 		r_sys_perror ("r_w32_cmd_pipe/systemdir");
2794 		goto err_r_w32_cmd_pipe;
2795 	}
2796 	_tcscat_s (systemdir, MAX_PATH, TEXT("\\cmd.exe"));
2797 	// exec windows process
2798 	if (!CreateProcess (systemdir, _shell_cmd_, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) {
2799 		r_sys_perror ("r_w32_cmd_pipe/CreateProcess");
2800 		goto err_r_w32_cmd_pipe;
2801 	}
2802 	fd_out = _open_osfhandle ((intptr_t)pipe[1], _O_WRONLY|_O_TEXT);
2803 	if (fd_out == -1) {
2804 		perror ("_open_osfhandle");
2805 		goto err_r_w32_cmd_pipe;
2806 	}
2807 	cons_out = dup (1);
2808 	dup2 (fd_out, 1);
2809 	// exec radare command
2810 	r_core_cmd (core, radare_cmd, 0);
2811 
2812 	HANDLE th = CreateThread (NULL, 0,(LPTHREAD_START_ROUTINE) r_cons_flush, NULL, 0, NULL);
2813 	if (!th) {
2814 		__CLOSE_DUPPED_PIPES ();
2815 		goto err_r_w32_cmd_pipe;
2816 	}
2817 	while (true) {
2818 		int ret = WaitForSingleObject (th, 50);
2819 		if (!ret) {
2820 			// Successfully written everything to pipe
2821 			__CLOSE_DUPPED_PIPES ();
2822 			WaitForSingleObject (pi.hProcess, INFINITE);
2823 			break;
2824 		}
2825 		ret = WaitForSingleObject (pi.hProcess, 50);
2826 		if (!ret) {
2827 			// Process exited before we finished writing to pipe
2828 			DWORD exit;
2829 			if (GetExitCodeThread (th, &exit) && exit == STILL_ACTIVE) {
2830 				CancelSynchronousIo (th);
2831 			}
2832 			WaitForSingleObject (th, INFINITE);
2833 			__CLOSE_DUPPED_PIPES ();
2834 			break;
2835 		}
2836 	}
2837 	CloseHandle (th);
2838 err_r_w32_cmd_pipe:
2839 	if (pi.hProcess) {
2840 		CloseHandle (pi.hProcess);
2841 	}
2842 	if (pi.hThread) {
2843 		CloseHandle (pi.hThread);
2844 	}
2845 	if (pipe[0]) {
2846 		CloseHandle (pipe[0]);
2847 	}
2848 	if (fd_out != -1) {
2849 		close (fd_out);
2850 	}
2851 	if (cons_out != -1) {
2852 		dup2 (cons_out, 1);
2853 		close (cons_out);
2854 	}
2855 	free (systemdir);
2856 	free (_shell_cmd_);
2857 	SetConsoleMode (GetStdHandle (STD_OUTPUT_HANDLE), mode);
2858 }
2859 #undef __CLOSE_DUPPED_PIPES
2860 #endif
2861 
r_core_cmd_pipe(RCore * core,char * radare_cmd,char * shell_cmd)2862 R_API int r_core_cmd_pipe(RCore *core, char *radare_cmd, char *shell_cmd) {
2863 #if __UNIX__
2864 	int stdout_fd, fds[2];
2865 	int child;
2866 #endif
2867 	int si, olen, ret = -1, pipecolor = -1;
2868 	char *str, *out = NULL;
2869 
2870 	if (r_sandbox_enable (0)) {
2871 		eprintf ("Pipes are not allowed in sandbox mode\n");
2872 		return -1;
2873 	}
2874 	si = r_cons_is_interactive ();
2875 	r_config_set_b (core->config, "scr.interactive", false);
2876 	if (!r_config_get_i (core->config, "scr.color.pipe")) {
2877 		pipecolor = r_config_get_i (core->config, "scr.color");
2878 		r_config_set_i (core->config, "scr.color", COLOR_MODE_DISABLED);
2879 	}
2880 	if (*shell_cmd=='!') {
2881 		r_cons_grep_parsecmd (shell_cmd, "\"");
2882 		olen = 0;
2883 		out = NULL;
2884 		// TODO: implement foo
2885 		str = r_core_cmd_str (core, radare_cmd);
2886 		r_sys_cmd_str_full (shell_cmd + 1, str, &out, &olen, NULL);
2887 		free (str);
2888 		r_cons_memcat (out, olen);
2889 		free (out);
2890 		ret = 0;
2891 	}
2892 #if __UNIX__
2893 	r_str_trim_head (radare_cmd);
2894 	r_str_trim_head (shell_cmd);
2895 
2896 	r_sys_signal (SIGPIPE, SIG_IGN);
2897 	stdout_fd = dup (1);
2898 	if (stdout_fd != -1) {
2899 		if (pipe (fds) == 0) {
2900 			child = r_sys_fork ();
2901 			if (child == -1) {
2902 				eprintf ("Cannot fork\n");
2903 				close (stdout_fd);
2904 			} else if (child) {
2905 				dup2 (fds[1], 1);
2906 				close (fds[1]);
2907 				close (fds[0]);
2908 				r_core_cmd (core, radare_cmd, 0);
2909 				r_cons_flush ();
2910 				close (1);
2911 				wait (&ret);
2912 				dup2 (stdout_fd, 1);
2913 				close (stdout_fd);
2914 			} else {
2915 				close (fds[1]);
2916 				dup2 (fds[0], 0);
2917 				//dup2 (1, 2); // stderr goes to stdout
2918 				r_sandbox_system (shell_cmd, 0);
2919 				close (stdout_fd);
2920 			}
2921 		} else {
2922 			eprintf ("r_core_cmd_pipe: Could not pipe\n");
2923 		}
2924 	}
2925 #elif __WINDOWS__
2926 	r_w32_cmd_pipe (core, radare_cmd, shell_cmd);
2927 #else
2928 #ifdef _MSC_VER
2929 #pragma message ("r_core_cmd_pipe UNIMPLEMENTED FOR THIS PLATFORM")
2930 #else
2931 #warning r_core_cmd_pipe UNIMPLEMENTED FOR THIS PLATFORM
2932 #endif
2933 	eprintf ("r_core_cmd_pipe: unimplemented for this platform\n");
2934 #endif
2935 	if (pipecolor != -1) {
2936 		r_config_set_i (core->config, "scr.color", pipecolor);
2937 	}
2938 	r_config_set_i (core->config, "scr.interactive", si);
2939 	return ret;
2940 }
2941 
parse_tmp_evals(RCore * core,const char * str)2942 static char *parse_tmp_evals(RCore *core, const char *str) {
2943 	char *s = strdup (str);
2944 	int i, argc = r_str_split (s, ',');
2945 	char *res = strdup ("");
2946 	if (!s || !res) {
2947 		free (s);
2948 		free (res);
2949 		return NULL;
2950 	}
2951 	for (i = 0; i < argc; i++) {
2952 		char *eq, *kv = (char *)r_str_word_get0 (s, i);
2953 		if (!kv) {
2954 			break;
2955 		}
2956 		eq = strchr (kv, '=');
2957 		if (eq) {
2958 			*eq = 0;
2959 			const char *ov = r_config_get (core->config, kv);
2960 			if (!ov) {
2961 				continue;
2962 			}
2963 			char *cmd = r_str_newf ("e %s=%s;", kv, ov);
2964 			if (!cmd) {
2965 				free (s);
2966 				free (res);
2967 				return NULL;
2968 			}
2969 			res = r_str_prepend (res, cmd);
2970 			free (cmd);
2971 			r_config_set (core->config, kv, eq + 1);
2972 			*eq = '=';
2973 		} else {
2974 			eprintf ("Missing '=' in e: expression (%s)\n", kv);
2975 		}
2976 	}
2977 	free (s);
2978 	return res;
2979 }
2980 
is_macro_command(const char * ptr)2981 static bool is_macro_command(const char *ptr) {
2982 	ptr = r_str_trim_head_ro (ptr);
2983 	while (IS_DIGIT (*ptr)) {
2984 		ptr++;
2985 	}
2986 	return *ptr == '(';
2987 }
2988 
find_ch_after_macro(char * ptr,char ch)2989 static char *find_ch_after_macro(char *ptr, char ch) {
2990 	int depth = 0;
2991 	while (*ptr) {
2992 		if (depth == 0 && *ptr == ch) {
2993 			return ptr;
2994 		}
2995 		if (*ptr == '(') {
2996 			depth++;
2997 		} else if (*ptr == ')') {
2998 			depth--;
2999 		}
3000 		ptr++;
3001 	}
3002 	return NULL;
3003 }
3004 
r_core_cmd_subst(RCore * core,char * cmd)3005 static int r_core_cmd_subst(RCore *core, char *cmd) {
3006 	ut64 rep = strtoull (cmd, NULL, 10);
3007 	int ret = 0, orep;
3008 	char *colon = NULL, *icmd = NULL;
3009 	bool tmpseek = false;
3010 	bool original_tmpseek = core->tmpseek;
3011 
3012 	if (r_str_startswith (cmd, "GET /cmd/")) {
3013 		memmove (cmd, cmd + 9, strlen (cmd + 9) + 1);
3014 		char *http = strstr (cmd, "HTTP");
3015 		if (http) {
3016 			*http = 0;
3017 			http--;
3018 			if (*http == ' ') {
3019 				*http = 0;
3020 			}
3021 		}
3022 		r_cons_printf ("HTTP/1.0 %d %s\r\n%s"
3023 				"Connection: close\r\nContent-Length: %d\r\n\r\n",
3024 				200, "OK", "", -1);
3025 		return r_core_cmd0 (core, cmd);
3026 	}
3027 
3028 	/* must store a local orig_offset because there can be
3029 	 * nested call of this function */
3030 	ut64 orig_offset = core->offset;
3031 	icmd = strdup (cmd);
3032 	if (!icmd) {
3033 		goto beach;
3034 	}
3035 
3036 	if (core->max_cmd_depth - core->cons->context->cmd_depth == 1) {
3037 		core->prompt_offset = core->offset;
3038 	}
3039 	cmd = (char *)r_str_trim_head_ro (icmd);
3040 	r_str_trim_tail (cmd);
3041 	// lines starting with # are ignored (never reach cmd_hash()), except #! and #?
3042 	if (!*cmd) {
3043 		if (core->cmdrepeat > 0) {
3044 			lastcmd_repeat (core, true);
3045 			ret = r_core_cmd_nullcallback (core);
3046 		}
3047 		goto beach;
3048 	}
3049 	if (!icmd || (cmd[0] == '#' && cmd[1] != '!' && cmd[1] != '?')) {
3050 		goto beach;
3051 	}
3052 	if (*icmd && !strchr (icmd, '"')) {
3053 		char *hash;
3054 		for (hash = icmd + 1; *hash; hash++) {
3055 			if (*hash == '\\') {
3056 				hash++;
3057 				if (*hash == '#') {
3058 					continue;
3059 				} else if (!*hash) {
3060 					break;
3061 				}
3062 			}
3063 			if (*hash == '#') {
3064 				break;
3065 			}
3066 		}
3067 		if (hash && *hash) {
3068 			*hash = 0;
3069 			r_str_trim_tail (icmd);
3070 		}
3071 	}
3072 	if (*cmd != '"') {
3073 		if (!strchr (cmd, '\'')) { // allow | awk '{foo;bar}' // ignore ; if there's a single quote
3074 			if (is_macro_command (cmd)) {
3075 				colon = find_ch_after_macro (cmd, ';');
3076 			} else {
3077 				colon = strchr (cmd, ';');
3078 			}
3079 			if (colon) {
3080 				*colon = 0;
3081 			}
3082 		}
3083 	} else {
3084 		colon = NULL;
3085 	}
3086 	if (rep > 0) {
3087 		while (IS_DIGIT (*cmd)) {
3088 			cmd++;
3089 		}
3090 		// do not repeat null cmd
3091 		if (!*cmd) {
3092 			goto beach;
3093 		}
3094 	}
3095 	if (rep < 1) {
3096 		rep = 1;
3097 	}
3098 	// XXX if output is a pipe then we don't want to be interactive
3099 	if (rep > 1 && r_sandbox_enable (0)) {
3100 		eprintf ("Command repeat sugar disabled in sandbox mode (%s)\n", cmd);
3101 		goto beach;
3102 	} else {
3103 		if (rep > INTERACTIVE_MAX_REP) {
3104 			if (r_cons_is_interactive ()) {
3105 				if (!r_cons_yesno ('n', "Are you sure to repeat this %"PFMT64d" times? (y/N)", rep)) {
3106 					goto beach;
3107 				}
3108 			}
3109 		}
3110 	}
3111 	// TODO: store in core->cmdtimes to speedup ?
3112 	const char *cmdrep = r_str_get (core->cmdtimes);
3113 	orep = rep;
3114 
3115 	r_cons_break_push (NULL, NULL);
3116 
3117 	int ocur_enabled = core->print && core->print->cur_enabled;
3118 	while (rep-- && *cmd) {
3119 		if (core->print) {
3120 			core->print->cur_enabled = false;
3121 			if (ocur_enabled && core->seltab >= 0) {
3122 				if (core->seltab == core->curtab) {
3123 					core->print->cur_enabled = true;
3124 				}
3125 			}
3126 		}
3127 		if (r_cons_is_breaked ()) {
3128 			break;
3129 		}
3130 		char *cr = strdup (cmdrep);
3131 		core->break_loop = false;
3132 		ret = r_core_cmd_subst_i (core, cmd, colon, (rep == orep - 1) ? &tmpseek : NULL);
3133 		if (*cmd == 's') {
3134 			// do not restore tmpseek if the command executed is the 's'eek
3135 			tmpseek = false;
3136 		}
3137 		if (ret && *cmd == 'q') {
3138 			free (cr);
3139 			goto beach;
3140 		}
3141 		if (core->break_loop) {
3142 			free (cr);
3143 			break;
3144 		}
3145 		if (cr && *cr && orep > 1) {
3146 			// XXX: do not flush here, we need r_cons_push () and r_cons_pop()
3147 			r_cons_flush ();
3148 			// XXX: we must import register flags in C
3149 			(void)r_core_cmd0 (core, ".dr*");
3150 			(void)r_core_cmd0 (core, cr);
3151 		}
3152 		free (cr);
3153 	}
3154 
3155 	r_cons_break_pop ();
3156 
3157 	if (tmpseek) {
3158 		r_core_seek (core, orig_offset, true);
3159 		core->tmpseek = original_tmpseek;
3160 	}
3161 	if (core->print) {
3162 		core->print->cur_enabled = ocur_enabled;
3163 	}
3164 	if (colon && colon[1]) {
3165 		for (++colon; *colon == ';'; colon++) {
3166 			;
3167 		}
3168 		r_core_cmd_subst (core, colon);
3169 	} else {
3170 		if (!*icmd) {
3171 			r_core_cmd_nullcallback (core);
3172 		}
3173 	}
3174 beach:
3175 	free (icmd);
3176 	return ret;
3177 }
3178 
find_eoq(char * p)3179 static char *find_eoq(char *p) {
3180 	for (; *p; p++) {
3181 		if (*p == '"') {
3182 			break;
3183 		}
3184 		if (*p == '\\' && p[1] == '"') {
3185 			p++;
3186 		}
3187 	}
3188 	return p;
3189 }
3190 
findSeparator(char * p)3191 static char* findSeparator(char *p) {
3192 	char *q = strchr (p, '+');
3193 	if (q) {
3194 		return q;
3195 	}
3196 	return strchr (p, '-');
3197 }
3198 
tmpenvs_free(void * item)3199 static void tmpenvs_free(void *item) {
3200 	r_sys_setenv (item, NULL);
3201 	free (item);
3202 }
3203 
set_tmp_arch(RCore * core,char * arch,char ** tmparch)3204 static bool set_tmp_arch(RCore *core, char *arch, char **tmparch) {
3205 	r_return_val_if_fail (tmparch, false);
3206 	*tmparch = strdup (r_config_get (core->config, "asm.arch"));
3207 	r_config_set (core->config, "asm.arch", arch);
3208 	core->fixedarch = true;
3209 	return true;
3210 }
3211 
set_tmp_bits(RCore * core,int bits,char ** tmpbits,int * cmd_ignbithints)3212 static bool set_tmp_bits(RCore *core, int bits, char **tmpbits, int *cmd_ignbithints) {
3213 	r_return_val_if_fail (tmpbits, false);
3214 	*tmpbits = strdup (r_config_get (core->config, "asm.bits"));
3215 	r_config_set_i (core->config, "asm.bits", bits);
3216 	core->fixedbits = true;
3217 	// XXX: why?
3218 	*cmd_ignbithints = r_config_get_i (core->config, "anal.ignbithints");
3219 	r_config_set_b (core->config, "anal.ignbithints", true);
3220 	return true;
3221 }
3222 
r_core_cmd_subst_i(RCore * core,char * cmd,char * colon,bool * tmpseek)3223 static int r_core_cmd_subst_i(RCore *core, char *cmd, char *colon, bool *tmpseek) {
3224 	RList *tmpenvs = r_list_newf (tmpenvs_free);
3225 	const char *quotestr = "`";
3226 	const char *tick = NULL;
3227 	char *ptr, *ptr2, *str;
3228 	char *arroba = NULL;
3229 	char *grep = NULL;
3230 	RIODesc *tmpdesc = NULL;
3231 	int pamode = !core->io->va;
3232 	int i, ret = 0, pipefd;
3233 	bool usemyblock = false;
3234 	int scr_html = -1;
3235 	int scr_color = -1;
3236 	bool eos = false;
3237 	bool haveQuote = false;
3238 	bool oldfixedarch = core->fixedarch;
3239 	bool oldfixedbits = core->fixedbits;
3240 	bool cmd_tmpseek = false;
3241 	ut64 tmpbsz = core->blocksize;
3242 	int cmd_ignbithints = -1;
3243 
3244 	if (!cmd) {
3245 		r_list_free (tmpenvs);
3246 		return 0;
3247 	}
3248 	r_str_trim (cmd);
3249 
3250 	char *$0 = strstr (cmd, "$(");
3251 	if ($0) {
3252 		char *$1 = strchr ($0 + 2, ')');
3253 		if ($1) {
3254 			*$0 = '`';
3255 			*$1 = '`';
3256 			memmove ($0 + 1, $0 + 2, strlen ($0 + 2) + 1);
3257 		} else {
3258 			eprintf ("Unterminated $() block\n");
3259 		}
3260 	}
3261 
3262 	/* quoted / raw command */
3263 	switch (*cmd) {
3264 	case '.':
3265 		if (cmd[1] == '"') { /* interpret */
3266 			r_list_free (tmpenvs);
3267 			return r_cmd_call (core->rcmd, cmd);
3268 		}
3269 		break;
3270 	case '"':
3271 		for (; *cmd; ) {
3272 			int pipefd = -1;
3273 			ut64 oseek = UT64_MAX;
3274 			char *line, *p;
3275 			haveQuote = *cmd == '"';
3276 			if (haveQuote) {
3277 				cmd++;
3278 				p = *cmd ? find_eoq (cmd) : NULL;
3279 				if (!p || !*p) {
3280 					eprintf ("Missing \" in (%s).", cmd);
3281 					r_list_free (tmpenvs);
3282 					return false;
3283 				}
3284 				*p++ = 0;
3285 				if (!*p) {
3286 					eos = true;
3287 				}
3288 			} else {
3289 				char *sc = strchr (cmd, ';');
3290 				if (sc) {
3291 					*sc = 0;
3292 				}
3293 				r_core_cmd0 (core, cmd);
3294 				if (!sc) {
3295 					break;
3296 				}
3297 				cmd = sc + 1;
3298 				continue;
3299 			}
3300 			char op0 = 0;
3301 			if (*p) {
3302 				// workaround :D
3303 				if (p[0] == '@') {
3304 					p--;
3305 				}
3306 				while (p[1] == ';' || IS_WHITESPACE (p[1])) {
3307 					p++;
3308 				}
3309 				if (p[1] == '@' || (p[1] && p[2] == '@')) {
3310 					char *q = strchr (p + 1, '"');
3311 					if (q) {
3312 						op0 = *q;
3313 						*q = 0;
3314 					}
3315 					haveQuote = q != NULL;
3316 					oseek = core->offset;
3317 					r_core_seek (core, r_num_math (core->num, p + 2), true);
3318 					if (q) {
3319 						*p = '"';
3320 						p = q;
3321 					} else {
3322 						p = strchr (p + 1, ';');
3323 					}
3324 				}
3325 				if (p && *p && p[1] == '>') {
3326 					str = p + 2;
3327 					while (*str == '>') {
3328 						str++;
3329 					}
3330 					str = (char *)r_str_trim_head_ro (str);
3331 					r_cons_flush ();
3332 					const bool append = p[2] == '>';
3333 					pipefd = r_cons_pipe_open (str, 1, append);
3334 				}
3335 			}
3336 			line = strdup (cmd);
3337 			line = r_str_replace (line, "\\\"", "\"", true);
3338 			if (p && *p && p[1] == '|') {
3339 				str = (char *)r_str_trim_head_ro (p + 2);
3340 				r_core_cmd_pipe (core, cmd, str);
3341 			} else {
3342 				r_cmd_call (core->rcmd, line);
3343 			}
3344 			free (line);
3345 			if (oseek != UT64_MAX) {
3346 				r_core_seek (core, oseek, true);
3347 			}
3348 			if (pipefd != -1) {
3349 				r_cons_flush ();
3350 				r_cons_pipe_close (pipefd);
3351 			}
3352 			if (!p) {
3353 				break;
3354 			}
3355 			if (eos) {
3356 				break;
3357 			}
3358 			if (haveQuote) {
3359 				if (*p == ';') {
3360 					cmd = p + 1;
3361 				} else {
3362 					if (*p == '"') {
3363 						cmd = p;
3364 					} else {
3365 						*p = op0;
3366 						cmd = p;
3367 					}
3368 				}
3369 			} else {
3370 				cmd = p + 1;
3371 			}
3372 		}
3373 		r_list_free (tmpenvs);
3374 		return true;
3375 	case '(':
3376 		if (cmd[1] != '*' && !strstr (cmd, ")()")) {
3377 			r_list_free (tmpenvs);
3378 			return r_cmd_call (core->rcmd, cmd);
3379 		}
3380 		break;
3381 	case '?':
3382 		if (cmd[1] == '>') {
3383 			r_core_cmd_help (core, help_msg_greater_sign);
3384 			r_list_free (tmpenvs);
3385 			return true;
3386 		}
3387 	}
3388 
3389 // TODO must honor `
3390 	/* comments */
3391 	if (*cmd != '#') {
3392 		ptr = (char *)r_str_firstbut (cmd, '#', "`\""); // TODO: use quotestr here
3393 		if (ptr && (ptr[1] == ' ' || ptr[1] == '\t')) {
3394 			*ptr = '\0';
3395 		}
3396 	}
3397 
3398 	/* multiple commands */
3399 	// TODO: must honor " and ` boundaries
3400 	//ptr = strrchr (cmd, ';');
3401 	if (*cmd != '#') {
3402 		if (is_macro_command (cmd)) {
3403 			ptr = find_ch_after_macro (cmd, ';');
3404 		} else {
3405 			ptr = (char *)r_str_lastbut (cmd, ';', quotestr);
3406 		}
3407 		if (colon && ptr) {
3408 			int ret ;
3409 			*ptr = '\0';
3410 			if (r_core_cmd_subst (core, cmd) == -1) {
3411 				r_list_free (tmpenvs);
3412 				return -1;
3413 			}
3414 			cmd = ptr + 1;
3415 			ret = r_core_cmd_subst (core, cmd);
3416 			*ptr = ';';
3417 			r_list_free (tmpenvs);
3418 			return ret;
3419 			//r_cons_flush ();
3420 		}
3421 	}
3422 
3423 	// TODO must honor " and `
3424 	/* pipe console to shell process */
3425 	//ptr = strchr (cmd, '|');
3426 	ptr = (char *)r_str_lastbut (cmd, '|', quotestr);
3427 	if (ptr) {
3428 		if (ptr > cmd) {
3429 			char *ch = ptr - 1;
3430 			if (*ch == '\\') {
3431 				memmove (ch, ptr, strlen (ptr) + 1);
3432 				goto escape_pipe;
3433 			}
3434 		}
3435 		char *ptr2 = strchr (cmd, '`');
3436 		if (!ptr2 || (ptr2 && ptr2 > ptr)) {
3437 			if (!tick || (tick && tick > ptr)) {
3438 				*ptr = '\0';
3439 				cmd = r_str_trim_nc (cmd);
3440 				if (!strcmp (ptr + 1, "?")) { // "|?"
3441 					r_core_cmd_help (core, help_msg_vertical_bar);
3442 					r_list_free (tmpenvs);
3443 					return ret;
3444 				} else if (!strncmp (ptr + 1, "H", 1)) { // "|H"
3445 					scr_html = r_config_get_b (core->config, "scr.html");
3446 					r_config_set_b (core->config, "scr.html", true);
3447 				} else if (!strcmp (ptr + 1, "T")) { // "|T"
3448 					scr_color = r_config_get_i (core->config, "scr.color");
3449 					r_config_set_i (core->config, "scr.color", COLOR_MODE_DISABLED);
3450 					core->cons->use_tts = true;
3451 				} else if (!strcmp (ptr + 1, ".")) { // "|."
3452 					ret = *cmd ? r_core_cmdf (core, ".%s", cmd) : 0;
3453 					r_list_free (tmpenvs);
3454 					return ret;
3455 				} else if (ptr[1]) { // "| grep .."
3456 					int value = core->num->value;
3457 					if (*cmd) {
3458 						r_core_cmd_pipe (core, cmd, ptr + 1);
3459 					} else {
3460 						char *res = r_io_system (core->io, ptr + 1);
3461 						if (res) {
3462 							r_cons_printf ("%s\n", res);
3463 							free (res);
3464 						}
3465 					}
3466 					core->num->value = value;
3467 					r_list_free (tmpenvs);
3468 					return 0;
3469 				} else { // "|"
3470 					scr_html = r_config_get_b (core->config, "scr.html");
3471 					r_config_set_b (core->config, "scr.html", false);
3472 					scr_color = r_config_get_i (core->config, "scr.color");
3473 					r_config_set_i (core->config, "scr.color", COLOR_MODE_DISABLED);
3474 				}
3475 			}
3476 		}
3477 	}
3478 escape_pipe:
3479 
3480 	// TODO must honor " and `
3481 	/* bool conditions */
3482 	ptr = (char *)r_str_lastbut (cmd, '&', quotestr);
3483 	//ptr = strchr (cmd, '&');
3484 	while (ptr && *ptr && ptr[1] == '&') {
3485 		*ptr = '\0';
3486 		ret = r_cmd_call (core->rcmd, cmd);
3487 		if (ret == -1) {
3488 			eprintf ("command error(%s)\n", cmd);
3489 			if (scr_html != -1) {
3490 				r_config_set_b (core->config, "scr.html", scr_html);
3491 			}
3492 			if (scr_color != -1) {
3493 				r_config_set_i (core->config, "scr.color", scr_color);
3494 			}
3495 			r_list_free (tmpenvs);
3496 			return ret;
3497 		}
3498 		for (cmd = ptr + 2; cmd && *cmd == ' '; cmd++) {
3499 			;
3500 		}
3501 		ptr = strchr (cmd, '&');
3502 	}
3503 
3504 	ptr = strstr (cmd, "?*");
3505 	if (ptr && (ptr == cmd || ptr[-1] != '~')) {
3506 		ptr[0] = 0;
3507 		if (*cmd != '#') {
3508 			int detail = 0;
3509 			if (cmd < ptr && ptr[-1] == '?') {
3510 				detail++;
3511 				if (cmd < ptr - 1 && ptr[-2] == '?') {
3512 					detail++;
3513 				}
3514 			}
3515 			r_cons_break_push (NULL, NULL);
3516 			recursive_help (core, detail, cmd);
3517 			r_cons_break_pop ();
3518 			r_cons_grep_parsecmd (ptr + 2, "`");
3519 			if (scr_html != -1) {
3520 				r_config_set_b (core->config, "scr.html", scr_html);
3521 			}
3522 			if (scr_color != -1) {
3523 				r_config_set_i (core->config, "scr.color", scr_color);
3524 			}
3525 			r_list_free (tmpenvs);
3526 			return 0;
3527 		}
3528 	}
3529 
3530 	/* pipe console to file */
3531 	ptr = (char *)r_str_firstbut (cmd, '>', "\"");
3532 	// TODO honor `
3533 	if (ptr) {
3534 		if (ptr > cmd) {
3535 			char *ch = ptr - 1;
3536 			if (*ch == '\\') {
3537 				memmove (ch, ptr, strlen (ptr) + 1);
3538 				goto escape_redir;
3539 			}
3540 		}
3541 		if (ptr[0] && ptr[1] == '?') {
3542 			r_core_cmd_help (core, help_msg_greater_sign);
3543 			r_list_free (tmpenvs);
3544 			return true;
3545 		}
3546 		int fdn = 1;
3547 		int pipecolor = r_config_get_i (core->config, "scr.color.pipe");
3548 		int use_editor = false;
3549 		int ocolor = r_config_get_i (core->config, "scr.color");
3550 		*ptr = '\0';
3551 		str = ptr + 1 + (ptr[1] == '>');
3552 		r_str_trim (str);
3553 		if (!*str) {
3554 			eprintf ("No output?\n");
3555 			goto next2;
3556 		}
3557 		/* r_cons_flush() handles interactive output (to the terminal)
3558 		 * differently (e.g. asking about too long output). This conflicts
3559 		 * with piping to a file. Disable it while piping. */
3560 		if (ptr > (cmd + 1) && IS_WHITECHAR (ptr[-2])) {
3561 			char *fdnum = ptr - 1;
3562 			if (*fdnum == 'H') { // "H>"
3563 				scr_html = r_config_get_i (core->config, "scr.html");
3564 				r_config_set_i (core->config, "scr.html", true);
3565 				pipecolor = true;
3566 				*fdnum = 0;
3567 			} else {
3568 				if (IS_DIGIT (*fdnum)) {
3569 					fdn = *fdnum - '0';
3570 				}
3571 				*fdnum = 0;
3572 			}
3573 		}
3574 		r_cons_set_interactive (false);
3575 		if (!strcmp (str, "-")) {
3576 			use_editor = true;
3577 			str = r_file_temp ("dumpedit");
3578 			r_config_set_i (core->config, "scr.color", COLOR_MODE_DISABLED);
3579 		}
3580 		const bool appendResult = (ptr[1] == '>');
3581 		if (*str == '$') {
3582 			// pipe to alias variable
3583 			// register output of command as an alias
3584 			char *o = r_core_cmd_str (core, cmd);
3585 			if (appendResult) {
3586 				const char *oldText = r_cmd_alias_get (core->rcmd, str, 1);
3587 				if (oldText) {
3588 					char *two = r_str_newf ("%s%s", oldText, o);
3589 					if (two) {
3590 						r_cmd_alias_set (core->rcmd, str, two, 1);
3591 						free (two);
3592 					}
3593 				} else {
3594 					char *n = r_str_newf ("$%s", o);
3595 					r_cmd_alias_set (core->rcmd, str, n, 1);
3596 					free (n);
3597 				}
3598 			} else {
3599 				char *n = r_str_newf ("$%s", o);
3600 				r_cmd_alias_set (core->rcmd, str, n, 1);
3601 				free (n);
3602 			}
3603 			ret = 0;
3604 			free (o);
3605 		} else if (fdn > 0) {
3606 			// pipe to file (or append)
3607 			pipefd = r_cons_pipe_open (str, fdn, appendResult);
3608 			if (pipefd != -1) {
3609 				if (!pipecolor) {
3610 					r_config_set_i (core->config, "scr.color", COLOR_MODE_DISABLED);
3611 				}
3612 				ret = r_core_cmd_subst (core, cmd);
3613 				r_cons_flush ();
3614 				r_cons_pipe_close (pipefd);
3615 			}
3616 		}
3617 		r_cons_set_last_interactive ();
3618 		if (!pipecolor) {
3619 			r_config_set_i (core->config, "scr.color", ocolor);
3620 		}
3621 		if (use_editor) {
3622 			const char *editor = r_config_get (core->config, "cfg.editor");
3623 			if (editor && *editor) {
3624 				r_sys_cmdf ("%s '%s'", editor, str);
3625 				r_file_rm (str);
3626 			} else {
3627 				eprintf ("No cfg.editor configured\n");
3628 			}
3629 			r_config_set_i (core->config, "scr.color", ocolor);
3630 			free (str);
3631 		}
3632 		if (scr_html != -1) {
3633 			r_config_set_i (core->config, "scr.html", scr_html);
3634 		}
3635 		if (scr_color != -1) {
3636 			r_config_set_i (core->config, "scr.color", scr_color);
3637 		}
3638 		core->cons->use_tts = false;
3639 		r_list_free (tmpenvs);
3640 		return ret;
3641 	}
3642 escape_redir:
3643 next2:
3644 	/* sub commands */
3645 	ptr = strchr (cmd, '`');
3646 	if (ptr) {
3647 		if (ptr > cmd) {
3648 			char *ch = ptr - 1;
3649 			if (*ch == '\\') {
3650 				memmove (ch, ptr, strlen (ptr) + 1);
3651 				goto escape_backtick;
3652 			}
3653 		}
3654 		bool empty = false;
3655 		int oneline = 1;
3656 		if (ptr[1] == '`') {
3657 			memmove (ptr, ptr + 1, strlen (ptr));
3658 			oneline = 0;
3659 			empty = true;
3660 		}
3661 		ptr2 = strchr (ptr + 1, '`');
3662 		if (empty) {
3663 			/* do nothing */
3664 		} else if (!ptr2) {
3665 			eprintf ("parse: Missing backtick in expression.\n");
3666 			goto fail;
3667 		} else {
3668 			int value = core->num->value;
3669 			*ptr = '\0';
3670 			*ptr2 = '\0';
3671 			if (ptr[1] == '!') {
3672 				str = r_core_cmd_str_pipe (core, ptr + 1);
3673 			} else {
3674 				// Color disabled when doing backticks ?e `pi 1`
3675 				int ocolor = r_config_get_i (core->config, "scr.color");
3676 				r_config_set_i (core->config, "scr.color", 0);
3677 				core->cmd_in_backticks = true;
3678 				str = r_core_cmd_str (core, ptr + 1);
3679 				core->cmd_in_backticks = false;
3680 				r_config_set_i (core->config, "scr.color", ocolor);
3681 			}
3682 			if (!str) {
3683 				goto fail;
3684 			}
3685 			// ignore contents if first char is pipe or comment
3686 			if (*str == '|' || *str == '*') {
3687 				eprintf ("r_core_cmd_subst_i: invalid backticked command\n");
3688 				free (str);
3689 				goto fail;
3690 			}
3691 			if (oneline && str) {
3692 				for (i = 0; str[i]; i++) {
3693 					if (str[i] == '\n') {
3694 						str[i] = ' ';
3695 					}
3696 				}
3697 			}
3698 			str = r_str_append (str, ptr2 + 1);
3699 			cmd = r_str_append (strdup (cmd), str);
3700 			core->num->value = value;
3701 			ret = r_core_cmd_subst (core, cmd);
3702 			free (cmd);
3703 			if (scr_html != -1) {
3704 				r_config_set_i (core->config, "scr.html", scr_html);
3705 			}
3706 			free (str);
3707 			r_list_free (tmpenvs);
3708 			return ret;
3709 		}
3710 	}
3711 escape_backtick:
3712 	// TODO must honor " and `
3713 	if (*cmd != '"' && *cmd) {
3714 		const char *s = strstr (cmd, "~?");
3715 		if (s) {
3716 			bool showHelp = false;
3717 			if (cmd == s) {
3718 				// ~?
3719 				// ~??
3720 				showHelp = true;
3721 			} else {
3722 				// pd~?
3723 				// pd~??
3724 				if (!strcmp (s, "~??")) {
3725 					showHelp = true;
3726 				}
3727 			}
3728 			if (showHelp) {
3729 				r_cons_grep_help ();
3730 				r_list_free (tmpenvs);
3731 				return true;
3732 			}
3733 		}
3734 	}
3735 	if (*cmd != '.') {
3736 		grep = r_cons_grep_strip (cmd, quotestr);
3737 	}
3738 
3739 	/* temporary seek commands */
3740 	// if (*cmd != '(' && *cmd != '"')
3741 	if (*cmd != '"') {
3742 		ptr = strchr (cmd, '@');
3743 		if (ptr == cmd + 1 && *cmd == '?') {
3744 			ptr = NULL;
3745 		}
3746 	} else {
3747 		ptr = NULL;
3748 	}
3749 
3750 	cmd_tmpseek = core->tmpseek = ptr != NULL;
3751 	int rc = 0;
3752 	if (ptr) {
3753 		char *f, *ptr2 = strchr (ptr + 1, '!');
3754 		ut64 addr = core->offset;
3755 		bool addr_is_set = false;
3756 		char *tmpbits = NULL;
3757 		const char *offstr = NULL;
3758 		bool is_bits_set = false;
3759 		bool is_arch_set = false;
3760 		char *tmpeval = NULL;
3761 		char *tmpasm = NULL;
3762 		bool flgspc_changed = false;
3763 		int tmpfd = -1;
3764 		size_t sz;
3765 		int len;
3766 		ut8 *buf;
3767 
3768 		*ptr++ = '\0';
3769 repeat_arroba:
3770 		arroba = (ptr[0] && ptr[1] && ptr[2])?
3771 				 strchr (ptr + 2, '@'): NULL;
3772 		if (arroba) {
3773 			*arroba = 0;
3774 		}
3775 
3776 		for (; *ptr == ' '; ptr++) {
3777 			//nothing to see here
3778 		}
3779 		if (*ptr && ptr[1] == ':') {
3780 			/* do nothing here */
3781 		} else {
3782 			ptr--;
3783 		}
3784 
3785 		r_str_trim_tail (ptr);
3786 
3787 		if (ptr[1] == '?') {
3788 			r_core_cmd_help (core, help_msg_at);
3789 		} else if (ptr[1] == '%') { // "@%"
3790 			char *k = strdup (ptr + 2);
3791 			char *v = strchr (k, '=');
3792 			if (v) {
3793 				*v++ = 0;
3794 				r_sys_setenv (k, v);
3795 				r_list_append (tmpenvs, k);
3796 			} else {
3797 				free (k);
3798 			}
3799 		} else if (ptr[1] == '.') { // "@."
3800 			if (ptr[2] == '.') { // "@.."
3801 				if (ptr[3] == '.') { // "@..."
3802 					ut64 addr = r_num_tail (core->num, core->offset, ptr + 4);
3803 					r_core_block_size (core, R_ABS ((st64)addr - (st64)core->offset));
3804 					goto fuji;
3805 				} else {
3806 					addr = r_num_tail (core->num, core->offset, ptr + 3);
3807 					r_core_seek (core, addr, true);
3808 					cmd_tmpseek = core->tmpseek = true;
3809 					goto fuji;
3810 				}
3811 			} else {
3812 				// WAT DU
3813 				eprintf ("TODO: what do you expect for @. import offset from file maybe?\n");
3814 			}
3815 		} else if (ptr[0] && ptr[1] == ':' && ptr[2]) {
3816 			switch (ptr[0]) {
3817 			case 'F': // "@F:" // temporary flag space
3818 				flgspc_changed = r_flag_space_push (core->flags, ptr + 2);
3819 				break;
3820 			case 'B': // "@B:#" // seek to the last instruction in current bb
3821 				{
3822 					int index = (int)r_num_math (core->num, ptr + 2);
3823 					RAnalBlock *bb = r_anal_bb_from_offset (core->anal, core->offset);
3824 					if (bb) {
3825 						// handle negative indices
3826 						if (index < 0) {
3827 							index = bb->ninstr + index;
3828 						}
3829 
3830 						if (index >= 0 && index < bb->ninstr) {
3831 							ut16 inst_off = r_anal_bb_offset_inst (bb, index);
3832 							r_core_seek (core, bb->addr + inst_off, true);
3833 							cmd_tmpseek = core->tmpseek = true;
3834 						} else {
3835 							eprintf ("The current basic block has %d instructions\n", bb->ninstr);
3836 						}
3837 					} else {
3838 						eprintf ("Can't find a basic block for 0x%08"PFMT64x"\n", core->offset);
3839 					}
3840 					break;
3841 				}
3842 				break;
3843 			case 'f': // "@f:" // slurp file in block
3844 				f = r_file_slurp (ptr + 2, &sz);
3845 				if (f) {
3846 					{
3847 						RBuffer *b = r_buf_new_with_bytes ((const ut8*)f, (ut64)sz);
3848 						RIODesc *d = r_io_open_buffer (core->io, b, R_PERM_RWX, 0);
3849 						if (d) {
3850 							if (tmpdesc) {
3851 								r_io_desc_close (tmpdesc);
3852 							}
3853 							tmpdesc = d;
3854 							if (pamode) {
3855 								r_config_set_i (core->config, "io.va", 1);
3856 							}
3857 							r_io_map_new (core->io, d->fd, d->perm, 0, core->offset, r_buf_size (b));
3858 						}
3859 					}
3860 				} else {
3861 					eprintf ("cannot open '%s'\n", ptr + 3);
3862 				}
3863 				break;
3864 			case 'r': // "@r:" // regname
3865 				if (ptr[1] == ':') {
3866 					ut64 regval;
3867 					char *mander = strdup (ptr + 2);
3868 					char *sep = findSeparator (mander);
3869 					if (sep) {
3870 						char ch = *sep;
3871 						*sep = 0;
3872 						regval = r_debug_reg_get (core->dbg, mander);
3873 						*sep = ch;
3874 						char *numexpr = r_str_newf ("0x%"PFMT64x"%s", regval, sep);
3875 						regval = r_num_math (core->num, numexpr);
3876 						free (numexpr);
3877 					} else {
3878 						regval = r_debug_reg_get (core->dbg, ptr + 2);
3879 					}
3880 					r_core_seek (core, regval, true);
3881 					cmd_tmpseek = core->tmpseek = true;
3882 					free (mander);
3883 				}
3884 				break;
3885 			case 'b': // "@b:" // bits
3886 				is_bits_set = set_tmp_bits (core, r_num_math (core->num, ptr + 2), &tmpbits, &cmd_ignbithints);
3887 				break;
3888 			case 'i': // "@i:"
3889 				{
3890 					ut64 addr = r_num_math (core->num, ptr + 2);
3891 					if (addr) {
3892 						r_core_cmdf (core, "so %s", ptr + 2);
3893 						cmd_tmpseek = core->tmpseek = true;
3894 					}
3895 				}
3896 				break;
3897 			case 'e': // "@e:"
3898 				{
3899 					char *cmd = parse_tmp_evals (core, ptr + 2);
3900 					if (!tmpeval) {
3901 						tmpeval = cmd;
3902 					} else {
3903 						tmpeval = r_str_prepend (tmpeval, cmd);
3904 						free (cmd);
3905 					}
3906 				}
3907 				break;
3908 			case 'v': // "@v:" // value (honors asm.bits and cfg.bigendian)
3909 				if (ptr[1] == ':') {
3910 					ut8 buf[8] = {0};
3911 					ut64 v = r_num_math (core->num, ptr + 2);
3912 					int be = r_config_get_i (core->config, "cfg.bigendian");
3913 					int bi = r_config_get_i (core->config, "asm.bits");
3914 					if (bi == 64) {
3915 						r_write_ble64 (buf, v, be);
3916 						len = 8;
3917 					} else {
3918 						r_write_ble32 (buf, v, be);
3919 						len = 4;
3920 					}
3921 					tmpfd = r_io_fd_get_current(core->io);
3922 					r_core_block_size (core, R_ABS (len));
3923 					RBuffer *b = r_buf_new_with_bytes (buf, len);
3924 					RIODesc *d = r_io_open_buffer (core->io, b, R_PERM_RWX, 0);
3925 					if (d) {
3926 						if (tmpdesc) {
3927 							r_io_desc_close (tmpdesc);
3928 						}
3929 						tmpdesc = d;
3930 						if (pamode) {
3931 							r_config_set_i (core->config, "io.va", 1);
3932 						}
3933 						r_io_map_new (core->io, d->fd, d->perm, 0, core->offset, r_buf_size (b));
3934 						r_core_block_size (core, len);
3935 						r_core_block_read (core);
3936 					}
3937 				} else {
3938 					eprintf ("Invalid @v: syntax\n");
3939 				}
3940 				break;
3941 			case 'x': // "@x:" // hexpairs
3942 				if (ptr[1] == ':') {
3943 					buf = malloc (strlen (ptr + 2) + 1);
3944 					if (buf) {
3945 						len = r_hex_str2bin (ptr + 2, buf);
3946 						r_core_block_size (core, R_ABS (len));
3947 						if (len > 0) {
3948 							RBuffer *b = r_buf_new_with_bytes (buf, len);
3949 							RIODesc *d = r_io_open_buffer (core->io, b, R_PERM_RWX, 0);
3950 							if (d) {
3951 								if (tmpdesc) {
3952 									r_io_desc_close (tmpdesc);
3953 								}
3954 								tmpdesc = d;
3955 								if (pamode) {
3956 									r_config_set_i (core->config, "io.va", 1);
3957 								}
3958 								r_io_map_new (core->io, d->fd, d->perm, 0, core->offset, r_buf_size (b));
3959 								r_core_block_size (core, len);
3960 								r_core_block_read (core);
3961 							}
3962 						} else {
3963 							eprintf ("Error: Invalid hexpairs for @x:\n");
3964 						}
3965 						free (buf);
3966 					} else {
3967 						eprintf ("cannot allocate\n");
3968 					}
3969 				} else {
3970 					eprintf ("Invalid @x: syntax\n");
3971 				}
3972 				break;
3973 			case 'k': // "@k"
3974 				 {
3975 					char *out = sdb_querys (core->sdb, NULL, 0, ptr + ((ptr[1])? 2: 1));
3976 					if (out) {
3977 						r_core_seek (core, r_num_math (core->num, out), true);
3978 						free (out);
3979 						usemyblock = true;
3980 					}
3981 				 }
3982 				break;
3983 			case 'o': // "@o:3"
3984 				if (ptr[1] == ':') {
3985 					tmpfd = core->io->desc ? core->io->desc->fd : -1;
3986 					r_io_use_fd (core->io, atoi (ptr + 2));
3987 				}
3988 				break;
3989 			case 'a': // "@a:"
3990 				if (ptr[1] == ':') {
3991 					char *q = strchr (ptr + 2, ':');
3992 					if (q) {
3993 						*q++ = 0;
3994 						int bits = r_num_math (core->num, q);
3995 						is_bits_set = set_tmp_bits (core, bits, &tmpbits, &cmd_ignbithints);
3996 					}
3997 					is_arch_set = set_tmp_arch (core, ptr + 2, &tmpasm);
3998 				} else {
3999 					eprintf ("Usage: pd 10 @a:arm:32\n");
4000 				}
4001 				break;
4002 			case 's': // "@s:" // wtf syntax
4003 				{
4004 					len = strlen (ptr + 2);
4005 					r_core_block_size (core, len);
4006 					const ut8 *buf = (const ut8*)r_str_trim_head_ro (ptr + 2);
4007 
4008 					if (len > 0) {
4009 						RBuffer *b = r_buf_new_with_bytes (buf, len);
4010 						RIODesc *d = r_io_open_buffer (core->io, b, R_PERM_RWX, 0);
4011 						if (!core->io->va) {
4012 							r_config_set_i (core->config, "io.va", 1);
4013 						}
4014 						if (d) {
4015 							if (tmpdesc) {
4016 								r_io_desc_close (tmpdesc);
4017 							}
4018 							tmpdesc = d;
4019 							if (pamode) {
4020 								r_config_set_i (core->config, "io.va", 1);
4021 							}
4022 							r_io_map_new (core->io, d->fd, d->perm, 0, core->offset, r_buf_size (b));
4023 							r_core_block_size (core, len);
4024 							// r_core_block_read (core);
4025 						}
4026 					}
4027 				}
4028 break;
4029 			default:
4030 				goto ignore;
4031 			}
4032 			*ptr = '@';
4033 			/* trim whitespaces before the @ */
4034 			/* Fixes pd @x:9090 */
4035 			char *trim = ptr - 2;
4036 			while (trim > cmd) {
4037 				if (!IS_WHITESPACE (*trim)) {
4038 					break;
4039 				}
4040 				*trim = 0;
4041 				trim--;
4042 			}
4043 			goto next_arroba;
4044 		}
4045 ignore:
4046 		r_str_trim_head (ptr + 1);
4047 		cmd = r_str_trim_nc (cmd);
4048 		if (ptr2) {
4049 			if (strlen (ptr + 1) == 13 && strlen (ptr2 + 1) == 6 &&
4050 				!memcmp (ptr + 1, "0x", 2) &&
4051 				!memcmp (ptr2 + 1, "0x", 2)) {
4052 				/* 0xXXXX:0xYYYY */
4053 			} else if (strlen (ptr + 1) == 9 && strlen (ptr2 + 1) == 4) {
4054 				/* XXXX:YYYY */
4055 			} else {
4056 				*ptr2 = '\0';
4057 				if (!ptr2[1]) {
4058 					goto fail;
4059 				}
4060 				r_core_block_size (
4061 					core, r_num_math (core->num, ptr2 + 1));
4062 			}
4063 		}
4064 
4065 		r_str_trim_head (ptr + 1);
4066 		offstr = ptr + 1;
4067 
4068 		addr = (*offstr == '{')? core->offset: r_num_math (core->num, offstr);
4069 		addr_is_set = true;
4070 
4071 		if (isalpha ((ut8)ptr[1]) && !addr) {
4072 			if (!r_flag_get (core->flags, ptr + 1)) {
4073 				eprintf ("Invalid address (%s)\n", ptr + 1);
4074 				goto fail;
4075 			}
4076 		} else {
4077 			char ch = *offstr;
4078 			if (ch == '-' || ch == '+') {
4079 				addr = core->offset + addr;
4080 			}
4081 		}
4082 		// remap thhe tmpdesc if any
4083 		if (addr) {
4084 			RIODesc *d = tmpdesc;
4085 			if (d) {
4086 				r_io_map_new (core->io, d->fd, d->perm, 0, addr, r_io_desc_size (d));
4087 			}
4088 		}
4089 next_arroba:
4090 		if (arroba) {
4091 			ptr = arroba + 1;
4092 			*arroba = '@';
4093 			arroba = NULL;
4094 			goto repeat_arroba;
4095 		}
4096 		core->fixedblock = !!tmpdesc;
4097 		if (core->fixedblock) {
4098 			r_core_block_read (core);
4099 		}
4100 		if (ptr[1] == '@') {
4101 			if (ptr[2] == '@') {
4102 				char *rule = ptr + 3;
4103 				while (*rule && *rule == ' ') {
4104 					rule++;
4105 				}
4106 				ret = r_core_cmd_foreach3 (core, cmd, rule);
4107 			} else {
4108 				ret = r_core_cmd_foreach (core, cmd, ptr + 2);
4109 			}
4110 		} else {
4111 			bool tmpseek = false;
4112 			const char *fromvars[] = { "anal.from", "diff.from", "graph.from", "search.from", "zoom.from", NULL };
4113 			const char *tovars[] = { "anal.to", "diff.to", "graph.to", "search.to", "zoom.to", NULL };
4114 			ut64 curfrom[R_ARRAY_SIZE (fromvars) - 1], curto[R_ARRAY_SIZE (tovars) - 1];
4115 
4116 			// "@{A B}"
4117 			if (ptr[1] == '{') {
4118 				char *range = ptr + 2;
4119 				char *p = strchr (range, ' ');
4120 				if (!p) {
4121 					eprintf ("Usage: / ABCD @{0x1000 0x3000}\n");
4122 					eprintf ("Run command and define the following vars:\n");
4123 					eprintf (" (anal|diff|graph|search|zoom).{from,to}\n");
4124 					free (tmpeval);
4125 					free (tmpasm);
4126 					free (tmpbits);
4127 					goto fail;
4128 				}
4129 				char *arg = p + 1;
4130 				int arg_len = strlen (arg);
4131 				if (arg_len > 0) {
4132 					arg[arg_len - 1] = 0;
4133 				}
4134 				*p = '\x00';
4135 				ut64 from = r_num_math (core->num, range);
4136 				ut64 to = r_num_math (core->num, arg);
4137 				// save current ranges
4138 				for (i = 0; fromvars[i]; i++) {
4139 					curfrom[i] = r_config_get_i (core->config, fromvars[i]);
4140 				}
4141 				for (i = 0; tovars[i]; i++) {
4142 					curto[i] = r_config_get_i (core->config, tovars[i]);
4143 				}
4144 				// set new ranges
4145 				for (i = 0; fromvars[i]; i++) {
4146 					r_config_set_i (core->config, fromvars[i], from);
4147 				}
4148 				for (i = 0; tovars[i]; i++) {
4149 					r_config_set_i (core->config, tovars[i], to);
4150 				}
4151 				tmpseek = true;
4152 			}
4153 			if (usemyblock) {
4154 				if (addr_is_set) {
4155 					core->offset = addr;
4156 				}
4157 				ret = r_cmd_call (core->rcmd, r_str_trim_head_ro (cmd));
4158 			} else {
4159 				if (addr_is_set) {
4160 					if (ptr[1]) {
4161 						r_core_seek (core, addr, true);
4162 						r_core_block_read (core);
4163 					}
4164 				}
4165 				ret = r_cmd_call (core->rcmd, r_str_trim_head_ro (cmd));
4166 
4167 			}
4168 			if (tmpseek) {
4169 				// restore ranges
4170 				for (i = 0; fromvars[i]; i++) {
4171 					r_config_set_i (core->config, fromvars[i], curfrom[i]);
4172 				}
4173 				for (i = 0; tovars[i]; i++) {
4174 					r_config_set_i (core->config, tovars[i], curto[i]);
4175 				}
4176 			}
4177 		}
4178 		if (ptr2) {
4179 			*ptr2 = '!';
4180 			r_core_block_size (core, tmpbsz);
4181 		}
4182 		if (is_arch_set) {
4183 			core->fixedarch = oldfixedarch;
4184 			r_config_set (core->config, "asm.arch", tmpasm);
4185 			R_FREE (tmpasm);
4186 		}
4187 		if (tmpdesc) {
4188 			if (pamode) {
4189 				r_config_set_i (core->config, "io.va", 0);
4190 			}
4191 			r_io_desc_close (tmpdesc);
4192 			tmpdesc = NULL;
4193 		}
4194 		if (tmpfd != -1) {
4195 			// TODO: reuse tmpfd instead of
4196 			r_io_use_fd (core->io, tmpfd);
4197 			tmpfd = -1;
4198 		}
4199 		if (is_bits_set) {
4200 			r_config_set (core->config, "asm.bits", tmpbits);
4201 			core->fixedbits = oldfixedbits;
4202 		}
4203 		if (tmpbsz != core->blocksize) {
4204 			r_core_block_size (core, tmpbsz);
4205 		}
4206 		if (tmpeval) {
4207 			r_core_cmd0 (core, tmpeval);
4208 			R_FREE (tmpeval);
4209 		}
4210 		if (flgspc_changed) {
4211 			r_flag_space_pop (core->flags);
4212 		}
4213 		*ptr = '@';
4214 		rc = ret;
4215 		goto beach;
4216 	}
4217 fuji:
4218 	if (cmd) {
4219 		r_str_trim_head (cmd);
4220 		rc = r_cmd_call (core->rcmd, cmd);
4221 	} else {
4222 		rc = false;
4223 	}
4224 beach:
4225 	if (grep) {
4226 		char *old_grep = grep;
4227 		grep = unescape_special_chars (old_grep, SPECIAL_CHARS_REGULAR);
4228 		free (old_grep);
4229 	}
4230 	r_cons_grep_process (grep);
4231 	if (scr_html != -1) {
4232 		r_cons_flush ();
4233 		r_config_set_i (core->config, "scr.html", scr_html);
4234 	}
4235 	if (scr_color != -1) {
4236 		r_config_set_i (core->config, "scr.color", scr_color);
4237 	}
4238 	r_list_free (tmpenvs);
4239 	if (tmpdesc) {
4240 		r_io_desc_close (tmpdesc);
4241 		tmpdesc = NULL;
4242 	}
4243 	core->fixedarch = oldfixedarch;
4244 	core->fixedbits = oldfixedbits;
4245 	if (tmpseek) {
4246 		*tmpseek = cmd_tmpseek;
4247 	}
4248 	if (cmd_ignbithints != -1) {
4249 		r_config_set_i (core->config, "anal.ignbithints", cmd_ignbithints);
4250 	}
4251 	return rc;
4252 fail:
4253 	rc = -1;
4254 	goto beach;
4255 }
4256 
4257 struct exec_command_t {
4258 	RCore *core;
4259 	const char *cmd;
4260 };
4261 
copy_into_flagitem_list(RFlagItem * flg,void * u)4262 static bool copy_into_flagitem_list(RFlagItem *flg, void *u) {
4263 	RFlagItem *fi = r_mem_dup (flg, sizeof (RFlagItem));
4264 	r_list_append (u, fi);
4265 	return true;
4266 }
4267 
foreach_pairs(RCore * core,const char * cmd,const char * each)4268 static void foreach_pairs(RCore *core, const char *cmd, const char *each) {
4269 	const char *arg;
4270 	int pair = 0;
4271 	for (arg = each ; ; ) {
4272 		char *next = strchr (arg, ' ');
4273 		if (next) {
4274 			*next = 0;
4275 		}
4276 		if (arg && *arg) {
4277 			ut64 n = r_num_get (NULL, arg);
4278 			if (pair%2) {
4279 				r_core_block_size (core, n);
4280 				r_core_cmd0 (core, cmd);
4281 			} else {
4282 				r_core_seek (core, n, true);
4283 			}
4284 			pair++;
4285 		}
4286 		if (!next) {
4287 			break;
4288 		}
4289 		arg = next + 1;
4290 	}
4291 }
4292 
r_core_cmd_foreach3(RCore * core,const char * cmd,char * each)4293 R_API int r_core_cmd_foreach3(RCore *core, const char *cmd, char *each) { // "@@@"
4294 	RDebug *dbg = core->dbg;
4295 	RList *list, *head;
4296 	RListIter *iter;
4297 	int i;
4298 	const char *filter = NULL;
4299 
4300 	if (each[0] && each[1] == ':') {
4301 		filter = each + 2;
4302 	}
4303 
4304 	switch (each[0]) {
4305 	case '=':
4306 		foreach_pairs (core, cmd, each + 1);
4307 		break;
4308 	case '?':
4309 		r_core_cmd_help (core, help_msg_at_at_at);
4310 		break;
4311 	case 'c':
4312 		if (filter) {
4313 			char *arg = r_core_cmd_str (core, filter);
4314 			foreach_pairs (core, cmd, arg);
4315 			free (arg);
4316 		} else {
4317 			eprintf ("Usage: @@@c:command   # same as @@@=`command`\n");
4318 		}
4319 		break;
4320 	case 'C': {
4321 		char *glob = filter ? r_str_trim_dup (filter): NULL;
4322 		RIntervalTreeIter it;
4323 		RAnalMetaItem *meta;
4324 		r_interval_tree_foreach (&core->anal->meta, it, meta) {
4325 			if (meta->type != R_META_TYPE_COMMENT) {
4326 				continue;
4327 			}
4328 			if (!glob || (meta->str && r_str_glob (meta->str, glob))) {
4329 				r_core_seek (core, r_interval_tree_iter_get (&it)->start, true);
4330 				r_core_cmd0 (core, cmd);
4331 			}
4332 		}
4333 		free (glob);
4334 		break;
4335 	}
4336 	case 'm':
4337 		{
4338 			int fd = r_io_fd_get_current (core->io);
4339 			// only iterate maps of current fd
4340 			RList *maps = r_io_map_get_for_fd (core->io, fd);
4341 			RIOMap *map;
4342 			if (maps) {
4343 				RListIter *iter;
4344 				r_list_foreach (maps, iter, map) {
4345 					r_core_seek (core, r_io_map_begin (map), true);
4346 					r_core_block_size (core, r_io_map_size (map));
4347 					r_core_cmd0 (core, cmd);
4348 				}
4349 				r_list_free (maps);
4350 			}
4351 		}
4352 		break;
4353 	case 'M':
4354 		if (dbg && dbg->h && dbg->maps) {
4355 			RDebugMap *map;
4356 			r_list_foreach (dbg->maps, iter, map) {
4357 				r_core_seek (core, map->addr, true);
4358 				//r_core_block_size (core, map->size);
4359 				r_core_cmd0 (core, cmd);
4360 			}
4361 		}
4362 		break;
4363 	case 't':
4364 		// iterate over all threads
4365 		if (dbg && dbg->h && dbg->h->threads) {
4366 			int origpid = dbg->pid;
4367 			RDebugPid *p;
4368 			list = dbg->h->threads (dbg, dbg->pid);
4369 			if (!list) {
4370 				return false;
4371 			}
4372 			r_list_foreach (list, iter, p) {
4373 				r_core_cmdf (core, "dp %d", p->pid);
4374 				r_cons_printf ("PID %d\n", p->pid);
4375 				r_core_cmd0 (core, cmd);
4376 			}
4377 			r_core_cmdf (core, "dp %d", origpid);
4378 			r_list_free (list);
4379 		}
4380 		break;
4381 	case 'r': // @@@r
4382 		{
4383 			ut64 offorig = core->offset;
4384 			for (i = 0; i < R_REG_TYPE_LAST; i++) {
4385 				RRegItem *item;
4386 				ut64 value;
4387 				head = r_reg_get_list (core->dbg->reg, i);
4388 				if (!head) {
4389 					continue;
4390 				}
4391 				RList *list = r_list_newf (free);
4392 				r_list_foreach (head, iter, item) {
4393 					if (item->size != core->anal->bits) {
4394 						continue;
4395 					}
4396 					if (item->type != i) {
4397 						continue;
4398 					}
4399 					r_list_append (list, strdup (item->name));
4400 				}
4401 				const char *item_name;
4402 				r_list_foreach (list, iter, item_name) {
4403 					value = r_reg_getv (core->dbg->reg, item_name);
4404 					r_core_seek (core, value, true);
4405 					r_cons_printf ("%s: ", item_name);
4406 					r_core_cmd0 (core, cmd);
4407 				}
4408 				r_list_free (list);
4409 			}
4410 			r_core_seek (core, offorig, true);
4411 		}
4412 		break;
4413 	case 'i': // @@@i
4414 		{
4415 			RBinImport *imp;
4416 			ut64 offorig = core->offset;
4417 			list = r_bin_get_imports (core->bin);
4418 			RList *lost = r_list_newf (free);
4419 			r_list_foreach (list, iter, imp) {
4420 				char *impflag = r_str_newf ("sym.imp.%s", imp->name);
4421 				ut64 addr = r_num_math (core->num, impflag);
4422 				ut64 *n = R_NEW (ut64);
4423 				*n = addr;
4424 				r_list_append (lost, n);
4425 				free (impflag);
4426 			}
4427 			ut64 *naddr;
4428 			r_list_foreach (lost, iter, naddr) {
4429 				ut64 addr = *naddr;
4430 				if (addr && addr != UT64_MAX) {
4431 					r_core_seek (core, addr, true);
4432 					r_core_cmd0 (core, cmd);
4433 				}
4434 			}
4435 			r_core_seek (core, offorig, true);
4436 			r_list_free (lost);
4437 		}
4438 		break;
4439 	case 'S': // "@@@S"
4440 		{
4441 			RBinObject *obj = r_bin_cur_object (core->bin);
4442 			if (obj) {
4443 				ut64 offorig = core->offset;
4444 				ut64 bszorig = core->blocksize;
4445 				RBinSection *sec;
4446 				RListIter *iter;
4447 				r_list_foreach (obj->sections, iter, sec) {
4448 					r_core_seek (core, sec->vaddr, true);
4449 					r_core_block_size (core, sec->vsize);
4450 					r_core_cmd0 (core, cmd);
4451 				}
4452 				r_core_block_size (core, bszorig);
4453 				r_core_seek (core, offorig, true);
4454 			}
4455 		}
4456 #if ATTIC
4457 		if (each[1] == 'S') {
4458 			RListIter *it;
4459 			RBinSection *sec;
4460 			RBinObject *obj = r_bin_cur_object (core->bin);
4461 			int cbsz = core->blocksize;
4462 			r_list_foreach (obj->sections, it, sec){
4463 				ut64 addr = sec->vaddr;
4464 				ut64 size = sec->vsize;
4465 				// TODO:
4466 				//if (R_BIN_SCN_EXECUTABLE & sec->perm) {
4467 				//	continue;
4468 				//}
4469 				r_core_seek_size (core, addr, size);
4470 				r_core_cmd (core, cmd, 0);
4471 			}
4472 			r_core_block_size (core, cbsz);
4473 		}
4474 #endif
4475 		break;
4476 	case 's':
4477 		if (each[1] == 't') { // strings
4478 			list = r_bin_get_strings (core->bin);
4479 			if (list) {
4480 				ut64 offorig = core->offset;
4481 				ut64 obs = core->blocksize;
4482 				RBinString *s;
4483 				RList *lost = r_list_newf (free);
4484 				r_list_foreach (list, iter, s) {
4485 					RBinString *bs = r_mem_dup (s, sizeof (RBinString));
4486 					r_list_append (lost, bs);
4487 				}
4488 				r_list_foreach (lost, iter, s) {
4489 					r_core_block_size (core, s->size);
4490 					r_core_seek (core, s->vaddr, true);
4491 					r_core_cmd0 (core, cmd);
4492 				}
4493 				r_core_block_size (core, obs);
4494 				r_core_seek (core, offorig, true);
4495 				r_list_free (lost);
4496 			}
4497 		} else {
4498 			// symbols
4499 			RBinSymbol *sym;
4500 			ut64 offorig = core->offset;
4501 			ut64 obs = core->blocksize;
4502 			list = r_bin_get_symbols (core->bin);
4503 			r_cons_break_push (NULL, NULL);
4504 			RList *lost = r_list_newf (free);
4505 			r_list_foreach (list, iter, sym) {
4506 				RBinSymbol *bs = r_mem_dup (sym, sizeof (RBinSymbol));
4507 				r_list_append (lost, bs);
4508 			}
4509 			r_list_foreach (lost, iter, sym) {
4510 				if (r_cons_is_breaked ()) {
4511 					break;
4512 				}
4513 				r_core_block_size (core, sym->size);
4514 				r_core_seek (core, sym->vaddr, true);
4515 				r_core_cmd0 (core, cmd);
4516 			}
4517 			r_cons_break_pop ();
4518 			r_list_free (lost);
4519 			r_core_block_size (core, obs);
4520 			r_core_seek (core, offorig, true);
4521 		}
4522 		break;
4523 	case 'f': // flags
4524 		{
4525 		// TODO: honor ^C
4526 			char *glob = filter? r_str_trim_dup (filter): NULL;
4527 			ut64 off = core->offset;
4528 			ut64 obs = core->blocksize;
4529 			RList *flags = r_list_newf (free);
4530 			r_flag_foreach_glob (core->flags, glob, copy_into_flagitem_list, flags);
4531 			RListIter *iter;
4532 			RFlagItem *f;
4533 			r_list_foreach (flags, iter, f) {
4534 				r_core_block_size (core, f->size);
4535 				r_core_seek (core, f->offset, true);
4536 				r_core_cmd0 (core, cmd);
4537 			}
4538 			r_core_seek (core, off, false);
4539 			r_core_block_size (core, obs);
4540 			free (glob);
4541 		}
4542 		break;
4543 	case 'F': // functions
4544 		{
4545 			ut64 obs = core->blocksize;
4546 			ut64 offorig = core->offset;
4547 			RAnalFunction *fcn;
4548 			list = core->anal->fcns;
4549 			r_cons_break_push (NULL, NULL);
4550 			r_list_foreach (list, iter, fcn) {
4551 				if (r_cons_is_breaked ()) {
4552 					break;
4553 				}
4554 				if (!filter || r_str_glob (fcn->name, filter)) {
4555 					r_core_seek (core, fcn->addr, true);
4556 					r_core_block_size (core, r_anal_function_linear_size (fcn));
4557 					r_core_cmd0 (core, cmd);
4558 				}
4559 			}
4560 			r_cons_break_pop ();
4561 			r_core_block_size (core, obs);
4562 			r_core_seek (core, offorig, true);
4563 		}
4564 		break;
4565 	case 'b':
4566 		{
4567 			RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, core->offset, 0);
4568 			ut64 offorig = core->offset;
4569 			ut64 obs = core->blocksize;
4570 			if (fcn) {
4571 				RListIter *iter;
4572 				RAnalBlock *bb;
4573 				r_list_foreach (fcn->bbs, iter, bb) {
4574 					r_core_seek (core, bb->addr, true);
4575 					r_core_block_size (core, bb->size);
4576 					r_core_cmd0 (core, cmd);
4577 				}
4578 				r_core_block_size (core, obs);
4579 				r_core_seek (core, offorig, true);
4580 			}
4581 		}
4582 		break;
4583 	}
4584 	return 0;
4585 }
4586 
foreachOffset(RCore * core,const char * _cmd,const char * each)4587 static void foreachOffset(RCore *core, const char *_cmd, const char *each) {
4588 	char *cmd = strdup (_cmd);
4589 	char *nextLine = NULL;
4590 	ut64 addr;
4591 	/* foreach list of items */
4592 	while (each) {
4593 		// skip spaces
4594 		while (*each == ' ') {
4595 			each++;
4596 		}
4597 		// stahp if empty string
4598 		if (!*each) {
4599 			break;
4600 		}
4601 		// find newline
4602 		char *nl = strchr (each, '\n');
4603 		if (nl) {
4604 			*nl = 0;
4605 			nextLine = nl + 1;
4606 		} else {
4607 			nextLine = NULL;
4608 		}
4609 		// chop comment in line
4610 		nl = strchr (each, '#');
4611 		if (nl) {
4612 			*nl = 0;
4613 		}
4614 		// space separated numbers
4615 		while (each && *each) {
4616 			// find spaces
4617 			while (*each == ' ') {
4618 				each++;
4619 			}
4620 			char *str = strchr (each, ' ');
4621 			if (str) {
4622 				*str = '\0';
4623 				addr = r_num_math (core->num, each);
4624 				*str = ' ';
4625 				each = str + 1;
4626 			} else {
4627 				if (!*each) {
4628 					break;
4629 				}
4630 				addr = r_num_math (core->num, each);
4631 				each = NULL;
4632 			}
4633 			r_core_seek (core, addr, true);
4634 			r_core_cmd (core, cmd, 0);
4635 			r_cons_flush ();
4636 		}
4637 		each = nextLine;
4638 	}
4639 	free (cmd);
4640 }
4641 
r_core_cmd_foreach(RCore * core,const char * cmd,char * each)4642 R_API int r_core_cmd_foreach(RCore *core, const char *cmd, char *each) {
4643 	int i, j;
4644 	char ch;
4645 	char *word = NULL;
4646 	char *str, *ostr = NULL;
4647 	RListIter *iter;
4648 	RFlagItem *flag;
4649 	ut64 oseek, addr;
4650 
4651 	for (; *cmd == ' '; cmd++) {
4652 		;
4653 	}
4654 
4655 	oseek = core->offset;
4656 	ostr = str = strdup (each);
4657 	r_cons_break_push (NULL, NULL); //pop on return
4658 	switch (each[0]) {
4659 	case '/': // "@@/"
4660 		{
4661 		char *cmdhit = strdup (r_config_get (core->config, "cmd.hit"));
4662 		r_config_set (core->config, "cmd.hit", cmd);
4663 		r_core_cmd0 (core, each);
4664 		r_config_set (core->config, "cmd.hit", cmdhit);
4665 		free (cmdhit);
4666 		}
4667 		free (ostr);
4668 		return 0;
4669 	case '?': // "@@?"
4670 		r_core_cmd_help (core, help_msg_at_at);
4671 		break;
4672 	case 'b': // "@@b" - function basic blocks
4673 		{
4674 			RListIter *iter;
4675 			RAnalBlock *bb;
4676 			RAnalFunction *fcn = r_anal_get_function_at (core->anal, core->offset);
4677 			int bs = core->blocksize;
4678 			if (fcn) {
4679 				r_list_sort (fcn->bbs, bb_cmp);
4680 				r_list_foreach (fcn->bbs, iter, bb) {
4681 					r_core_block_size (core, bb->size);
4682 					r_core_seek (core, bb->addr, true);
4683 					r_core_cmd (core, cmd, 0);
4684 					if (r_cons_is_breaked ()) {
4685 						break;
4686 					}
4687 				}
4688 			}
4689 			r_core_block_size (core, bs);
4690 			goto out_finish;
4691 		}
4692 		break;
4693 	case 's': // "@@s" - sequence
4694 		{
4695 			char *str = each + 1;
4696 			if (*str == ':' || *str == ' ') {
4697 				str++;
4698 			}
4699 			int count = r_str_split (str, ' ');
4700 			if (count == 3) {
4701 				ut64 cur;
4702 				ut64 from = r_num_math (core->num, r_str_word_get0 (str, 0));
4703 				ut64 to = r_num_math (core->num, r_str_word_get0 (str, 1));
4704 				ut64 step = r_num_math (core->num, r_str_word_get0 (str, 2));
4705 				for (cur = from; cur <= to; cur += step) {
4706 					(void) r_core_seek (core, cur, true);
4707 					r_core_cmd (core, cmd, 0);
4708 					if (r_cons_is_breaked ()) {
4709 						break;
4710 					}
4711 				}
4712 			} else {
4713 				eprintf ("Usage: cmd @@s:from to step\n");
4714 			}
4715 			goto out_finish;
4716 		}
4717 		break;
4718 	case 'i': // "@@i" - function instructions
4719 		{
4720 			RListIter *iter;
4721 			RAnalBlock *bb;
4722 			int i;
4723 			RAnalFunction *fcn = r_anal_get_function_at (core->anal, core->offset);
4724 			if (fcn) {
4725 				r_list_sort (fcn->bbs, bb_cmp);
4726 				r_list_foreach (fcn->bbs, iter, bb) {
4727 					for (i = 0; i < bb->op_pos_size; i++) {
4728 						ut64 addr = bb->addr + bb->op_pos[i];
4729 						r_core_seek (core, addr, true);
4730 						r_core_cmd (core, cmd, 0);
4731 						if (r_cons_is_breaked ()) {
4732 							break;
4733 						}
4734 					}
4735 				}
4736 			}
4737 			goto out_finish;
4738 		}
4739 		break;
4740 	case 'f': // "@@f"
4741 		if (each[1] == ':') {
4742 			RAnalFunction *fcn;
4743 			RListIter *iter;
4744 			if (core->anal) {
4745 				r_list_foreach (core->anal->fcns, iter, fcn) {
4746 					if (each[2] && strstr (fcn->name, each + 2)) {
4747 						r_core_seek (core, fcn->addr, true);
4748 						r_core_cmd (core, cmd, 0);
4749 						if (r_cons_is_breaked ()) {
4750 							break;
4751 						}
4752 					}
4753 				}
4754 			}
4755 			goto out_finish;
4756 		} else {
4757 			RAnalFunction *fcn;
4758 			RListIter *iter;
4759 			if (core->anal) {
4760 				RConsGrep grep = core->cons->context->grep;
4761 				r_list_foreach (core->anal->fcns, iter, fcn) {
4762 					char *buf;
4763 					r_core_seek (core, fcn->addr, true);
4764 					r_cons_push ();
4765 					r_core_cmd (core, cmd, 0);
4766 					buf = (char *)r_cons_get_buffer ();
4767 					if (buf) {
4768 						buf = strdup (buf);
4769 					}
4770 					r_cons_pop ();
4771 					r_cons_strcat (buf);
4772 					free (buf);
4773 					if (r_cons_is_breaked ()) {
4774 						break;
4775 					}
4776 				}
4777 				core->cons->context->grep = grep;
4778 			}
4779 			goto out_finish;
4780 		}
4781 		break;
4782 	case 't': // "@@t"
4783 		{
4784 			RDebugPid *p;
4785 			int pid = core->dbg->pid;
4786 			if (core->dbg->h && core->dbg->h->pids) {
4787 				RList *list = core->dbg->h->pids (core->dbg, R_MAX (0, pid));
4788 				r_list_foreach (list, iter, p) {
4789 					r_cons_printf ("# PID %d\n", p->pid);
4790 					r_debug_select (core->dbg, p->pid, p->pid);
4791 					r_core_cmd (core, cmd, 0);
4792 					r_cons_newline ();
4793 				}
4794 				r_list_free (list);
4795 			}
4796 			r_debug_select (core->dbg, pid, pid);
4797 			goto out_finish;
4798 		}
4799 		break;
4800 	case 'c': // "@@c:"
4801 		if (each[1] == ':') {
4802 			char *arg = r_core_cmd_str (core, each + 2);
4803 			if (arg) {
4804 				foreachOffset (core, cmd, arg);
4805 				free (arg);
4806 			}
4807 		}
4808 		break;
4809 	case '=': // "@@="
4810 		foreachOffset (core, cmd, str + 1);
4811 		break;
4812 	case 'd': // "@@d"
4813 		if (each[1] == 'b' && each[2] == 't') {
4814 			ut64 oseek = core->offset;
4815 			RDebugFrame *frame;
4816 			RListIter *iter;
4817 			RList *list;
4818 			list = r_debug_frames (core->dbg, UT64_MAX);
4819 			i = 0;
4820 			r_list_foreach (list, iter, frame) {
4821 				switch (each[3]) {
4822 				case 'b':
4823 					r_core_seek (core, frame->bp, true);
4824 					break;
4825 				case 's':
4826 					r_core_seek (core, frame->sp, true);
4827 					break;
4828 				default:
4829 				case 'a':
4830 					r_core_seek (core, frame->addr, true);
4831 					break;
4832 				}
4833 				r_core_cmd (core, cmd, 0);
4834 				r_cons_newline ();
4835 				i++;
4836 			}
4837 			r_core_seek (core, oseek, false);
4838 			r_list_free (list);
4839 		} else {
4840 			eprintf("Invalid for-each statement. Use @@=dbt[abs]\n");
4841 		}
4842 		break;
4843 	case 'k': // "@@k"
4844 		/* foreach list of items */
4845 		{
4846 		char *out = sdb_querys (core->sdb, NULL, 0, str + ((str[1])? 2: 1));
4847 		if (out) {
4848 			each = out;
4849 			do {
4850 				while (*each == ' ') {
4851 					each++;
4852 				}
4853 				if (!*each) {
4854 					break;
4855 				}
4856 				str = strchr (each, ' ');
4857 				if (str) {
4858 					*str = '\0';
4859 					addr = r_num_math (core->num, each);
4860 					*str = ' ';
4861 				} else {
4862 					addr = r_num_math (core->num, each);
4863 				}
4864 				//eprintf ("; 0x%08"PFMT64x":\n", addr);
4865 				each = str + 1;
4866 				r_core_seek (core, addr, true);
4867 				r_core_cmd (core, cmd, 0);
4868 				r_cons_flush ();
4869 			} while (str != NULL);
4870 			free (out);
4871 		}
4872 		}
4873 		break;
4874 	case '.': // "@@."
4875 		if (each[1] == '(') {
4876 			char cmd2[1024];
4877 			// XXX what's this 999 ?
4878 			i = 0;
4879 			for (core->rcmd->macro.counter = 0; i < 999; core->rcmd->macro.counter++) {
4880 				if (r_cons_is_breaked ()) {
4881 					break;
4882 				}
4883 				r_cmd_macro_call (&core->rcmd->macro, each + 2);
4884 				if (!core->rcmd->macro.brk_value) {
4885 					break;
4886 				}
4887 				addr = core->rcmd->macro._brk_value;
4888 				sprintf (cmd2, "%s @ 0x%08"PFMT64x"", cmd, addr);
4889 				eprintf ("0x%08"PFMT64x" (%s)\n", addr, cmd2);
4890 				r_core_seek (core, addr, true);
4891 				r_core_cmd (core, cmd2, 0);
4892 				i++;
4893 			}
4894 		} else {
4895 			char buf[1024];
4896 			char cmd2[1024];
4897 			FILE *fd = r_sandbox_fopen (each + 1, "r");
4898 			if (fd) {
4899 				core->rcmd->macro.counter = 0;
4900 				while (!feof (fd)) {
4901 					buf[0] = '\0';
4902 					if (!fgets (buf, sizeof (buf), fd)) {
4903 						break;
4904 					}
4905 					addr = r_num_math (core->num, buf);
4906 					eprintf ("0x%08"PFMT64x": %s\n", addr, cmd);
4907 					sprintf (cmd2, "%s @ 0x%08"PFMT64x"", cmd, addr);
4908 					r_core_seek (core, addr, true); // XXX
4909 					r_core_cmd (core, cmd2, 0);
4910 					core->rcmd->macro.counter++;
4911 				}
4912 				fclose (fd);
4913 			} else {
4914 				eprintf ("cannot open file '%s' to read offsets\n", each + 1);
4915 			}
4916 		}
4917 		break;
4918 	default:
4919 		core->rcmd->macro.counter = 0;
4920 		for (; *each == ' '; each++) {
4921 			;
4922 		}
4923 		i = 0;
4924 		while (str[i]) {
4925 			j = i;
4926 			for (; str[j] && str[j] == ' '; j++) {
4927 				; // skip spaces
4928 			}
4929 			for (i = j; str[i] && str[i] != ' '; i++) {
4930 				; // find EOS
4931 			}
4932 			ch = str[i];
4933 			str[i] = '\0';
4934 			word = strdup (str + j);
4935 			if (!word) {
4936 				break;
4937 			}
4938 			str[i] = ch;
4939 			{
4940 				const RSpace *flagspace = r_flag_space_cur (core->flags);
4941 				RList *match_flag_items = r_list_newf ((RListFree)r_flag_item_free);
4942 				if (!match_flag_items) {
4943 					break;
4944 				}
4945 
4946 				/* duplicate flags that match word, to be sure
4947 				   the command is going to be executed on flags
4948 				   values at the moment the command is called
4949 				   (without side effects) */
4950 				struct duplicate_flag_t u = {
4951 					.ret = match_flag_items,
4952 					.word = word,
4953 				};
4954 				r_flag_foreach_space (core->flags, flagspace, duplicate_flag, &u);
4955 
4956 				/* for all flags that match */
4957 				r_list_foreach (match_flag_items, iter, flag) {
4958 					if (r_cons_is_breaked ()) {
4959 						break;
4960 					}
4961 
4962 					char *buf = NULL;
4963 					const char *tmp = NULL;
4964 					r_core_seek (core, flag->offset, true);
4965 					r_cons_push ();
4966 					r_core_cmd (core, cmd, 0);
4967 					tmp = r_cons_get_buffer ();
4968 					buf = tmp? strdup (tmp): NULL;
4969 					r_cons_pop ();
4970 					r_cons_strcat (buf);
4971 					free (buf);
4972 					r_core_task_yield (&core->tasks);
4973 				}
4974 
4975 				r_list_free (match_flag_items);
4976 				core->rcmd->macro.counter++ ;
4977 				R_FREE (word);
4978 			}
4979 		}
4980 	}
4981 	r_cons_break_pop ();
4982 	// XXX: use r_core_seek here
4983 	core->offset = oseek;
4984 
4985 	free (word);
4986 	free (ostr);
4987 	return true;
4988 out_finish:
4989 	free (ostr);
4990 	r_cons_break_pop ();
4991 	return false;
4992 }
4993 
4994 static int run_cmd_depth(RCore *core, char *cmd);
4995 
4996 struct tsr2cmd_state {
4997 	TSParser *parser;
4998 	RCore *core;
4999 	char *input;
5000 	char *saved_input;
5001 	TSTree *tree;
5002 	TSTree *saved_tree;
5003 	bool log;
5004 	bool split_lines;
5005 	bool is_last_cmd;
5006 	TSNode substitute_cmd;
5007 };
5008 
5009 struct tsr2cmd_edit {
5010 	char *new_text;
5011 	char *old_text;
5012 	ut32 start;
5013 	ut32 end;
5014 	TSPoint start_point;
5015 	TSPoint end_point;
5016 };
5017 
5018 typedef RCmdStatus (*ts_handler)(struct tsr2cmd_state *state, TSNode node);
5019 
5020 struct ts_data_symbol_map {
5021 	const char *name;
5022 	void *data;
5023 };
5024 
5025 #define TS_START_END(node, start, end) do {		\
5026 		start = ts_node_start_byte (node);	\
5027 		end = ts_node_end_byte (node);		\
5028 	} while (0)
5029 
ts_node_sub_string(TSNode node,const char * cstr)5030 static char *ts_node_sub_string(TSNode node, const char *cstr) {
5031 	ut32 start, end;
5032 	TS_START_END (node, start, end);
5033 	return r_str_newf ("%.*s", end - start, cstr + start);
5034 }
5035 
ts_node_sub_parent_string(TSNode parent,TSNode node,const char * cstr)5036 static char *ts_node_sub_parent_string(TSNode parent, TSNode node, const char *cstr) {
5037 	ut32 start, end;
5038 	TS_START_END (node, start, end);
5039 	ut32 parent_start = ts_node_start_byte (parent);
5040 	start -= parent_start;
5041 	end -= parent_start;
5042 	return r_str_newf ("%.*s", end - start, cstr + start);
5043 }
5044 
5045 #define DEFINE_SYMBOL_TS_FCN(name) TSSymbol ts_##name##_symbol
5046 
5047 #define DEFINE_IS_TS_FCN(name) \
5048 	static inline bool is_ts_##name(TSNode node) { \
5049 		return ts_node_symbol (node) == ts_##name##_symbol; \
5050 	}
5051 
5052 #define DEFINE_IS_TS_FCN_AND_SYMBOL(name) \
5053 	DEFINE_SYMBOL_TS_FCN (name); \
5054 	DEFINE_IS_TS_FCN (name)
5055 
5056 #define DEFINE_HANDLE_TS_FCN(name) \
5057 	static RCmdStatus handle_ts_##name##_internal(struct tsr2cmd_state *state, TSNode node, char *node_string); \
5058 	static RCmdStatus handle_ts_##name(struct tsr2cmd_state *state, TSNode node) { \
5059 		char *node_string = ts_node_sub_string (node, state->input); \
5060 		R_LOG_DEBUG (#name ": '%s'\n", node_string); \
5061 		RCmdStatus res = handle_ts_##name##_internal (state, node, node_string); \
5062 		free (node_string); \
5063 		return res; \
5064 	} \
5065 	static RCmdStatus handle_ts_##name##_internal(struct tsr2cmd_state *state, TSNode node, char *node_string)
5066 
5067 #define DEFINE_HANDLE_TS_FCN_AND_SYMBOL(name) \
5068 	DEFINE_SYMBOL_TS_FCN (name); \
5069 	DEFINE_HANDLE_TS_FCN (name)
5070 
5071 #define UPDATE_CMD_STATUS_RES(res, cmd_res, label) \
5072 	if ((cmd_res) != R_CMD_STATUS_OK) { \
5073 		res = (cmd_res); \
5074 		goto label; \
5075 	}
5076 
5077 static RCmdStatus handle_ts_command(struct tsr2cmd_state *state, TSNode node);
5078 static RCmdStatus handle_ts_command_tmpseek(struct tsr2cmd_state *state, TSNode node);
5079 static RCmdStatus core_cmd_tsr2cmd(RCore *core, const char *cstr, bool split_lines, bool log);
5080 
5081 DEFINE_IS_TS_FCN_AND_SYMBOL(fdn_redirect_operator)
DEFINE_IS_TS_FCN_AND_SYMBOL(fdn_append_operator)5082 DEFINE_IS_TS_FCN_AND_SYMBOL(fdn_append_operator)
5083 DEFINE_IS_TS_FCN_AND_SYMBOL(html_redirect_operator)
5084 DEFINE_IS_TS_FCN_AND_SYMBOL(html_append_operator)
5085 DEFINE_IS_TS_FCN_AND_SYMBOL(cmd_substitution_arg)
5086 DEFINE_IS_TS_FCN_AND_SYMBOL(args)
5087 DEFINE_IS_TS_FCN_AND_SYMBOL(arg)
5088 DEFINE_IS_TS_FCN_AND_SYMBOL(arg_identifier)
5089 DEFINE_IS_TS_FCN_AND_SYMBOL(pf_arg)
5090 DEFINE_IS_TS_FCN_AND_SYMBOL(pf_args)
5091 DEFINE_IS_TS_FCN_AND_SYMBOL(pf_dot_cmd_args)
5092 DEFINE_IS_TS_FCN_AND_SYMBOL(pf_new_args)
5093 DEFINE_IS_TS_FCN_AND_SYMBOL(pf_concatenation)
5094 DEFINE_IS_TS_FCN_AND_SYMBOL(double_quoted_arg)
5095 DEFINE_IS_TS_FCN_AND_SYMBOL(single_quoted_arg)
5096 DEFINE_IS_TS_FCN_AND_SYMBOL(concatenation)
5097 DEFINE_IS_TS_FCN_AND_SYMBOL(grep_specifier)
5098 DEFINE_IS_TS_FCN_AND_SYMBOL(commands)
5099 
5100 static struct tsr2cmd_edit *create_cmd_edit(struct tsr2cmd_state *state, TSNode arg, char *new_text) {
5101 	struct tsr2cmd_edit *e = R_NEW0 (struct tsr2cmd_edit);
5102 	ut32 command_start = ts_node_start_byte (state->substitute_cmd);
5103 	TSPoint command_point = ts_node_start_point (state->substitute_cmd);
5104 	e->new_text = new_text;
5105 	e->old_text = ts_node_sub_parent_string (state->substitute_cmd, arg, state->input);
5106 	e->start = ts_node_start_byte (arg) - command_start;
5107 	e->end = ts_node_end_byte (arg) - command_start;
5108 	e->start_point = ts_node_start_point (arg);
5109 	e->end_point = ts_node_end_point (arg);
5110 	if (e->start_point.row == command_point.row) {
5111 		e->start_point.column -= command_point.column;
5112 	}
5113 	if (e->end_point.row == command_point.row) {
5114 		e->end_point.column -= command_point.column;
5115 	}
5116 	e->start_point.row -= command_point.row;
5117 	e->end_point.row -= command_point.row;
5118 	return e;
5119 }
5120 
replace_whitespaces(char * s,char ch)5121 static void replace_whitespaces(char *s, char ch) {
5122 	while (*s) {
5123 		if (*s == '#') {
5124 			while (*s && *s != '\r' && *s != '\n') {
5125 				*s = ch;
5126 				s++;
5127 			}
5128 		}
5129 		if (isspace ((unsigned char)*s)) {
5130 			*s = ch;
5131 		}
5132 		s++;
5133 	}
5134 }
5135 
escape_special_chars(char * s,const char * special_chars)5136 static char *escape_special_chars(char *s, const char *special_chars) {
5137 	size_t s_len = strlen (s);
5138 	char *d = R_NEWS (char, s_len * 2 + 1);
5139 	int i, j = 0;
5140 	for (i = 0; i < s_len; i++) {
5141 		if (strchr (special_chars, s[i])) {
5142 			d[j++] = '\\';
5143 		}
5144 		d[j++] = s[i];
5145 	}
5146 	d[j++] = '\0';
5147 	free (s);
5148 	return d;
5149 }
5150 
free_tsr2cmd_edit(struct tsr2cmd_edit * edit)5151 void free_tsr2cmd_edit(struct tsr2cmd_edit *edit) {
5152 	free (edit->new_text);
5153 	free (edit->old_text);
5154 	free (edit);
5155 }
5156 
do_handle_substitution_cmd(struct tsr2cmd_state * state,TSNode inn_cmd)5157 static char *do_handle_substitution_cmd(struct tsr2cmd_state *state, TSNode inn_cmd) {
5158 	RCore *core = state->core;
5159 	int value = core->num->value;
5160 	char *inn_str = ts_node_sub_parent_string (state->substitute_cmd, inn_cmd, state->input);
5161 
5162 	// save current color and disable it
5163 	int ocolor = r_config_get_i (core->config, "scr.color");
5164 	r_config_set_i (core->config, "scr.color", 0);
5165 	core->cmd_in_backticks = true;
5166 
5167 	// execute the sub command
5168 	char *o_out = inn_str[0] == '!'?
5169 		r_core_cmd_str_pipe (core, inn_str):
5170 		r_core_cmd_str (core, inn_str);
5171 
5172 	// restore color and cmd_in_backticks
5173 	core->num->value = value;
5174 	core->cmd_in_backticks = false;
5175 	r_config_set_i (core->config, "scr.color", ocolor);
5176 	free (inn_str);
5177 
5178 	// replace the output of the sub command with the current argument
5179 	char *out = strdup (o_out);
5180 	r_str_trim (out);
5181 	R_LOG_DEBUG ("output of inner command: '%s'\n", out);
5182 	free (o_out);
5183 
5184 	// replace newlines and similar with spaces
5185 	replace_whitespaces (out, ' ');
5186 	return out;
5187 }
5188 
handle_cmd_substitution_arg(struct tsr2cmd_state * state,TSNode arg,RList * edits)5189 static void handle_cmd_substitution_arg(struct tsr2cmd_state *state, TSNode arg, RList *edits) {
5190 	TSNode inn_cmd = ts_node_child (arg, 1);
5191 	r_return_if_fail (!ts_node_is_null (inn_cmd));
5192 	char *out = do_handle_substitution_cmd (state, inn_cmd);
5193 	// escape special chars to prevent creation of new tokens when parsing again
5194 	const char *special_chars;
5195 	if (is_ts_double_quoted_arg (ts_node_parent (arg))) {
5196 		special_chars = SPECIAL_CHARS_DOUBLE_QUOTED;
5197 	} else if (is_ts_pf_arg (ts_node_parent (arg))) {
5198 		special_chars = SPECIAL_CHARS_PF;
5199 	} else {
5200 		special_chars = SPECIAL_CHARS_REGULAR;
5201 	}
5202 	out = escape_special_chars (out, special_chars);
5203 	struct tsr2cmd_edit *e = create_cmd_edit (state, arg, out);
5204 	r_list_append (edits, e);
5205 }
5206 
is_group_of_args(TSNode args)5207 static bool is_group_of_args(TSNode args) {
5208 	return is_ts_args (args) || is_ts_concatenation (args) ||
5209 		is_ts_double_quoted_arg (args) ||
5210 		is_ts_pf_concatenation (args) || is_ts_pf_args (args) ||
5211 		is_ts_pf_dot_cmd_args (args) || is_ts_pf_new_args (args) ||
5212 		is_ts_grep_specifier (args);
5213 }
5214 
is_arg(TSNode args)5215 static bool is_arg(TSNode args) {
5216 	return is_ts_arg (args) || is_ts_pf_arg (args);
5217 }
5218 
is_handled_args(TSNode args)5219 static bool is_handled_args(TSNode args) {
5220 	return is_group_of_args (args) || is_arg (args) ||
5221 		is_ts_cmd_substitution_arg (args) || is_ts_grep_specifier (args);
5222 }
5223 
handle_substitution_args(struct tsr2cmd_state * state,TSNode args,RList * edits)5224 static void handle_substitution_args(struct tsr2cmd_state *state, TSNode args, RList *edits) {
5225 	if (is_group_of_args (args)) {
5226 		uint32_t n_children = ts_node_named_child_count (args);
5227 		uint32_t i;
5228 		for (i = 0; i < n_children; i++) {
5229 			TSNode arg = ts_node_named_child (args, i);
5230 			handle_substitution_args (state, arg, edits);
5231 		}
5232 	} else if (is_ts_cmd_substitution_arg (args)) {
5233 		handle_cmd_substitution_arg (state, args, edits);
5234 	} else if (is_arg (args)) {
5235 		TSNode arg = ts_node_named_child (args, 0);
5236 		handle_substitution_args (state, arg, edits);
5237 	}
5238 }
5239 
unescape_arg_str(struct tsr2cmd_state * state,const char * arg_str,const char * special_chars)5240 static char *unescape_arg_str(struct tsr2cmd_state *state, const char *arg_str, const char *special_chars) {
5241 	char *unescaped_arg = unescape_special_chars (arg_str, special_chars);
5242 	R_LOG_DEBUG ("original arg = '%s', unescaped arg = '%s'\n", arg_str, unescaped_arg);
5243 	return unescaped_arg;
5244 }
5245 
unescape_arg(struct tsr2cmd_state * state,TSNode arg,const char * special_chars)5246 static char *unescape_arg(struct tsr2cmd_state *state, TSNode arg, const char *special_chars) {
5247 	char *arg_str = ts_node_sub_string (arg, state->input);
5248 	char *unescaped_arg = unescape_arg_str (state, arg_str, special_chars);
5249 	free (arg_str);
5250 	return unescaped_arg;
5251 }
5252 
do_handle_ts_unescape_arg(struct tsr2cmd_state * state,TSNode arg,bool do_unwrap)5253 static char *do_handle_ts_unescape_arg(struct tsr2cmd_state *state, TSNode arg, bool do_unwrap) {
5254 	if (is_ts_arg (arg)) {
5255 		return do_handle_ts_unescape_arg (state, ts_node_named_child (arg, 0), do_unwrap);
5256 	} else if (is_ts_arg_identifier (arg)) {
5257 		return unescape_arg (state, arg, SPECIAL_CHARS_REGULAR);
5258 	} else if (is_ts_single_quoted_arg (arg) || is_ts_double_quoted_arg (arg)) {
5259 		const char *special = is_ts_single_quoted_arg (arg)? SPECIAL_CHARS_SINGLE_QUOTED: SPECIAL_CHARS_DOUBLE_QUOTED;
5260 		char *o_arg_str = ts_node_sub_string (arg, state->input);
5261 		char *arg_str = o_arg_str;
5262 		if (do_unwrap) {
5263 			// remove quotes
5264 			arg_str[strlen (arg_str) - 1] = '\0';
5265 			arg_str++;
5266 		}
5267 		char *res = unescape_arg_str (state, arg_str, special);
5268 		free (o_arg_str);
5269 		return res;
5270 	} else if (is_ts_concatenation (arg)) {
5271 		uint32_t i, n_children = ts_node_named_child_count (arg);
5272 		RStrBuf *sb = r_strbuf_new (NULL);
5273 		for (i = 0; i < n_children; i++) {
5274 			TSNode sub_arg = ts_node_named_child (arg, i);
5275 			char *s = do_handle_ts_unescape_arg (state, sub_arg, do_unwrap);
5276 			r_strbuf_append (sb, s);
5277 		}
5278 		return r_strbuf_drain (sb);
5279 	} else {
5280 		return ts_node_sub_string (arg, state->input);
5281 	}
5282 }
5283 
parse_args(struct tsr2cmd_state * state,TSNode args,bool do_unwrap)5284 static RCmdParsedArgs *parse_args(struct tsr2cmd_state *state, TSNode args, bool do_unwrap) {
5285 	if (ts_node_is_null (args)) {
5286 		return r_cmd_parsed_args_newargs (0, NULL);
5287 	} else if (is_ts_args (args)) {
5288 		uint32_t n_children = ts_node_named_child_count (args);
5289 		uint32_t i;
5290 		char **unescaped_args = R_NEWS0 (char *, n_children);
5291 		for (i = 0; i < n_children; i++) {
5292 			TSNode arg = ts_node_named_child (args, i);
5293 			unescaped_args[i] = do_handle_ts_unescape_arg (state, arg, do_unwrap);
5294 		}
5295 		RCmdParsedArgs *res = r_cmd_parsed_args_newargs (n_children, unescaped_args);
5296 		for (i = 0; i < n_children; i++) {
5297 			free (unescaped_args[i]);
5298 		}
5299 		free (unescaped_args);
5300 		return res;
5301 	} else {
5302 		char *unescaped_args[] = { do_handle_ts_unescape_arg (state, args, do_unwrap) };
5303 		RCmdParsedArgs *res = r_cmd_parsed_args_newargs (1, unescaped_args);
5304 		free (unescaped_args[0]);
5305 		return res;
5306 	}
5307 }
5308 
apply_edits(struct tsr2cmd_state * state,RList * edits)5309 static TSTree *apply_edits(struct tsr2cmd_state *state, RList *edits) {
5310 	struct tsr2cmd_edit *edit;
5311 	RListIter *it;
5312 
5313 	R_LOG_DEBUG ("old input = '%s'\n", state->input);
5314 	r_list_foreach (edits, it, edit) {
5315 		R_LOG_DEBUG ("apply_edits: about to replace '%s' with '%s'\n", edit->old_text, edit->new_text);
5316 		state->input = r_str_replace (state->input, edit->old_text, edit->new_text, 0);
5317 	}
5318 	R_LOG_DEBUG ("new input = '%s'\n", state->input);
5319 	return ts_parser_parse_string (state->parser, NULL, state->input, strlen (state->input));
5320 }
5321 
substitute_args_fini(struct tsr2cmd_state * state)5322 static void substitute_args_fini(struct tsr2cmd_state *state) {
5323 	if (state->tree != state->saved_tree) {
5324 		ts_tree_delete (state->tree);
5325 	}
5326 	state->tree = state->saved_tree;
5327 	state->saved_tree = NULL;
5328 	if (state->input != state->saved_input) {
5329 		free (state->input);
5330 	}
5331 	state->input = state->saved_input;
5332 	state->saved_input = NULL;
5333 }
5334 
substitute_args_init(struct tsr2cmd_state * state,TSNode command)5335 static void substitute_args_init(struct tsr2cmd_state *state, TSNode command) {
5336 	state->saved_input = state->input;
5337 	state->saved_tree = state->tree;
5338 	state->substitute_cmd = command;
5339 	state->input = ts_node_sub_string (state->substitute_cmd, state->input);
5340 	R_LOG_DEBUG ("Shrinking input to '%s'\n", state->input);
5341 }
5342 
substitute_args_do(struct tsr2cmd_state * state,RList * edits,TSNode * new_command)5343 static bool substitute_args_do(struct tsr2cmd_state *state, RList *edits, TSNode *new_command) {
5344 	TSTree *new_tree = apply_edits (state, edits);
5345 	if (!new_tree) {
5346 		return false;
5347 	}
5348 
5349 	TSNode root = ts_tree_root_node (new_tree);
5350 	if (ts_node_has_error (root)) {
5351 		ts_tree_delete (new_tree);
5352 		return false;
5353 	}
5354 	*new_command = ts_node_named_child (root, 0);
5355 	state->tree = new_tree;
5356 	return true;
5357 }
5358 
substitute_args(struct tsr2cmd_state * state,TSNode args,TSNode * new_command)5359 static bool substitute_args(struct tsr2cmd_state *state, TSNode args, TSNode *new_command) {
5360 	RList *edits = r_list_newf ((RListFree)free_tsr2cmd_edit);
5361 
5362 	if (is_handled_args (args)) {
5363 		handle_substitution_args (state, args, edits);
5364 	}
5365 
5366 	bool res = substitute_args_do (state, edits, new_command);
5367 	r_list_free (edits);
5368 	return res;
5369 }
5370 
ts_node_handle_arg_prargs(struct tsr2cmd_state * state,TSNode command,TSNode arg,uint32_t child_idx,bool do_unwrap)5371 static RCmdParsedArgs *ts_node_handle_arg_prargs(struct tsr2cmd_state *state, TSNode command, TSNode arg, uint32_t child_idx, bool do_unwrap) {
5372 	RCmdParsedArgs *res = NULL;
5373 	TSNode new_command;
5374 	substitute_args_init (state, command);
5375 	bool ok = substitute_args (state, arg, &new_command);
5376 	if (!ok) {
5377 		R_LOG_ERROR ("Error while substituting arguments\n");
5378 		goto err;
5379 	}
5380 
5381 	arg = ts_node_named_child (new_command, child_idx);
5382 	res = parse_args (state, arg, do_unwrap);
5383 	if (res == NULL) {
5384 		R_LOG_ERROR ("Cannot parse arg\n");
5385 		goto err;
5386 	}
5387 err:
5388 	substitute_args_fini (state);
5389 	return res;
5390 }
5391 
ts_node_handle_arg(struct tsr2cmd_state * state,TSNode command,TSNode arg,uint32_t child_idx)5392 static char *ts_node_handle_arg(struct tsr2cmd_state *state, TSNode command, TSNode arg, uint32_t child_idx) {
5393 	RCmdParsedArgs *a = ts_node_handle_arg_prargs (state, command, arg, child_idx, true);
5394 	char *str = r_cmd_parsed_args_argstr (a);
5395 	r_cmd_parsed_args_free (a);
5396 	return str;
5397 }
5398 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(arged_command)5399 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(arged_command) {
5400 	TSNode command = ts_node_child_by_field_name (node, "command", strlen ("command"));
5401 	r_return_val_if_fail (!ts_node_is_null (command), false);
5402 	char *command_str = ts_node_sub_string (command, state->input);
5403 	R_LOG_DEBUG ("arged_command command: '%s'\n", command_str);
5404 	TSNode args = ts_node_child_by_field_name (node, "args", strlen ("args"));
5405 	RCmdStatus res = R_CMD_STATUS_INVALID;
5406 
5407 	// FIXME: this special handling should be removed once we have a proper
5408 	//        command tree
5409 	if (!strcmp (command_str, "|.")) {
5410 		char *cmd_str = ts_node_sub_string (args, state->input);
5411 		char *exec_string = r_str_newf (".%s", cmd_str);
5412 		free (cmd_str);
5413 		free (command_str);
5414 		res = core_cmd_tsr2cmd (state->core, exec_string, state->split_lines, false);
5415 		free (exec_string);
5416 		return res;
5417 	}
5418 
5419 	RCmdParsedArgs *pr_args = NULL;
5420 	if (!ts_node_is_null (args)) {
5421 		RCmdDesc *cd = r_cmd_get_desc (state->core->rcmd, command_str);
5422 		bool do_unwrap = cd && cd->type != R_CMD_DESC_TYPE_OLDINPUT;
5423 		pr_args = ts_node_handle_arg_prargs (state, node, args, 1, do_unwrap);
5424 		if (!pr_args) {
5425 			goto err;
5426 		}
5427 		r_cmd_parsed_args_setcmd (pr_args, command_str);
5428 	} else {
5429 		pr_args = r_cmd_parsed_args_newcmd (command_str);
5430 		if (!pr_args) {
5431 			goto err;
5432 		}
5433 	}
5434 
5435 	int i;
5436 	const char *s;
5437 	r_cmd_parsed_args_foreach_arg (pr_args, i, s) {
5438 		R_LOG_DEBUG ("parsed_arg %d: '%s'\n", i, s);
5439 	}
5440 
5441 	pr_args->has_space_after_cmd = !ts_node_is_null (args) && ts_node_end_byte (command) < ts_node_start_byte (args);
5442 	res = r_cmd_call_parsed_args (state->core->rcmd, pr_args);
5443 	if (res == R_CMD_STATUS_WRONG_ARGS) {
5444 		const char *cmdname = r_cmd_parsed_args_cmd (pr_args);
5445 		eprintf ("Wrong number of arguments passed to `%s`, see its help with `%s?`\n", cmdname, cmdname);
5446 	} else if (res == R_CMD_STATUS_ERROR) {
5447 		const char *cmdname = r_cmd_parsed_args_cmd (pr_args);
5448 		R_LOG_DEBUG ("Something wrong during the execution of `%s` command.\n", cmdname);
5449 	}
5450 
5451 err:
5452 	r_cmd_parsed_args_free (pr_args);
5453 	free (command_str);
5454 	return res;
5455 }
5456 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(legacy_quoted_command)5457 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(legacy_quoted_command) {
5458 	return r_cmd_int2status(run_cmd_depth (state->core, node_string));
5459 }
5460 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(repeat_command)5461 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(repeat_command) {
5462 	TSNode number = ts_node_child_by_field_name (node, "arg", strlen ("arg"));
5463 	char *number_str = ts_node_sub_string (number, state->input);
5464 	int rep = atoi (number_str);
5465 	free (number_str);
5466 
5467 	TSNode command = ts_node_child_by_field_name (node, "command", strlen ("command"));
5468 	if (rep > 1 && r_sandbox_enable (0)) {
5469 		eprintf ("Command repeat sugar disabled in sandbox mode (%s)\n", node_string);
5470 		return R_CMD_STATUS_INVALID;
5471 	}
5472 	if (rep > INTERACTIVE_MAX_REP && r_cons_is_interactive ()) {
5473 		if (!r_cons_yesno ('n', "Are you sure to repeat this %d times? (y/N)", rep)) {
5474 			return R_CMD_STATUS_INVALID;
5475 		}
5476 	}
5477 
5478 	RCmdStatus res = R_CMD_STATUS_OK;
5479 	size_t i;
5480 	for (i = 0; i < rep; i++) {
5481 		RCmdStatus cmd_res = handle_ts_command (state, command);
5482 		UPDATE_CMD_STATUS_RES (res, cmd_res, err);
5483 	}
5484 err:
5485 	return res;
5486 }
5487 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(redirect_command)5488 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(redirect_command) {
5489 	int pipecolor = r_config_get_i (state->core->config, "scr.color.pipe");
5490 	int ocolor = r_config_get_i (state->core->config, "scr.color");
5491 	int scr_html = -1;
5492 	RCmdStatus res = R_CMD_STATUS_INVALID, is_append = false, is_html = false;
5493 	int fdn = 1;
5494 
5495 	TSNode redirect_op = ts_node_child_by_field_name (node, "redirect_operator", strlen ("redirect_operator"));
5496 	if (is_ts_fdn_redirect_operator (redirect_op)) {
5497 		// this is the default operation, no html and no append
5498 	} else if (is_ts_fdn_append_operator (redirect_op)) {
5499 		is_append = true;
5500 	} else if (is_ts_html_redirect_operator (redirect_op)) {
5501 		is_html = true;
5502 	} else if (is_ts_html_append_operator (redirect_op)) {
5503 		is_html = true;
5504 		is_append = true;
5505 	} else {
5506 		R_LOG_ERROR ("This should never happen, redirect_operator is no known type");
5507 		r_warn_if_reached ();
5508 	}
5509 
5510 	if (is_html) {
5511 		scr_html = r_config_get_i (state->core->config, "scr.html");
5512 		r_config_set_i (state->core->config, "scr.html", true);
5513 		pipecolor = true;
5514 	} else {
5515 		TSNode fd_desc = ts_node_named_child (redirect_op, 0);
5516 		if (!ts_node_is_null (fd_desc)) {
5517 			char *fd_str = ts_node_sub_string (fd_desc, state->input);
5518 			fdn = atoi (fd_str);
5519 			free (fd_str);
5520 		}
5521 	}
5522 
5523 	r_cons_set_interactive (false);
5524 	// TODO: allow to use editor as the old behaviour
5525 
5526 	// extract the string of the filename we need to write to
5527 	TSNode arg = ts_node_child_by_field_name (node, "arg", strlen ("arg"));
5528 	char *arg_str = ts_node_sub_string (arg, state->input);
5529 
5530 	if (arg_str[0] == '$') {
5531 		// redirect output of command to an alias variable
5532 		R_LOG_DEBUG ("redirect_command: alias = '%s'\n", arg_str);
5533 		TSNode command = ts_node_child_by_field_name (node, "command", strlen ("command"));
5534 		char *command_str = ts_node_sub_string (command, state->input);
5535 
5536 		char *output = r_core_cmd_str (state->core, command_str);
5537 		const char *old_alias_value = r_cmd_alias_get (state->core->rcmd, arg_str, 1);
5538 		char *new_alias_value;
5539 		const char *start_char = "$";
5540 		if (is_append && old_alias_value) {
5541 			start_char = "";
5542 		} else {
5543 			old_alias_value = "";
5544 		}
5545 		new_alias_value = r_str_newf ("%s%s%s", start_char, old_alias_value, output);
5546 		r_cmd_alias_set (state->core->rcmd, arg_str, new_alias_value, 1);
5547 		free (new_alias_value);
5548 		free (command_str);
5549 		res = R_CMD_STATUS_OK;
5550 	} else {
5551 		r_cons_flush ();
5552 		R_LOG_DEBUG ("redirect_command: fdn = %d, is_append = %d\n", fdn, is_append);
5553 		int pipefd = r_cons_pipe_open (arg_str, fdn, is_append);
5554 		if (pipefd != -1) {
5555 			if (!pipecolor) {
5556 				r_config_set_i (state->core->config, "scr.color", COLOR_MODE_DISABLED);
5557 			}
5558 			TSNode command = ts_node_child_by_field_name (node, "command", strlen ("command"));
5559 			res = handle_ts_command (state, command);
5560 			r_cons_flush ();
5561 			r_cons_pipe_close (pipefd);
5562 		} else {
5563 			R_LOG_WARN ("Could not open pipe to %d", fdn);
5564 		}
5565 	}
5566 	free (arg_str);
5567 	r_cons_set_last_interactive ();
5568 	if (!pipecolor) {
5569 		r_config_set_i (state->core->config, "scr.color", ocolor);
5570 	}
5571 	if (scr_html != -1) {
5572 		r_config_set_i (state->core->config, "scr.html", scr_html);
5573 	}
5574 	state->core->cons->use_tts = false;
5575 	return res;
5576 }
5577 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(help_command)5578 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(help_command) {
5579 	// TODO: traverse command tree to print help
5580 	// FIXME: once we have a command tree, this special handling should be removed
5581 	size_t node_str_len = strlen (node_string);
5582 	if (!strcmp (node_string, "@?")) {
5583 		r_core_cmd_help (state->core, help_msg_at);
5584 	} else if (!strcmp (node_string, "@@?")) {
5585 		r_core_cmd_help (state->core, help_msg_at_at);
5586 	} else if (!strcmp (node_string, "@@@?")) {
5587 		r_core_cmd_help (state->core, help_msg_at_at_at);
5588 	} else if (!strcmp (node_string, "|?")) {
5589 		r_core_cmd_help (state->core, help_msg_vertical_bar);
5590 	} else if (!strcmp (node_string, "~?")) {
5591 		r_cons_grep_help ();
5592 	} else if (!strcmp (node_string, ">?")) {
5593 		r_core_cmd_help (state->core, help_msg_greater_sign);
5594 	} else if (node_str_len >= 2 && !strcmp (node_string + node_str_len - 2, "?*")) {
5595 		int detail = 0;
5596 		if (node_str_len > 3 && node_string[node_str_len - 3] == '?') {
5597 			detail++;
5598 			if (node_str_len > 4 && node_string[node_str_len - 4] == '?') {
5599 				detail++;
5600 			}
5601 		}
5602 		node_string[node_str_len - 2 - detail] = '\0';
5603 		recursive_help (state->core, detail, node_string);
5604 		return R_CMD_STATUS_OK;
5605 	} else {
5606 		TSNode command = ts_node_child_by_field_name (node, "command", strlen ("command"));
5607 		char *command_str = ts_node_sub_string (command, state->input);
5608 		TSNode args = ts_node_child_by_field_name (node, "args", strlen ("args"));
5609 		RCmdParsedArgs *pr_args = NULL;
5610 		RCmdStatus res = R_CMD_STATUS_INVALID;
5611 		if (!ts_node_is_null (args)) {
5612 			RCmdDesc *cd = r_cmd_get_desc (state->core->rcmd, command_str);
5613 			bool do_unwrap = cd && cd->type != R_CMD_DESC_TYPE_OLDINPUT;
5614 			pr_args = ts_node_handle_arg_prargs (state, node, args, 1, do_unwrap);
5615 			if (!pr_args) {
5616 				goto err_else;
5617 			}
5618 			r_cmd_parsed_args_setcmd (pr_args, command_str);
5619 		} else {
5620 			pr_args = r_cmd_parsed_args_newcmd (command_str);
5621 			if (!pr_args) {
5622 				goto err_else;
5623 			}
5624 		}
5625 
5626 		// let's try first with the new auto-generated help, if
5627 		// something fails fallback to old behaviour
5628 		char *help_msg = r_cmd_get_help (state->core->rcmd, pr_args, state->core->print->flags & R_PRINT_FLAGS_COLOR);
5629 		if (help_msg) {
5630 			r_cons_printf ("%s", help_msg);
5631 			free (help_msg);
5632 			res = R_CMD_STATUS_OK;
5633 		} else {
5634 			res = r_cmd_call_parsed_args (state->core->rcmd, pr_args);
5635 		}
5636 	err_else:
5637 		r_cmd_parsed_args_free (pr_args);
5638 		free (command_str);
5639 		return res;
5640 	}
5641 	return R_CMD_STATUS_OK;
5642 }
5643 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_seek_command)5644 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_seek_command) {
5645 	TSNode command = ts_node_named_child (node, 0);
5646 	TSNode offset = ts_node_named_child (node, 1);
5647 	char *offset_string = ts_node_handle_arg (state, node, offset, 1);
5648 	ut64 offset_val = r_num_math (state->core->num, offset_string);
5649 	ut64 orig_offset = state->core->offset;
5650 	if (!offset_val && isalpha ((int)offset_string[0])) {
5651 		if (!r_flag_get (state->core->flags, offset_string)) {
5652 			eprintf ("Invalid address (%s)\n", offset_string);
5653 			free (offset_string);
5654 			return R_CMD_STATUS_INVALID;
5655 		}
5656 	}
5657 	if (offset_string[0] == '-' || offset_string[0] == '+') {
5658 		offset_val += state->core->offset;
5659 	}
5660 	R_LOG_DEBUG ("tmp_seek_command, changing offset to %" PFMT64x "\n", offset_val);
5661 	r_core_seek (state->core, offset_val, true);
5662 	RCmdStatus res = handle_ts_command_tmpseek (state, command);
5663 	r_core_seek (state->core, orig_offset, true);
5664 	free (offset_string);
5665 	return res;
5666 }
5667 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_blksz_command)5668 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_blksz_command) {
5669 	TSNode command = ts_node_named_child (node, 0);
5670 	TSNode blksz = ts_node_named_child (node, 1);
5671 	char *blksz_string = ts_node_handle_arg (state, node, blksz, 1);
5672 	ut64 orig_blksz = state->core->blocksize;
5673 	R_LOG_DEBUG ("tmp_blksz_command, changing blksz to %s\n", blksz_string);
5674 	r_core_block_size (state->core, r_num_math (state->core->num, blksz_string));
5675 	RCmdStatus res = handle_ts_command (state, command);
5676 	r_core_block_size (state->core, orig_blksz);
5677 	free (blksz_string);
5678 	return res;
5679 }
5680 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_fromto_command)5681 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_fromto_command) {
5682 	RCore *core = state->core;
5683 	TSNode command = ts_node_named_child (node, 0);
5684 	TSNode from = ts_node_named_child (node, 1);
5685 	TSNode to = ts_node_named_child (node, 2);
5686 	char *from_str = ts_node_handle_arg (state, node, from, 1);
5687 	char *to_str = ts_node_handle_arg (state, node, to, 2);
5688 
5689 	const char *fromvars[] = { "anal.from", "diff.from", "graph.from",
5690 		"io.buffer.from", "lines.from", "search.from", "zoom.from", NULL };
5691 	const char *tovars[] = { "anal.to", "diff.to", "graph.to",
5692 		"io.buffer.to", "lines.to", "search.to", "zoom.to", NULL };
5693 	ut64 from_val = r_num_math (core->num, from_str);
5694 	ut64 to_val = r_num_math (core->num, to_str);
5695 	R_LOG_DEBUG ("tmp_fromto_command, changing fromto to (%" PFMT64x ", %" PFMT64x ")\n", from_val, to_val);
5696 
5697 	RConfigHold *hc = r_config_hold_new (core->config);
5698 	int i;
5699 	for (i = 0; fromvars[i]; i++) {
5700 		r_config_hold (hc, fromvars[i], NULL);
5701 		r_config_set_i (core->config, fromvars[i], from_val);
5702 	}
5703 	for (i = 0; tovars[i]; i++) {
5704 		r_config_hold (hc, tovars[i], NULL);
5705 		r_config_set_i (core->config, tovars[i], to_val);
5706 	}
5707 
5708 	RCmdStatus res = handle_ts_command (state, command);
5709 
5710 	r_config_hold_restore (hc);
5711 
5712 	r_config_hold_free (hc);
5713 	free (from_str);
5714 	free (to_str);
5715 	return res;
5716 }
5717 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_arch_command)5718 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_arch_command) {
5719 	RCore *core = state->core;
5720 	TSNode command = ts_node_named_child (node, 0);
5721 	TSNode arg = ts_node_named_child (node, 1);
5722 	char *arg_str = ts_node_handle_arg (state, node, arg, 1);
5723 	char *tmparch, *tmpbits;
5724 	bool is_arch_set = false, is_bits_set = false;
5725 	bool oldfixedarch = core->fixedarch, oldfixedbits = core->fixedbits;
5726 	int cmd_ignbithints = -1;
5727 
5728 	// change arch and bits
5729 	char *q = strchr (arg_str, ':');
5730 	if (q) {
5731 		*q++ = '\0';
5732 		int bits = r_num_math (core->num, q);
5733 		is_bits_set = set_tmp_bits (core, bits, &tmpbits, &cmd_ignbithints);
5734 	}
5735 	is_arch_set = set_tmp_arch (core, arg_str, &tmparch);
5736 
5737 	// execute command with changed settings
5738 	RCmdStatus res = handle_ts_command (state, command);
5739 
5740 	// restore original settings
5741 	if (is_arch_set) {
5742 		core->fixedarch = oldfixedarch;
5743 		r_config_set (core->config, "asm.arch", tmparch);
5744 		free (tmparch);
5745 	}
5746 	if (is_bits_set) {
5747 		r_config_set (core->config, "asm.bits", tmpbits);
5748 		core->fixedbits = oldfixedbits;
5749 		free (tmpbits);
5750 	}
5751 	if (cmd_ignbithints != -1) {
5752 		r_config_set_i (core->config, "anal.ignbithints", cmd_ignbithints);
5753 	}
5754 	free (arg_str);
5755 	return res;
5756 }
5757 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_bits_command)5758 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_bits_command) {
5759 	RCore *core = state->core;
5760 	TSNode command = ts_node_named_child (node, 0);
5761 	TSNode arg = ts_node_named_child (node, 1);
5762 	char *arg_str = ts_node_handle_arg (state, node, arg, 1);
5763 	bool oldfixedbits = core->fixedbits;
5764 	char *tmpbits;
5765 	int cmd_ignbithints;
5766 
5767 	int bits = r_num_math (core->num, arg_str);
5768 	set_tmp_bits (core, bits, &tmpbits, &cmd_ignbithints);
5769 
5770 	RCmdStatus res = handle_ts_command (state, command);
5771 
5772 	r_config_set (core->config, "asm.bits", tmpbits);
5773 	core->fixedbits = oldfixedbits;
5774 	r_config_set_i (core->config, "anal.ignbithints", cmd_ignbithints);
5775 
5776 	free (tmpbits);
5777 	free (arg_str);
5778 	return res;
5779 }
5780 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_nthi_command)5781 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_nthi_command) {
5782 	RCore *core = state->core;
5783 	TSNode command = ts_node_named_child (node, 0);
5784 	TSNode arg = ts_node_named_child (node, 1);
5785 	char *arg_str = ts_node_handle_arg (state, node, arg, 1);
5786 
5787 	ut64 orig_offset = state->core->offset;
5788 	int index = r_num_math (core->num, arg_str);
5789 	RAnalBlock *bb = r_anal_bb_from_offset (core->anal, core->offset);
5790 	if (bb) {
5791 		// handle negative indices
5792 		if (index < 0) {
5793 			index = bb->ninstr + index;
5794 		}
5795 
5796 		if (index >= 0 && index < bb->ninstr) {
5797 			ut16 inst_off = r_anal_bb_offset_inst (bb, index);
5798 			r_core_seek (core, bb->addr + inst_off, true);
5799 		} else {
5800 			eprintf ("The current basic block has just %d instructions\n", bb->ninstr);
5801 		}
5802 	} else {
5803 		eprintf ("Can't find a basic block for 0x%08" PFMT64x "\n", core->offset);
5804 	}
5805 
5806 	RCmdStatus res = handle_ts_command_tmpseek (state, command);
5807 
5808 	r_core_seek (core, orig_offset, true);
5809 
5810 	free (arg_str);
5811 	return res;
5812 }
5813 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_eval_command)5814 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_eval_command) {
5815 	// TODO: support cmd_substitution in tmp_eval_args
5816 	RCore *core = state->core;
5817 	TSNode command = ts_node_named_child (node, 0);
5818 	TSNode args = ts_node_named_child (node, 1);
5819 
5820 	RConfigHold *hc = r_config_hold_new (core->config);
5821 	uint32_t i, n_args = ts_node_named_child_count (args);
5822 	for (i = 0; i < n_args; i++) {
5823 		TSNode arg = ts_node_named_child (args, i);
5824 		char *arg_str = ts_node_sub_string (arg, state->input);
5825 		char *eq = strchr (arg_str, '=');
5826 		if (eq) {
5827 			*eq = 0;
5828 			r_config_hold (hc, arg_str, NULL);
5829 			r_config_set (core->config, arg_str, eq + 1);
5830 		} else {
5831 			eprintf ("Missing '=' in e: expression (%s)\n", arg_str);
5832 		}
5833 		free (arg_str);
5834 	}
5835 
5836 	RCmdStatus res = handle_ts_command (state, command);
5837 
5838 	r_config_hold_restore (hc);
5839 	r_config_hold_free (hc);
5840 	return res;
5841 }
5842 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_fs_command)5843 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_fs_command) {
5844 	RCore *core = state->core;
5845 	TSNode command = ts_node_named_child (node, 0);
5846 	TSNode arg = ts_node_named_child (node, 1);
5847 	char *arg_str = ts_node_handle_arg (state, node, arg, 1);
5848 	r_flag_space_push (core->flags, arg_str);
5849 	RCmdStatus res = handle_ts_command (state, command);
5850 	r_flag_space_pop (core->flags);
5851 	free (arg_str);
5852 	return res;
5853 }
5854 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_reli_command)5855 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_reli_command) {
5856 	RCore *core = state->core;
5857 	TSNode command = ts_node_named_child (node, 0);
5858 	TSNode arg = ts_node_named_child (node, 1);
5859 	char *arg_str = ts_node_handle_arg (state, node, arg, 1);
5860 	ut64 orig_offset = state->core->offset;
5861 	ut64 addr = r_num_math (core->num, arg_str);
5862 	if (addr) {
5863 		r_core_cmdf (core, "so %" PFMT64d, addr);
5864 	}
5865 	RCmdStatus res = handle_ts_command_tmpseek (state, command);
5866 	r_core_seek (state->core, orig_offset, true);
5867 	free (arg_str);
5868 	return res;
5869 }
5870 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_kuery_command)5871 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_kuery_command) {
5872 	RCore *core = state->core;
5873 	TSNode command = ts_node_named_child (node, 0);
5874 	TSNode arg = ts_node_named_child (node, 1);
5875 	char *arg_str = ts_node_handle_arg (state, node, arg, 1);
5876 	ut64 orig_offset = state->core->offset;
5877 	char *out = sdb_querys (core->sdb, NULL, 0, arg_str);
5878 	if (out) {
5879 		r_core_seek (core, r_num_math (core->num, out), true);
5880 		free (out);
5881 	}
5882 	RCmdStatus res = handle_ts_command_tmpseek (state, command);
5883 	r_core_seek (state->core, orig_offset, true);
5884 	free (arg_str);
5885 	return res;
5886 }
5887 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_fd_command)5888 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_fd_command) {
5889 	RCore *core = state->core;
5890 	TSNode command = ts_node_named_child (node, 0);
5891 	TSNode arg = ts_node_named_child (node, 1);
5892 	char *arg_str = ts_node_handle_arg (state, node, arg, 1);
5893 	int tmpfd = core->io->desc? core->io->desc->fd: -1;
5894 	r_io_use_fd (core->io, atoi (arg_str));
5895 	RCmdStatus res = handle_ts_command (state, command);
5896 	r_io_use_fd (core->io, tmpfd);
5897 	free (arg_str);
5898 	return res;
5899 }
5900 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_reg_command)5901 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_reg_command) {
5902 	RCore *core = state->core;
5903 	TSNode command = ts_node_named_child (node, 0);
5904 	TSNode arg = ts_node_named_child (node, 1);
5905 	char *arg_str = ts_node_handle_arg (state, node, arg, 1);
5906 	ut64 orig_offset = state->core->offset;
5907 	// TODO: add support for operations (e.g. @r:PC+10)
5908 	ut64 regval = r_debug_reg_get (core->dbg, arg_str);
5909 	r_core_seek (core, regval, true);
5910 	RCmdStatus res = handle_ts_command_tmpseek (state, command);
5911 	r_core_seek (core, orig_offset, true);
5912 	free (arg_str);
5913 	return res;
5914 }
5915 
handle_tmp_desc(struct tsr2cmd_state * state,TSNode command,const ut8 * buf,int sz)5916 static bool handle_tmp_desc(struct tsr2cmd_state *state, TSNode command, const ut8 *buf, int sz) {
5917 	RCore *core = state->core;
5918 	int pamode = !core->io->va;
5919 	RCmdStatus res = R_CMD_STATUS_INVALID, o_fixedblock = core->fixedblock;
5920 	RBuffer *b = r_buf_new_with_bytes (buf, sz);
5921 	RIODesc *d = r_io_open_buffer (core->io, b, R_PERM_RWX, 0);
5922 	if (!d) {
5923 		eprintf ("Cannot open io buffer\n");
5924 		goto out_buf;
5925 	}
5926 	if (pamode) {
5927 		r_config_set_i (core->config, "io.va", 1);
5928 	}
5929 	r_io_map_new (core->io, d->fd, d->perm, 0, core->offset, r_buf_size (b));
5930 	r_core_block_size (core, r_buf_size (b));
5931 	core->fixedblock = true;
5932 	r_core_block_read (core);
5933 
5934 	res = handle_ts_command (state, command);
5935 
5936 	core->fixedblock = o_fixedblock;
5937 	if (pamode) {
5938 		r_config_set_i (core->config, "io.va", 0);
5939 	}
5940 	r_io_desc_close (d);
5941 
5942 out_buf:
5943 	r_buf_free (b);
5944 	return res;
5945 }
5946 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_file_command)5947 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_file_command) {
5948 	TSNode command = ts_node_named_child (node, 0);
5949 	TSNode arg = ts_node_named_child (node, 1);
5950 	char *arg_str = ts_node_handle_arg (state, node, arg, 1);
5951 	size_t sz;
5952 	RCmdStatus res = R_CMD_STATUS_INVALID;
5953 
5954 	char *f = r_file_slurp (arg_str, &sz);
5955 	if (!f) {
5956 		eprintf ("Cannot open '%s'\n", arg_str);
5957 		goto out;
5958 	}
5959 
5960 	res = handle_tmp_desc (state, command, (ut8 *)f, (int)sz);
5961 
5962 	free (f);
5963 out:
5964 	free (arg_str);
5965 	return res;
5966 }
5967 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_string_command)5968 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_string_command) {
5969 	TSNode command = ts_node_named_child (node, 0);
5970 	TSNode arg = ts_node_named_child (node, 1);
5971 	char *arg_str = ts_node_handle_arg (state, node, arg, 1);
5972 	int sz;
5973 
5974 	sz = strlen (arg_str);
5975 	const ut8 *buf = (const ut8 *)arg_str;
5976 
5977 	RCmdStatus res = handle_tmp_desc (state, command, buf, sz);
5978 
5979 	free (arg_str);
5980 	return res;
5981 }
5982 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_hex_command)5983 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_hex_command) {
5984 	TSNode command = ts_node_named_child (node, 0);
5985 	TSNode arg = ts_node_named_child (node, 1);
5986 	char *arg_str = ts_node_handle_arg (state, node, arg, 1);
5987 	int sz;
5988 
5989 	size_t len = strlen (arg_str);
5990 	ut8 *buf = R_NEWS (ut8, len + 1);
5991 	sz = r_hex_str2bin (arg_str, buf);
5992 
5993 	RCmdStatus res = handle_tmp_desc (state, command, buf, sz);
5994 
5995 	free (buf);
5996 	free (arg_str);
5997 	return res;
5998 }
5999 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_flags_command)6000 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_flags_command) {
6001 	RCore *core = state->core;
6002 	TSNode command = ts_node_named_child (node, 0);
6003 	TSNode arg = ts_node_named_child (node, 1);
6004 	char *arg_str = ts_node_handle_arg(state, node, arg, 1);
6005 	const RSpace *flagspace = r_flag_space_cur (core->flags);
6006 	RFlagItem *flag;
6007 	RListIter *iter;
6008 	RCmdStatus ret = R_CMD_STATUS_OK;
6009 	RList *match_flag_items = r_list_newf ((RListFree)r_flag_item_free);
6010 	if (!match_flag_items) {
6011 		return R_CMD_STATUS_OK;
6012 	}
6013 
6014 	/* duplicate flags that match word, to be sure the command is going to
6015 	   be executed on flags values at the moment the command is called
6016 	   (without side effects) */
6017 	struct duplicate_flag_t u = {
6018 		.ret = match_flag_items,
6019 		.word = arg_str,
6020 	};
6021 	r_flag_foreach_space (core->flags, flagspace, duplicate_flag, &u);
6022 
6023 	/* for all flags that match */
6024 	r_list_foreach (match_flag_items, iter, flag) {
6025 		if (r_cons_is_breaked ()) {
6026 			break;
6027 		}
6028 
6029 		char *buf = NULL;
6030 		const char *tmp = NULL;
6031 		R_LOG_DEBUG ("iter_flags_command: seek to %" PFMT64x "\n", flag->offset);
6032 		r_core_seek (core, flag->offset, true);
6033 		r_cons_push ();
6034 		RCmdStatus cmd_res = handle_ts_command_tmpseek (state, command);
6035 		tmp = r_cons_get_buffer ();
6036 		buf = tmp? strdup (tmp): NULL;
6037 		r_cons_pop ();
6038 		r_cons_strcat (buf);
6039 		free (buf);
6040 		r_core_task_yield (&core->tasks);
6041 		UPDATE_CMD_STATUS_RES (ret, cmd_res, err);
6042 	}
6043 
6044 err:
6045 	r_list_free (match_flag_items);
6046 	free (arg_str);
6047 	return ret;
6048 }
6049 
6050 enum dbt_commands_mode {
6051 	DBT_COMMANDS_MODE_ADDR,
6052 	DBT_COMMANDS_MODE_BP,
6053 	DBT_COMMANDS_MODE_SP,
6054 };
6055 
iter_dbt_commands(struct tsr2cmd_state * state,TSNode node,enum dbt_commands_mode mode)6056 static bool iter_dbt_commands(struct tsr2cmd_state *state, TSNode node, enum dbt_commands_mode mode) {
6057 	RCore *core = state->core;
6058 	TSNode command = ts_node_named_child (node, 0);
6059 	RList *list = r_debug_frames (core->dbg, UT64_MAX);
6060 	ut64 orig_offset = core->offset;
6061 	RDebugFrame *frame;
6062 	RListIter *iter;
6063 	RCmdStatus res = R_CMD_STATUS_OK;
6064 
6065 	r_list_foreach (list, iter, frame) {
6066 		switch (mode) {
6067 		case DBT_COMMANDS_MODE_ADDR:
6068 			r_core_seek (core, frame->addr, true);
6069 			break;
6070 		case DBT_COMMANDS_MODE_SP:
6071 			r_core_seek (core, frame->sp, true);
6072 			break;
6073 		case DBT_COMMANDS_MODE_BP:
6074 			r_core_seek (core, frame->bp, true);
6075 			break;
6076 		default:
6077 			r_warn_if_reached ();
6078 			return R_CMD_STATUS_INVALID;
6079 		}
6080 		RCmdStatus cmd_res = handle_ts_command_tmpseek (state, command);
6081 		r_cons_newline ();
6082 		UPDATE_CMD_STATUS_RES (res, cmd_res, err);
6083 	}
6084 err:
6085 	r_core_seek (core, orig_offset, true);
6086 	r_list_free (list);
6087 	return res;
6088 }
6089 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_dbta_command)6090 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_dbta_command) {
6091 	return iter_dbt_commands (state, node, DBT_COMMANDS_MODE_ADDR);
6092 }
6093 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_dbtb_command)6094 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_dbtb_command) {
6095 	return iter_dbt_commands (state, node, DBT_COMMANDS_MODE_BP);
6096 }
6097 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_dbts_command)6098 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_dbts_command) {
6099 	return iter_dbt_commands (state, node, DBT_COMMANDS_MODE_SP);
6100 }
6101 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_file_lines_command)6102 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_file_lines_command) {
6103 	// TODO: old implementation has some unknown check on '('
6104 	RCore *core = state->core;
6105 	RCmdStatus res = R_CMD_STATUS_OK;
6106 	TSNode command = ts_node_named_child (node, 0);
6107 	TSNode arg = ts_node_named_child (node, 1);
6108 	char *arg_str = ts_node_handle_arg(state, node, arg, 1);
6109 	ut64 orig_offset = core->offset;
6110 	FILE *fd = r_sandbox_fopen (arg_str, "r");
6111 	if (!fd) {
6112 		res = R_CMD_STATUS_INVALID;
6113 		goto arg_out;
6114 	}
6115 
6116 	core->rcmd->macro.counter = 0;
6117 	while (!feof (fd)) {
6118 		char buf[1024];
6119 		buf[0] = '\0';
6120 		if (!fgets (buf, sizeof (buf), fd)) {
6121 			break;
6122 		}
6123 		ut64 addr = r_num_math (core->num, buf);
6124 		r_core_seek (core, addr, true);
6125 		RCmdStatus cmd_res = handle_ts_command_tmpseek (state, command);
6126 		core->rcmd->macro.counter++;
6127 		UPDATE_CMD_STATUS_RES (res, cmd_res, err);
6128 	}
6129 err:
6130 	r_core_seek (core, orig_offset, true);
6131 	fclose (fd);
6132 
6133 arg_out:
6134 	free (arg_str);
6135 	return res;
6136 }
6137 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_offsets_command)6138 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_offsets_command) {
6139 	RCore *core = state->core;
6140 	RCmdStatus res = R_CMD_STATUS_OK;
6141 	TSNode command = ts_node_named_child (node, 0);
6142 	if (ts_node_named_child_count (node) < 2) {
6143 		// no offsets provided, all's good.
6144 		return R_CMD_STATUS_OK;
6145 	}
6146 
6147 	TSNode args = ts_node_named_child (node, 1);
6148 	ut64 orig_offset = core->offset;
6149 
6150 	RCmdParsedArgs *a = ts_node_handle_arg_prargs (state, node, args, 1, true);
6151 	if (!a) {
6152 		R_LOG_ERROR ("Cannot parse args\n");
6153 		return R_CMD_STATUS_INVALID;
6154 	}
6155 
6156 	const char *s;
6157 	int i;
6158 	r_cmd_parsed_args_foreach_arg (a, i, s) {
6159 		ut64 addr = r_num_math (core->num, s);
6160 		R_LOG_DEBUG ("iter_offsets_command: seek to %" PFMT64x "\n", addr);
6161 		r_core_seek (core, addr, true);
6162 		RCmdStatus cmd_res = handle_ts_command_tmpseek (state, command);
6163 		r_cons_flush ();
6164 		UPDATE_CMD_STATUS_RES (res, cmd_res, err);
6165 	}
6166 
6167 err:
6168 	r_core_seek (core, orig_offset, true);
6169 	r_cmd_parsed_args_free (a);
6170 	return res;
6171 }
6172 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_sdbquery_command)6173 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_sdbquery_command) {
6174 	RCore *core = state->core;
6175 	TSNode command = ts_node_named_child (node, 0);
6176 	TSNode arg = ts_node_named_child (node, 1);
6177 	char *arg_str = ts_node_handle_arg (state, node, arg, 1);
6178 	ut64 orig_offset = core->offset;
6179 
6180 	char *out = sdb_querys (core->sdb, NULL, 0, arg_str);
6181 	if (!out) {
6182 		return R_CMD_STATUS_INVALID;
6183 	}
6184 	char *str, *each = out;
6185 	ut64 addr;
6186 	RCmdStatus res = R_CMD_STATUS_OK;
6187 	do {
6188 		while (*each == ' ') {
6189 			each++;
6190 		}
6191 		if (!*each) {
6192 			break;
6193 		}
6194 		str = strchr (each, ' ');
6195 		if (str) {
6196 			*str = '\0';
6197 			addr = r_num_math (core->num, each);
6198 			*str = ' ';
6199 		} else {
6200 			addr = r_num_math (core->num, each);
6201 		}
6202 		each = str + 1;
6203 		r_core_seek (core, addr, true);
6204 		RCmdStatus cmd_res = handle_ts_command_tmpseek (state, command);
6205 		r_cons_flush ();
6206 		UPDATE_CMD_STATUS_RES (res, cmd_res, err);
6207 	} while (str != NULL);
6208 err:
6209 	r_core_seek (core, orig_offset, true);
6210 	free (out);
6211 	free (arg_str);
6212 	return res;
6213 }
6214 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_threads_command)6215 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_threads_command) {
6216 	RCore *core = state->core;
6217 	TSNode command = ts_node_named_child (node, 0);
6218 	int pid = core->dbg->pid;
6219 	if (!core->dbg->h || !core->dbg->h->pids) {
6220 		return R_CMD_STATUS_INVALID;
6221 	}
6222 
6223 	RCmdStatus res = R_CMD_STATUS_OK;
6224 	RList *list = core->dbg->h->pids (core->dbg, R_MAX (0, pid));
6225 	RListIter *iter;
6226 	RDebugPid *p;
6227 	r_list_foreach (list, iter, p) {
6228 		r_cons_printf ("# PID %d\n", p->pid);
6229 		r_debug_select (core->dbg, p->pid, p->pid);
6230 		RCmdStatus cmd_res = handle_ts_command (state, command);
6231 		UPDATE_CMD_STATUS_RES (res, cmd_res, err);
6232 		r_cons_newline ();
6233 	}
6234 err:
6235 	r_list_free (list);
6236 	r_debug_select (core->dbg, pid, pid);
6237 	return res;
6238 }
6239 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_bbs_command)6240 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_bbs_command) {
6241 	RCore *core = state->core;
6242 	TSNode command = ts_node_named_child (node, 0);
6243 	RListIter *iter;
6244 	RAnalBlock *bb;
6245 	int bs = core->blocksize;
6246 	ut64 orig_offset = core->offset;
6247 	RCmdStatus res = R_CMD_STATUS_OK;
6248 	RAnalFunction *fcn = r_anal_get_function_at (core->anal, core->offset);
6249 	if (!fcn) {
6250 		eprintf ("No function at current address\n");
6251 		return R_CMD_STATUS_INVALID;
6252 	}
6253 	r_list_sort (fcn->bbs, bb_cmp);
6254 	r_list_foreach (fcn->bbs, iter, bb) {
6255 		r_core_block_size (core, bb->size);
6256 		r_core_seek (core, bb->addr, true);
6257 		RCmdStatus cmd_res = handle_ts_command_tmpseek (state, command);
6258 		UPDATE_CMD_STATUS_RES (res, cmd_res, err);
6259 		if (r_cons_is_breaked ()) {
6260 			break;
6261 		}
6262 	}
6263 err:
6264 	r_core_block_size (core, bs);
6265 	r_core_seek (core, orig_offset, true);
6266 	return res;
6267 }
6268 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_instrs_command)6269 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_instrs_command) {
6270 	TSNode command = ts_node_named_child (node, 0);
6271 	RCore *core = state->core;
6272 	RListIter *iter;
6273 	RAnalBlock *bb;
6274 	int i;
6275 	RCmdStatus res = R_CMD_STATUS_OK;
6276 	ut64 orig_offset = core->offset;
6277 	int bs = core->blocksize;
6278 	RAnalFunction *fcn = r_anal_get_function_at (core->anal, core->offset);
6279 	if (!fcn) {
6280 		eprintf ("No function at current address\n");
6281 		return R_CMD_STATUS_INVALID;
6282 	}
6283 	r_list_sort (fcn->bbs, bb_cmp);
6284 	r_list_foreach (fcn->bbs, iter, bb) {
6285 		for (i = 0; i < bb->ninstr; i++) {
6286 			ut64 addr = bb->addr + r_anal_bb_offset_inst (bb, i);
6287 			int sz = r_anal_bb_size_i (bb, i);
6288 			r_core_block_size (core, sz);
6289 			r_core_seek (core, addr, true);
6290 			RCmdStatus cmd_res = handle_ts_command_tmpseek (state, command);
6291 			UPDATE_CMD_STATUS_RES (res, cmd_res, err);
6292 			if (r_cons_is_breaked ()) {
6293 				break;
6294 			}
6295 		}
6296 	}
6297 
6298 err:
6299 	r_core_block_size (core, bs);
6300 	r_core_seek (core, orig_offset, true);
6301 	return res;
6302 }
6303 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_functions_command)6304 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_functions_command) {
6305 	TSNode command = ts_node_named_child (node, 0);
6306 	TSNode arg = ts_node_named_child (node, 1);
6307 	char *arg_str = NULL;
6308 	RCore *core = state->core;
6309 	RCmdStatus res = R_CMD_STATUS_OK;
6310 	ut64 orig_offset = core->offset;
6311 	int bs = core->blocksize;
6312 	RAnalFunction *fcn;
6313 	RListIter *iter;
6314 
6315 	if (!ts_node_is_null (arg)) {
6316 		arg_str = ts_node_handle_arg (state, node, arg, 1);
6317 	}
6318 
6319 	r_list_foreach (core->anal->fcns, iter, fcn) {
6320 		if (arg_str && !strstr (fcn->name, arg_str)) {
6321 			continue;
6322 		}
6323 		char *buf;
6324 		r_core_block_size (core, r_anal_function_linear_size (fcn));
6325 		r_core_seek (core, fcn->addr, true);
6326 		r_cons_push ();
6327 		RCmdStatus cmd_res = handle_ts_command_tmpseek (state, command);
6328 		buf = (char *)r_cons_get_buffer ();
6329 		if (buf) {
6330 			buf = strdup (buf);
6331 		}
6332 		r_cons_pop ();
6333 		r_cons_strcat (buf);
6334 		free (buf);
6335 		UPDATE_CMD_STATUS_RES (res, cmd_res, err);
6336 		if (r_cons_is_breaked ()) {
6337 			break;
6338 		}
6339 	}
6340 
6341 err:
6342 	r_core_block_size (core, bs);
6343 	r_core_seek (core, orig_offset, true);
6344 	free (arg_str);
6345 	return res;
6346 }
6347 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_step_command)6348 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_step_command) {
6349 	TSNode command = ts_node_named_child (node, 0);
6350 	TSNode from_n = ts_node_named_child (node, 1);
6351 	TSNode to_n = ts_node_named_child (node, 2);
6352 	TSNode step_n = ts_node_named_child (node, 3);
6353 	RCore *core = state->core;
6354 	RCmdStatus res = R_CMD_STATUS_OK;
6355 	ut64 orig_offset = core->offset;
6356 	int bs = core->blocksize;
6357 
6358 	char *from_str = ts_node_handle_arg (state, node, from_n, 1);
6359 	char *to_str = ts_node_handle_arg (state, node, to_n, 2);
6360 	char *step_str = ts_node_handle_arg (state, node, step_n, 3);
6361 	ut64 from = r_num_math (core->num, from_str);
6362 	ut64 to = r_num_math (core->num, to_str);
6363 	ut64 step = r_num_math (core->num, step_str);
6364 	free (from_str);
6365 	free (to_str);
6366 	free (step_str);
6367 
6368 	ut64 cur;
6369 	for (cur = from; cur <= to; cur += step) {
6370 		r_core_seek (core, cur, true);
6371 		r_core_block_size (core, step);
6372 		RCmdStatus cmd_res = handle_ts_command_tmpseek (state, command);
6373 		UPDATE_CMD_STATUS_RES (res, cmd_res, err);
6374 		if (r_cons_is_breaked ()) {
6375 			break;
6376 		}
6377 	}
6378 
6379 err:
6380 	r_core_block_size (core, bs);
6381 	r_core_seek (core, orig_offset, true);
6382 	return res;
6383 }
6384 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_interpret_command)6385 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_interpret_command) {
6386 	RCore *core = state->core;
6387 	TSNode command = ts_node_named_child (node, 0);
6388 	TSNode in_cmd = ts_node_named_child (node, 1);
6389 	substitute_args_init (state, node);
6390 
6391 	RList *edits = r_list_newf ((RListFree)free_tsr2cmd_edit);
6392 
6393 	char *in_cmd_out = do_handle_substitution_cmd (state, in_cmd);
6394 	in_cmd_out = escape_special_chars (in_cmd_out, SPECIAL_CHARS_REGULAR);
6395 	struct tsr2cmd_edit *e = create_cmd_edit (state, in_cmd, in_cmd_out);
6396 	r_list_append (edits, e);
6397 
6398 	TSNode op = ts_node_child (node, 1);
6399 	e = create_cmd_edit (state, op, strdup ("@@="));
6400 	r_list_append (edits, e);
6401 
6402 	TSNode new_command;
6403 	bool ok = substitute_args_do (state, edits, &new_command);
6404 	if (!ok) {
6405 		r_list_free (edits);
6406 		substitute_args_fini (state);
6407 		return R_CMD_STATUS_INVALID;
6408 	}
6409 	TSNode args = ts_node_named_child (new_command, 1);
6410 
6411 	RCmdParsedArgs *a = parse_args (state, args, true);
6412 	if (!a) {
6413 		r_list_free (edits);
6414 		substitute_args_fini (state);
6415 		return R_CMD_STATUS_INVALID;
6416 	}
6417 
6418 	r_list_free (edits);
6419 	substitute_args_fini (state);
6420 
6421 	const char *s;
6422 	int i;
6423 	ut64 orig_offset = core->offset;
6424 	RCmdStatus res = R_CMD_STATUS_OK;
6425 	r_cmd_parsed_args_foreach_arg (a, i, s) {
6426 		ut64 addr = r_num_math (core->num, s);
6427 		R_LOG_DEBUG ("iter_interpret_command: seek to %" PFMT64x "\n", addr);
6428 		r_core_seek (core, addr, true);
6429 		RCmdStatus cmd_res = handle_ts_command_tmpseek (state, command);
6430 		r_cons_flush ();
6431 		UPDATE_CMD_STATUS_RES (res, cmd_res, err);
6432 	}
6433 err:
6434 	r_core_seek (core, orig_offset, true);
6435 	r_cmd_parsed_args_free (a);
6436 	return res;
6437 }
6438 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_hit_command)6439 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_hit_command) {
6440 	RCore *core = state->core;
6441 	TSNode command = ts_node_named_child (node, 0);
6442 	TSNode search_cmd = ts_node_named_child (node, 1);
6443 	char *command_str = ts_node_sub_string (command, state->input);
6444 	char *cmdhit = strdup (r_config_get (core->config, "cmd.hit"));
6445 	r_config_set (core->config, "cmd.hit", command_str);
6446 	RCmdStatus res = handle_ts_command (state, search_cmd);
6447 	r_config_set (core->config, "cmd.hit", cmdhit);
6448 	free (command_str);
6449 	return res;
6450 }
6451 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_addrsize_command)6452 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_addrsize_command) {
6453 	RCore *core = state->core;
6454 	TSNode command = ts_node_named_child (node, 0);
6455 	uint32_t i = 1;
6456 	RCmdStatus ret = R_CMD_STATUS_OK;
6457 	TSNode seek_addr_node = ts_node_named_child (node, i);
6458 	TSNode blk_sz_node = ts_node_named_child (node, i + 1);
6459 	ut64 orig_offset = core->offset;
6460 	ut64 orig_blksz = core->blocksize;
6461 	while (!ts_node_is_null (seek_addr_node)) {
6462 		char *seek_addr_str = ts_node_handle_arg (state, node, seek_addr_node, i);
6463 		char *blk_sz_str = ts_node_handle_arg (state, node, blk_sz_node, i + 1);
6464 		ut64 seek_addr_val = r_num_get (core->num, seek_addr_str);
6465 		ut64 blk_sz_val = r_num_get (core->num, blk_sz_str);
6466 		free (seek_addr_str);
6467 		free (blk_sz_str);
6468 		r_core_seek (core, seek_addr_val, true);
6469 		r_core_block_size (core, blk_sz_val);
6470 		RCmdStatus cmd_res = handle_ts_command_tmpseek (state, command);
6471 		UPDATE_CMD_STATUS_RES (ret, cmd_res, err);
6472 		i += 2;
6473 		seek_addr_node = ts_node_named_child (node, i);
6474 		blk_sz_node = ts_node_named_child (node, i + 1);
6475 	}
6476 err:
6477 	r_core_block_size (core, orig_blksz);
6478 	r_core_seek (core, orig_offset, true);
6479 	return ret;
6480 }
6481 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_bb_command)6482 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_bb_command) {
6483 	RCore *core = state->core;
6484 	TSNode command = ts_node_named_child (node, 0);
6485 	RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, core->offset, 0);
6486 	ut64 offorig = core->offset;
6487 	ut64 obs = core->blocksize;
6488 	if (!fcn) {
6489 		return R_CMD_STATUS_INVALID;
6490 	}
6491 
6492 	RListIter *iter;
6493 	RAnalBlock *bb;
6494 	RCmdStatus ret = R_CMD_STATUS_OK;
6495 	r_list_foreach (fcn->bbs, iter, bb) {
6496 		r_core_seek (core, bb->addr, true);
6497 		r_core_block_size (core, bb->size);
6498 		RCmdStatus cmd_res = handle_ts_command_tmpseek (state, command);
6499 		UPDATE_CMD_STATUS_RES (ret, cmd_res, err);
6500 	}
6501 err:
6502 	r_core_block_size (core, obs);
6503 	r_core_seek (core, offorig, true);
6504 	return ret;
6505 }
6506 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_cmd_command)6507 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_cmd_command) {
6508 	// convert @@@c: command into a @@@= one, by using the output of the
6509 	// in_cmd as addr/blksz of @@@=
6510 	TSNode in_cmd = ts_node_named_child (node, 1);
6511 	substitute_args_init (state, node);
6512 
6513 	RList *edits = r_list_newf ((RListFree)free_tsr2cmd_edit);
6514 	if (!edits) {
6515 		substitute_args_fini (state);
6516 		return R_CMD_STATUS_INVALID;
6517 	}
6518 
6519 	char *in_cmd_out = do_handle_substitution_cmd (state, in_cmd);
6520 	in_cmd_out = escape_special_chars (in_cmd_out, SPECIAL_CHARS_REGULAR);
6521 	struct tsr2cmd_edit *e = create_cmd_edit (state, in_cmd, in_cmd_out);
6522 	r_list_append (edits, e);
6523 
6524 	TSNode op = ts_node_child (node, 1);
6525 	e = create_cmd_edit (state, op, strdup ("@@@="));
6526 	r_list_append (edits, e);
6527 
6528 	TSNode new_command;
6529 	if (!substitute_args_do (state, edits, &new_command)) {
6530 		r_list_free (edits);
6531 		substitute_args_fini (state);
6532 		return R_CMD_STATUS_INVALID;
6533 	}
6534 	RCmdStatus res = handle_ts_command (state, new_command);
6535 	r_list_free (edits);
6536 	substitute_args_fini (state);
6537 	return res;
6538 }
6539 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_comment_command)6540 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_comment_command) {
6541 	RCore *core = state->core;
6542 	TSNode command = ts_node_named_child (node, 0);
6543 	TSNode filter_node = ts_node_named_child (node, 1);
6544 	char *glob = !ts_node_is_null (filter_node)
6545 			? ts_node_sub_string (filter_node, state->input)
6546 			: NULL;
6547 	ut64 off = core->offset;
6548 	RCmdStatus res = R_CMD_STATUS_OK;
6549 	RIntervalTreeIter it;
6550 	RAnalMetaItem *meta;
6551 	r_interval_tree_foreach (&core->anal->meta, it, meta) {
6552 		if (meta->type != R_META_TYPE_COMMENT) {
6553 			continue;
6554 		}
6555 		if (!glob || (meta->str && r_str_glob (meta->str, glob))) {
6556 			r_core_seek (core, r_interval_tree_iter_get (&it)->start, true);
6557 			RCmdStatus cmd_res = handle_ts_command_tmpseek (state, command);
6558 			UPDATE_CMD_STATUS_RES (res, cmd_res, err);
6559 		}
6560 	}
6561 err:
6562 	r_core_seek (core, off, false);
6563 	free (glob);
6564 	return res;
6565 }
6566 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_import_command)6567 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_import_command) {
6568 	RCore *core = state->core;
6569 	TSNode command = ts_node_named_child (node, 0);
6570 	RBinImport *imp;
6571 	ut64 offorig = core->offset;
6572 	RList *list = r_bin_get_imports (core->bin);
6573 	if (!list) {
6574 		return R_CMD_STATUS_OK;
6575 	}
6576 
6577 	RList *lost = r_list_newf (free);
6578 	RListIter *iter;
6579 	r_list_foreach (list, iter, imp) {
6580 		char *impflag = r_str_newf ("sym.imp.%s", imp->name);
6581 		ut64 addr = r_num_math (core->num, impflag);
6582 		ut64 *n = R_NEW (ut64);
6583 		*n = addr;
6584 		r_list_append (lost, n);
6585 		free (impflag);
6586 	}
6587 	ut64 *naddr;
6588 	RCmdStatus res = R_CMD_STATUS_OK;
6589 	r_list_foreach (lost, iter, naddr) {
6590 		ut64 addr = *naddr;
6591 		if (addr && addr != UT64_MAX) {
6592 			r_core_seek (core, addr, true);
6593 			RCmdStatus cmd_res = handle_ts_command_tmpseek (state, command);
6594 			UPDATE_CMD_STATUS_RES (res, cmd_res, err);
6595 		}
6596 	}
6597 err:
6598 	r_core_seek (core, offorig, true);
6599 	r_list_free (lost);
6600 	return res;
6601 }
6602 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_register_command)6603 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_register_command) {
6604 	RCore *core = state->core;
6605 	TSNode command = ts_node_named_child (node, 0);
6606 	ut64 offorig = core->offset;
6607 	int i;
6608 	RCmdStatus res = R_CMD_STATUS_OK;
6609 	for (i = 0; i < R_REG_TYPE_LAST; i++) {
6610 		RRegItem *item;
6611 		ut64 value;
6612 		RList *head = r_reg_get_list (core->dbg->reg, i);
6613 		if (!head) {
6614 			continue;
6615 		}
6616 		RList *list = r_list_newf (free);
6617 		RListIter *iter;
6618 		r_list_foreach (head, iter, item) {
6619 			if (item->size != core->anal->bits) {
6620 				continue;
6621 			}
6622 			if (item->type != i) {
6623 				continue;
6624 			}
6625 			r_list_append (list, strdup (item->name));
6626 		}
6627 		const char *item_name;
6628 		r_list_foreach (list, iter, item_name) {
6629 			value = r_reg_getv (core->dbg->reg, item_name);
6630 			r_core_seek (core, value, true);
6631 			r_cons_printf ("%s: ", item_name);
6632 			RCmdStatus cmd_res = handle_ts_command_tmpseek (state, command);
6633 			UPDATE_CMD_STATUS_RES (res, cmd_res, err);
6634 		}
6635 	err:
6636 		r_list_free (list);
6637 	}
6638 	r_core_seek (core, offorig, true);
6639 	return res;
6640 }
6641 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_symbol_command)6642 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_symbol_command) {
6643 	RCore *core = state->core;
6644 	TSNode command = ts_node_named_child (node, 0);
6645 	RBinSymbol *sym;
6646 	ut64 offorig = core->offset;
6647 	ut64 obs = core->blocksize;
6648 	RList *list = r_bin_get_symbols (core->bin);
6649 	RListIter *iter;
6650 	r_cons_break_push (NULL, NULL);
6651 	RList *lost = r_list_newf (free);
6652 	r_list_foreach (list, iter, sym) {
6653 		RBinSymbol *bs = r_mem_dup (sym, sizeof (RBinSymbol));
6654 		r_list_append (lost, bs);
6655 	}
6656 	RCmdStatus res = R_CMD_STATUS_OK;
6657 	r_list_foreach (lost, iter, sym) {
6658 		if (r_cons_is_breaked ()) {
6659 			break;
6660 		}
6661 		r_core_block_size (core, sym->size);
6662 		r_core_seek (core, sym->vaddr, true);
6663 		RCmdStatus cmd_res = handle_ts_command_tmpseek (state, command);
6664 		UPDATE_CMD_STATUS_RES (res, cmd_res, err);
6665 	}
6666 err:
6667 	r_cons_break_pop ();
6668 	r_list_free (lost);
6669 	r_core_block_size (core, obs);
6670 	r_core_seek (core, offorig, true);
6671 	return res;
6672 }
6673 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_string_command)6674 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_string_command) {
6675 	RCore *core = state->core;
6676 	TSNode command = ts_node_named_child (node, 0);
6677 	RList *list = r_bin_get_strings (core->bin);
6678 	RCmdStatus res = R_CMD_STATUS_OK;
6679 	if (list) {
6680 		ut64 offorig = core->offset;
6681 		ut64 obs = core->blocksize;
6682 		RBinString *s;
6683 		RList *lost = r_list_newf (free);
6684 		RListIter *iter;
6685 		r_list_foreach (list, iter, s) {
6686 			RBinString *bs = r_mem_dup (s, sizeof (RBinString));
6687 			r_list_append (lost, bs);
6688 		}
6689 		r_list_foreach (lost, iter, s) {
6690 			r_core_block_size (core, s->size);
6691 			r_core_seek (core, s->vaddr, true);
6692 			RCmdStatus cmd_res = handle_ts_command_tmpseek (state, command);
6693 			UPDATE_CMD_STATUS_RES (res, cmd_res, err);
6694 		}
6695 	err:
6696 		r_core_block_size (core, obs);
6697 		r_core_seek (core, offorig, true);
6698 		r_list_free (lost);
6699 	}
6700 	return res;
6701 }
6702 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_section_command)6703 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_section_command) {
6704 	RCore *core = state->core;
6705 	TSNode command = ts_node_named_child (node, 0);
6706 	RBinObject *obj = r_bin_cur_object (core->bin);
6707 	if (!obj) {
6708 		return false;
6709 	}
6710 	RCmdStatus res = R_CMD_STATUS_OK;
6711 	ut64 offorig = core->offset;
6712 	ut64 bszorig = core->blocksize;
6713 	RBinSection *sec;
6714 	RListIter *iter;
6715 	r_list_foreach (obj->sections, iter, sec) {
6716 		r_core_seek (core, sec->vaddr, true);
6717 		r_core_block_size (core, sec->vsize);
6718 		RCmdStatus cmd_res = handle_ts_command_tmpseek (state, command);
6719 		UPDATE_CMD_STATUS_RES (res, cmd_res, err);
6720 	}
6721 err:
6722 	r_core_block_size (core, bszorig);
6723 	r_core_seek (core, offorig, true);
6724 	return res;
6725 }
6726 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_iomap_command)6727 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_iomap_command) {
6728 	RCore *core = state->core;
6729 	TSNode command = ts_node_named_child (node, 0);
6730 	int fd = r_io_fd_get_current (core->io);
6731 	// only iterate maps of current fd
6732 	RList *maps = r_io_map_get_for_fd (core->io, fd);
6733 	RIOMap *map;
6734 	RCmdStatus res = R_CMD_STATUS_OK;
6735 	if (maps) {
6736 		RListIter *iter;
6737 		r_list_foreach (maps, iter, map) {
6738 			r_core_seek (core, r_io_map_begin (map), true);
6739 			r_core_block_size (core, r_io_map_size (map));
6740 			RCmdStatus cmd_res = handle_ts_command_tmpseek (state, command);
6741 			UPDATE_CMD_STATUS_RES (res, cmd_res, err);
6742 		}
6743 	err:
6744 		r_list_free (maps);
6745 	}
6746 	return res;
6747 }
6748 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_dbgmap_command)6749 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_dbgmap_command) {
6750 	RCore *core = state->core;
6751 	TSNode command = ts_node_named_child (node, 0);
6752 	RDebug *dbg = core->dbg;
6753 	RCmdStatus res = R_CMD_STATUS_OK;
6754 	if (dbg && dbg->h && dbg->maps) {
6755 		RDebugMap *map;
6756 		RListIter *iter;
6757 		r_list_foreach (dbg->maps, iter, map) {
6758 			r_core_seek (core, map->addr, true);
6759 			RCmdStatus cmd_res = handle_ts_command_tmpseek (state, command);
6760 			UPDATE_CMD_STATUS_RES (res, cmd_res, err);
6761 		}
6762 	}
6763 err:
6764 	return res;
6765 }
6766 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_flag_command)6767 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_flag_command) {
6768 	RCore *core = state->core;
6769 	TSNode command = ts_node_named_child (node, 0);
6770 	TSNode filter_node = ts_node_named_child (node, 1);
6771 	char *glob = NULL;
6772 	if (!ts_node_is_null (filter_node)) {
6773 		glob = ts_node_sub_string (filter_node, state->input);
6774 	}
6775 	ut64 off = core->offset;
6776 	ut64 obs = core->blocksize;
6777 	RList *flags = r_list_newf (free);
6778 	r_flag_foreach_glob (core->flags, glob, copy_into_flagitem_list, flags);
6779 	RListIter *iter;
6780 	RFlagItem *f;
6781 	RCmdStatus res = R_CMD_STATUS_OK;
6782 	r_list_foreach (flags, iter, f) {
6783 		r_core_block_size (core, f->size);
6784 		r_core_seek (core, f->offset, true);
6785 		RCmdStatus cmd_res = handle_ts_command_tmpseek (state, command);
6786 		UPDATE_CMD_STATUS_RES (res, cmd_res, err);
6787 	}
6788 err:
6789 	r_core_seek (core, off, false);
6790 	r_core_block_size (core, obs);
6791 	free (glob);
6792 	return res;
6793 }
6794 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_function_command)6795 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_function_command) {
6796 	RCore *core = state->core;
6797 	TSNode command = ts_node_named_child (node, 0);
6798 	TSNode filter_node = ts_node_named_child (node, 1);
6799 	char *filter = NULL;
6800 	if (!ts_node_is_null (filter_node)) {
6801 		filter = ts_node_sub_string (filter_node, state->input);
6802 	}
6803 	ut64 obs = core->blocksize;
6804 	ut64 offorig = core->offset;
6805 	RAnalFunction *fcn;
6806 	RList *list = core->anal->fcns;
6807 	RListIter *iter;
6808 	RCmdStatus res = R_CMD_STATUS_OK;
6809 	r_cons_break_push (NULL, NULL);
6810 	r_list_foreach (list, iter, fcn) {
6811 		if (r_cons_is_breaked ()) {
6812 			break;
6813 		}
6814 		if (!filter || r_str_glob (fcn->name, filter)) {
6815 			r_core_seek (core, fcn->addr, true);
6816 			r_core_block_size (core, r_anal_function_linear_size (fcn));
6817 			RCmdStatus cmd_res = handle_ts_command_tmpseek (state, command);
6818 			UPDATE_CMD_STATUS_RES (res, cmd_res, err);
6819 		}
6820 	}
6821 err:
6822 	r_cons_break_pop ();
6823 	r_core_block_size (core, obs);
6824 	r_core_seek (core, offorig, true);
6825 	return res;
6826 }
6827 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_thread_command)6828 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_thread_command) {
6829 	RCore *core = state->core;
6830 	TSNode command = ts_node_named_child (node, 0);
6831 	RDebug *dbg = core->dbg;
6832 	RCmdStatus res = R_CMD_STATUS_OK;
6833 	if (dbg && dbg->h && dbg->h->threads) {
6834 		int origtid = dbg->tid;
6835 		RDebugPid *p;
6836 		RList *list = dbg->h->threads (dbg, dbg->pid);
6837 		if (!list) {
6838 			return R_CMD_STATUS_INVALID;
6839 		}
6840 		RListIter *iter;
6841 		r_list_foreach (list, iter, p) {
6842 			r_debug_select (dbg, dbg->pid, p->pid);
6843 			r_cons_printf ("PID %d\n", p->pid);
6844 			RCmdStatus cmd_res = handle_ts_command (state, command);
6845 			UPDATE_CMD_STATUS_RES (res, cmd_res, err);
6846 		}
6847 	err:
6848 		r_debug_select (dbg, dbg->pid, origtid);
6849 		r_list_free (list);
6850 	}
6851 	return res;
6852 }
6853 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(last_command)6854 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(last_command) {
6855 	TSNode command = ts_node_child_by_field_name (node, "command", strlen ("command"));
6856 	char *command_str = ts_node_sub_string (command, state->input);
6857 	RCmdStatus res = R_CMD_STATUS_INVALID;
6858 	state->is_last_cmd = true;
6859 	if (!strcmp (command_str, ".")) {
6860 		res = lastcmd_repeat (state->core, 0);
6861 	} else if (!strcmp (command_str, "...")) {
6862 		res = lastcmd_repeat (state->core, 1);
6863 	} else {
6864 		r_warn_if_reached ();
6865 	}
6866 	free (command_str);
6867 	return res;
6868 }
6869 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(grep_command)6870 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(grep_command) {
6871 	TSNode command = ts_node_child_by_field_name (node, "command", strlen ("command"));
6872 	TSNode arg = ts_node_child_by_field_name (node, "specifier", strlen ("specifier"));
6873 	char *arg_str = ts_node_handle_arg (state, node, arg, 1);
6874 	RCmdStatus res = handle_ts_command (state, command);
6875 	R_LOG_DEBUG ("grep_command specifier: '%s'\n", arg_str);
6876 	RStrBuf *sb = r_strbuf_new (arg_str);
6877 	r_strbuf_prepend (sb, "~");
6878 	char *specifier_str = r_cons_grep_strip (r_strbuf_get (sb), "`");
6879 	r_strbuf_free (sb);
6880 	specifier_str = unescape_special_chars (specifier_str, SPECIAL_CHARS_REGULAR);
6881 	R_LOG_DEBUG ("grep_command processed specifier: '%s'\n", specifier_str);
6882 	r_cons_grep_process (specifier_str);
6883 	free (arg_str);
6884 	return res;
6885 }
6886 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(html_disable_command)6887 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(html_disable_command) {
6888 	TSNode command = ts_node_child_by_field_name (node, "command", strlen ("command"));
6889 	int scr_html = r_config_get_i (state->core->config, "scr.html");
6890 	r_config_set_i (state->core->config, "scr.html", 0);
6891 	int scr_color = r_config_get_i (state->core->config, "scr.color");
6892 	r_config_set_i (state->core->config, "scr.color", COLOR_MODE_DISABLED);
6893 	RCmdStatus res = handle_ts_command (state, command);
6894 	if (scr_html != -1) {
6895 		r_cons_flush ();
6896 		r_config_set_i (state->core->config, "scr.html", scr_html);
6897 	}
6898 	if (scr_color != -1) {
6899 		r_config_set_i (state->core->config, "scr.color", scr_color);
6900 	}
6901 	return res;
6902 }
6903 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(html_enable_command)6904 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(html_enable_command) {
6905 	TSNode command = ts_node_child_by_field_name (node, "command", strlen ("command"));
6906 	int scr_html = r_config_get_i (state->core->config, "scr.html");
6907 	r_config_set_i (state->core->config, "scr.html", true);
6908 	RCmdStatus res = handle_ts_command (state, command);
6909 	if (scr_html != -1) {
6910 		r_cons_flush ();
6911 		r_config_set_i (state->core->config, "scr.html", scr_html);
6912 	}
6913 	return res;
6914 }
6915 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(pipe_command)6916 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(pipe_command) {
6917 	TSNode first_cmd = ts_node_named_child (node, 0);
6918 	r_return_val_if_fail (!ts_node_is_null (first_cmd), false);
6919 	TSNode second_cmd = ts_node_named_child (node, 1);
6920 	r_return_val_if_fail (!ts_node_is_null (second_cmd), false);
6921 	char *first_str = ts_node_sub_string (first_cmd, state->input);
6922 	char *second_str = ts_node_sub_string (second_cmd, state->input);
6923 	int value = state->core->num->value;
6924 	RCmdStatus res = r_cmd_int2status (r_core_cmd_pipe (state->core, first_str, second_str));
6925 	state->core->num->value = value;
6926 	free (first_str);
6927 	free (second_str);
6928 	return res;
6929 }
6930 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(scr_tts_command)6931 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(scr_tts_command) {
6932 	TSNode command = ts_node_child_by_field_name (node, "command", strlen ("command"));
6933 	int scr_color = r_config_get_i (state->core->config, "scr.color");
6934 	r_config_set_i (state->core->config, "scr.color", COLOR_MODE_DISABLED);
6935 	state->core->cons->use_tts = true;
6936 	RCmdStatus res = handle_ts_command (state, command);
6937 	if (scr_color != -1) {
6938 		r_config_set_i (state->core->config, "scr.color", scr_color);
6939 	}
6940 	return res;
6941 }
6942 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(task_command)6943 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(task_command) {
6944 	// TODO: this should be handled differently, if the argument is a command.
6945 	//       For now we just treat everything as an arged_command
6946 	return handle_ts_arged_command (state, node);
6947 }
6948 
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(number_command)6949 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(number_command) {
6950 	ut64 addr = r_num_math (state->core->num, node_string);
6951 	r_core_seek (state->core, addr, true);
6952 	return R_CMD_STATUS_OK;
6953 }
6954 
handle_ts_command(struct tsr2cmd_state * state,TSNode node)6955 static RCmdStatus handle_ts_command(struct tsr2cmd_state *state, TSNode node) {
6956 	RCmdStatus ret = R_CMD_STATUS_INVALID;
6957 	RCmd *cmd = state->core->rcmd;
6958 
6959 	TSSymbol node_symbol = ts_node_symbol (node);
6960 	ts_handler handler = ht_up_find (cmd->ts_symbols_ht, node_symbol, NULL);
6961 
6962 	state->is_last_cmd = false;
6963 	if (handler) {
6964 		ret = handler (state, node);
6965 	} else {
6966 		R_LOG_WARN ("No handler for this kind of command `%s`\n", ts_node_type (node));
6967 	}
6968 	if (state->log && !state->is_last_cmd) {
6969 		free (state->core->lastcmd);
6970 		state->core->lastcmd = ts_node_sub_string (node, state->input);
6971 	}
6972 	return ret;
6973 }
6974 
handle_ts_command_tmpseek(struct tsr2cmd_state * state,TSNode node)6975 static RCmdStatus handle_ts_command_tmpseek(struct tsr2cmd_state *state, TSNode node) {
6976 	RCore *core = state->core;
6977 	bool saved_tmpseek = core->tmpseek;
6978 	core->tmpseek = true;
6979 	RCmdStatus ret = handle_ts_command (state, node);
6980 	core->tmpseek = saved_tmpseek;
6981 	return ret;
6982 }
6983 
DEFINE_HANDLE_TS_FCN(commands)6984 DEFINE_HANDLE_TS_FCN(commands) {
6985 	RCore *core = state->core;
6986 	RCmdStatus res = R_CMD_STATUS_OK;
6987 	ut32 child_count = ts_node_named_child_count (node);
6988 	int i;
6989 
6990 	R_LOG_DEBUG ("commands with %d childs\n", child_count);
6991 	if (child_count == 0 && !*state->input) {
6992 		if (core->cons->context->breaked) {
6993 			core->cons->context->breaked = false;
6994 			return R_CMD_STATUS_INVALID;
6995 		}
6996 		if (!core->cmdrepeat) {
6997 			return R_CMD_STATUS_OK;
6998 		}
6999 		return lastcmd_repeat (core, true)? R_CMD_STATUS_OK: R_CMD_STATUS_INVALID;
7000 	}
7001 	if (state->split_lines) {
7002 		r_cons_break_push (NULL, NULL);
7003 	}
7004 	for (i = 0; i < child_count; i++) {
7005 		if (core->cons->context->cmd_depth < 1) {
7006 			R_LOG_ERROR ("handle_ts_commands: That was too deep...\n");
7007 			return R_CMD_STATUS_INVALID;
7008 		}
7009 		core->cons->context->cmd_depth--;
7010 		if (core->max_cmd_depth - core->cons->context->cmd_depth == 1) {
7011 			core->prompt_offset = core->offset;
7012 		}
7013 
7014 		if (state->split_lines && r_cons_is_breaked ()) {
7015 			r_cons_break_pop ();
7016 			return res;
7017 		}
7018 		TSNode command = ts_node_named_child (node, i);
7019 		RCmdStatus cmd_res = handle_ts_command (state, command);
7020 		if (state->split_lines) {
7021 			r_cons_flush ();
7022 			r_core_task_yield (&core->tasks);
7023 		}
7024 		core->cons->context->cmd_depth++;
7025 		if (cmd_res == R_CMD_STATUS_INVALID) {
7026 			char *command_str = ts_node_sub_string (command, state->input);
7027 			eprintf ("Error while executing command: %s\n", command_str);
7028 			free (command_str);
7029 			res = cmd_res;
7030 			goto err;
7031 		} else if (cmd_res != R_CMD_STATUS_OK) {
7032 			res = cmd_res;
7033 			goto err;
7034 		}
7035 	}
7036 err:
7037 	if (state->split_lines) {
7038 		r_cons_break_pop ();
7039 	}
7040 	return res;
7041 }
7042 
7043 #define HANDLER_RULE_OP(name) { #name, handle_ts_##name },
7044 #define RULE_OP(name)
7045 
7046 struct ts_data_symbol_map map_ts_command_handlers[] = {
7047 	#include "r2-shell-parser-cmds.inc"
7048 	{ NULL, NULL },
7049 };
7050 
7051 #define RULE_OP(name) { #name, &ts_##name##_symbol },
7052 #define HANDLER_RULE_OP(name) RULE_OP(name)
7053 
7054 struct ts_data_symbol_map map_ts_symbols[] = {
7055 	#include "r2-shell-parser-cmds.inc"
7056 	{ NULL, NULL },
7057 };
7058 
ts_symbols_init(RCmd * cmd)7059 static void ts_symbols_init(RCmd *cmd) {
7060 	if (cmd->language) {
7061 		return;
7062 	}
7063 	TSLanguage *lang = tree_sitter_r2cmd ();
7064 	cmd->language = lang;
7065 	cmd->ts_symbols_ht = ht_up_new0 ();
7066 	struct ts_data_symbol_map *entry = map_ts_command_handlers;
7067 	while (entry->name) {
7068 		TSSymbol symbol = ts_language_symbol_for_name (lang, entry->name, strlen (entry->name), true);
7069 		ht_up_insert (cmd->ts_symbols_ht, symbol, entry->data);
7070 		entry++;
7071 	}
7072 
7073 	entry = map_ts_symbols;
7074 	while (entry->name) {
7075 		TSSymbol *sym_ptr = entry->data;
7076 		*sym_ptr = ts_language_symbol_for_name (lang, entry->name, strlen (entry->name), true);
7077 		entry++;
7078 	}
7079 }
7080 
core_cmd_tsr2cmd(RCore * core,const char * cstr,bool split_lines,bool log)7081 static RCmdStatus core_cmd_tsr2cmd(RCore *core, const char *cstr, bool split_lines, bool log) {
7082 	char *input = strdup (r_str_trim_head_ro (cstr));
7083 
7084 	ts_symbols_init (core->rcmd);
7085 
7086 	TSParser *parser = ts_parser_new ();
7087 	ts_parser_set_language (parser, (TSLanguage *)core->rcmd->language);
7088 
7089 	TSTree *tree = ts_parser_parse_string (parser, NULL, input, strlen (input));
7090 	TSNode root = ts_tree_root_node (tree);
7091 
7092 	RCmdStatus res = R_CMD_STATUS_INVALID;
7093 	struct tsr2cmd_state state;
7094 	state.parser = parser;
7095 	state.core = core;
7096 	state.input = input;
7097 	state.tree = tree;
7098 	state.log = log;
7099 	state.split_lines = split_lines;
7100 
7101 	if (state.log) {
7102 		r_line_hist_add (state.input);
7103 	}
7104 
7105 	char *ts_str = ts_node_string (root);
7106 	R_LOG_DEBUG("s-expr %s\n", ts_str);
7107 	free (ts_str);
7108 
7109 	if (is_ts_commands (root) && !ts_node_has_error (root)) {
7110 		res = handle_ts_commands (&state, root);
7111 	} else {
7112 		// TODO: print a more meaningful error message and use the ERROR
7113 		// tokens to indicate where, probably, the error is.
7114 		eprintf ("Error while parsing command: `%s`\n", input);
7115 	}
7116 
7117 	ts_tree_delete (tree);
7118 	ts_parser_delete (parser);
7119 	free (input);
7120 	return res;
7121 }
7122 
run_cmd_depth(RCore * core,char * cmd)7123 static int run_cmd_depth(RCore *core, char *cmd) {
7124 	char *rcmd;
7125 	int ret = false;
7126 
7127 	if (core->cons->context->cmd_depth < 1) {
7128 		eprintf ("r_core_cmd: That was too deep (%s)...\n", cmd);
7129 		return false;
7130 	}
7131 	core->cons->context->cmd_depth--;
7132 	for (rcmd = cmd;;) {
7133 		char *ptr = strchr (rcmd, '\n');
7134 		if (ptr) {
7135 			*ptr = '\0';
7136 		}
7137 		ret = r_core_cmd_subst (core, rcmd);
7138 		if (ret == -1) {
7139 			r_cons_eprintf ("|ERROR| Invalid command '%s' (0x%02x)\n", rcmd, *rcmd);
7140 			break;
7141 		}
7142 		if (!ptr) {
7143 			break;
7144 		}
7145 		rcmd = ptr + 1;
7146 	}
7147 	core->cons->context->cmd_depth++;
7148 	return ret;
7149 }
7150 
r_core_cmd(RCore * core,const char * cstr,bool log)7151 R_API int r_core_cmd(RCore *core, const char *cstr, bool log) {
7152 	if (core->use_tree_sitter_r2cmd) {
7153 		return r_cmd_status2int (core_cmd_tsr2cmd (core, cstr, false, log));
7154 	}
7155 
7156 	int ret = false;
7157 	size_t i;
7158 	if (core->cmdfilter) {
7159 		const char *invalid_chars = ";|>`@";
7160 		for (i = 0; invalid_chars[i]; i++) {
7161 			if (strchr (cstr, invalid_chars[i])) {
7162 				ret = true;
7163 				goto beach;
7164 			}
7165 		}
7166 		if (strncmp (cstr, core->cmdfilter, strlen (core->cmdfilter))) {
7167 			ret = true;
7168 			goto beach;
7169 		}
7170 	}
7171 	if (core->cmdremote) {
7172 		if (*cstr == 'q') {
7173 			R_FREE (core->cmdremote);
7174 			goto beach; // false
7175 		} else if (*cstr != '=' && strncmp (cstr, "!=", 2)) {
7176 			if (core->cmdremote[0]) {
7177 				char *s = r_str_newf ("%s %s", core->cmdremote, cstr);
7178 				r_core_rtr_cmd (core, s);
7179 				free (s);
7180 			} else {
7181 				char *res = r_io_system (core->io, cstr);
7182 				if (res) {
7183 					r_cons_printf ("%s\n", res);
7184 					free (res);
7185 				}
7186 			}
7187 			if (log) {
7188 				r_line_hist_add (cstr);
7189 			}
7190 			goto beach; // false
7191 		}
7192 	}
7193 
7194 	if (!cstr || (*cstr == '|' && cstr[1] != '?')) {
7195 		// raw comment syntax
7196 		goto beach; // false;
7197 	}
7198 	if (!strncmp (cstr, "/*", 2)) {
7199 		if (r_sandbox_enable (0)) {
7200 			eprintf ("This command is disabled in sandbox mode\n");
7201 			goto beach; // false
7202 		}
7203 		core->incomment = true;
7204 	} else if (!strncmp (cstr, "*/", 2)) {
7205 		core->incomment = false;
7206 		goto beach; // false
7207 	}
7208 	if (core->incomment) {
7209 		goto beach; // false
7210 	}
7211 	if (log && (*cstr && (*cstr != '.' || !strncmp (cstr, ".(", 2)))) {
7212 		free (core->lastcmd);
7213 		core->lastcmd = strdup (cstr);
7214 	}
7215 
7216 	char *cmd = malloc (strlen (cstr) + 4096);
7217 	if (!cmd) {
7218 		goto beach;
7219 	}
7220 	r_str_cpy (cmd, cstr);
7221 	if (log) {
7222 		r_line_hist_add (cstr);
7223 	}
7224 
7225 	ret = run_cmd_depth (core, cmd);
7226 	free (cmd);
7227 beach:
7228 	return ret;
7229 }
7230 
r_core_cmd_lines(RCore * core,const char * lines)7231 R_API int r_core_cmd_lines(RCore *core, const char *lines) {
7232 	if (core->use_tree_sitter_r2cmd) {
7233 		RCmdStatus status = core_cmd_tsr2cmd (core, lines, true, false);
7234 		return status == R_CMD_STATUS_OK;
7235 	}
7236 	int r, ret = true;
7237 	char *nl, *data, *odata;
7238 
7239 	if (!lines || !*lines) {
7240 		return true;
7241 	}
7242 	data = odata = strdup (lines);
7243 	if (!odata) {
7244 		return false;
7245 	}
7246 	size_t line_count = r_str_char_count(lines, '\n');
7247 
7248 #if __UNIX__
7249 	const bool istty = r_cons_isatty ();
7250 #else
7251 	const bool istty = true;
7252 #endif
7253 	const bool show_progress_bar = core->print->enable_progressbar && r_config_get_i (core->config, "scr.interactive") && r_config_get_i (core->config, "scr.progressbar") && istty;
7254 	size_t current_line = 0;
7255 	nl = strchr (odata, '\n');
7256 	if (nl) {
7257 		r_cons_break_push (NULL, NULL);
7258 		do {
7259 			if (show_progress_bar) {
7260 				r_print_progressbar_with_count (core->print, current_line++, line_count, 80, true);
7261 			}
7262 			if (r_cons_is_breaked ()) {
7263 				free (odata);
7264 				r_cons_break_pop ();
7265 				return ret;
7266 			}
7267 			*nl = '\0';
7268 			r = r_core_cmd (core, data, 0);
7269 			if (r < 0) {
7270 				data = nl + 1;
7271 				ret = -1;
7272 				break;
7273 			}
7274 			r_cons_flush ();
7275 			if (data[0] == 'q') {
7276 				if (data[1] == '!') {
7277 					ret = -1;
7278 				} else {
7279 					eprintf ("'q': quit ignored. Use 'q!'\n");
7280 				}
7281 				data = nl + 1;
7282 				break;
7283 			}
7284 			data = nl + 1;
7285 			r_core_task_yield (&core->tasks);
7286 		} while ((nl = strchr (data, '\n')));
7287 		r_cons_break_pop ();
7288 		if (show_progress_bar) {
7289 			r_print_progressbar_with_count (core->print, line_count, line_count, 80, true);
7290 			r_cons_newline ();
7291 		}
7292 	}
7293 	if (ret >= 0 && data && *data) {
7294 		r_core_cmd (core, data, 0);
7295 		r_cons_flush ();
7296 		r_core_task_yield (&core->tasks);
7297 	}
7298 	free (odata);
7299 	return ret;
7300 }
7301 
r_core_cmd_file(RCore * core,const char * file)7302 R_API int r_core_cmd_file(RCore *core, const char *file) {
7303 	char *data = r_file_abspath (file);
7304 	if (!data) {
7305 		return false;
7306 	}
7307 	char *odata = r_file_slurp (data, NULL);
7308 	free (data);
7309 	if (!odata) {
7310 		return false;
7311 	}
7312 	if (!r_core_cmd_lines (core, odata)) {
7313 		eprintf ("Failed to run script '%s'\n", file);
7314 		free (odata);
7315 		return false;
7316 	}
7317 	free (odata);
7318 	return true;
7319 }
7320 
r_core_cmd_command(RCore * core,const char * command)7321 R_API int r_core_cmd_command(RCore *core, const char *command) {
7322 	int ret, len;
7323 	char *buf, *rcmd, *ptr;
7324 	char *cmd = r_core_sysenv_begin (core, command);
7325 	rcmd = ptr = buf = r_sys_cmd_str (cmd, 0, &len);
7326 	if (!buf) {
7327 		free (cmd);
7328 		return -1;
7329 	}
7330 	ret = r_core_cmd (core, rcmd, 0);
7331 	r_core_sysenv_end (core, command);
7332 	free (buf);
7333 	return ret;
7334 }
7335 
7336 //TODO: Fix disasm loop is mandatory
r_core_disassemble_instr(RCore * core,ut64 addr,int l)7337 R_API char *r_core_disassemble_instr(RCore *core, ut64 addr, int l) {
7338 	char *cmd, *ret = NULL;
7339 	cmd = r_str_newf ("pd %i @ 0x%08"PFMT64x, l, addr);
7340 	if (cmd) {
7341 		ret = r_core_cmd_str (core, cmd);
7342 		free (cmd);
7343 	}
7344 	return ret;
7345 }
7346 
r_core_disassemble_bytes(RCore * core,ut64 addr,int b)7347 R_API char *r_core_disassemble_bytes(RCore *core, ut64 addr, int b) {
7348 	char *cmd, *ret = NULL;
7349 	cmd = r_str_newf ("pD %i @ 0x%08"PFMT64x, b, addr);
7350 	if (cmd) {
7351 		ret = r_core_cmd_str (core, cmd);
7352 		free (cmd);
7353 	}
7354 	return ret;
7355 }
7356 
r_core_cmd_buffer(RCore * core,const char * buf)7357 R_API int r_core_cmd_buffer(RCore *core, const char *buf) {
7358 	char *ptr, *optr, *str = strdup (buf);
7359 	if (!str) {
7360 		return false;
7361 	}
7362 	optr = str;
7363 	ptr = strchr (str, '\n');
7364 	while (ptr) {
7365 		*ptr = '\0';
7366 		r_core_cmd (core, optr, 0);
7367 		optr = ptr + 1;
7368 		ptr = strchr (str, '\n');
7369 	}
7370 	r_core_cmd (core, optr, 0);
7371 	free (str);
7372 	return true;
7373 }
7374 
r_core_cmdf(RCore * core,const char * fmt,...)7375 R_API int r_core_cmdf(RCore *core, const char *fmt, ...) {
7376 	char string[4096];
7377 	int ret;
7378 	va_list ap;
7379 	va_start (ap, fmt);
7380 	vsnprintf (string, sizeof (string), fmt, ap);
7381 	ret = r_core_cmd (core, string, 0);
7382 	va_end (ap);
7383 	return ret;
7384 }
7385 
r_core_cmd0(RCore * core,const char * cmd)7386 R_API int r_core_cmd0(RCore *core, const char *cmd) {
7387 	return r_core_cmd (core, cmd, 0);
7388 }
7389 
r_core_flush(RCore * core,const char * cmd)7390 R_API int r_core_flush(RCore *core, const char *cmd) {
7391 	int ret = r_core_cmd (core, cmd, 0);
7392 	r_cons_flush ();
7393 	return ret;
7394 }
7395 
r_core_cmd_str_pipe(RCore * core,const char * cmd)7396 R_API char *r_core_cmd_str_pipe(RCore *core, const char *cmd) {
7397 	char *tmp = NULL;
7398 	char *p = (*cmd != '"')? strchr (cmd, '|'): NULL;
7399 	if (!p && *cmd != '!' && *cmd != '.') {
7400 		return r_core_cmd_str (core, cmd);
7401 	}
7402 	r_cons_reset ();
7403 	r_sandbox_disable (true);
7404 	if (r_file_mkstemp ("cmd", &tmp) != -1) {
7405 		int pipefd = r_cons_pipe_open (tmp, 1, 0);
7406 		if (pipefd == -1) {
7407 			r_file_rm (tmp);
7408 			r_sandbox_disable (false);
7409 			free (tmp);
7410 			return r_core_cmd_str (core, cmd);
7411 		}
7412 		char *_cmd = strdup (cmd);
7413 		if (core->use_tree_sitter_r2cmd) {
7414 			r_core_cmd (core, _cmd, 0);
7415 		} else {
7416 			r_core_cmd_subst (core, _cmd);
7417 		}
7418 		r_cons_flush ();
7419 		r_cons_pipe_close (pipefd);
7420 		if (r_file_exists (tmp)) {
7421 			char *s = r_file_slurp (tmp, NULL);
7422 			r_file_rm (tmp);
7423 			r_sandbox_disable (false);
7424 			free (tmp);
7425 			free (_cmd);
7426 			return s? s: strdup ("");
7427 		}
7428 		eprintf ("slurp %s fails\n", tmp);
7429 		r_file_rm (tmp);
7430 		free (tmp);
7431 		free (_cmd);
7432 		r_sandbox_disable (false);
7433 		return r_core_cmd_str (core, cmd);
7434 	}
7435 	r_sandbox_disable (0);
7436 	return NULL;
7437 }
7438 
r_core_cmd_strf(RCore * core,const char * fmt,...)7439 R_API char *r_core_cmd_strf(RCore *core, const char *fmt, ...) {
7440 	char string[4096];
7441 	va_list ap;
7442 	va_start (ap, fmt);
7443 	vsnprintf (string, sizeof (string), fmt, ap);
7444 	char *ret = r_core_cmd_str (core, string);
7445 	va_end (ap);
7446 	return ret;
7447 }
7448 
7449 /* return: pointer to a buffer with the output of the command */
r_core_cmd_str(RCore * core,const char * cmd)7450 R_API char *r_core_cmd_str(RCore *core, const char *cmd) {
7451 	r_cons_push ();
7452 	if (r_core_cmd (core, cmd, 0) == -1) {
7453 		//eprintf ("Invalid command: %s\n", cmd);
7454 		return NULL;
7455 	}
7456 	r_cons_filter ();
7457 	const char *static_str = r_cons_get_buffer ();
7458 	char *retstr = strdup (r_str_get (static_str));
7459 	r_cons_pop ();
7460 	r_cons_echo (NULL);
7461 	return retstr;
7462 }
7463 
7464 /* run cmd in the main task synchronously */
r_core_cmd_task_sync(RCore * core,const char * cmd,bool log)7465 R_API int r_core_cmd_task_sync(RCore *core, const char *cmd, bool log) {
7466 	RCoreTask *task = core->tasks.main_task;
7467 	char *s = strdup (cmd);
7468 	if (!s) {
7469 		return 0;
7470 	}
7471 	task->cmd = s;
7472 	task->cmd_log = log;
7473 	task->state = R_CORE_TASK_STATE_BEFORE_START;
7474 	int res = r_core_task_run_sync (&core->tasks, task);
7475 	free (s);
7476 	return res;
7477 }
7478 
cmd_ox(void * data,const char * input)7479 static int cmd_ox(void *data, const char *input) {
7480 	return r_core_cmdf ((RCore*)data, "s 0%s", input);
7481 }
7482 
compare_cmd_descriptor_name(const void * a,const void * b)7483 static int compare_cmd_descriptor_name(const void *a, const void *b) {
7484 	return strcmp (((RCmdDescriptor *)a)->cmd, ((RCmdDescriptor *)b)->cmd);
7485 }
7486 
cmd_descriptor_init(RCore * core)7487 static void cmd_descriptor_init(RCore *core) {
7488 	const ut8 *p;
7489 	RListIter *iter;
7490 	RCmdDescriptor *x, *y;
7491 	int n = core->cmd_descriptors->length;
7492 	r_list_sort (core->cmd_descriptors, compare_cmd_descriptor_name);
7493 	r_list_foreach (core->cmd_descriptors, iter, y) {
7494 		if (--n < 0) {
7495 			break;
7496 		}
7497 		x = &core->root_cmd_descriptor;
7498 		for (p = (const ut8 *)y->cmd; *p; p++) {
7499 			if (!x->sub[*p]) {
7500 				if (p[1]) {
7501 					RCmdDescriptor *d = R_NEW0 (RCmdDescriptor);
7502 					r_list_append (core->cmd_descriptors, d);
7503 					x->sub[*p] = d;
7504 				} else {
7505 					x->sub[*p] = y;
7506 				}
7507 			} else if (!p[1]) {
7508 				eprintf ("Command '%s' is duplicated, please check\n", y->cmd);
7509 			}
7510 			x = x->sub[*p];
7511 		}
7512 	}
7513 }
7514 
core_cmd0_wrapper(void * core,const char * cmd)7515 static int core_cmd0_wrapper(void *core, const char *cmd) {
7516 	return r_core_cmd0 ((RCore *)core, cmd);
7517 }
7518 
r_core_cmd_init(RCore * core)7519 R_API void r_core_cmd_init(RCore *core) {
7520 	struct {
7521 		const char *cmd;
7522 		const char *description;
7523 		RCmdCb cb;
7524 		void (*descriptor_init)(RCore *core, RCmdDesc *parent);
7525 		const RCmdDescHelp *help;
7526 		const RCmdDescHelp *group_help;
7527 		RCmdDescType type;
7528 		RCmdArgvCb argv_cb;
7529 	} cmds[] = {
7530 		{"!", "run system command", cmd_system, NULL, &system_help},
7531 		{"_", "print last output", cmd_last, NULL, &underscore_help},
7532 		{"#", "calculate hash", cmd_hash, NULL, &hash_help},
7533 		{"$", "alias", cmd_alias, NULL, &alias_help},
7534 		{"%", "short version of 'env' command", cmd_env, NULL, &env_help},
7535 		{"&", "tasks", cmd_tasks, NULL, &tasks_help},
7536 		{"(", "macro", cmd_macro, cmd_macro_init, &macro_help},
7537 		{"*", "pointer read/write", cmd_pointer, NULL, &pointer_help},
7538 		{"-", "open cfg.editor and run script", cmd_stdin, NULL, &stdin_help},
7539 		{".", "interpret", cmd_interpret, NULL, &interpret_help},
7540 		{",", "create and manipulate tables", cmd_table, NULL, &table_help},
7541 		{"/", "search kw, pattern aes", cmd_search, cmd_search_init, &search_help},
7542 		{"=", "io pipe", cmd_rap, NULL, &rap_help},
7543 		{"?", "help message", cmd_help, cmd_help_init, &help_help},
7544 		{"\\","alias for =!", cmd_rap_run, NULL, &rap_run_help},
7545 		{"'", "alias for =!", cmd_rap_run, NULL, &rap_run_help},
7546 		{"0", "alias for s 0x", cmd_ox, NULL, &zero_help},
7547 		{"a", "analysis", cmd_anal, cmd_anal_init, &anal_help},
7548 		{"b", "change block size", cmd_bsize, NULL, &b_help},
7549 		{"c", "compare memory", cmd_cmp, cmd_cmp_init, &c_help},
7550 		{"C", "code metadata", cmd_meta, cmd_meta_init, &C_help},
7551 		{"d", "debugger operations", cmd_debug, cmd_debug_init, &d_help},
7552 		{"e", "evaluate configuration variable", cmd_eval, cmd_eval_init, &e_help},
7553 		{"f", "get/set flags", cmd_flag, cmd_flag_init, &f_help},
7554 		{"g", "egg manipulation", cmd_egg, cmd_egg_init, &g_help},
7555 		{"i", "get file info", cmd_info, cmd_info_init, &i_help},
7556 		{"k", "perform sdb query", cmd_kuery, NULL, &k_help},
7557 		{"l", "list files and directories", cmd_ls, NULL, &l_help},
7558 		{"j", "join the contents of the two files", cmd_join, NULL, &j_help},
7559 		{"h", "show the top n number of line in file", cmd_head, NULL, &h_help},
7560 		{"L", "manage dynamically loaded plugins", cmd_plugins, NULL, &L_help},
7561 		{"m", "mount filesystem", cmd_mount, cmd_mount_init, &m_help},
7562 		{"o", "open or map file", cmd_open, cmd_open_init, &o_help},
7563 		{"p", "print current block", cmd_print, cmd_print_init, &p_help},
7564 		{"P", "project", cmd_project, cmd_project_init, &P_help},
7565 		{"q", "exit program session", cmd_quit, cmd_quit_init, &q_help},
7566 		{"Q", "alias for q!", cmd_Quit, NULL, &Q_help},
7567 		{":", "long commands starting with :", cmd_colon, NULL, &colon_help},
7568 		{"r", "change file size", cmd_resize, NULL, &r_help},
7569 		{"s", "seek to an offset", cmd_seek, cmd_seek_init, &s_help},
7570 		{"t", "type information (cparse)", cmd_type, cmd_type_init, &t_help},
7571 		{"T", "Text log utility", cmd_log, cmd_log_init, &T_help},
7572 		{"u", "uname/undo", cmd_undo, NULL, &u_help},
7573 		{"<", "pipe into RCons.readChar", cmd_pipein, NULL, &pipein_help},
7574 		{"V", "enter visual mode", cmd_visual, NULL, &V_help},
7575 		{"v", "enter visual mode", cmd_panels, NULL, &v_help},
7576 		{"w", "write bytes", cmd_write, cmd_write_init, &w_help, &w_group_help, R_CMD_DESC_TYPE_GROUP, w_handler},
7577 		{"x", "alias for px", cmd_hexdump, NULL, &x_help},
7578 		{"y", "yank bytes", cmd_yank, NULL, &y_help},
7579 		{"z", "zignatures", cmd_zign, cmd_zign_init, &z_help},
7580 	};
7581 
7582 	core->rcmd = r_cmd_new ();
7583 	core->rcmd->macro.user = core;
7584 	core->rcmd->macro.num = core->num;
7585 	core->rcmd->macro.cmd = core_cmd0_wrapper;
7586 	core->rcmd->nullcallback = r_core_cmd_nullcallback;
7587 	core->rcmd->macro.cb_printf = (PrintfCallback)r_cons_printf;
7588 	r_cmd_set_data (core->rcmd, core);
7589 	core->cmd_descriptors = r_list_newf (free);
7590 
7591 	RCmdDesc *root = r_cmd_get_root (core->rcmd);
7592 	size_t i;
7593 	for (i = 0; i < R_ARRAY_SIZE (cmds); i++) {
7594 		r_cmd_add (core->rcmd, cmds[i].cmd, cmds[i].cb);
7595 
7596 		RCmdDesc *cd = NULL;
7597 		switch (cmds[i].type) {
7598 		case R_CMD_DESC_TYPE_OLDINPUT:
7599 			cd = r_cmd_desc_oldinput_new (core->rcmd, root, cmds[i].cmd, cmds[i].cb, cmds[i].help);
7600 			break;
7601 		case R_CMD_DESC_TYPE_ARGV:
7602 			cd = r_cmd_desc_argv_new (core->rcmd, root, cmds[i].cmd, cmds[i].argv_cb, cmds[i].help);
7603 			break;
7604 		case R_CMD_DESC_TYPE_INNER:
7605 			cd = r_cmd_desc_inner_new (core->rcmd, root, cmds[i].cmd, cmds[i].help);
7606 			break;
7607 		case R_CMD_DESC_TYPE_GROUP:
7608 			cd = r_cmd_desc_group_new (core->rcmd, root, cmds[i].cmd, cmds[i].argv_cb, cmds[i].help, cmds[i].group_help);
7609 			break;
7610 		}
7611 		if (cd && cmds[i].descriptor_init) {
7612 			cmds[i].descriptor_init (core, cd);
7613 		}
7614 	}
7615 	DEFINE_CMD_DESCRIPTOR_SPECIAL (core, $, dollar);
7616 	DEFINE_CMD_DESCRIPTOR_SPECIAL (core, %, percent);
7617 	DEFINE_CMD_DESCRIPTOR_SPECIAL (core, *, star);
7618 	DEFINE_CMD_DESCRIPTOR_SPECIAL (core, ., dot);
7619 	DEFINE_CMD_DESCRIPTOR_SPECIAL (core, =, equal);
7620 
7621 	DEFINE_CMD_DESCRIPTOR (core, b);
7622 	DEFINE_CMD_DESCRIPTOR (core, k);
7623 	DEFINE_CMD_DESCRIPTOR (core, r);
7624 	DEFINE_CMD_DESCRIPTOR (core, u);
7625 	DEFINE_CMD_DESCRIPTOR (core, y);
7626 	cmd_descriptor_init (core);
7627 }
7628