Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 36 additions & 62 deletions libr/core/cmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -155,12 +155,9 @@ static RCoreHelpMessage help_msg_l = {

static RCoreHelpMessage help_msg_quote = {
"Usage:", "\"[\"..|..\"]", "quote the command to avoid evaluating special characters",
"\"?", "", "show this help, NOTE that a single quote is simpler and works the same",
"\"?", "", "show this help",
"\"", "?e hello \\\"world\\\"\"", "print (hello \"world\")",
"\"", "?e x;y\";\"?e y;x\"", "run two commands (prints x;y\ny;x)",
"\"\"", "[cmd]", "directly call a command ignoring all special chars (fast)",
"\"\"@addr\"\"", "[cmd]", "call a command with a temporal seek (EXPERIMENTAL)",
"\"\"?e x;y\";\"?e y;x", "", "run two commands ignoring special chars (prints x;y\";\"?e y;x) ",
NULL
};

Expand Down Expand Up @@ -3933,67 +3930,45 @@ static char *find_ch_after_macro(char *ptr, char ch) {
}

static int handle_command_call(RCore *core, const char *cmd) {
const char cmd0 = *cmd;
if (cmd0 != '\'' && cmd0 != '"') {
if (*cmd != '\'') {
return -1;
}
if (R_UNLIKELY (*cmd == '\'')) {
bool isaddr = cmd[1] == '@';
if (!strcmp (cmd, "'?")) {
r_core_cmd_help (core, help_msg_single_quote);
return true;
}
if (isaddr) {
cmd += 2;
bool isaddr = cmd[1] == '@';
if (!strcmp (cmd, "'?")) {
r_core_cmd_help (core, help_msg_single_quote);
return true;
}
if (isaddr) {
cmd += 2;
} else {
cmd++;
}
if (isaddr || r_str_startswith (cmd, "0x")) {
int res = 1;
char *arg = strdup (cmd);
Comment on lines +3947 to +3948
char *end = strstr (arg, "'");
if (end) {
*end = 0;
cmd = end + 1;
ut64 addr = core->addr;
ut64 at = r_num_math (core->num, arg);
r_core_seek (core, at, true);
res = r_core_call (core, cmd);
r_core_seek (core, addr, true);
free (arg);
} else {
cmd++;
}
if (isaddr || r_str_startswith (cmd, "0x")) {
int res = 1;
char *arg = strdup (cmd);
char *end = strstr (arg, "'");
if (end) {
*end = 0;
cmd = end + 1;
ut64 addr = core->addr;
ut64 at = r_num_math (core->num, arg);
r_core_seek (core, at, true);
res = r_core_call (core, cmd);
r_core_seek (core, addr, true);
free (arg);
} else {
R_LOG_ERROR ("Invalid syntax, expected \"'@addr'command\"");
free (arg);
}
return res;
R_LOG_ERROR ("Invalid syntax, expected \"'@addr'command\"");
free (arg);
}
return r_core_call (core, cmd);
return res;
}
if (R_UNLIKELY (r_str_startswith (cmd, "\"\""))) {
R_LOG_DEBUG ("The double quote syntax is now deprecated, use the single quote instead");
// R2_600 - deprecate "" -> use ' <---------- discuss!
if (cmd[2] == '@') {
int res = 1;
char *arg = strdup (cmd + 2);
char *end = strstr (arg, "\"\"");
if (!end) {
R_LOG_ERROR ("Invalid syntax, expected \"\"@addr\"\"command");
free (arg);
} else {
*end = 0;
cmd = end + 2;
ut64 addr = core->addr;
ut64 at = r_num_math (core->num, arg + 1);
r_core_seek (core, at, true);
res = r_core_call (core, cmd);
r_core_seek (core, addr, true);
free (arg);
}
return res;
}
return r_core_call (core, cmd + 2);
return r_core_call (core, cmd);
}

static void remove_leading_empty_quotes(char *cmd) {
while (r_str_startswith (cmd, "\"\"")) {
memmove (cmd, cmd + 2, strlen (cmd + 2) + 1);
}
Comment on lines +3968 to 3971
return -1;
}

static int r_core_cmd_subst(RCore *core, char *cmd) {
Expand All @@ -4009,9 +3984,6 @@ static int r_core_cmd_subst(RCore *core, char *cmd) {
return res;
}
if (R_UNLIKELY (r_str_startswith (cmd, "?t"))) {
if (r_str_startswith (cmd + 2, "\"\"")) {
return r_core_callf (core, "?t'%s", cmd + 4);
}
if (r_str_startswith (cmd + 2, "'")) {
return r_core_callf (core, "?t'%s", cmd + 3);
}
Expand Down Expand Up @@ -4047,6 +4019,7 @@ static int r_core_cmd_subst(RCore *core, char *cmd) {
}
cmd = (char *)r_str_trim_head_ro (icmd);
r_str_trim_tail (cmd);
remove_leading_empty_quotes (cmd);
rep = isdigit ((ut8)*cmd)? strtoull (cmd, NULL, 10): 0;
R_CRITICAL_LEAVE (core);
// lines starting with # are ignored (never reach cmd_hash()), except #! and #?
Expand Down Expand Up @@ -4571,6 +4544,7 @@ static int r_core_cmd_subst_i(RCore *core, char *cmd, char *colon, bool *tmpseek
return 0;
}
r_str_trim (cmd);
remove_leading_empty_quotes (cmd);

R_CRITICAL_LEAVE (core);
/* quoted / raw command */
Expand Down
2 changes: 1 addition & 1 deletion test/db/cmd/cmd_fnj
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ fj~{} > $fj
$fj~__throw_length_error_char_const_
fnj~{} > $fnj
$fnj~__throw_length_error_char_const_
""js a=r2.cmdj("fj").filter((x)=>x.name.indexOf("throw") !== -1);console.log(JSON.stringify(a,null, 2))
'js a=r2.cmdj("fj").filter((x)=>x.name.indexOf("throw") !== -1);console.log(JSON.stringify(a,null, 2))
EOF
EXPECT=<<EOF
"name": "sym.imp.std::__throw_length_error_char_const_",
Expand Down
30 changes: 15 additions & 15 deletions test/db/cmd/cmd_js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ NAME=qjs async test
BROKEN=1
FILE=-
CMDS=<<EOF
""js import("r2pipe").then((r2pipe)=> {console.log(r2pipe.open());}).catch(console.error);
'js import("r2pipe").then((r2pipe)=> {console.log(r2pipe.open());}).catch(console.error);
EOF
EXPECT=<<EOF
[object Object]
Expand All @@ -34,26 +34,26 @@ FILE=-
CMDS=<<EOF
Lc~qjs?
?e
""js (function() { function examplePlugin() { function coreCall(input) { if (input.startsWith("t1")) { console.log("This is a QJS test"); return true; } return false; } return { name: "qjs-example", desc: "Example QJS plugin (type 't1') in the r2 shell", call: coreCall, }; }; console.log("load qjs-example", r2.plugin("core", examplePlugin)); })();
'js (function() { function examplePlugin() { function coreCall(input) { if (input.startsWith("t1")) { console.log("This is a QJS test"); return true; } return false; } return { name: "qjs-example", desc: "Example QJS plugin (type 't1') in the r2 shell", call: coreCall, }; }; console.log("load qjs-example", r2.plugin("core", examplePlugin)); })();
Lc~qjs
?e
""js (function() { function examplePlugin() { function coreCall(input) { if (input.startsWith("t1")) { console.log("This is a QJS test"); return true; } return false; } return { name: "qjs-example", desc: "Example QJS plugin (type 't1') in the r2 shell", call: coreCall, }; }; console.log("load qjs-example", r2.plugin("core", examplePlugin)); })();
'js (function() { function examplePlugin() { function coreCall(input) { if (input.startsWith("t1")) { console.log("This is a QJS test"); return true; } return false; } return { name: "qjs-example", desc: "Example QJS plugin (type 't1') in the r2 shell", call: coreCall, }; }; console.log("load qjs-example", r2.plugin("core", examplePlugin)); })();
Lc~qjs
?e
""js (function() { function examplePlugin2() { function coreCall(input) { if (input.startsWith("t2")) { console.log("This is another QJS test"); return true; } return false; } return { name: "qjs-example2", desc: "Example QJS plugin (type 't2') in the r2 shell", call: coreCall, }; }; console.log("load qjs-example2", r2.plugin("core", examplePlugin2)); })();
'js (function() { function examplePlugin2() { function coreCall(input) { if (input.startsWith("t2")) { console.log("This is another QJS test"); return true; } return false; } return { name: "qjs-example2", desc: "Example QJS plugin (type 't2') in the r2 shell", call: coreCall, }; }; console.log("load qjs-example2", r2.plugin("core", examplePlugin2)); })();
Lc~qjs
t1
t2
""js console.log("unload unknown", r2.unload("core", "unknownPlugin"))
'js console.log("unload unknown", r2.unload("core", "unknownPlugin"))
Lc~qjs
?e
""js console.log("unload qjs-example", r2.unload("core", "qjs-example"))
'js console.log("unload qjs-example", r2.unload("core", "qjs-example"))
Lc~qjs
?e
""js console.log("unload qjs-example again", r2.unload("core", "qjs-example"))
'js console.log("unload qjs-example again", r2.unload("core", "qjs-example"))
Lc~qjs
?e
""js console.log("unload qjs-example2", r2.unload("core", "qjs-example2"))
'js console.log("unload qjs-example2", r2.unload("core", "qjs-example2"))
?e
Lc~qjs?
EOF
Expand Down Expand Up @@ -96,25 +96,25 @@ FILE=-
CMDS=<<EOF
LA~qjs?
?e
""js (function() { function archPlugin() { return { name: "myarch qjs plugin", arch: "myarch_qjs", desc: "this is a test arch", license: "LGPL3", decode: function(op) { op.mnemonic = "nop"; return true; } } }; console.log('load plugin1', r2.plugin("arch", archPlugin)); })()
'js (function() { function archPlugin() { return { name: "myarch qjs plugin", arch: "myarch_qjs", desc: "this is a test arch", license: "LGPL3", decode: function(op) { op.mnemonic = "nop"; return true; } } }; console.log('load plugin1', r2.plugin("arch", archPlugin)); })()
LA~qjs
?e
""js (function() { function archPlugin() { return { name: "myarch qjs plugin", arch: "myarch_qjs", desc: "this is a test arch", license: "LGPL3", decode: function(op) { op.mnemonic = "nop"; return true; } } }; console.log('load plugin1 again', r2.plugin("arch", archPlugin)); })()
'js (function() { function archPlugin() { return { name: "myarch qjs plugin", arch: "myarch_qjs", desc: "this is a test arch", license: "LGPL3", decode: function(op) { op.mnemonic = "nop"; return true; } } }; console.log('load plugin1 again', r2.plugin("arch", archPlugin)); })()
LA~qjs
?e
""js (function() { function archPlugin2() { return { name: "myarch qjs plugin2", arch: "myarch_qjs2", desc: "this is a test arch2", license: "LGPL3", decode: function(op) { op.mnemonic = "nop"; return true; } } }; console.log('load plugin2', r2.plugin("arch", archPlugin2)); })()
'js (function() { function archPlugin2() { return { name: "myarch qjs plugin2", arch: "myarch_qjs2", desc: "this is a test arch2", license: "LGPL3", decode: function(op) { op.mnemonic = "nop"; return true; } } }; console.log('load plugin2', r2.plugin("arch", archPlugin2)); })()
LA~qjs
?e
""js console.log("unload unknown", r2.unload("arch", "unknownPlugin"))
'js console.log("unload unknown", r2.unload("arch", "unknownPlugin"))
LA~qjs
?e
""js console.log("unload qjs-example", r2.unload("arch", "myarch_qjs"))
'js console.log("unload qjs-example", r2.unload("arch", "myarch_qjs"))
LA~qjs
?e
""js console.log("unload qjs-example again", r2.unload("arch", "myarch_qjs"))
'js console.log("unload qjs-example again", r2.unload("arch", "myarch_qjs"))
LA~qjs
?e
""js console.log("unload qjs-example2", r2.unload("arch", "myarch_qjs2"))
'js console.log("unload qjs-example2", r2.unload("arch", "myarch_qjs2"))
?e
LA~qjs?
EOF
Expand Down
24 changes: 16 additions & 8 deletions test/db/cmd/shell
Original file line number Diff line number Diff line change
Expand Up @@ -136,16 +136,24 @@ EXPECT=<<EOF
EOF
RUN

NAME=quote + quoteseek
NAME=empty leading double quotes use normal parser
FILE=malloc://32
CMDS=<<EOF
woe 1
""p8 8
""@16""p8 8
""?e ONE;?e TWO
""?e $(?e THREE)
""""?e FOUR
3""?e REPEAT
""?e "FIVE;SIX"
EOF
EXPECT=<<EOF
0001020304050607
1011121314151617
ONE
TWO
THREE
FOUR
REPEAT
REPEAT
REPEAT
FIVE;SIX
EOF
RUN

Expand Down Expand Up @@ -192,10 +200,10 @@ EXPECT=<<EOF
EOF
RUN

NAME=nested escaped or with double quote
NAME=nested escaped or after empty double quotes
FILE=malloc://32
CMDS=<<EOF
?v 4 \| `""?v 1 | 2`
?v 4 \| `""?v 1 \| 2`
EOF
EXPECT=<<EOF
0x7
Expand Down
Loading