/* * Copyright (c) 2018 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #define MAX_CMD_CNT (20u) #define MAX_CMD_LEN (33u) /* buffer holding dynamically created user commands */ static char dynamic_cmd_buffer[MAX_CMD_CNT][MAX_CMD_LEN]; /* commands counter */ static uint8_t dynamic_cmd_cnt; typedef int cmp_t(const void *, const void *); extern void qsort(void *a, size_t n, size_t es, cmp_t *cmp); /* function required by qsort */ static int string_cmp(const void *p_a, const void *p_b) { return strcmp((const char *)p_a, (const char *)p_b); } static int cmd_dynamic_add(const struct shell *sh, size_t argc, char **argv) { uint16_t cmd_len; uint8_t idx; ARG_UNUSED(argc); if (dynamic_cmd_cnt >= MAX_CMD_CNT) { shell_error(sh, "command limit reached"); return -ENOEXEC; } cmd_len = strlen(argv[1]); if (cmd_len >= MAX_CMD_LEN) { shell_error(sh, "too long command"); return -ENOEXEC; } for (idx = 0U; idx < cmd_len; idx++) { if (isalnum((int)(argv[1][idx])) == 0) { shell_error(sh, "bad command name - please use only" " alphanumerical characters"); return -ENOEXEC; } } for (idx = 0U; idx < MAX_CMD_CNT; idx++) { if (!strcmp(dynamic_cmd_buffer[idx], argv[1])) { shell_error(sh, "duplicated command"); return -ENOEXEC; } } sprintf(dynamic_cmd_buffer[dynamic_cmd_cnt++], "%s", argv[1]); qsort(dynamic_cmd_buffer, dynamic_cmd_cnt, sizeof(dynamic_cmd_buffer[0]), string_cmp); shell_print(sh, "command added successfully"); return 0; } static int cmd_dynamic_execute(const struct shell *sh, size_t argc, char **argv) { ARG_UNUSED(argc); ARG_UNUSED(argv); for (uint8_t idx = 0; idx < dynamic_cmd_cnt; idx++) { if (!strcmp(dynamic_cmd_buffer[idx], argv[1])) { shell_print(sh, "dynamic command: %s", argv[1]); return 0; } } shell_error(sh, "%s: unknown parameter: %s", argv[0], argv[1]); return -ENOEXEC; } static int cmd_dynamic_remove(const struct shell *sh, size_t argc, char **argv) { ARG_UNUSED(argc); ARG_UNUSED(argv); for (uint8_t idx = 0; idx < dynamic_cmd_cnt; idx++) { if (!strcmp(dynamic_cmd_buffer[idx], argv[1])) { if (idx == MAX_CMD_CNT - 1) { dynamic_cmd_buffer[idx][0] = '\0'; } else { memmove(dynamic_cmd_buffer[idx], dynamic_cmd_buffer[idx + 1], sizeof(dynamic_cmd_buffer[idx]) * (dynamic_cmd_cnt - idx)); } --dynamic_cmd_cnt; shell_print(sh, "command removed successfully"); return 0; } } shell_error(sh, "did not find command: %s", argv[1]); return -ENOEXEC; } static int cmd_dynamic_show(const struct shell *sh, size_t argc, char **argv) { ARG_UNUSED(argc); ARG_UNUSED(argv); if (dynamic_cmd_cnt == 0U) { shell_warn(sh, "Please add some commands first."); return -ENOEXEC; } shell_print(sh, "Dynamic command list:"); for (uint8_t i = 0; i < dynamic_cmd_cnt; i++) { shell_print(sh, "[%3d] %s", i, dynamic_cmd_buffer[i]); } return 0; } /* dynamic command creation */ static void dynamic_cmd_get(size_t idx, struct shell_static_entry *entry) { if (idx < dynamic_cmd_cnt) { /* m_dynamic_cmd_buffer must be sorted alphabetically to ensure * correct CLI completion */ entry->syntax = dynamic_cmd_buffer[idx]; entry->handler = NULL; entry->subcmd = NULL; entry->help = "Show dynamic command name."; } else { /* if there are no more dynamic commands available syntax * must be set to NULL. */ entry->syntax = NULL; } } SHELL_DYNAMIC_CMD_CREATE(m_sub_dynamic_set, dynamic_cmd_get); SHELL_STATIC_SUBCMD_SET_CREATE(m_sub_dynamic, SHELL_CMD_ARG(add, NULL, "Add a new dynamic command.\nExample usage: [ dynamic add test " "] will add a dynamic command 'test'.\nIn this example, command" " name length is limited to 32 chars. You can add up to 20" " commands. Commands are automatically sorted to ensure correct" " shell completion.", cmd_dynamic_add, 2, 0), SHELL_CMD_ARG(execute, &m_sub_dynamic_set, "Execute a command.", cmd_dynamic_execute, 2, 0), SHELL_CMD_ARG(remove, &m_sub_dynamic_set, "Remove a command.", cmd_dynamic_remove, 2, 0), SHELL_CMD_ARG(show, NULL, "Show all added dynamic commands.", cmd_dynamic_show, 1, 0), SHELL_SUBCMD_SET_END ); SHELL_CMD_REGISTER(dynamic, &m_sub_dynamic, "Demonstrate dynamic command usage.", NULL);