shell: Add macros for creating conditional commands
Added macros which can be used to create a command which depends on compilation flag. Macros are a cleaner alternative to #ifdefs around command registration and command handler. Signed-off-by: Krzysztof Chruscinski <krzysztof.chruscinski@nordicsemi.no>
This commit is contained in:
parent
e96673dca7
commit
7e26f53470
3 changed files with 172 additions and 24 deletions
|
@ -82,10 +82,22 @@ 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_COND_CMD_REGISTER` - Conditionally (if compile time flag is
|
||||
set) 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_COND_CMD_ARG_REGISTER` - Conditionally (if compile time flag
|
||||
is set) create root command with arguments. All root commands must have
|
||||
different name.
|
||||
* :c:macro:`SHELL_CMD` - Initialize a command.
|
||||
* :c:macro:`SHELL_COND_CMD` - Initialize a command if compile time flag is set.
|
||||
* :c:macro:`SHELL_EXPR_CMD` - Initialize a command if compile time expression is
|
||||
non-zero.
|
||||
* :c:macro:`SHELL_CMD_ARG` - Initialize a command with arguments.
|
||||
* :c:macro:`SHELL_COND_CMD_ARG` - Initialize a command with arguments if compile
|
||||
time flag is set.
|
||||
* :c:macro:`SHELL_EXPR_CMD_ARG` - Initialize a command with arguments if compile
|
||||
time expression is non-zero.
|
||||
* :c:macro:`SHELL_STATIC_SUBCMD_SET_CREATE` - Create a static subcommands
|
||||
array.
|
||||
* :c:macro:`SHELL_DYNAMIC_CMD_CREATE` - Create a dynamic subcommands array.
|
||||
|
|
|
@ -129,6 +129,41 @@ struct shell_static_entry {
|
|||
.u = {.entry = &UTIL_CAT(_shell_, syntax)} \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Macro for defining and adding a conditional root command (level 0)
|
||||
* with required number of arguments.
|
||||
*
|
||||
* @see SHELL_CMD_ARG_REGISTER for details.
|
||||
*
|
||||
* Macro can be used to create a command which can be conditionally present.
|
||||
* It is and alternative to \#ifdefs around command registration and command
|
||||
* handler. If command is disabled handler and subcommands are removed from
|
||||
* the application.
|
||||
*
|
||||
* @param[in] flag Compile time flag. Command is present only if flag
|
||||
* exists and equals 1.
|
||||
* @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_COND_CMD_ARG_REGISTER(flag, syntax, subcmd, help, handler, \
|
||||
mandatory, optional) \
|
||||
COND_CODE_1(\
|
||||
flag, \
|
||||
(\
|
||||
SHELL_CMD_ARG_REGISTER(syntax, subcmd, help, handler, \
|
||||
mandatory, optional) \
|
||||
), \
|
||||
(\
|
||||
static shell_cmd_handler dummy_##syntax##handler \
|
||||
__attribute__((unused)) = handler;\
|
||||
static const struct shell_cmd_entry *dummy_subcmd_##syntax \
|
||||
__attribute__((unused)) = subcmd\
|
||||
)\
|
||||
)
|
||||
/**
|
||||
* @brief Macro for defining and adding a root command (level 0) with
|
||||
* arguments.
|
||||
|
@ -141,15 +176,23 @@ struct shell_static_entry {
|
|||
* @param[in] handler Pointer to a function 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); \
|
||||
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) } \
|
||||
}
|
||||
SHELL_CMD_ARG_REGISTER(syntax, subcmd, help, handler, 0, 0)
|
||||
|
||||
/**
|
||||
* @brief Macro for defining and adding a conditional root command (level 0)
|
||||
* with arguments.
|
||||
*
|
||||
* @see SHELL_COND_CMD_ARG_REGISTER.
|
||||
*
|
||||
* @param[in] flag Compile time flag. Command is present only if flag
|
||||
* exists and equals 1.
|
||||
* @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.
|
||||
*/
|
||||
#define SHELL_COND_CMD_REGISTER(flag, syntax, subcmd, help, handler) \
|
||||
SHELL_COND_CMD_ARG_REGISTER(flag, syntax, subcmd, help, handler, 0, 0)
|
||||
|
||||
/**
|
||||
* @brief Macro for creating a subcommand set. It must be used outside of any
|
||||
|
@ -226,21 +269,68 @@ struct shell_static_entry {
|
|||
* @note If a command will be called with wrong number of arguments shell will
|
||||
* print an error message and command handler will not be called.
|
||||
*
|
||||
* @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] mand Number of mandatory arguments.
|
||||
* @param[in] opt Number of optional arguments.
|
||||
*/
|
||||
#define SHELL_CMD_ARG(syntax, subcmd, help, handler, mand, opt) \
|
||||
SHELL_EXPR_CMD_ARG(1, syntax, subcmd, help, handler, mand, opt)
|
||||
|
||||
/**
|
||||
* @brief Initializes a conditional shell command with arguments.
|
||||
*
|
||||
* @see SHELL_CMD_ARG. Based on the flag, creates a valid entry or an empty
|
||||
* command which is ignored by the shell. It is an alternative to \#ifdefs
|
||||
* around command registration and command handler. However, empty structure is
|
||||
* present in the flash even if command is disabled (subcommands and handler are
|
||||
* removed). Macro internally handles case if flag is not defined so flag must
|
||||
* be provided without any wrapper, e.g.: SHELL_COND_CMD_ARG(CONFIG_FOO, ...)
|
||||
*
|
||||
* @param[in] flag Compile time flag. Command is present only if flag
|
||||
* exists and equals 1.
|
||||
* @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] mand Number of mandatory arguments.
|
||||
* @param[in] opt Number of optional arguments.
|
||||
*/
|
||||
#define SHELL_COND_CMD_ARG(flag, syntax, subcmd, help, handler, mand, opt) \
|
||||
SHELL_EXPR_CMD_ARG(IS_ENABLED(flag), syntax, subcmd, help, \
|
||||
handler, mand, opt)
|
||||
|
||||
/**
|
||||
* @brief Initializes a conditional shell command with arguments if expression
|
||||
* gives non-zero result at compile time.
|
||||
*
|
||||
* @see SHELL_CMD_ARG. Based on the expression, creates a valid entry or an
|
||||
* empty command which is ignored by the shell. It should be used instead of
|
||||
* @ref SHELL_COND_CMD_ARG if condition is not a single configuration flag,
|
||||
* e.g.:
|
||||
* SHELL_EXPR_CMD_ARG(IS_ENABLED(CONFIG_FOO) &&
|
||||
* IS_ENABLED(CONFIG_FOO_SETTING_1), ...)
|
||||
*
|
||||
* @param[in] _expr Expression.
|
||||
* @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.
|
||||
* @param[in] _mand Number of mandatory arguments.
|
||||
* @param[in] _opt Number of optional arguments.
|
||||
*/
|
||||
#define SHELL_CMD_ARG(_syntax, _subcmd, _help, _handler, \
|
||||
_mandatory, _optional) { \
|
||||
.syntax = (const char *)STRINGIFY(_syntax), \
|
||||
.help = (const char *)_help, \
|
||||
.subcmd = _subcmd, \
|
||||
.handler = _handler, \
|
||||
.args = {. mandatory = _mandatory, .optional = _optional} \
|
||||
}
|
||||
#define SHELL_EXPR_CMD_ARG(_expr, _syntax, _subcmd, _help, _handler, \
|
||||
_mand, _opt) \
|
||||
{ \
|
||||
.syntax = (_expr) ? (const char *)STRINGIFY(_syntax) : "", \
|
||||
.help = (_expr) ? (const char *)_help : NULL, \
|
||||
.subcmd = (const struct shell_cmd_entry *)((_expr) ? \
|
||||
_subcmd : NULL), \
|
||||
.handler = (shell_cmd_handler)((_expr) ? _handler : NULL), \
|
||||
.args = { .mandatory = _mand, .optional = _opt} \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initializes a shell command.
|
||||
|
@ -253,6 +343,36 @@ struct shell_static_entry {
|
|||
#define SHELL_CMD(_syntax, _subcmd, _help, _handler) \
|
||||
SHELL_CMD_ARG(_syntax, _subcmd, _help, _handler, 0, 0)
|
||||
|
||||
/**
|
||||
* @brief Initializes a conditional shell command.
|
||||
*
|
||||
* @see SHELL_COND_CMD_ARG.
|
||||
*
|
||||
* @param[in] _flag Compile time flag. Command is present only if flag
|
||||
* exists and equals 1.
|
||||
* @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.
|
||||
*/
|
||||
#define SHELL_COND_CMD(_flag, _syntax, _subcmd, _help, _handler) \
|
||||
SHELL_COND_CMD_ARG(_flag, _syntax, _subcmd, _help, _handler, 0, 0)
|
||||
|
||||
/**
|
||||
* @brief Initializes shell command if expression gives non-zero result at
|
||||
* compile time.
|
||||
*
|
||||
* @see SHELL_EXPR_CMD_ARG.
|
||||
*
|
||||
* @param[in] _expr Compile time expression. Command is present only if
|
||||
* expression is non-zero.
|
||||
* @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.
|
||||
*/
|
||||
#define SHELL_EXPR_CMD(_expr, _syntax, _subcmd, _help, _handler) \
|
||||
SHELL_EXPR_CMD_ARG(_expr, _syntax, _subcmd, _help, _handler, 0, 0)
|
||||
|
||||
/**
|
||||
* @internal @brief Internal shell state in response to data received from the
|
||||
|
|
|
@ -321,6 +321,15 @@ static bool tab_prepare(const struct shell *shell,
|
|||
return true;
|
||||
}
|
||||
|
||||
/* Empty command is identified by null handler and subcommand but contrary
|
||||
* to array termination null command, it has non-null syntax address.
|
||||
*/
|
||||
static inline bool is_empty_cmd(const struct shell_static_entry *entry)
|
||||
{
|
||||
return entry->syntax &&
|
||||
(entry->handler == NULL) && (entry->subcmd == NULL);
|
||||
}
|
||||
|
||||
static inline bool is_completion_candidate(const char *candidate,
|
||||
const char *str, size_t len)
|
||||
{
|
||||
|
@ -342,6 +351,9 @@ static void find_completion_candidates(const struct shell_static_entry *cmd,
|
|||
*cnt = 0;
|
||||
|
||||
while (true) {
|
||||
bool is_empty;
|
||||
bool is_candidate;
|
||||
|
||||
shell_cmd_get(cmd ? cmd->subcmd : NULL, cmd ? 1 : 0,
|
||||
idx, &candidate, &dynamic_entry);
|
||||
|
||||
|
@ -349,8 +361,10 @@ static void find_completion_candidates(const struct shell_static_entry *cmd,
|
|||
break;
|
||||
}
|
||||
|
||||
if (is_completion_candidate(candidate->syntax, incompl_cmd,
|
||||
incompl_cmd_len)) {
|
||||
is_empty = is_empty_cmd(candidate);
|
||||
is_candidate = is_completion_candidate(candidate->syntax,
|
||||
incompl_cmd, incompl_cmd_len);
|
||||
if (!is_empty && is_candidate) {
|
||||
size_t slen = strlen(candidate->syntax);
|
||||
|
||||
*longest = (slen > *longest) ? slen : *longest;
|
||||
|
@ -438,15 +452,17 @@ static void tab_options_print(const struct shell *shell,
|
|||
tab_item_print(shell, SHELL_INIT_OPTION_PRINTER, longest);
|
||||
|
||||
while (cnt) {
|
||||
bool is_empty;
|
||||
|
||||
/* shell->ctx->active_cmd can be safely used outside of command
|
||||
* context to save stack
|
||||
*/
|
||||
shell_cmd_get(cmd ? cmd->subcmd : NULL, cmd ? 1 : 0,
|
||||
idx, &match, &shell->ctx->active_cmd);
|
||||
idx++;
|
||||
|
||||
if (str && match->syntax &&
|
||||
!is_completion_candidate(match->syntax, str, str_len)) {
|
||||
is_empty = is_empty_cmd(match);
|
||||
if (is_empty || (str && match->syntax &&
|
||||
!is_completion_candidate(match->syntax, str, str_len))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue