You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
191 lines
5.8 KiB
191 lines
5.8 KiB
/* |
|
* Copyright (c) 2018 Nordic Semiconductor ASA |
|
* |
|
* SPDX-License-Identifier: Apache-2.0 |
|
*/ |
|
|
|
#include <string.h> |
|
#include <zephyr/posix/fnmatch.h> |
|
#include "shell_wildcard.h" |
|
#include "shell_utils.h" |
|
#include "shell_ops.h" |
|
|
|
static enum shell_wildcard_status command_add(char *buff, uint16_t *buff_len, |
|
char const *cmd, |
|
char const *pattern) |
|
{ |
|
uint16_t cmd_len = z_shell_strlen(cmd); |
|
char *completion_addr; |
|
uint16_t shift; |
|
|
|
/* +1 for space */ |
|
if ((*buff_len + cmd_len + 1) > CONFIG_SHELL_CMD_BUFF_SIZE) { |
|
return SHELL_WILDCARD_CMD_MISSING_SPACE; |
|
} |
|
|
|
completion_addr = strstr(buff, pattern); |
|
|
|
if (!completion_addr) { |
|
return SHELL_WILDCARD_CMD_NO_MATCH_FOUND; |
|
} |
|
|
|
shift = z_shell_strlen(completion_addr); |
|
|
|
/* make place for new command: + 1 for space + 1 for EOS */ |
|
memmove(completion_addr + cmd_len + 1, completion_addr, shift + 1); |
|
memcpy(completion_addr, cmd, cmd_len); |
|
/* adding space to not brake next command in the buffer */ |
|
completion_addr[cmd_len] = ' '; |
|
|
|
*buff_len += cmd_len + 1; /* + 1 for space */ |
|
|
|
return SHELL_WILDCARD_CMD_ADDED; |
|
} |
|
|
|
/** |
|
* @internal @brief Function for searching and adding commands to the temporary |
|
* shell buffer matching to wildcard pattern. |
|
* |
|
* Function will search commands tree for commands matching wildcard pattern |
|
* stored in argv[cmd_lvl]. When match is found wildcard pattern will be |
|
* replaced by matching commands. If there is no space in the buffer to add all |
|
* matching commands function will add as many as possible. Next it will |
|
* continue to search for next wildcard pattern and it will try to add matching |
|
* commands. |
|
* |
|
* |
|
* This function is internal to shell module and shall be not called directly. |
|
* |
|
* @param[in/out] shell Pointer to the CLI instance. |
|
* @param[in] cmd Pointer to command which will be processed |
|
* @param[in] pattern Pointer to wildcard pattern. |
|
* |
|
* @retval WILDCARD_CMD_ADDED All matching commands added to the buffer. |
|
* @retval WILDCARD_CMD_ADDED_MISSING_SPACE Not all matching commands added |
|
* because CONFIG_SHELL_CMD_BUFF_SIZE |
|
* is too small. |
|
* @retval WILDCARD_CMD_NO_MATCH_FOUND No matching command found. |
|
*/ |
|
static enum shell_wildcard_status commands_expand(const struct shell *sh, |
|
const struct shell_static_entry *cmd, |
|
const char *pattern) |
|
{ |
|
enum shell_wildcard_status ret_val = SHELL_WILDCARD_CMD_NO_MATCH_FOUND; |
|
struct shell_static_entry const *entry = NULL; |
|
struct shell_static_entry dloc; |
|
size_t cmd_idx = 0; |
|
size_t cnt = 0; |
|
|
|
while ((entry = z_shell_cmd_get(cmd, cmd_idx++, &dloc)) != NULL) { |
|
|
|
if (fnmatch(pattern, entry->syntax, 0) == 0) { |
|
ret_val = command_add(sh->ctx->temp_buff, |
|
&sh->ctx->cmd_tmp_buff_len, |
|
entry->syntax, pattern); |
|
if (ret_val == SHELL_WILDCARD_CMD_MISSING_SPACE) { |
|
z_shell_fprintf(sh, SHELL_WARNING, |
|
"Command buffer is too short to" |
|
" expand all commands matching" |
|
" wildcard pattern: %s\n", pattern); |
|
break; |
|
} else if (ret_val != SHELL_WILDCARD_CMD_ADDED) { |
|
break; |
|
} |
|
cnt++; |
|
} |
|
} |
|
|
|
if (cnt > 0) { |
|
z_shell_pattern_remove(sh->ctx->temp_buff, |
|
&sh->ctx->cmd_tmp_buff_len, pattern); |
|
} |
|
|
|
return ret_val; |
|
} |
|
|
|
bool z_shell_has_wildcard(const char *str) |
|
{ |
|
uint16_t str_len = z_shell_strlen(str); |
|
|
|
for (size_t i = 0; i < str_len; i++) { |
|
if ((str[i] == '?') || (str[i] == '*')) { |
|
return true; |
|
} |
|
} |
|
|
|
return false; |
|
} |
|
|
|
void z_shell_wildcard_prepare(const struct shell *sh) |
|
{ |
|
/* Wildcard can be correctly handled under following conditions: |
|
* - wildcard command does not have a handler |
|
* - wildcard command is on the deepest commands level |
|
* - other commands on the same level as wildcard command shall also not |
|
* have a handler |
|
* |
|
* Algorithm: |
|
* 1. Command buffer: ctx->cmd_buff is copied to temporary buffer: |
|
* ctx->temp_buff. |
|
* 2. Algorithm goes through command buffer to find handlers and |
|
* subcommands. |
|
* 3. If algorithm will find a wildcard character it switches to |
|
* Temporary buffer. |
|
* 4. In the Temporary buffer command containing wildcard character is |
|
* replaced by matching command(s). |
|
* 5. Algorithm switch back to Command buffer and analyzes next command. |
|
* 6. When all arguments are analyzed from Command buffer, Temporary |
|
* buffer with all expanded commands is copied to Command buffer. |
|
* 7. Deepest found handler is executed and all lower level commands, |
|
* including expanded commands, are passed as arguments. |
|
*/ |
|
|
|
memset(sh->ctx->temp_buff, 0, sizeof(sh->ctx->temp_buff)); |
|
memcpy(sh->ctx->temp_buff, |
|
sh->ctx->cmd_buff, |
|
sh->ctx->cmd_buff_len); |
|
|
|
/* Function shell_spaces_trim must be used instead of shell_make_argv. |
|
* At this point it is important to keep temp_buff as one string. |
|
* It will allow to find wildcard commands easily with strstr function. |
|
*/ |
|
z_shell_spaces_trim(sh->ctx->temp_buff); |
|
|
|
/* +1 for EOS*/ |
|
sh->ctx->cmd_tmp_buff_len = z_shell_strlen(sh->ctx->temp_buff) + 1; |
|
} |
|
|
|
|
|
enum shell_wildcard_status z_shell_wildcard_process(const struct shell *sh, |
|
const struct shell_static_entry *cmd, |
|
const char *pattern) |
|
{ |
|
enum shell_wildcard_status ret_val = SHELL_WILDCARD_NOT_FOUND; |
|
|
|
if (cmd == NULL) { |
|
return ret_val; |
|
} |
|
|
|
if (!z_shell_has_wildcard(pattern)) { |
|
return ret_val; |
|
} |
|
|
|
/* Function will search commands tree for commands matching wildcard |
|
* pattern stored in argv[cmd_lvl]. When match is found wildcard pattern |
|
* will be replaced by matching commands. If there is no space in the |
|
* buffer to add all matching commands function will add as many as |
|
* possible. Next it will continue to search for next wildcard pattern |
|
* and it will try to add matching commands. |
|
*/ |
|
ret_val = commands_expand(sh, cmd, pattern); |
|
|
|
return ret_val; |
|
} |
|
|
|
void z_shell_wildcard_finalize(const struct shell *sh) |
|
{ |
|
memcpy(sh->ctx->cmd_buff, |
|
sh->ctx->temp_buff, |
|
sh->ctx->cmd_tmp_buff_len); |
|
sh->ctx->cmd_buff_len = sh->ctx->cmd_tmp_buff_len; |
|
}
|
|
|