rizin/libr/core/cmd_macro.c
Riccardo Schirone c1c54be39e Change macro syntax to use ; instead of ,
This change is to ease the switch to the new parser and make the syntax
more consistent and easy. As things were before this patch, ',' could be
part of an argument of a command, but at the same time it was used as a
separator when defining a new macro. This difference in how `,` is
interpreter, makes parsing commands harder, as grep specifiers,
arguments, etc. should be parsed differently based on whether they are
inside a macro body or not.

By switching to using `;` as separator in the macro body, arguments,
grep specifiers, etc. can be parsed as they would be outside of a macro
body, making the new parser more consistent and easier.
2020-03-11 00:11:01 +01:00

92 lines
2.1 KiB
C

/* radare - LGPL - Copyright 2009-2014 - pancake */
#include "r_cmd.h"
#include "r_core.h"
static const char *help_msg_lparen[] = {
"Usage:", "(foo args;cmd1;cmd2;..)", "Aliases",
"(foo args;..;..)", "", "define a macro",
"(foo args;..;..)()", "", "define and call a macro",
"(-foo)", "", "remove a macro",
".(foo)", "", "to call it",
"()", "", "break inside macro",
"(*", "", "list all defined macros",
"", "Argument support:", "",
"(foo x y; $0 @ $1)", "", "define fun with args (x - $0; y - $1)",
".(foo 128 0x804800)", "", "call it with args",
"", "Iterations:", "",
".(foo;() $@)", "", "define iterator returning iter index",
"x @@ .(foo)", "", "iterate over them",
NULL
};
static void cmd_macro_init(RCore *core) {
RCmdDescriptor *d = R_NEW0 (RCmdDescriptor);
if (d) {
d->cmd = "(";
d->help_msg = help_msg_lparen;
r_list_append (core->cmd_descriptors, d);
}
}
static int cmd_macro(void *data, const char *input) {
char *buf = NULL;
RCore *core = (RCore*)data;
switch (*input) {
case ')':
r_cmd_macro_break (&core->rcmd->macro, input + 1);
break;
case '-':
r_cmd_macro_rm (&core->rcmd->macro, input + 1);
break;
case '*':
r_cmd_macro_meta (&core->rcmd->macro);
break;
case '\0':
r_cmd_macro_list (&core->rcmd->macro);
break;
case '(':
case '?':
r_core_cmd_help (core, help_msg_lparen);
break;
default: {
// XXX: stop at first ')'. if next is '(' and last
//int lastiscp = input[strlen (input)-1] == ')';
int mustcall = 0;
int i, j = 0;
buf = strdup (input);
for (i = 0; buf[i]; i++) {
switch (buf[i]) {
case '(':
j++;
break;
case ')':
j--;
if (buf[i+1] =='(') {
buf[i + 1] = 0;
mustcall = i + 2;
}
break;
}
}
buf[strlen (buf) - 1]=0;
r_cmd_macro_add (&core->rcmd->macro, buf);
if (mustcall) {
char *comma = strchr (buf, ' ');
if (!comma) {
comma = strchr (buf, ';');
}
if (comma) {
*comma = ' ';
memmove (comma + 1, buf + mustcall, strlen (buf + mustcall) + 1);
r_cmd_macro_call (&core->rcmd->macro, buf);
} else {
eprintf ("Invalid syntax for macro\n");
}
}
free (buf);
} break;
}
return 0;
}