From 652df7f49730341a7155316dafcd01ee65cc1764 Mon Sep 17 00:00:00 2001 From: Riccardo Schirone Date: Fri, 24 Jul 2020 08:23:56 +0200 Subject: [PATCH] Add `r_cmd_desc_remove` API to unregister commands (#17349) --- libr/core/cmd_api.c | 54 +++++++++++++++++++++++++++++++++----------- libr/include/r_cmd.h | 2 +- test/unit/test_cmd.c | 29 ++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 14 deletions(-) diff --git a/libr/core/cmd_api.c b/libr/core/cmd_api.c index 1e7f6153b3..a8b75a742d 100644 --- a/libr/core/cmd_api.c +++ b/libr/core/cmd_api.c @@ -30,6 +30,34 @@ static bool cmd_desc_set_parent(RCmdDesc *cd, RCmdDesc *parent) { return true; } +static void cmd_desc_unset_parent(RCmdDesc *cd) { + r_return_if_fail (cd && cd->parent); + RCmdDesc *parent = cd->parent; + r_pvector_remove_data (&parent->children, cd); + parent->n_children--; + cd->parent = NULL; +} + +static void cmd_desc_remove_from_ht_cmds(RCmd *cmd, RCmdDesc *cd) { + void **it_cd; + bool res = ht_pp_delete (cmd->ht_cmds, cd->name); + r_return_if_fail (res); + r_cmd_desc_children_foreach (cd, it_cd) { + RCmdDesc *child_cd = *it_cd; + cmd_desc_remove_from_ht_cmds (cmd, child_cd); + } +} + +static void cmd_desc_free(RCmdDesc *cd) { + if (!cd) { + return; + } + + r_pvector_clear (&cd->children); + free (cd->name); + free (cd); +} + static RCmdDesc *create_cmd_desc(RCmd *cmd, RCmdDesc *parent, RCmdDescType type, const char *name, const RCmdDescHelp *help) { RCmdDesc *res = R_NEW0 (RCmdDesc); if (!res) { @@ -42,14 +70,14 @@ 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)r_cmd_desc_free); + r_pvector_init (&res->children, (RPVectorFree)cmd_desc_free); if (!ht_pp_insert (cmd->ht_cmds, name, res)) { goto err; } cmd_desc_set_parent (res, parent); return res; err: - r_cmd_desc_free (res); + cmd_desc_free (res); return NULL; } @@ -97,7 +125,7 @@ R_API RCmd *r_cmd_free(RCmd *cmd) { R_FREE (cmd->cmds[i]); } } - r_cmd_desc_free (cmd->root_cmd_desc); + cmd_desc_free (cmd->root_cmd_desc); free (cmd); return NULL; } @@ -1132,17 +1160,17 @@ R_API RCmdDesc *r_cmd_desc_oldinput_new(RCmd *cmd, RCmdDesc *parent, const char return res; } -R_API void r_cmd_desc_free(RCmdDesc *cd) { - if (!cd) { - return; - } - - r_pvector_clear (&cd->children); - free (cd->name); - free (cd); -} - R_API RCmdDesc *r_cmd_desc_parent(RCmdDesc *cd) { r_return_val_if_fail (cd, NULL); return cd->parent; } + +R_API bool r_cmd_desc_remove(RCmd *cmd, RCmdDesc *cd) { + r_return_val_if_fail (cmd && cd, false); + if (cd->parent) { + cmd_desc_unset_parent (cd); + } + cmd_desc_remove_from_ht_cmds (cmd, cd); + cmd_desc_free (cd); + return true; +} diff --git a/libr/include/r_cmd.h b/libr/include/r_cmd.h index 0f14b3929b..b038a17369 100644 --- a/libr/include/r_cmd.h +++ b/libr/include/r_cmd.h @@ -167,8 +167,8 @@ R_API char *r_cmd_get_help(RCmd *cmd, RCmdParsedArgs *args, bool use_color); /* 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_oldinput_new(RCmd *cmd, RCmdDesc *parent, const char *name, RCmdCb cb, const RCmdDescHelp *help); -R_API void r_cmd_desc_free(RCmdDesc *cd); R_API RCmdDesc *r_cmd_desc_parent(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) diff --git a/test/unit/test_cmd.c b/test/unit/test_cmd.c index 3fcf2057ff..c08913d0cf 100644 --- a/test/unit/test_cmd.c +++ b/test/unit/test_cmd.c @@ -385,6 +385,34 @@ bool test_cmd_oldinput_help(void) { mu_end; } +bool test_remove_cmd(void) { + RCmd *cmd = r_cmd_new (); + RCmdDesc *root = r_cmd_get_root (cmd); + RCmdDesc *x_cd = r_cmd_desc_argv_new (cmd, root, "x", NULL, NULL); + RCmdDesc *p_cd = r_cmd_desc_argv_new (cmd, root, "p", NULL, NULL); + RCmdDesc *pd_cd = r_cmd_desc_argv_new (cmd, p_cd, "pd", pd_handler, NULL); + r_cmd_desc_argv_new (cmd, p_cd, "px", pd_handler, NULL); + + mu_assert_ptreq (r_cmd_get_desc (cmd, "x"), x_cd, "x is found"); + mu_assert_ptreq (r_cmd_get_desc (cmd, "pd"), pd_cd, "pd is found"); + mu_assert_eq (root->n_children, 2, "root has 2 commands as children"); + r_cmd_desc_remove (cmd, p_cd); + mu_assert_eq (root->n_children, 1, "p was removed, now root has 1 command as children"); + mu_assert_null (r_cmd_get_desc (cmd, "p"), "p should not be found anymore"); + mu_assert_null (r_cmd_get_desc (cmd, "pd"), "pd should not be found anymore"); + mu_assert_null (r_cmd_get_desc (cmd, "px"), "px should not be found anymore"); + + void **it_cd; + r_cmd_desc_children_foreach (root, it_cd) { + RCmdDesc *cd = *it_cd; + mu_assert_ptrneq (cd, p_cd, "p should not be found anymore"); + } + + r_cmd_free (cmd); + r_cons_free (); + mu_end; +} + int all_tests() { mu_run_test (test_parsed_args_noargs); mu_run_test (test_parsed_args_onearg); @@ -401,6 +429,7 @@ int all_tests() { mu_run_test (test_cmd_help); mu_run_test (test_cmd_group_help); mu_run_test (test_cmd_oldinput_help); + mu_run_test (test_remove_cmd); return tests_passed != tests_run; }