From a89690d10f175cac792c829ed042c0e6f65eb4e2 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Tue, 6 Nov 2018 15:34:11 +0200 Subject: [PATCH] shell: Add APIs to set number of arguments This allows the shell core to perform precheck before calling the handler which then can assume the number of arguments is correct. Signed-off-by: Luiz Augusto von Dentz --- doc/subsystems/shell/shell.rst | 3 ++ include/shell/shell.h | 76 ++++++++++++++++++++++++++++++---- subsys/shell/shell.c | 67 ++++++++++++++++++++++-------- 3 files changed, 120 insertions(+), 26 deletions(-) diff --git a/doc/subsystems/shell/shell.rst b/doc/subsystems/shell/shell.rst index 9c8ef384d57..008f0238eed 100644 --- a/doc/subsystems/shell/shell.rst +++ b/doc/subsystems/shell/shell.rst @@ -78,7 +78,10 @@ Use the following macros for adding shell commands: * :c:macro:`SHELL_CMD_REGISTER` - Create root command. All root commands must have different name. +* :c:macro:`SHELL_CMD_ARG_REGISTER` - Create root command with arguments. + All root commands must have different name. * :c:macro:`SHELL_CMD` - Initialize a command. +* :c:macro:`SHELL_CMD_ARG` - Initialize a command with arguments. * :c:macro:`SHELL_CREATE_STATIC_SUBCMD_SET` - Create a static subcommands array. * :c:macro:`SHELL_SUBCMD_SET_END` - shall be placed as last in diff --git a/include/shell/shell.h b/include/shell/shell.h index 2025ca2ef4e..78a46af734c 100644 --- a/include/shell/shell.h +++ b/include/shell/shell.h @@ -71,6 +71,22 @@ struct shell_cmd_entry { struct shell; +/** + * @brief Initializes a shell command arguments + * + * @param[in] _mandatory Number of mandatory arguments. + * @param[in] _optional Number of optional arguments. + */ +#define SHELL_ARG(_mandatory, _optional) { \ + .mandatory = _mandatory, \ + .optional = _optional, \ +} + +struct shell_static_args { + u8_t mandatory; /*!< Number of mandatory arguments. */ + u8_t optional; /*!< Number of optional arguments. */ +}; + /** * @brief Shell command handler prototype. */ @@ -85,10 +101,37 @@ struct shell_static_entry { const char *help; /*!< Command help string. */ const struct shell_cmd_entry *subcmd; /*!< Pointer to subcommand. */ shell_cmd_handler handler; /*!< Command handler. */ + const struct shell_static_args *args; /*!< Command arguments. */ }; /** - * @brief Macro for defining and adding a root command (level 0). + * @brief Macro for defining and adding a root command (level 0) with + * arguments. + * + * @note Each root command shall have unique syntax. + * + * @param[in] syntax Command syntax (for example: history). + * @param[in] subcmd Pointer to a subcommands array. + * @param[in] help Pointer to a command help string. + * @param[in] handler Pointer to a function handler. + * @param[in] mandatory Number of mandatory arguments. + * @param[in] optional Number of optional arguments. + */ +#define SHELL_CMD_ARG_REGISTER(syntax, subcmd, help, handler, \ + mandatory, optional) \ + static const struct shell_static_entry UTIL_CAT(shell_, syntax) = \ + SHELL_CMD_ARG(syntax, subcmd, help, handler, mandatory, optional); \ + static const struct shell_cmd_entry UTIL_CAT(shell_cmd_, syntax) \ + __attribute__ ((section("." \ + STRINGIFY(UTIL_CAT(shell_root_cmd_, syntax))))) \ + __attribute__((used)) = { \ + .is_dynamic = false, \ + .u.entry = &UTIL_CAT(shell_, syntax) \ + } + +/** + * @brief Macro for defining and adding a root command (level 0) with + * arguments. * * @note Each root command shall have unique syntax. * @@ -97,7 +140,7 @@ struct shell_static_entry { * @param[in] help Pointer to a command help string. * @param[in] handler Pointer to a function handler. */ -#define SHELL_CMD_REGISTER(syntax, subcmd, help, handler) \ +#define SHELL_CMD_REGISTER(syntax, subcmd, help, handler) \ static const struct shell_static_entry UTIL_CAT(shell_, syntax) = \ SHELL_CMD(syntax, subcmd, help, handler); \ static const struct shell_cmd_entry UTIL_CAT(shell_cmd_, syntax) \ @@ -140,6 +183,26 @@ struct shell_static_entry { .u.dynamic_get = get \ } +/** + * @brief Initializes a shell command with arguments + * + * @param[in] _syntax Command syntax (for example: history). + * @param[in] _subcmd Pointer to a subcommands array. + * @param[in] _help Pointer to a command help string. + * @param[in] _handler Pointer to a function handler. + * @param[in] _mandatory Number of mandatory arguments. + * @param[in] _optional Number of optional arguments. + */ +#define SHELL_CMD_ARG(_syntax, _subcmd, _help, _handler, \ + _mandatory, _optional) { \ + .syntax = (const char *)STRINGIFY(_syntax), \ + .subcmd = _subcmd, \ + .help = (const char *)_help, \ + .handler = _handler, \ + .args = _mandatory ? \ + (&(struct shell_static_args) SHELL_ARG(_mandatory, _optional)) : NULL\ +} + /** * @brief Initializes a shell command. * @@ -148,12 +211,9 @@ struct shell_static_entry { * @param[in] _help Pointer to a command help string. * @param[in] _handler Pointer to a function handler. */ -#define SHELL_CMD(_syntax, _subcmd, _help, _handler) { \ - .syntax = (const char *)STRINGIFY(_syntax), \ - .subcmd = _subcmd, \ - .help = (const char *)_help, \ - .handler = _handler \ -} +#define SHELL_CMD(_syntax, _subcmd, _help, _handler) \ + SHELL_CMD_ARG(_syntax, _subcmd, _help, _handler, 0, 0) + /** * @internal @brief Internal shell state in response to data received from the diff --git a/subsys/shell/shell.c b/subsys/shell/shell.c index d6cd133aca5..6d0be617904 100644 --- a/subsys/shell/shell.c +++ b/subsys/shell/shell.c @@ -946,6 +946,53 @@ static const struct shell_cmd_entry *root_cmd_find(const char *syntax) return NULL; } +static int exec_cmd(const struct shell *shell, size_t argc, char **argv) +{ + int ret_val = 0; + + if (shell->ctx->active_cmd.handler == NULL) { + if (shell->ctx->active_cmd.help) { + shell_help_print(shell, NULL, 0); + } else { + shell_fprintf(shell, SHELL_ERROR, + SHELL_MSG_SPECIFY_SUBCOMMAND); + ret_val = -ENOEXEC; + goto clear; + } + } + + if (shell->ctx->active_cmd.args) { + const struct shell_static_args *args; + + args = shell->ctx->active_cmd.args; + + if (args->optional > 0) { + /* Check if argc is within allowed range */ + ret_val = shell_cmd_precheck(shell, + ((argc >= args->mandatory) + && + (argc <= args->mandatory + + args->optional)), + NULL, 0); + } else { + /* Perform exact match if there are no optional args */ + ret_val = shell_cmd_precheck(shell, + (args->mandatory == argc), + NULL, 0); + } + } + + if (!ret_val) { + ret_val = shell->ctx->active_cmd.handler(shell, argc, argv); + } + +clear: + help_flag_clear(shell); + + return ret_val; +} + + /* Function is analyzing the command buffer to find matching commands. Next, it * invokes the last recognized command which has a handler and passes the rest * of command buffer as arguments. @@ -959,7 +1006,6 @@ static int shell_execute(const struct shell *shell) size_t cmd_lvl = SHELL_CMD_ROOT_LVL; size_t cmd_with_handler_lvl = 0; bool wildcard_found = false; - int ret_val = 0; size_t cmd_idx; size_t argc; char quote; @@ -1102,23 +1148,8 @@ static int shell_execute(const struct shell *shell) } /* Executing the deepest found handler. */ - if (shell->ctx->active_cmd.handler == NULL) { - if (shell->ctx->active_cmd.help) { - shell_help_print(shell, NULL, 0); - } else { - shell_fprintf(shell, SHELL_ERROR, - SHELL_MSG_SPECIFY_SUBCOMMAND); - ret_val = -ENOEXEC; - } - } else { - ret_val = shell->ctx->active_cmd.handler(shell, - argc - cmd_with_handler_lvl, - &argv[cmd_with_handler_lvl]); - } - - help_flag_clear(shell); - - return ret_val; + return exec_cmd(shell, argc - cmd_with_handler_lvl, + &argv[cmd_with_handler_lvl]); } static void shell_transport_evt_handler(enum shell_transport_evt evt_type,