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
|
* :c:macro:`SHELL_CMD_REGISTER` - Create root command. All root commands must
|
||||||
have different name.
|
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.
|
* :c:macro:`SHELL_CMD_ARG_REGISTER` - Create root command with arguments.
|
||||||
All root commands must have different name.
|
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_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_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
|
* :c:macro:`SHELL_STATIC_SUBCMD_SET_CREATE` - Create a static subcommands
|
||||||
array.
|
array.
|
||||||
* :c:macro:`SHELL_DYNAMIC_CMD_CREATE` - Create a dynamic 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)} \
|
.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
|
* @brief Macro for defining and adding a root command (level 0) with
|
||||||
* arguments.
|
* arguments.
|
||||||
|
@ -141,15 +176,23 @@ struct shell_static_entry {
|
||||||
* @param[in] handler Pointer to a function handler.
|
* @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_ARG_REGISTER(syntax, subcmd, help, handler, 0, 0)
|
||||||
SHELL_CMD(syntax, subcmd, help, handler); \
|
|
||||||
const struct shell_cmd_entry UTIL_CAT(shell_cmd_, syntax) \
|
/**
|
||||||
__attribute__ ((section("." \
|
* @brief Macro for defining and adding a conditional root command (level 0)
|
||||||
STRINGIFY(UTIL_CAT(shell_root_cmd_, syntax))))) \
|
* with arguments.
|
||||||
__attribute__((used)) = { \
|
*
|
||||||
.is_dynamic = false, \
|
* @see SHELL_COND_CMD_ARG_REGISTER.
|
||||||
.u = { .entry = &UTIL_CAT(_shell_, syntax) } \
|
*
|
||||||
}
|
* @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
|
* @brief Macro for creating a subcommand set. It must be used outside of any
|
||||||
|
@ -226,20 +269,67 @@ struct shell_static_entry {
|
||||||
* @note If a command will be called with wrong number of arguments shell will
|
* @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.
|
* 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] _syntax Command syntax (for example: history).
|
||||||
* @param[in] _subcmd Pointer to a subcommands array.
|
* @param[in] _subcmd Pointer to a subcommands array.
|
||||||
* @param[in] _help Pointer to a command help string.
|
* @param[in] _help Pointer to a command help string.
|
||||||
* @param[in] _handler Pointer to a function handler.
|
* @param[in] _handler Pointer to a function handler.
|
||||||
* @param[in] _mandatory Number of mandatory arguments.
|
* @param[in] _mand Number of mandatory arguments.
|
||||||
* @param[in] _optional Number of optional arguments.
|
* @param[in] _opt Number of optional arguments.
|
||||||
*/
|
*/
|
||||||
#define SHELL_CMD_ARG(_syntax, _subcmd, _help, _handler, \
|
#define SHELL_EXPR_CMD_ARG(_expr, _syntax, _subcmd, _help, _handler, \
|
||||||
_mandatory, _optional) { \
|
_mand, _opt) \
|
||||||
.syntax = (const char *)STRINGIFY(_syntax), \
|
{ \
|
||||||
.help = (const char *)_help, \
|
.syntax = (_expr) ? (const char *)STRINGIFY(_syntax) : "", \
|
||||||
.subcmd = _subcmd, \
|
.help = (_expr) ? (const char *)_help : NULL, \
|
||||||
.handler = _handler, \
|
.subcmd = (const struct shell_cmd_entry *)((_expr) ? \
|
||||||
.args = {. mandatory = _mandatory, .optional = _optional} \
|
_subcmd : NULL), \
|
||||||
|
.handler = (shell_cmd_handler)((_expr) ? _handler : NULL), \
|
||||||
|
.args = { .mandatory = _mand, .optional = _opt} \
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -253,6 +343,36 @@ struct shell_static_entry {
|
||||||
#define SHELL_CMD(_syntax, _subcmd, _help, _handler) \
|
#define SHELL_CMD(_syntax, _subcmd, _help, _handler) \
|
||||||
SHELL_CMD_ARG(_syntax, _subcmd, _help, _handler, 0, 0)
|
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
|
* @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;
|
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,
|
static inline bool is_completion_candidate(const char *candidate,
|
||||||
const char *str, size_t len)
|
const char *str, size_t len)
|
||||||
{
|
{
|
||||||
|
@ -342,6 +351,9 @@ static void find_completion_candidates(const struct shell_static_entry *cmd,
|
||||||
*cnt = 0;
|
*cnt = 0;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
bool is_empty;
|
||||||
|
bool is_candidate;
|
||||||
|
|
||||||
shell_cmd_get(cmd ? cmd->subcmd : NULL, cmd ? 1 : 0,
|
shell_cmd_get(cmd ? cmd->subcmd : NULL, cmd ? 1 : 0,
|
||||||
idx, &candidate, &dynamic_entry);
|
idx, &candidate, &dynamic_entry);
|
||||||
|
|
||||||
|
@ -349,8 +361,10 @@ static void find_completion_candidates(const struct shell_static_entry *cmd,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_completion_candidate(candidate->syntax, incompl_cmd,
|
is_empty = is_empty_cmd(candidate);
|
||||||
incompl_cmd_len)) {
|
is_candidate = is_completion_candidate(candidate->syntax,
|
||||||
|
incompl_cmd, incompl_cmd_len);
|
||||||
|
if (!is_empty && is_candidate) {
|
||||||
size_t slen = strlen(candidate->syntax);
|
size_t slen = strlen(candidate->syntax);
|
||||||
|
|
||||||
*longest = (slen > *longest) ? slen : *longest;
|
*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);
|
tab_item_print(shell, SHELL_INIT_OPTION_PRINTER, longest);
|
||||||
|
|
||||||
while (cnt) {
|
while (cnt) {
|
||||||
|
bool is_empty;
|
||||||
|
|
||||||
/* shell->ctx->active_cmd can be safely used outside of command
|
/* shell->ctx->active_cmd can be safely used outside of command
|
||||||
* context to save stack
|
* context to save stack
|
||||||
*/
|
*/
|
||||||
shell_cmd_get(cmd ? cmd->subcmd : NULL, cmd ? 1 : 0,
|
shell_cmd_get(cmd ? cmd->subcmd : NULL, cmd ? 1 : 0,
|
||||||
idx, &match, &shell->ctx->active_cmd);
|
idx, &match, &shell->ctx->active_cmd);
|
||||||
idx++;
|
idx++;
|
||||||
|
is_empty = is_empty_cmd(match);
|
||||||
if (str && match->syntax &&
|
if (is_empty || (str && match->syntax &&
|
||||||
!is_completion_candidate(match->syntax, str, str_len)) {
|
!is_completion_candidate(match->syntax, str, str_len))) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue