Everywhere the return of this function was being assigned to u16_t to save space on stack. Instead of casting in all these places (and may end up with overflow), just changing this function's return. Note that the function itself is not checking for overflow yet since I'm not sure this can happen and/or is a problem. Though now we have only one single point to fix this problem. Signed-off-by: Flavio Ceolin <flavio.ceolin@intel.com>
380 lines
7.6 KiB
C
380 lines
7.6 KiB
C
/*
|
|
* Copyright (c) 2018 Nordic Semiconductor ASA
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
#include "shell_utils.h"
|
|
#include <ctype.h>
|
|
|
|
extern const struct shell_cmd_entry __shell_root_cmds_start[0];
|
|
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)
|
|
{
|
|
return &__shell_root_cmds_start[id];
|
|
}
|
|
|
|
/* Calculates relative line number of given position in buffer */
|
|
static u32_t line_num_with_buffer_offset_get(struct shell_multiline_cons *cons,
|
|
u16_t buffer_pos)
|
|
{
|
|
return ((buffer_pos + cons->name_len) / cons->terminal_wid);
|
|
}
|
|
|
|
/* Calculates column number of given position in buffer */
|
|
static u32_t col_num_with_buffer_offset_get(struct shell_multiline_cons *cons,
|
|
u16_t buffer_pos)
|
|
{
|
|
/* columns are counted from 1 */
|
|
return (1 + ((buffer_pos + cons->name_len) % cons->terminal_wid));
|
|
}
|
|
|
|
s32_t column_span_with_buffer_offsets_get(struct shell_multiline_cons *cons,
|
|
u16_t offset1,
|
|
u16_t offset2)
|
|
{
|
|
return col_num_with_buffer_offset_get(cons, offset2)
|
|
- col_num_with_buffer_offset_get(cons, offset1);
|
|
}
|
|
|
|
s32_t row_span_with_buffer_offsets_get(struct shell_multiline_cons *cons,
|
|
u16_t offset1,
|
|
u16_t offset2)
|
|
{
|
|
return line_num_with_buffer_offset_get(cons, offset2)
|
|
- line_num_with_buffer_offset_get(cons, offset1);
|
|
}
|
|
|
|
void shell_multiline_data_calc(struct shell_multiline_cons *cons,
|
|
u16_t buff_pos, u16_t buff_len)
|
|
{
|
|
/* Current cursor position in command.
|
|
* +1 -> because home position is (1, 1)
|
|
*/
|
|
cons->cur_x = (buff_pos + cons->name_len) % cons->terminal_wid + 1;
|
|
cons->cur_y = (buff_pos + cons->name_len) / cons->terminal_wid + 1;
|
|
|
|
/* Extreme position when cursor is at the end of command. */
|
|
cons->cur_y_end = (buff_len + cons->name_len) / cons->terminal_wid + 1;
|
|
cons->cur_x_end = (buff_len + cons->name_len) % cons->terminal_wid + 1;
|
|
}
|
|
|
|
static char make_argv(char **ppcmd, u8_t c)
|
|
{
|
|
char *cmd = *ppcmd;
|
|
char quote = 0;
|
|
|
|
while (1) {
|
|
c = *cmd;
|
|
|
|
if (c == '\0') {
|
|
break;
|
|
}
|
|
|
|
if (!quote) {
|
|
switch (c) {
|
|
case '\\':
|
|
memmove(cmd, cmd + 1,
|
|
shell_strlen(cmd));
|
|
cmd += 1;
|
|
continue;
|
|
|
|
case '\'':
|
|
case '\"':
|
|
memmove(cmd, cmd + 1,
|
|
shell_strlen(cmd));
|
|
quote = c;
|
|
continue;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (quote == c) {
|
|
memmove(cmd, cmd + 1, shell_strlen(cmd));
|
|
quote = 0;
|
|
continue;
|
|
}
|
|
|
|
if (quote && c == '\\') {
|
|
char t = *(cmd + 1);
|
|
|
|
if (t == quote) {
|
|
memmove(cmd, cmd + 1,
|
|
shell_strlen(cmd));
|
|
cmd += 1;
|
|
continue;
|
|
}
|
|
|
|
if (t == '0') {
|
|
u8_t i;
|
|
u8_t v = 0U;
|
|
|
|
for (i = 2U; i < (2 + 3); i++) {
|
|
t = *(cmd + i);
|
|
|
|
if (t >= '0' && t <= '7') {
|
|
v = (v << 3) | (t - '0');
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i > 2) {
|
|
memmove(cmd, cmd + (i - 1),
|
|
shell_strlen(cmd) - (i - 2));
|
|
*cmd++ = v;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (t == 'x') {
|
|
u8_t i;
|
|
u8_t v = 0U;
|
|
|
|
for (i = 2U; i < (2 + 2); i++) {
|
|
t = *(cmd + i);
|
|
|
|
if (t >= '0' && t <= '9') {
|
|
v = (v << 4) | (t - '0');
|
|
} else if ((t >= 'a') &&
|
|
(t <= 'f')) {
|
|
v = (v << 4) | (t - 'a' + 10);
|
|
} else if ((t >= 'A') && (t <= 'F')) {
|
|
v = (v << 4) | (t - 'A' + 10);
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i > 2) {
|
|
memmove(cmd, cmd + (i - 1),
|
|
shell_strlen(cmd) - (i - 2));
|
|
*cmd++ = v;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!quote && isspace((int) c)) {
|
|
break;
|
|
}
|
|
|
|
cmd += 1;
|
|
}
|
|
*ppcmd = cmd;
|
|
|
|
return quote;
|
|
}
|
|
|
|
|
|
char shell_make_argv(size_t *argc, char **argv, char *cmd, u8_t max_argc)
|
|
{
|
|
char quote = 0;
|
|
char c;
|
|
|
|
*argc = 0;
|
|
do {
|
|
c = *cmd;
|
|
if (c == '\0') {
|
|
break;
|
|
}
|
|
|
|
if (isspace((int) c)) {
|
|
*cmd++ = '\0';
|
|
continue;
|
|
}
|
|
|
|
argv[(*argc)++] = cmd;
|
|
quote = make_argv(&cmd, c);
|
|
} while (*argc < max_argc);
|
|
|
|
argv[*argc] = 0;
|
|
|
|
return quote;
|
|
}
|
|
|
|
void shell_pattern_remove(char *buff, u16_t *buff_len, const char *pattern)
|
|
{
|
|
char *pattern_addr = strstr(buff, pattern);
|
|
u16_t shift;
|
|
u16_t pattern_len = shell_strlen(pattern);
|
|
|
|
if (!pattern_addr) {
|
|
return;
|
|
}
|
|
|
|
if (pattern_addr > buff) {
|
|
if (*(pattern_addr - 1) == ' ') {
|
|
pattern_len++; /* space needs to be removed as well */
|
|
pattern_addr--; /* set pointer to space */
|
|
}
|
|
}
|
|
|
|
shift = shell_strlen(pattern_addr) - pattern_len + 1; /* +1 for EOS */
|
|
*buff_len -= pattern_len;
|
|
|
|
memmove(pattern_addr, pattern_addr + pattern_len, shift);
|
|
}
|
|
|
|
static inline u32_t shell_root_cmd_count(void)
|
|
{
|
|
return ((u8_t *)__shell_root_cmds_end -
|
|
(u8_t *)__shell_root_cmds_start)/
|
|
sizeof(struct shell_cmd_entry);
|
|
}
|
|
|
|
/* Function returning pointer to root command matching requested syntax. */
|
|
const struct shell_cmd_entry *shell_root_cmd_find(const char *syntax)
|
|
{
|
|
const size_t cmd_count = shell_root_cmd_count();
|
|
const struct shell_cmd_entry *cmd;
|
|
|
|
for (size_t cmd_idx = 0; cmd_idx < cmd_count; ++cmd_idx) {
|
|
cmd = shell_root_cmd_get(cmd_idx);
|
|
if (strcmp(syntax, cmd->u.entry->syntax) == 0) {
|
|
return cmd;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void shell_cmd_get(const struct shell_cmd_entry *command, size_t lvl,
|
|
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 (lvl == SHELL_CMD_ROOT_LVL) {
|
|
if (idx < shell_root_cmd_count()) {
|
|
const struct shell_cmd_entry *cmd;
|
|
|
|
cmd = shell_root_cmd_get(idx);
|
|
*entry = cmd->u.entry;
|
|
} else {
|
|
*entry = NULL;
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (command == NULL) {
|
|
*entry = NULL;
|
|
return;
|
|
}
|
|
|
|
if (command->is_dynamic) {
|
|
command->u.dynamic_get(idx, d_entry);
|
|
*entry = (d_entry->syntax != NULL) ? d_entry : NULL;
|
|
} else {
|
|
*entry = (command->u.entry[idx].syntax != NULL) ?
|
|
&command->u.entry[idx] : NULL;
|
|
}
|
|
}
|
|
|
|
int shell_command_add(char *buff, u16_t *buff_len,
|
|
const char *new_cmd, const char *pattern)
|
|
{
|
|
u16_t cmd_len = shell_strlen(new_cmd);
|
|
char *cmd_source_addr;
|
|
u16_t shift;
|
|
|
|
/* +1 for space */
|
|
if ((*buff_len + cmd_len + 1) > CONFIG_SHELL_CMD_BUFF_SIZE) {
|
|
return -ENOMEM;
|
|
}
|
|
|
|
cmd_source_addr = strstr(buff, pattern);
|
|
|
|
if (!cmd_source_addr) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
shift = shell_strlen(cmd_source_addr);
|
|
|
|
/* make place for new command: + 1 for space + 1 for EOS */
|
|
memmove(cmd_source_addr + cmd_len + 1, cmd_source_addr, shift + 1);
|
|
memcpy(cmd_source_addr, new_cmd, cmd_len);
|
|
cmd_source_addr[cmd_len] = ' ';
|
|
|
|
*buff_len += cmd_len + 1; /* + 1 for space */
|
|
|
|
return 0;
|
|
}
|
|
|
|
void shell_spaces_trim(char *str)
|
|
{
|
|
u16_t len = shell_strlen(str);
|
|
u16_t shift = 0U;
|
|
|
|
if (!str) {
|
|
return;
|
|
}
|
|
|
|
for (u16_t i = 0; i < len - 1; i++) {
|
|
if (isspace((int)str[i])) {
|
|
for (u16_t j = i + 1; j < len; j++) {
|
|
if (isspace((int)str[j])) {
|
|
shift++;
|
|
continue;
|
|
}
|
|
|
|
if (shift > 0) {
|
|
/* +1 for EOS */
|
|
memmove(&str[i + 1],
|
|
&str[j],
|
|
len - shift + 1);
|
|
len -= shift;
|
|
shift = 0U;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/** @brief Remove white chars from beginning and end of command buffer.
|
|
*
|
|
*/
|
|
static void buffer_trim(char *buff, u16_t *buff_len)
|
|
{
|
|
u16_t i = 0U;
|
|
|
|
/* no command in the buffer */
|
|
if (buff[0] == '\0') {
|
|
return;
|
|
}
|
|
|
|
while (isspace((int) buff[*buff_len - 1])) {
|
|
*buff_len -= 1;
|
|
if (*buff_len == 0) {
|
|
buff[0] = '\0';
|
|
return;
|
|
}
|
|
}
|
|
buff[*buff_len] = '\0';
|
|
|
|
/* Counting whitespace characters starting from beginning of the
|
|
* command.
|
|
*/
|
|
while (isspace((int) buff[i++])) {
|
|
if (i == 0) {
|
|
buff[0] = '\0';
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* Removing counted whitespace characters. */
|
|
if (--i > 0) {
|
|
memmove(buff, buff + i, (*buff_len + 1) - i); /* +1 for '\0' */
|
|
*buff_len = *buff_len - i;
|
|
}
|
|
}
|
|
|
|
void shell_cmd_trim(const struct shell *shell)
|
|
{
|
|
buffer_trim(shell->ctx->cmd_buff, &shell->ctx->cmd_buff_len);
|
|
shell->ctx->cmd_buff_pos = shell->ctx->cmd_buff_len;
|
|
}
|