mirror of
https://github.com/radareorg/radare2.git
synced 2025-02-04 04:28:20 +00:00
Automatically group sub-commands ##newshell (#17663)
* Add GROUP RCmdDesc type and fix where the args_str is shown * Adjust color of `[?]` * Differentiate between cmd<?> and cmd[?] <?> when cmd is not valid by itself [?] when cmd is valid but there are also other sub-commands available * Fix usage for commands like `w` that are both commands and groups * Do not automatically switch to detail=2 for leaf commands * Fix test due to change in `?`/`??` behaviour
This commit is contained in:
parent
46aff1ec53
commit
9b59074787
@ -7149,6 +7149,9 @@ R_API void r_core_cmd_init(RCore *core) {
|
||||
case R_CMD_DESC_TYPE_ARGV:
|
||||
cd = r_cmd_desc_argv_new (core->rcmd, root, cmds[i].cmd, cmds[i].argv_cb, cmds[i].help);
|
||||
break;
|
||||
case R_CMD_DESC_TYPE_GROUP:
|
||||
cd = r_cmd_desc_group_new (core->rcmd, root, cmds[i].cmd, cmds[i].help);
|
||||
break;
|
||||
}
|
||||
if (cmds[i].descriptor_init) {
|
||||
cmds[i].descriptor_init (core, cd);
|
||||
|
@ -7,6 +7,26 @@
|
||||
#include <r_cmd.h>
|
||||
#include <r_util.h>
|
||||
|
||||
/*!
|
||||
* Number of sub-commands to show as options when displaying the help of a
|
||||
* command. When a command has more options than MAX_CHILDREN_SHOW, `?` is shown
|
||||
* instead.
|
||||
*
|
||||
* Example with MAX_CHILDREN_SHOW=3:
|
||||
* w -> wa
|
||||
* -> wb
|
||||
* -> wc
|
||||
*
|
||||
* When doing `?`, you would see:
|
||||
* w[abc]
|
||||
*
|
||||
* If there is also:
|
||||
* -> wd
|
||||
* you would see:
|
||||
* w[?]
|
||||
*/
|
||||
#define MAX_CHILDREN_SHOW 7
|
||||
|
||||
static const RCmdDescHelp not_defined_help = {
|
||||
.usage = "Usage not defined",
|
||||
.summary = "Help summary not defined",
|
||||
@ -74,7 +94,7 @@ static RCmdDesc *create_cmd_desc(RCmd *cmd, RCmdDesc *parent, RCmdDescType type,
|
||||
res->n_children = 0;
|
||||
res->help = help? help: ¬_defined_help;
|
||||
r_pvector_init (&res->children, (RPVectorFree)cmd_desc_free);
|
||||
if (!ht_pp_insert (cmd->ht_cmds, name, res)) {
|
||||
if (type != R_CMD_DESC_TYPE_GROUP && !ht_pp_insert (cmd->ht_cmds, name, res)) {
|
||||
goto err;
|
||||
}
|
||||
cmd_desc_set_parent (res, parent);
|
||||
@ -396,10 +416,55 @@ static size_t strlen0(const char *s) {
|
||||
return s? strlen (s): 0;
|
||||
}
|
||||
|
||||
static void fill_usage_strbuf(RStrBuf *sb, RCmdDesc *cd, bool use_color) {
|
||||
static void fill_children_chars(RStrBuf *sb, RCmdDesc *cd) {
|
||||
if (cd->help->options) {
|
||||
r_strbuf_append (sb, cd->help->options);
|
||||
return;
|
||||
}
|
||||
|
||||
RStrBuf csb;
|
||||
r_strbuf_init (&csb);
|
||||
|
||||
void **it;
|
||||
r_cmd_desc_children_foreach (cd, it) {
|
||||
RCmdDesc *child = *(RCmdDesc **)it;
|
||||
if (r_str_startswith (child->name, cd->name) && strlen (child->name) == strlen (cd->name) + 1) {
|
||||
r_strbuf_appendf (&csb, "%c", child->name[strlen (cd->name)]);
|
||||
}
|
||||
}
|
||||
|
||||
if (r_strbuf_is_empty (&csb) || r_strbuf_length (&csb) >= MAX_CHILDREN_SHOW) {
|
||||
r_strbuf_fini (&csb);
|
||||
r_strbuf_set (&csb, "?");
|
||||
}
|
||||
|
||||
if (!cd->n_children || r_cmd_desc_has_handler (cd)) {
|
||||
r_strbuf_prepend (&csb, "[");
|
||||
r_strbuf_append (&csb, "]");
|
||||
} else {
|
||||
r_strbuf_prepend (&csb, "<");
|
||||
r_strbuf_append (&csb, ">");
|
||||
}
|
||||
r_strbuf_append (sb, r_strbuf_drain_nofree (&csb));
|
||||
}
|
||||
|
||||
static bool show_children_shortcut(RCmdDesc *cd, RCmdDesc *parent) {
|
||||
return (cd != parent && (cd->n_children || cd->help->options)) || cd->type == R_CMD_DESC_TYPE_OLDINPUT;
|
||||
}
|
||||
|
||||
static bool show_args(RCmdDesc *cd, RCmdDesc *parent) {
|
||||
return (cd->n_children == 0 || cd == parent) && cd->help->args_str;
|
||||
}
|
||||
|
||||
static bool show_group_args(RCmdDesc *cd, RCmdDesc *parent) {
|
||||
return !show_args (cd, parent) && cd->help->group_args_str;
|
||||
}
|
||||
|
||||
static void fill_usage_strbuf(RStrBuf *sb, RCmdDesc *cd, bool use_color, RCmdDesc *parent) {
|
||||
RCons *cons = r_cons_singleton ();
|
||||
const char *pal_label_color = use_color? cons->context->pal.label: "",
|
||||
*pal_args_color = use_color? cons->context->pal.args: "",
|
||||
*pal_input_color = use_color? cons->context->pal.input: "",
|
||||
*pal_help_color = use_color? cons->context->pal.help: "",
|
||||
*pal_reset = use_color? cons->context->pal.reset: "";
|
||||
|
||||
@ -407,8 +472,17 @@ static void fill_usage_strbuf(RStrBuf *sb, RCmdDesc *cd, bool use_color) {
|
||||
if (cd->help->usage) {
|
||||
r_strbuf_appendf (sb, "%s%s%s", cd->help->usage, pal_args_color, pal_reset);
|
||||
} else {
|
||||
const char *cd_args_str = cd->help->args_str? cd->help->args_str: "";
|
||||
r_strbuf_appendf (sb, "%s%s%s%s", cd->name, pal_args_color, cd_args_str, pal_reset);
|
||||
r_strbuf_appendf (sb, "%s%s", pal_input_color, cd->name);
|
||||
if (show_children_shortcut (cd, parent)) {
|
||||
r_strbuf_append (sb, pal_reset);
|
||||
fill_children_chars (sb, cd);
|
||||
}
|
||||
if (show_args (cd, parent)) {
|
||||
const char *cd_args_str = cd->help->args_str? cd->help->args_str: "";
|
||||
r_strbuf_appendf (sb, "%s%s%s", pal_args_color, cd_args_str, pal_reset);
|
||||
} else if (show_group_args (cd, parent)) {
|
||||
r_strbuf_appendf (sb, "%s%s%s", pal_args_color, cd->help->group_args_str, pal_reset);
|
||||
}
|
||||
}
|
||||
if (cd->help->group_summary) {
|
||||
r_strbuf_appendf (sb, " %s# %s%s", pal_help_color, cd->help->group_summary, pal_reset);
|
||||
@ -418,52 +492,76 @@ static void fill_usage_strbuf(RStrBuf *sb, RCmdDesc *cd, bool use_color) {
|
||||
r_strbuf_append (sb, "\n");
|
||||
}
|
||||
|
||||
static size_t update_max_len(RCmdDesc *cd, size_t max_len) {
|
||||
static size_t calc_padding_len(RCmdDesc *cd, RCmdDesc *parent) {
|
||||
size_t name_len = strlen (cd->name);
|
||||
size_t args_len = strlen0 (cd->help->args_str);
|
||||
if (name_len + args_len > max_len) {
|
||||
return name_len + args_len;
|
||||
size_t args_len = 0;
|
||||
size_t children_length = 0;
|
||||
if (show_children_shortcut (cd, parent)) {
|
||||
RStrBuf sb;
|
||||
r_strbuf_init (&sb);
|
||||
fill_children_chars (&sb, cd);
|
||||
children_length += r_strbuf_length (&sb);
|
||||
r_strbuf_fini (&sb);
|
||||
}
|
||||
return max_len;
|
||||
if (show_args (cd, parent)) {
|
||||
args_len = strlen0 (cd->help->args_str);
|
||||
} else if (show_group_args (cd, parent)) {
|
||||
args_len = strlen0 (cd->help->group_args_str);
|
||||
}
|
||||
return name_len + args_len + children_length;
|
||||
}
|
||||
|
||||
static void print_child_help(RStrBuf *sb, RCmdDesc *cd, size_t max_len, bool use_color) {
|
||||
size_t str_len = strlen (cd->name) + strlen0 (cd->help->args_str);
|
||||
static size_t update_max_len(RCmdDesc *cd, size_t max_len, RCmdDesc *parent) {
|
||||
size_t val = calc_padding_len (cd, parent);
|
||||
return val > max_len? val: max_len;
|
||||
}
|
||||
|
||||
static void print_child_help(RStrBuf *sb, RCmdDesc *cd, size_t max_len, bool use_color, RCmdDesc *parent) {
|
||||
size_t str_len = calc_padding_len (cd, parent);
|
||||
size_t padding = str_len < max_len? max_len - str_len: 0;
|
||||
const char *cd_args_str = cd->help->args_str? cd->help->args_str: "";
|
||||
const char *cd_summary = cd->help->summary? cd->help->summary: "";
|
||||
|
||||
RCons *cons = r_cons_singleton ();
|
||||
const char *pal_args_color = use_color? cons->context->pal.args: "",
|
||||
*pal_opt_color = use_color? cons->context->pal.reset: "",
|
||||
*pal_help_color = use_color? cons->context->pal.help: "",
|
||||
*pal_input_color = use_color? cons->context->pal.input: "",
|
||||
*pal_reset = use_color? cons->context->pal.reset: "";
|
||||
|
||||
r_strbuf_appendf (sb, "| %s%s%s%s %*s%s# %s%s\n", pal_input_color, cd->name,
|
||||
pal_args_color, cd_args_str, padding, "", pal_help_color, cd_summary, pal_reset);
|
||||
r_strbuf_appendf (sb, "| %s%s", pal_input_color, cd->name);
|
||||
if (show_children_shortcut (cd, parent)) {
|
||||
r_strbuf_append (sb, pal_opt_color);
|
||||
fill_children_chars (sb, cd);
|
||||
}
|
||||
if (show_args (cd, parent)) {
|
||||
r_strbuf_appendf (sb, "%s%s", pal_args_color, cd->help->args_str);
|
||||
} else if (show_group_args (cd, parent)) {
|
||||
r_strbuf_appendf (sb, "%s%s", pal_args_color, cd->help->group_args_str);
|
||||
}
|
||||
r_strbuf_appendf (sb, " %*s%s# %s%s\n", padding, "", pal_help_color, cd_summary, pal_reset);
|
||||
}
|
||||
|
||||
static char *inner_get_help(RCmd *cmd, RCmdDesc *cd, bool use_color) {
|
||||
RStrBuf *sb = r_strbuf_new (NULL);
|
||||
fill_usage_strbuf (sb, cd, use_color);
|
||||
fill_usage_strbuf (sb, cd, use_color, cd->parent);
|
||||
|
||||
void **it_cd;
|
||||
size_t max_len = 0;
|
||||
|
||||
if (cd->d.argv_data.cb) {
|
||||
max_len = update_max_len (cd, max_len);
|
||||
max_len = update_max_len (cd, max_len, cd);
|
||||
}
|
||||
r_cmd_desc_children_foreach (cd, it_cd) {
|
||||
RCmdDesc *child = *(RCmdDesc **)it_cd;
|
||||
max_len = update_max_len (child, max_len);
|
||||
max_len = update_max_len (child, max_len, cd);
|
||||
}
|
||||
|
||||
if (cd->d.argv_data.cb) {
|
||||
print_child_help (sb, cd, max_len, use_color);
|
||||
print_child_help (sb, cd, max_len, use_color, cd);
|
||||
}
|
||||
r_cmd_desc_children_foreach (cd, it_cd) {
|
||||
RCmdDesc *child = *(RCmdDesc **)it_cd;
|
||||
print_child_help (sb, child, max_len, use_color);
|
||||
print_child_help (sb, child, max_len, use_color, cd);
|
||||
}
|
||||
return r_strbuf_drain (sb);
|
||||
}
|
||||
@ -477,7 +575,7 @@ static char *argv_get_help(RCmd *cmd, RCmdDesc *cd, RCmdParsedArgs *a, size_t de
|
||||
|
||||
RStrBuf *sb = r_strbuf_new (NULL);
|
||||
|
||||
fill_usage_strbuf (sb, cd, use_color);
|
||||
fill_usage_strbuf (sb, cd, use_color, cd);
|
||||
|
||||
switch (detail) {
|
||||
case 1:
|
||||
@ -545,11 +643,6 @@ R_API char *r_cmd_get_help(RCmd *cmd, RCmdParsedArgs *args, bool use_color) {
|
||||
}
|
||||
return inner_get_help (cmd, cd, use_color);
|
||||
}
|
||||
if (detail == 1 && r_pvector_empty (&cd->children)) {
|
||||
// if the current node does not have children, just
|
||||
// print the full help
|
||||
detail = 2;
|
||||
}
|
||||
return argv_get_help (cmd, cd, args, detail, use_color);
|
||||
case R_CMD_DESC_TYPE_OLDINPUT:
|
||||
return oldinput_get_help (cmd, cd, args);
|
||||
@ -1147,6 +1240,11 @@ R_API RCmdDesc *r_cmd_desc_argv_new(RCmd *cmd, RCmdDesc *parent, const char *nam
|
||||
return res;
|
||||
}
|
||||
|
||||
R_API RCmdDesc *r_cmd_desc_group_new(RCmd *cmd, RCmdDesc *parent, const char *name, const RCmdDescHelp *help) {
|
||||
r_return_val_if_fail (cmd && parent && name, NULL);
|
||||
return create_cmd_desc (cmd, parent, R_CMD_DESC_TYPE_GROUP, name, help);
|
||||
}
|
||||
|
||||
R_API RCmdDesc *r_cmd_desc_oldinput_new(RCmd *cmd, RCmdDesc *parent, const char *name, RCmdCb cb, const RCmdDescHelp *help) {
|
||||
r_return_val_if_fail (cmd && parent && name && cb, NULL);
|
||||
RCmdDesc *res = create_cmd_desc (cmd, parent, R_CMD_DESC_TYPE_OLDINPUT, name, help);
|
||||
@ -1162,6 +1260,19 @@ R_API RCmdDesc *r_cmd_desc_parent(RCmdDesc *cd) {
|
||||
return cd->parent;
|
||||
}
|
||||
|
||||
R_API bool r_cmd_desc_has_handler(RCmdDesc *cd) {
|
||||
r_return_val_if_fail (cd, false);
|
||||
switch (cd->type) {
|
||||
case R_CMD_DESC_TYPE_ARGV:
|
||||
return cd->d.argv_data.cb;
|
||||
case R_CMD_DESC_TYPE_OLDINPUT:
|
||||
return cd->d.oldinput_data.cb;
|
||||
case R_CMD_DESC_TYPE_GROUP:
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
R_API bool r_cmd_desc_remove(RCmd *cmd, RCmdDesc *cd) {
|
||||
r_return_val_if_fail (cmd && cd, false);
|
||||
if (cd->parent) {
|
||||
|
@ -213,38 +213,100 @@ const RCmdDescExample w_incdec_help_examples[] = {
|
||||
{ 0 },
|
||||
};
|
||||
|
||||
const RCmdDescHelp w_incdec_help = {
|
||||
.summary = "increment/decrement byte,word..",
|
||||
.group_args_str = " [n]",
|
||||
.options = "<1248><+->",
|
||||
};
|
||||
|
||||
const RCmdDescHelp w1_incdec_help = {
|
||||
.summary = "Increment/decrement a byte",
|
||||
.usage = "w1[+-] [n]",
|
||||
.options = "<+->",
|
||||
.args_str = " [n]",
|
||||
.description = "Increment/decrement a byte at the current offset by 1 or n, if specified",
|
||||
.examples = w_incdec_help_examples,
|
||||
};
|
||||
|
||||
const RCmdDescHelp w1_inc_help = {
|
||||
.summary = "Increment a byte",
|
||||
.args_str = " [n]",
|
||||
.description = "Increment a byte at the current offset by 1 or n, if specified",
|
||||
.examples = w_incdec_help_examples,
|
||||
};
|
||||
|
||||
const RCmdDescHelp w1_dec_help = {
|
||||
.summary = "Decrement a byte",
|
||||
.args_str = " [n]",
|
||||
.description = "Decrement a byte at the current offset by 1 or n, if specified",
|
||||
.examples = w_incdec_help_examples,
|
||||
};
|
||||
|
||||
const RCmdDescHelp w2_incdec_help = {
|
||||
.summary = "Increment/decrement a word",
|
||||
.usage = "w2[+-] [n]",
|
||||
.options = "<+->",
|
||||
.args_str = " [n]",
|
||||
.description = "Increment/decrement a word at the current offset by 1 or n, if specified",
|
||||
.examples = w_incdec_help_examples,
|
||||
};
|
||||
|
||||
const RCmdDescHelp w2_inc_help = {
|
||||
.summary = "Increment a word",
|
||||
.args_str = " [n]",
|
||||
.description = "Increment a word at the current offset by 1 or n, if specified",
|
||||
.examples = w_incdec_help_examples,
|
||||
};
|
||||
|
||||
const RCmdDescHelp w2_dec_help = {
|
||||
.summary = "Decrement a word",
|
||||
.args_str = " [n]",
|
||||
.description = "Decrement a word at the current offset by 1 or n, if specified",
|
||||
.examples = w_incdec_help_examples,
|
||||
};
|
||||
|
||||
const RCmdDescHelp w4_incdec_help = {
|
||||
.summary = "Increment/decrement a dword",
|
||||
.usage = "w4[+-] [n]",
|
||||
.options = "<+->",
|
||||
.args_str = " [n]",
|
||||
.description = "Increment/decrement a dword at the current offset by 1 or n, if specified",
|
||||
.examples = w_incdec_help_examples,
|
||||
};
|
||||
|
||||
const RCmdDescHelp w4_inc_help = {
|
||||
.summary = "Increment a dword",
|
||||
.args_str = " [n]",
|
||||
.description = "Increment a dword at the current offset by 1 or n, if specified",
|
||||
.examples = w_incdec_help_examples,
|
||||
};
|
||||
|
||||
const RCmdDescHelp w4_dec_help = {
|
||||
.summary = "Decrement a dword",
|
||||
.args_str = " [n]",
|
||||
.description = "Decrement a dword at the current offset by 1 or n, if specified",
|
||||
.examples = w_incdec_help_examples,
|
||||
};
|
||||
|
||||
const RCmdDescHelp w8_incdec_help = {
|
||||
.summary = "Increment/decrement a qword",
|
||||
.usage = "w8[+-] [n]",
|
||||
.options = "<+->",
|
||||
.args_str = " [n]",
|
||||
.description = "Increment/decrement a qword at the current offset by 1 or n, if specified",
|
||||
.examples = w_incdec_help_examples,
|
||||
};
|
||||
|
||||
const RCmdDescHelp w8_inc_help = {
|
||||
.summary = "Increment a qword",
|
||||
.args_str = " [n]",
|
||||
.description = "Increment a qword at the current offset by 1 or n, if specified",
|
||||
.examples = w_incdec_help_examples,
|
||||
};
|
||||
|
||||
const RCmdDescHelp w8_dec_help = {
|
||||
.summary = "Decrement a qword",
|
||||
.args_str = " [n]",
|
||||
.description = "Decrement a qword at the current offset by 1 or n, if specified",
|
||||
.examples = w_incdec_help_examples,
|
||||
};
|
||||
|
||||
// wB helps
|
||||
|
||||
const RCmdDescExample wB_help_examples[] = {
|
||||
@ -255,6 +317,7 @@ const RCmdDescExample wB_help_examples[] = {
|
||||
const RCmdDescHelp wB_help = {
|
||||
.summary = "Set bits with given value",
|
||||
.args_str = " [value]",
|
||||
.group_args_str = " [value]",
|
||||
.group_summary = "Set or unset bits with given value",
|
||||
.description = "Set the bits that are set in the value passed as arguments. 0 bits in the value argument are ignored, while the others are set at the current offset",
|
||||
.examples = wB_help_examples,
|
||||
@ -274,9 +337,10 @@ const RCmdDescExample wv_help_examples[] = {
|
||||
};
|
||||
|
||||
const RCmdDescHelp wv_help = {
|
||||
.usage = "wv[size] [value]",
|
||||
.summary = "Write value as 4 - bytes / 8 - bytes based on value",
|
||||
.options = "[size]",
|
||||
.args_str = " [value]",
|
||||
.group_args_str = " [value]",
|
||||
.description = "Write the number passed as argument at the current offset as a 4 - bytes value or 8 - bytes value if the input is bigger than UT32_MAX, respecting the cfg.bigendian variable",
|
||||
.group_summary = "Write value of given size",
|
||||
.examples = wv_help_examples,
|
||||
|
@ -58,10 +58,19 @@ extern const RCmdDescHelp w0_help;
|
||||
|
||||
// w[1248][+-] helps
|
||||
|
||||
extern const RCmdDescHelp w_incdec_help;
|
||||
extern const RCmdDescHelp w1_incdec_help;
|
||||
extern const RCmdDescHelp w1_inc_help;
|
||||
extern const RCmdDescHelp w1_dec_help;
|
||||
extern const RCmdDescHelp w2_incdec_help;
|
||||
extern const RCmdDescHelp w2_inc_help;
|
||||
extern const RCmdDescHelp w2_dec_help;
|
||||
extern const RCmdDescHelp w4_incdec_help;
|
||||
extern const RCmdDescHelp w4_inc_help;
|
||||
extern const RCmdDescHelp w4_dec_help;
|
||||
extern const RCmdDescHelp w8_incdec_help;
|
||||
extern const RCmdDescHelp w8_inc_help;
|
||||
extern const RCmdDescHelp w8_dec_help;
|
||||
|
||||
// wB helps
|
||||
|
||||
|
@ -2086,19 +2086,19 @@ static void cmd_write_init(RCore *core, RCmdDesc *parent) {
|
||||
|
||||
DEFINE_CMD_ARGV_DESC (core, w0, parent);
|
||||
|
||||
DEFINE_CMD_ARGV_DESC_GROUP (core, w[1248][+-], w_incdec, parent);
|
||||
DEFINE_CMD_ARGV_DESC_GROUP (core, w, w_incdec, parent);
|
||||
DEFINE_CMD_ARGV_DESC_DETAIL (core, w1, w1, w_incdec_cd, NULL, &w1_incdec_help);
|
||||
DEFINE_CMD_ARGV_DESC_DETAIL (core, w1+, w1_inc, w1_cd, w1_incdec_handler, &w1_incdec_help);
|
||||
DEFINE_CMD_ARGV_DESC_DETAIL (core, w1-, w1_dec, w1_cd, w1_incdec_handler, &w1_incdec_help);
|
||||
DEFINE_CMD_ARGV_DESC_DETAIL (core, w1+, w1_inc, w1_cd, w1_incdec_handler, &w1_inc_help);
|
||||
DEFINE_CMD_ARGV_DESC_DETAIL (core, w1-, w1_dec, w1_cd, w1_incdec_handler, &w1_dec_help);
|
||||
DEFINE_CMD_ARGV_DESC_DETAIL (core, w2, w2, w_incdec_cd, NULL, &w2_incdec_help);
|
||||
DEFINE_CMD_ARGV_DESC_DETAIL (core, w2+, w2_inc, w2_cd, w2_incdec_handler, &w2_incdec_help);
|
||||
DEFINE_CMD_ARGV_DESC_DETAIL (core, w2-, w2_dec, w2_cd, w2_incdec_handler, &w2_incdec_help);
|
||||
DEFINE_CMD_ARGV_DESC_DETAIL (core, w2+, w2_inc, w2_cd, w2_incdec_handler, &w2_inc_help);
|
||||
DEFINE_CMD_ARGV_DESC_DETAIL (core, w2-, w2_dec, w2_cd, w2_incdec_handler, &w2_dec_help);
|
||||
DEFINE_CMD_ARGV_DESC_DETAIL (core, w4, w4, w_incdec_cd, NULL, &w4_incdec_help);
|
||||
DEFINE_CMD_ARGV_DESC_DETAIL (core, w4+, w4_inc, w4_cd, w4_incdec_handler, &w4_incdec_help);
|
||||
DEFINE_CMD_ARGV_DESC_DETAIL (core, w4-, w4_dec, w4_cd, w4_incdec_handler, &w4_incdec_help);
|
||||
DEFINE_CMD_ARGV_DESC_DETAIL (core, w4+, w4_inc, w4_cd, w4_incdec_handler, &w4_inc_help);
|
||||
DEFINE_CMD_ARGV_DESC_DETAIL (core, w4-, w4_dec, w4_cd, w4_incdec_handler, &w4_dec_help);
|
||||
DEFINE_CMD_ARGV_DESC_DETAIL (core, w8, w8, w_incdec_cd, NULL, &w8_incdec_help);
|
||||
DEFINE_CMD_ARGV_DESC_DETAIL (core, w8+, w8_inc, w8_cd, w8_incdec_handler, &w8_incdec_help);
|
||||
DEFINE_CMD_ARGV_DESC_DETAIL (core, w8-, w8_dec, w8_cd, w8_incdec_handler, &w8_incdec_help);
|
||||
DEFINE_CMD_ARGV_DESC_DETAIL (core, w8+, w8_inc, w8_cd, w8_incdec_handler, &w8_inc_help);
|
||||
DEFINE_CMD_ARGV_DESC_DETAIL (core, w8-, w8_dec, w8_cd, w8_incdec_handler, &w8_dec_help);
|
||||
|
||||
DEFINE_CMD_OLDINPUT_DESC (core, w6, parent);
|
||||
DEFINE_CMD_OLDINPUT_DESC (core, wh, parent);
|
||||
|
@ -114,6 +114,15 @@ typedef struct r_cmd_desc_help_t {
|
||||
* Optional.
|
||||
*/
|
||||
const char *usage;
|
||||
/**
|
||||
* String to use as sub-commands suggestions instead of the
|
||||
* auto-generated one (e.g. [abcd] or [?] that you can see near command
|
||||
* names when doing `w?`). If not provided, the options will be
|
||||
* auto-generated.
|
||||
*
|
||||
* Optional.
|
||||
*/
|
||||
const char *options;
|
||||
/**
|
||||
* When a command is used both as a parent command and as a subcommand
|
||||
* (e.g. `w` is both the parent of `wv`, `ws`, etc. and it's also the
|
||||
@ -123,6 +132,16 @@ typedef struct r_cmd_desc_help_t {
|
||||
* Optional.
|
||||
*/
|
||||
const char *group_summary;
|
||||
/**
|
||||
* When a command is used both as a parent command and as a subcommand
|
||||
* (e.g. `w` is both the parent of `wv`, `ws`, etc. and it's also the
|
||||
* command `w`), this is the argument string used for the parent level,
|
||||
* while args_str becomes the text used for the subcommand.
|
||||
*
|
||||
* Optional.
|
||||
* TODO: explain how to differentiate between required and optional arguments
|
||||
*/
|
||||
const char *group_args_str;
|
||||
/**
|
||||
* List of examples used to better explain how to use the command. This
|
||||
* is shown together with the long description.
|
||||
@ -137,6 +156,10 @@ typedef enum {
|
||||
R_CMD_DESC_TYPE_OLDINPUT = 0,
|
||||
// for handlers that accept argc/argv
|
||||
R_CMD_DESC_TYPE_ARGV,
|
||||
// for cmd descriptors that are just used to group together related
|
||||
// sub-commands. Do not use this if the command can be used by itself or
|
||||
// if it's necessary to show its help.
|
||||
R_CMD_DESC_TYPE_GROUP,
|
||||
} RCmdDescType;
|
||||
|
||||
typedef struct r_cmd_desc_t {
|
||||
@ -198,7 +221,8 @@ typedef struct r_core_plugin_t {
|
||||
#define DEFINE_CMD_ARGV_DESC_SPECIAL(core, name, c_name, parent) \
|
||||
DEFINE_CMD_ARGV_DESC_DETAIL (core, name, c_name, parent, c_name##_handler, &c_name##_help)
|
||||
#define DEFINE_CMD_ARGV_DESC_GROUP(core, name, c_name, parent) \
|
||||
DEFINE_CMD_ARGV_DESC_DETAIL (core, name, c_name, parent, NULL, NULL)
|
||||
RCmdDesc *c_name##_cd = r_cmd_desc_group_new (core->rcmd, parent, #name, &c_name##_help); \
|
||||
r_warn_if_fail (c_name##_cd)
|
||||
#define DEFINE_CMD_ARGV_DESC(core, name, parent) \
|
||||
DEFINE_CMD_ARGV_DESC_SPECIAL (core, name, name, parent)
|
||||
#define DEFINE_CMD_OLDINPUT_DESC(core, name, parent) \
|
||||
@ -248,8 +272,10 @@ static inline int r_cmd_status2int(RCmdStatus s) {
|
||||
|
||||
/* RCmdDescriptor */
|
||||
R_API RCmdDesc *r_cmd_desc_argv_new(RCmd *cmd, RCmdDesc *parent, const char *name, RCmdArgvCb cb, const RCmdDescHelp *help);
|
||||
R_API RCmdDesc *r_cmd_desc_group_new(RCmd *cmd, RCmdDesc *parent, const char *name, const RCmdDescHelp *help);
|
||||
R_API RCmdDesc *r_cmd_desc_oldinput_new(RCmd *cmd, RCmdDesc *parent, const char *name, RCmdCb cb, const RCmdDescHelp *help);
|
||||
R_API RCmdDesc *r_cmd_desc_parent(RCmdDesc *cd);
|
||||
R_API bool r_cmd_desc_has_handler(RCmdDesc *cd);
|
||||
R_API bool r_cmd_desc_remove(RCmd *cmd, RCmdDesc *cd);
|
||||
|
||||
#define r_cmd_desc_children_foreach(root, it_cd) r_pvector_foreach (&root->children, it_cd)
|
||||
|
@ -288,8 +288,8 @@ bool test_cmd_help(void) {
|
||||
r_cmd_desc_oldinput_new (cmd, p_cd, "px", px_handler, &px_help);
|
||||
|
||||
const char *p_help_exp = "Usage: p-usage # p summary\n"
|
||||
"| pd <num> # pd summary\n"
|
||||
"| px <verylongarg_str_num> # px summary\n";
|
||||
"| pd <num> # pd summary\n"
|
||||
"| px[?] <verylongarg_str_num> # px summary\n";
|
||||
RCmdParsedArgs *a = r_cmd_parsed_args_newcmd ("p?");
|
||||
char *h = r_cmd_get_help (cmd, a, false);
|
||||
mu_assert_notnull (h, "help is not null");
|
||||
@ -297,10 +297,7 @@ bool test_cmd_help(void) {
|
||||
free (h);
|
||||
r_cmd_parsed_args_free (a);
|
||||
|
||||
const char *pd_help_exp = "Usage: pd <num> # pd summary\n"
|
||||
"\npd long description\n"
|
||||
"\nExamples:\n"
|
||||
"| pd 10 # print 10 disassembled instructions\n";
|
||||
const char *pd_help_exp = "Usage: pd <num> # pd summary\n";
|
||||
a = r_cmd_parsed_args_newcmd ("pd?");
|
||||
h = r_cmd_get_help (cmd, a, false);
|
||||
mu_assert_notnull (h, "help is not null");
|
||||
|
Loading…
x
Reference in New Issue
Block a user