shell: Refactor command getters

Refactor and simplified fetching commands from the tree
of commands.

Signed-off-by: Krzysztof Chruscinski <krzysztof.chruscinski@nordicsemi.no>
This commit is contained in:
Krzysztof Chruscinski 2020-04-08 15:42:06 +02:00 committed by Carles Cufí
commit 53b5bae41b
7 changed files with 108 additions and 195 deletions

View file

@ -252,7 +252,7 @@ static bool tab_prepare(const struct shell *shell,
/* root command completion */ /* root command completion */
if ((*argc == 0) || ((space == 0) && (*argc == 1))) { if ((*argc == 0) || ((space == 0) && (*argc == 1))) {
*complete_arg_idx = SHELL_CMD_ROOT_LVL; *complete_arg_idx = SHELL_CMD_ROOT_LVL;
*cmd = NULL; *cmd = shell->ctx->selected_cmd;
return true; return true;
} }
@ -294,39 +294,25 @@ static void find_completion_candidates(const struct shell *shell,
{ {
size_t incompl_cmd_len = shell_strlen(incompl_cmd); size_t incompl_cmd_len = shell_strlen(incompl_cmd);
const struct shell_static_entry *candidate; const struct shell_static_entry *candidate;
struct shell_static_entry dynamic_entry; struct shell_static_entry dloc;
bool found = false;
size_t idx = 0; size_t idx = 0;
*longest = 0U; *longest = 0U;
*cnt = 0; *cnt = 0;
while (true) { while ((candidate = shell_cmd_get(cmd, idx, &dloc)) != NULL) {
bool is_empty;
bool is_candidate; bool is_candidate;
shell_cmd_get(shell, cmd ? cmd->subcmd : NULL, cmd ? 1 : 0,
idx, &candidate, &dynamic_entry);
if (!candidate) {
break;
}
is_empty = is_empty_cmd(candidate);
is_candidate = is_completion_candidate(candidate->syntax, is_candidate = is_completion_candidate(candidate->syntax,
incompl_cmd, incompl_cmd_len); incompl_cmd, incompl_cmd_len);
if (!is_empty && is_candidate) { if (!is_empty_cmd(candidate) && is_candidate) {
size_t slen = strlen(candidate->syntax); *longest = Z_MAX(strlen(candidate->syntax), *longest);
if (*cnt == 0) {
*longest = (slen > *longest) ? slen : *longest;
(*cnt)++;
if (!found) {
*first_idx = idx; *first_idx = idx;
} }
(*cnt)++;
found = true;
} }
idx++; idx++;
} }
} }
@ -343,8 +329,8 @@ static void autocomplete(const struct shell *shell,
/* shell->ctx->active_cmd can be safely used outside of command context /* shell->ctx->active_cmd can be safely used outside of command context
* to save stack * to save stack
*/ */
shell_cmd_get(shell, cmd ? cmd->subcmd : NULL, cmd ? 1 : 0, match = shell_cmd_get(cmd, subcmd_idx, &shell->ctx->active_cmd);
subcmd_idx, &match, &shell->ctx->active_cmd); __ASSERT_NO_MSG(match != NULL);
cmd_len = shell_strlen(match->syntax); cmd_len = shell_strlen(match->syntax);
/* no exact match found */ /* no exact match found */
@ -408,8 +394,8 @@ static void tab_options_print(const struct shell *shell,
/* 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(shell, cmd ? cmd->subcmd : NULL, cmd ? 1 : 0, match = shell_cmd_get(cmd, idx, &shell->ctx->active_cmd);
idx, &match, &shell->ctx->active_cmd); __ASSERT_NO_MSG(match != NULL);
idx++; idx++;
is_empty = is_empty_cmd(match); is_empty = is_empty_cmd(match);
if (is_empty || (str && match->syntax && if (is_empty || (str && match->syntax &&
@ -437,8 +423,8 @@ static u16_t common_beginning_find(const struct shell *shell,
__ASSERT_NO_MSG(cnt > 1); __ASSERT_NO_MSG(cnt > 1);
shell_cmd_get(shell, cmd ? cmd->subcmd : NULL, cmd ? 1 : 0, match = shell_cmd_get(cmd, first, &dynamic_entry);
first, &match, &dynamic_entry); __ASSERT_NO_MSG(match);
strncpy(shell->ctx->temp_buff, match->syntax, strncpy(shell->ctx->temp_buff, match->syntax,
sizeof(shell->ctx->temp_buff) - 1); sizeof(shell->ctx->temp_buff) - 1);
@ -449,9 +435,7 @@ static u16_t common_beginning_find(const struct shell *shell,
const struct shell_static_entry *match2; const struct shell_static_entry *match2;
int curr_common; int curr_common;
shell_cmd_get(shell, cmd ? cmd->subcmd : NULL, cmd ? 1 : 0, match2 = shell_cmd_get(cmd, idx++, &dynamic_entry2);
idx++, &match2, &dynamic_entry2);
if (match2 == NULL) { if (match2 == NULL) {
break; break;
} }
@ -535,10 +519,10 @@ static int exec_cmd(const struct shell *shell, size_t argc, char **argv,
*/ */
static int execute(const struct shell *shell) static int execute(const struct shell *shell)
{ {
struct shell_static_entry d_entry; /* Memory for dynamic commands. */ struct shell_static_entry dloc; /* Memory for dynamic commands. */
char *argv[CONFIG_SHELL_ARGC_MAX + 1]; /* +1 reserved for NULL */ char *argv[CONFIG_SHELL_ARGC_MAX + 1]; /* +1 reserved for NULL */
const struct shell_static_entry *p_static_entry = NULL; const struct shell_static_entry *parent = shell->ctx->selected_cmd;
const struct shell_cmd_entry *p_cmd = NULL; const struct shell_static_entry *entry = NULL;
struct shell_static_entry help_entry; struct shell_static_entry help_entry;
size_t cmd_lvl = SHELL_CMD_ROOT_LVL; size_t cmd_lvl = SHELL_CMD_ROOT_LVL;
size_t cmd_with_handler_lvl = 0; size_t cmd_with_handler_lvl = 0;
@ -607,7 +591,7 @@ static int execute(const struct shell *shell)
if (IS_ENABLED(CONFIG_SHELL_WILDCARD) && (cmd_lvl > 0)) { if (IS_ENABLED(CONFIG_SHELL_WILDCARD) && (cmd_lvl > 0)) {
enum shell_wildcard_status status; enum shell_wildcard_status status;
status = shell_wildcard_process(shell, p_cmd, status = shell_wildcard_process(shell, entry,
argv[cmd_lvl]); argv[cmd_lvl]);
/* Wildcard character found but there is no matching /* Wildcard character found but there is no matching
* command. * command.
@ -626,10 +610,9 @@ static int execute(const struct shell *shell)
} }
} }
shell_cmd_get(shell, p_cmd, cmd_lvl, cmd_idx++, &p_static_entry, entry = shell_cmd_get(parent, cmd_idx++, &dloc);
&d_entry);
if ((cmd_idx == 0) || (p_static_entry == NULL)) { if ((cmd_idx == 0) || (entry == NULL)) {
if (cmd_lvl == 0 && if (cmd_lvl == 0 &&
(!shell_in_select_mode(shell) || (!shell_in_select_mode(shell) ||
shell->ctx->selected_cmd->handler == NULL)) { shell->ctx->selected_cmd->handler == NULL)) {
@ -640,16 +623,16 @@ static int execute(const struct shell *shell)
} }
if (shell_in_select_mode(shell) && if (shell_in_select_mode(shell) &&
shell->ctx->selected_cmd->handler != NULL) { shell->ctx->selected_cmd->handler != NULL) {
p_static_entry = shell->ctx->selected_cmd; entry = shell->ctx->selected_cmd;
shell->ctx->active_cmd = *p_static_entry; shell->ctx->active_cmd = *entry;
cmd_with_handler_lvl = cmd_lvl; cmd_with_handler_lvl = cmd_lvl;
} }
break; break;
} }
if (strcmp(argv[cmd_lvl], p_static_entry->syntax) == 0) { if (strcmp(argv[cmd_lvl], entry->syntax) == 0) {
/* checking if command has a handler */ /* checking if command has a handler */
if (p_static_entry->handler != NULL) { if (entry->handler != NULL) {
if (IS_ENABLED(CONFIG_SHELL_WILDCARD) && if (IS_ENABLED(CONFIG_SHELL_WILDCARD) &&
(wildcard_found)) { (wildcard_found)) {
shell_op_cursor_end_move(shell); shell_op_cursor_end_move(shell);
@ -668,17 +651,17 @@ static int execute(const struct shell *shell)
return -ENOEXEC; return -ENOEXEC;
} }
shell->ctx->active_cmd = *p_static_entry; shell->ctx->active_cmd = *entry;
cmd_with_handler_lvl = cmd_lvl; cmd_with_handler_lvl = cmd_lvl;
} }
/* checking if function has a help handler */ /* checking if function has a help handler */
if (p_static_entry->help != NULL) { if (entry->help != NULL) {
help_entry = *p_static_entry; help_entry = *entry;
} }
cmd_lvl++; cmd_lvl++;
cmd_idx = 0; cmd_idx = 0;
p_cmd = p_static_entry->subcmd; parent = entry;
} }
} }

View file

@ -380,6 +380,11 @@ static int cmd_resize(const struct shell *shell, size_t argc, char **argv)
return 0; return 0;
} }
static bool no_args(const struct shell_static_entry *entry)
{
return (entry->args.mandatory == 1) && (entry->args.optional == 0);
}
static int cmd_select(const struct shell *shell, size_t argc, char **argv) static int cmd_select(const struct shell *shell, size_t argc, char **argv)
{ {
const struct shell_static_entry *candidate = NULL; const struct shell_static_entry *candidate = NULL;
@ -391,7 +396,8 @@ static int cmd_select(const struct shell *shell, size_t argc, char **argv)
candidate = shell_get_last_command(shell, argc, argv, &matching_argc, candidate = shell_get_last_command(shell, argc, argv, &matching_argc,
&entry, true); &entry, true);
if ((candidate != NULL) && (argc == matching_argc)) { if ((candidate != NULL) && !no_args(candidate)
&& (argc == matching_argc)) {
shell->ctx->selected_cmd = candidate; shell->ctx->selected_cmd = candidate;
return 0; return 0;
} }

View file

@ -148,50 +148,28 @@ static void help_item_print(const struct shell *shell, const char *item_name,
void shell_help_subcmd_print(const struct shell *shell) void shell_help_subcmd_print(const struct shell *shell)
{ {
const struct shell_static_entry *entry = NULL; const struct shell_static_entry *entry = NULL;
struct shell_static_entry static_entry; const struct shell_static_entry *parent = &shell->ctx->active_cmd;
u16_t longest_syntax = 0U; struct shell_static_entry dloc;
size_t cmd_idx = 0; u16_t longest = 0U;
size_t idx = 0;
/* Checking if there are any subcommands available. */
if (!shell->ctx->active_cmd.subcmd) {
return;
}
/* Searching for the longest subcommand to print. */ /* Searching for the longest subcommand to print. */
do { while ((entry = shell_cmd_get(parent, idx++, &dloc)) != NULL) {
shell_cmd_get(shell, shell->ctx->active_cmd.subcmd, longest = Z_MAX(longest, shell_strlen(entry->syntax));
!SHELL_CMD_ROOT_LVL, };
cmd_idx++, &entry, &static_entry);
if (!entry) { /* No help to print */
break; if (longest == 0) {
}
u16_t len = shell_strlen(entry->syntax);
longest_syntax = longest_syntax > len ? longest_syntax : len;
} while (cmd_idx != 0); /* too many commands */
if (cmd_idx == 1) {
return; return;
} }
shell_internal_fprintf(shell, SHELL_NORMAL, "Subcommands:\n"); shell_internal_fprintf(shell, SHELL_NORMAL, "Subcommands:\n");
/* Printing subcommands and help string (if exists). */ /* Printing subcommands and help string (if exists). */
cmd_idx = 0; idx = 0;
while (true) { while ((entry = shell_cmd_get(parent, idx++, &dloc)) != NULL) {
shell_cmd_get(shell, shell->ctx->active_cmd.subcmd, help_item_print(shell, entry->syntax, longest, entry->help);
!SHELL_CMD_ROOT_LVL,
cmd_idx++, &entry, &static_entry);
if (entry == NULL) {
break;
}
help_item_print(shell, entry->syntax, longest_syntax,
entry->help);
} }
} }

View file

@ -12,7 +12,7 @@ extern const struct shell_cmd_entry __shell_root_cmds_end[0];
static inline const struct shell_cmd_entry *shell_root_cmd_get(u32_t id) static inline const struct shell_cmd_entry *shell_root_cmd_get(u32_t id)
{ {
return &__shell_root_cmds_start[id]; return &__shell_root_cmds_start[id];
} }
/* Calculates relative line number of given position in buffer */ /* Calculates relative line number of given position in buffer */
@ -225,7 +225,7 @@ static inline u32_t shell_root_cmd_count(void)
sizeof(struct shell_cmd_entry); sizeof(struct shell_cmd_entry);
} }
/* Function returning pointer to root command matching requested syntax. */ /* Function returning pointer to parent command matching requested syntax. */
const struct shell_static_entry *shell_root_cmd_find(const char *syntax) const struct shell_static_entry *shell_root_cmd_find(const char *syntax)
{ {
const size_t cmd_count = shell_root_cmd_count(); const size_t cmd_count = shell_root_cmd_count();
@ -241,46 +241,33 @@ const struct shell_static_entry *shell_root_cmd_find(const char *syntax)
return NULL; return NULL;
} }
void shell_cmd_get(const struct shell *shell, const struct shell_static_entry *shell_cmd_get(
const struct shell_cmd_entry *command, size_t lvl, const struct shell_static_entry *parent,
size_t idx, const struct shell_static_entry **entry, size_t idx,
struct shell_static_entry *d_entry) struct shell_static_entry *dloc)
{ {
__ASSERT_NO_MSG(entry != NULL); __ASSERT_NO_MSG(dloc != NULL);
__ASSERT_NO_MSG(d_entry != NULL); const struct shell_static_entry *res = NULL;
*entry = NULL; if (parent == NULL) {
return (idx < shell_root_cmd_count()) ?
shell_root_cmd_get(idx)->u.entry : NULL;
}
if (lvl == SHELL_CMD_ROOT_LVL) { if (parent->subcmd) {
if (shell_in_select_mode(shell)) { if (parent->subcmd->is_dynamic) {
const struct shell_static_entry *ptr = parent->subcmd->u.dynamic_get(idx, dloc);
shell->ctx->selected_cmd; if (dloc->syntax != NULL) {
if (ptr->subcmd->u.entry[idx].syntax != NULL) { res = dloc;
*entry = &ptr->subcmd->u.entry[idx]; }
} else {
if (parent->subcmd->u.entry[idx].syntax != NULL) {
res = &parent->subcmd->u.entry[idx];
} }
} else if (idx < shell_root_cmd_count()) {
const struct shell_cmd_entry *cmd;
cmd = shell_root_cmd_get(idx);
*entry = cmd->u.entry;
}
return;
}
if (command == NULL) {
return;
}
if (command->is_dynamic) {
command->u.dynamic_get(idx, d_entry);
if (d_entry->syntax != NULL) {
*entry = d_entry;
}
} else {
if (command->u.entry[idx].syntax != NULL) {
*entry = &command->u.entry[idx];
} }
} }
return res;
} }
/* Function returns pointer to a command matching given pattern. /* Function returns pointer to a command matching given pattern.
@ -288,28 +275,26 @@ void shell_cmd_get(const struct shell *shell,
* @param shell Shell instance. * @param shell Shell instance.
* @param cmd Pointer to commands array that will be searched. * @param cmd Pointer to commands array that will be searched.
* @param lvl Root command indicator. If set to 0 shell will search * @param lvl Root command indicator. If set to 0 shell will search
* for pattern in root commands. * for pattern in parent commands.
* @param cmd_str Command pattern to be found. * @param cmd_str Command pattern to be found.
* @param d_entry Shell static command descriptor. * @param dloc Shell static command descriptor.
* *
* @return Pointer to found command. * @return Pointer to found command.
*/ */
static const struct shell_static_entry *find_cmd( static const struct shell_static_entry *find_cmd(
const struct shell *shell, const struct shell *shell,
const struct shell_cmd_entry *cmd, const struct shell_static_entry *parent,
size_t lvl, char *cmd_str,
char *cmd_str, struct shell_static_entry *dloc)
struct shell_static_entry *d_entry)
{ {
const struct shell_static_entry *entry = NULL; const struct shell_static_entry *entry;
size_t idx = 0; size_t idx = 0;
do { while ((entry = shell_cmd_get(parent, idx++, dloc)) != NULL) {
shell_cmd_get(shell, cmd, lvl, idx++, &entry, d_entry); if (strcmp(cmd_str, entry->syntax) == 0) {
if (entry && (strcmp(cmd_str, entry->syntax) == 0)) {
return entry; return entry;
} }
} while (entry); };
return NULL; return NULL;
} }
@ -319,12 +304,11 @@ const struct shell_static_entry *shell_get_last_command(
size_t argc, size_t argc,
char *argv[], char *argv[],
size_t *match_arg, size_t *match_arg,
struct shell_static_entry *d_entry, struct shell_static_entry *dloc,
bool only_static) bool only_static)
{ {
const struct shell_static_entry *prev_entry = NULL; const struct shell_static_entry *prev_entry = NULL;
const struct shell_static_entry *entry = NULL; const struct shell_static_entry *entry = shell->ctx->selected_cmd;
const struct shell_cmd_entry *cmd = NULL;
*match_arg = SHELL_CMD_ROOT_LVL; *match_arg = SHELL_CMD_ROOT_LVL;
@ -338,21 +322,16 @@ const struct shell_static_entry *shell_get_last_command(
} }
} }
entry = find_cmd(shell, cmd, *match_arg, argv[*match_arg], prev_entry = entry;
d_entry); entry = find_cmd(shell, entry, argv[*match_arg], dloc);
if (entry) { if (entry) {
cmd = entry->subcmd;
prev_entry = entry;
(*match_arg)++; (*match_arg)++;
} else { } else {
entry = prev_entry;
break; break;
} }
if (cmd == NULL) { if (only_static && (entry == dloc)) {
return NULL;
}
if (only_static && cmd->is_dynamic) {
(*match_arg)--; (*match_arg)--;
return NULL; return NULL;
} }

View file

@ -43,25 +43,18 @@ char shell_make_argv(size_t *argc, char **argv, char *cmd, uint8_t max_argc);
*/ */
void shell_pattern_remove(char *buff, u16_t *buff_len, const char *pattern); void shell_pattern_remove(char *buff, u16_t *buff_len, const char *pattern);
/* @brief Function shall be used to search commands. /** @brief Get subcommand with given index from the root.
* *
* It moves the pointer entry to command of static command structure. If the * @param parent Parent entry. Null to get root command from index.
* command cannot be found, the function will set entry to NULL. * @param idx Command index.
* @param dloc Location used to write dynamic entry.
* *
* @param shell Shell instance. * @return Fetched command or null if command with that index does not exist.
* @param command Pointer to command which will be processed (no matter
* the root command).
* @param lvl Level of the requested command.
* @param idx Index of the requested command.
* @param entry Pointer which points to subcommand[idx] after function
* execution.
* @param st_entry Pointer to the structure where dynamic entry data can
* be stored.
*/ */
void shell_cmd_get(const struct shell *shell, const struct shell_static_entry *shell_cmd_get(
const struct shell_cmd_entry *command, size_t lvl, const struct shell_static_entry *parent,
size_t idx, const struct shell_static_entry **entry, size_t idx,
struct shell_static_entry *d_entry); struct shell_static_entry *dloc);
/* @internal @brief Function returns pointer to a shell's subcommands array /* @internal @brief Function returns pointer to a shell's subcommands array

View file

@ -10,27 +10,6 @@
#include "shell_utils.h" #include "shell_utils.h"
#include "shell_ops.h" #include "shell_ops.h"
static void subcmd_get(const struct shell_cmd_entry *cmd,
size_t idx, const struct shell_static_entry **entry,
struct shell_static_entry *d_entry)
{
__ASSERT_NO_MSG(entry != NULL);
__ASSERT_NO_MSG(d_entry != NULL);
if (cmd == NULL) {
*entry = NULL;
return;
}
if (cmd->is_dynamic) {
cmd->u.dynamic_get(idx, d_entry);
*entry = (d_entry->syntax != NULL) ? d_entry : NULL;
} else {
*entry = (cmd->u.entry[idx].syntax != NULL) ?
&cmd->u.entry[idx] : NULL;
}
}
static enum shell_wildcard_status command_add(char *buff, u16_t *buff_len, static enum shell_wildcard_status command_add(char *buff, u16_t *buff_len,
char const *cmd, char const *cmd,
char const *pattern) char const *pattern)
@ -88,26 +67,21 @@ static enum shell_wildcard_status command_add(char *buff, u16_t *buff_len,
* @retval WILDCARD_CMD_NO_MATCH_FOUND No matching command found. * @retval WILDCARD_CMD_NO_MATCH_FOUND No matching command found.
*/ */
static enum shell_wildcard_status commands_expand(const struct shell *shell, static enum shell_wildcard_status commands_expand(const struct shell *shell,
const struct shell_cmd_entry *cmd, const struct shell_static_entry *cmd,
const char *pattern) const char *pattern)
{ {
enum shell_wildcard_status ret_val = SHELL_WILDCARD_CMD_NO_MATCH_FOUND; enum shell_wildcard_status ret_val = SHELL_WILDCARD_CMD_NO_MATCH_FOUND;
struct shell_static_entry const *p_static_entry = NULL; struct shell_static_entry const *entry = NULL;
struct shell_static_entry static_entry; struct shell_static_entry dloc;
size_t cmd_idx = 0; size_t cmd_idx = 0;
size_t cnt = 0; size_t cnt = 0;
do { while ((entry = shell_cmd_get(cmd, cmd_idx++, &dloc)) != NULL) {
subcmd_get(cmd, cmd_idx++, &p_static_entry, &static_entry);
if (!p_static_entry) { if (fnmatch(pattern, entry->syntax, 0) == 0) {
break;
}
if (fnmatch(pattern, p_static_entry->syntax, 0) == 0) {
ret_val = command_add(shell->ctx->temp_buff, ret_val = command_add(shell->ctx->temp_buff,
&shell->ctx->cmd_tmp_buff_len, &shell->ctx->cmd_tmp_buff_len,
p_static_entry->syntax, pattern); entry->syntax, pattern);
if (ret_val == SHELL_WILDCARD_CMD_MISSING_SPACE) { if (ret_val == SHELL_WILDCARD_CMD_MISSING_SPACE) {
shell_internal_fprintf(shell, shell_internal_fprintf(shell,
SHELL_WARNING, SHELL_WARNING,
@ -121,7 +95,7 @@ static enum shell_wildcard_status commands_expand(const struct shell *shell,
} }
cnt++; cnt++;
} }
} while (cmd_idx); };
if (cnt > 0) { if (cnt > 0) {
shell_pattern_remove(shell->ctx->temp_buff, shell_pattern_remove(shell->ctx->temp_buff,
@ -185,8 +159,8 @@ void shell_wildcard_prepare(const struct shell *shell)
enum shell_wildcard_status shell_wildcard_process(const struct shell *shell, enum shell_wildcard_status shell_wildcard_process(const struct shell *shell,
const struct shell_cmd_entry *cmd, const struct shell_static_entry *cmd,
const char *pattern) const char *pattern)
{ {
enum shell_wildcard_status ret_val = SHELL_WILDCARD_NOT_FOUND; enum shell_wildcard_status ret_val = SHELL_WILDCARD_NOT_FOUND;

View file

@ -45,8 +45,8 @@ bool shell_wildcard_character_exist(const char *str);
* @param[in] pattern Pointer to wildcard pattern. * @param[in] pattern Pointer to wildcard pattern.
*/ */
enum shell_wildcard_status shell_wildcard_process(const struct shell *shell, enum shell_wildcard_status shell_wildcard_process(const struct shell *shell,
const struct shell_cmd_entry *cmd, const struct shell_static_entry *cmd,
const char *pattern); const char *pattern);
/* Function finalizing wildcard expansion procedure. /* Function finalizing wildcard expansion procedure.
* *