-
Notifications
You must be signed in to change notification settings - Fork 571
/
dynamic_cmd.c
178 lines (146 loc) · 4.33 KB
/
dynamic_cmd.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
/*
* Copyright (c) 2018 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/shell/shell.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#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);