1*10465441SEvalZero /*
2*10465441SEvalZero This file is part of UFFS, the Ultra-low-cost Flash File System.
3*10465441SEvalZero
4*10465441SEvalZero Copyright (C) 2005-2009 Ricky Zheng <[email protected]>
5*10465441SEvalZero
6*10465441SEvalZero UFFS is free software; you can redistribute it and/or modify it under
7*10465441SEvalZero the GNU Library General Public License as published by the Free Software
8*10465441SEvalZero Foundation; either version 2 of the License, or (at your option) any
9*10465441SEvalZero later version.
10*10465441SEvalZero
11*10465441SEvalZero UFFS is distributed in the hope that it will be useful, but WITHOUT
12*10465441SEvalZero ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13*10465441SEvalZero FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14*10465441SEvalZero or GNU Library General Public License, as applicable, for more details.
15*10465441SEvalZero
16*10465441SEvalZero You should have received a copy of the GNU General Public License
17*10465441SEvalZero and GNU Library General Public License along with UFFS; if not, write
18*10465441SEvalZero to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19*10465441SEvalZero Boston, MA 02110-1301, USA.
20*10465441SEvalZero
21*10465441SEvalZero As a special exception, if other files instantiate templates or use
22*10465441SEvalZero macros or inline functions from this file, or you compile this file
23*10465441SEvalZero and link it with other works to produce a work based on this file,
24*10465441SEvalZero this file does not by itself cause the resulting work to be covered
25*10465441SEvalZero by the GNU General Public License. However the source code for this
26*10465441SEvalZero file must still be made available in accordance with section (3) of
27*10465441SEvalZero the GNU General Public License v2.
28*10465441SEvalZero
29*10465441SEvalZero This exception does not invalidate any other reasons why a work based
30*10465441SEvalZero on this file might be covered by the GNU General Public License.
31*10465441SEvalZero */
32*10465441SEvalZero
33*10465441SEvalZero /**
34*10465441SEvalZero * \file cmdline.c
35*10465441SEvalZero * \brief command line test interface
36*10465441SEvalZero * \author Ricky Zheng, created in 22th Feb, 2007
37*10465441SEvalZero */
38*10465441SEvalZero
39*10465441SEvalZero #include <string.h>
40*10465441SEvalZero #include <stdio.h>
41*10465441SEvalZero //#include <conio.h>
42*10465441SEvalZero #include "uffs_config.h"
43*10465441SEvalZero #include "cmdline.h"
44*10465441SEvalZero #include "uffs/uffs_fs.h"
45*10465441SEvalZero
46*10465441SEvalZero #define PROMPT "UFFS>"
47*10465441SEvalZero
48*10465441SEvalZero #define PFX "cli : "
49*10465441SEvalZero #define MSGLN(msg,...) uffs_Perror(UFFS_MSG_NORMAL, msg, ## __VA_ARGS__)
50*10465441SEvalZero #define MSG(msg,...) uffs_PerrorRaw(UFFS_MSG_NORMAL, msg, ## __VA_ARGS__)
51*10465441SEvalZero
52*10465441SEvalZero #define MAX_CLI_ARGS_BUF_LEN 120
53*10465441SEvalZero #define MAX_CLI_ARGS_NUM 20
54*10465441SEvalZero #define MAX_CLI_ENV_NUM 11 // '?', '0' - '9'
55*10465441SEvalZero
56*10465441SEvalZero
57*10465441SEvalZero struct cli_arg {
58*10465441SEvalZero int argc;
59*10465441SEvalZero char *argv[MAX_CLI_ARGS_NUM];
60*10465441SEvalZero char _buf[MAX_CLI_ARGS_BUF_LEN];
61*10465441SEvalZero };
62*10465441SEvalZero
63*10465441SEvalZero static BOOL m_exit = FALSE;
64*10465441SEvalZero static BOOL m_abort = FALSE;
65*10465441SEvalZero static struct cli_commandset *m_cmdset_head = NULL;
66*10465441SEvalZero
67*10465441SEvalZero // Note: last command return code stored in env 0.
68*10465441SEvalZero static int m_cli_envs[MAX_CLI_ENV_NUM] = {0}; // cli environment variables
69*10465441SEvalZero
70*10465441SEvalZero static const struct cli_command * cli_find(const char *cmd);
71*10465441SEvalZero static int cmd_help(int argc, char *argv[]);
72*10465441SEvalZero
73*10465441SEvalZero
74*10465441SEvalZero #define FOR_EACH_CLI_CMD(set, cmd) \
75*10465441SEvalZero for (set = m_cmdset_head; set && set->cmds; set = set->next) \
76*10465441SEvalZero for (cmd = set->cmds; cmd && cmd->handler; cmd++)
77*10465441SEvalZero
78*10465441SEvalZero
79*10465441SEvalZero /*** filter out leading and tailing spaces, discard comments
80*10465441SEvalZero * return pointer to start of new command line
81*10465441SEvalZero */
cli_process_line(char * p)82*10465441SEvalZero static char * cli_process_line(char *p)
83*10465441SEvalZero {
84*10465441SEvalZero char *s;
85*10465441SEvalZero char *x;
86*10465441SEvalZero
87*10465441SEvalZero if (!p)
88*10465441SEvalZero return NULL;
89*10465441SEvalZero
90*10465441SEvalZero // skip leading spaces
91*10465441SEvalZero while (p && (*p == ' ' || *p == '\t'))
92*10465441SEvalZero p++;
93*10465441SEvalZero
94*10465441SEvalZero for (s = x = p; *p; x++, p++) {
95*10465441SEvalZero switch(*p) {
96*10465441SEvalZero case '\\':
97*10465441SEvalZero p++;
98*10465441SEvalZero if (*p) {
99*10465441SEvalZero switch(*p) {
100*10465441SEvalZero case 'n':
101*10465441SEvalZero *x = '\n';
102*10465441SEvalZero break;
103*10465441SEvalZero case 'r':
104*10465441SEvalZero *x = '\r';
105*10465441SEvalZero break;
106*10465441SEvalZero case 't':
107*10465441SEvalZero *x = '\t';
108*10465441SEvalZero break;
109*10465441SEvalZero case 'b':
110*10465441SEvalZero *x = '\b';
111*10465441SEvalZero break;
112*10465441SEvalZero default:
113*10465441SEvalZero if (*p >= '0' && *p <= '9')
114*10465441SEvalZero *x = *p - '0';
115*10465441SEvalZero else
116*10465441SEvalZero *x = *p;
117*10465441SEvalZero break;
118*10465441SEvalZero }
119*10465441SEvalZero }
120*10465441SEvalZero break;
121*10465441SEvalZero default:
122*10465441SEvalZero if (*p == '\r' || *p == '\n' || *p == '#') *p = '\0';
123*10465441SEvalZero *x = *p;
124*10465441SEvalZero break;
125*10465441SEvalZero }
126*10465441SEvalZero
127*10465441SEvalZero if (*p == 0)
128*10465441SEvalZero break;
129*10465441SEvalZero }
130*10465441SEvalZero
131*10465441SEvalZero // trim tailing spaces
132*10465441SEvalZero p--;
133*10465441SEvalZero while (p > s && (*p == ' ' || *p == '\t'))
134*10465441SEvalZero *p-- = '\0';
135*10465441SEvalZero
136*10465441SEvalZero return s;
137*10465441SEvalZero }
138*10465441SEvalZero
cli_env_to_idx(char env)139*10465441SEvalZero static int cli_env_to_idx(char env)
140*10465441SEvalZero {
141*10465441SEvalZero int idx = -1;
142*10465441SEvalZero
143*10465441SEvalZero if (env >= '0' && env <= '9') {
144*10465441SEvalZero idx = env - '0' + 1;
145*10465441SEvalZero }
146*10465441SEvalZero else if (env == '?') {
147*10465441SEvalZero idx = 0;
148*10465441SEvalZero }
149*10465441SEvalZero
150*10465441SEvalZero return idx;
151*10465441SEvalZero }
152*10465441SEvalZero
cli_env_set(char env,int val)153*10465441SEvalZero int cli_env_set(char env, int val)
154*10465441SEvalZero {
155*10465441SEvalZero int idx = cli_env_to_idx(env);
156*10465441SEvalZero
157*10465441SEvalZero if (idx >= 0) {
158*10465441SEvalZero m_cli_envs[idx] = val;
159*10465441SEvalZero return 0;
160*10465441SEvalZero }
161*10465441SEvalZero else
162*10465441SEvalZero return -1;
163*10465441SEvalZero }
164*10465441SEvalZero
cli_env_get(char env)165*10465441SEvalZero int cli_env_get(char env)
166*10465441SEvalZero {
167*10465441SEvalZero int idx = cli_env_to_idx(env);
168*10465441SEvalZero
169*10465441SEvalZero return idx >= 0 ? m_cli_envs[idx] : 0;
170*10465441SEvalZero }
171*10465441SEvalZero
172*10465441SEvalZero /** exec command <n> times:
173*10465441SEvalZero * exec <n> <cmd> [...]
174*10465441SEvalZero */
cmd_exec(int argc,char * argv[])175*10465441SEvalZero static int cmd_exec(int argc, char *argv[])
176*10465441SEvalZero {
177*10465441SEvalZero int n = 0;
178*10465441SEvalZero const struct cli_command *cmd;
179*10465441SEvalZero
180*10465441SEvalZero CHK_ARGC(3, 0);
181*10465441SEvalZero
182*10465441SEvalZero if (sscanf(argv[1], "%d", &n) != 1)
183*10465441SEvalZero return CLI_INVALID_ARG;
184*10465441SEvalZero if (n <= 0)
185*10465441SEvalZero return CLI_INVALID_ARG;
186*10465441SEvalZero
187*10465441SEvalZero cmd = cli_find(argv[2]);
188*10465441SEvalZero if (cmd == NULL) {
189*10465441SEvalZero MSG("Unknown command '%s'\n", argv[2]);
190*10465441SEvalZero return -1;
191*10465441SEvalZero }
192*10465441SEvalZero else {
193*10465441SEvalZero argv += 2;
194*10465441SEvalZero while (n-- >= 0) {
195*10465441SEvalZero if (cmd->handler(argc - 2, argv) != 0)
196*10465441SEvalZero return -1;
197*10465441SEvalZero }
198*10465441SEvalZero }
199*10465441SEvalZero
200*10465441SEvalZero return 0;
201*10465441SEvalZero }
202*10465441SEvalZero
203*10465441SEvalZero /**
204*10465441SEvalZero * test expression
205*10465441SEvalZero * test <a> <op> <b>
206*10465441SEvalZero * for example:
207*10465441SEvalZero * test 1 > 0 ==> return 0
208*10465441SEvalZero * test 1 <= 0 ==> return -1
209*10465441SEvalZero */
cmd_test(int argc,char * argv[])210*10465441SEvalZero static int cmd_test(int argc, char *argv[])
211*10465441SEvalZero {
212*10465441SEvalZero int a, b;
213*10465441SEvalZero char *op;
214*10465441SEvalZero BOOL tst = FALSE;
215*10465441SEvalZero
216*10465441SEvalZero CHK_ARGC(4, 4);
217*10465441SEvalZero
218*10465441SEvalZero if (sscanf(argv[1], "%d", &a) != 1 ||
219*10465441SEvalZero sscanf(argv[3], "%d", &b) != 1)
220*10465441SEvalZero {
221*10465441SEvalZero return CLI_INVALID_ARG;
222*10465441SEvalZero }
223*10465441SEvalZero
224*10465441SEvalZero op = argv[2];
225*10465441SEvalZero if (!strcmp(op, ">")) {
226*10465441SEvalZero tst = (a > b);
227*10465441SEvalZero }
228*10465441SEvalZero else if (!strcmp(op, "<")) {
229*10465441SEvalZero tst = (a < b);
230*10465441SEvalZero }
231*10465441SEvalZero else if (!strcmp(op, "==")) {
232*10465441SEvalZero tst = (a == b);
233*10465441SEvalZero }
234*10465441SEvalZero else if (!strcmp(op, ">=")) {
235*10465441SEvalZero tst = (a >= b);
236*10465441SEvalZero }
237*10465441SEvalZero else if (!strcmp(op, "<=")) {
238*10465441SEvalZero tst = (a <= b);
239*10465441SEvalZero }
240*10465441SEvalZero else if (!strcmp(op, "!=")) {
241*10465441SEvalZero tst = (a != b);
242*10465441SEvalZero }
243*10465441SEvalZero else {
244*10465441SEvalZero return CLI_INVALID_ARG;
245*10465441SEvalZero }
246*10465441SEvalZero
247*10465441SEvalZero return tst ? 0 : -1;
248*10465441SEvalZero }
249*10465441SEvalZero
250*10465441SEvalZero /** if last command failed (return != 0), run <cmd>
251*10465441SEvalZero * ! <cmd>
252*10465441SEvalZero */
cmd_failed(int argc,char * argv[])253*10465441SEvalZero static int cmd_failed(int argc, char *argv[])
254*10465441SEvalZero {
255*10465441SEvalZero const struct cli_command *cmd;
256*10465441SEvalZero
257*10465441SEvalZero CHK_ARGC(2, 0);
258*10465441SEvalZero
259*10465441SEvalZero cmd = cli_find(argv[1]);
260*10465441SEvalZero if (cmd == NULL) {
261*10465441SEvalZero MSG("Unknown command '%s'\n", argv[1]);
262*10465441SEvalZero return -1;
263*10465441SEvalZero }
264*10465441SEvalZero else {
265*10465441SEvalZero argv++;
266*10465441SEvalZero return (cli_env_get('?') == 0 ? 0 : cmd->handler(argc - 1, argv));
267*10465441SEvalZero }
268*10465441SEvalZero }
269*10465441SEvalZero
270*10465441SEvalZero /** print messages
271*10465441SEvalZero * echo [<arg> ...]
272*10465441SEvalZero */
cmd_echo(int argc,char * argv[])273*10465441SEvalZero static int cmd_echo(int argc, char *argv[])
274*10465441SEvalZero {
275*10465441SEvalZero int i;
276*10465441SEvalZero
277*10465441SEvalZero for (i = 1; i < argc; i++) {
278*10465441SEvalZero MSG("%s%s", i > 1 ? " " : "", argv[i]);
279*10465441SEvalZero }
280*10465441SEvalZero MSG("\n");
281*10465441SEvalZero
282*10465441SEvalZero return 0;
283*10465441SEvalZero }
284*10465441SEvalZero
285*10465441SEvalZero /** set cli environment variable
286*10465441SEvalZero * set <env> <value>
287*10465441SEvalZero */
cmd_set(int argc,char * argv[])288*10465441SEvalZero static int cmd_set(int argc, char *argv[])
289*10465441SEvalZero {
290*10465441SEvalZero int val;
291*10465441SEvalZero int ret = -1;
292*10465441SEvalZero
293*10465441SEvalZero CHK_ARGC(3, 0);
294*10465441SEvalZero
295*10465441SEvalZero if (sscanf(argv[2], "%d", &val) == 1) {
296*10465441SEvalZero ret = cli_env_set(argv[1][0], val);
297*10465441SEvalZero }
298*10465441SEvalZero
299*10465441SEvalZero return ret;
300*10465441SEvalZero }
301*10465441SEvalZero
302*10465441SEvalZero /** evaluation the expresstion, result to $1
303*10465441SEvalZero * evl <value> <op> <value>
304*10465441SEvalZero */
cmd_evl(int argc,char * argv[])305*10465441SEvalZero static int cmd_evl(int argc, char *argv[])
306*10465441SEvalZero {
307*10465441SEvalZero int val1, val2, result = 0;
308*10465441SEvalZero int ret = -1;
309*10465441SEvalZero
310*10465441SEvalZero CHK_ARGC(4, 4);
311*10465441SEvalZero
312*10465441SEvalZero if (sscanf(argv[1], "%d", &val1) == 1 &&
313*10465441SEvalZero sscanf(argv[3], "%d", &val2) == 1) {
314*10465441SEvalZero ret = 0;
315*10465441SEvalZero switch(argv[2][0]) {
316*10465441SEvalZero case '+':
317*10465441SEvalZero result = val1 + val2;
318*10465441SEvalZero break;
319*10465441SEvalZero case '-':
320*10465441SEvalZero result = val1 - val2;
321*10465441SEvalZero break;
322*10465441SEvalZero case '*':
323*10465441SEvalZero result = val1 * val2;
324*10465441SEvalZero break;
325*10465441SEvalZero case '/':
326*10465441SEvalZero if (val2 == 0)
327*10465441SEvalZero ret = -1;
328*10465441SEvalZero else
329*10465441SEvalZero result = val1 / val2;
330*10465441SEvalZero break;
331*10465441SEvalZero case '%':
332*10465441SEvalZero if (val2 == 0)
333*10465441SEvalZero ret = -1;
334*10465441SEvalZero else
335*10465441SEvalZero result = val1 % val2;
336*10465441SEvalZero break;
337*10465441SEvalZero default:
338*10465441SEvalZero ret = CLI_INVALID_ARG;
339*10465441SEvalZero break;
340*10465441SEvalZero }
341*10465441SEvalZero }
342*10465441SEvalZero
343*10465441SEvalZero if (ret == 0)
344*10465441SEvalZero ret = cli_env_set('1', result);
345*10465441SEvalZero
346*10465441SEvalZero return ret;
347*10465441SEvalZero }
348*10465441SEvalZero
cmd_exit(int argc,char * argv[])349*10465441SEvalZero static int cmd_exit(int argc, char *argv[])
350*10465441SEvalZero {
351*10465441SEvalZero m_exit = TRUE;
352*10465441SEvalZero return 0;
353*10465441SEvalZero }
354*10465441SEvalZero
355*10465441SEvalZero /** Abort current script
356*10465441SEvalZero * abort [...]
357*10465441SEvalZero */
cmd_abort(int argc,char * argv[])358*10465441SEvalZero static int cmd_abort(int argc, char *argv[])
359*10465441SEvalZero {
360*10465441SEvalZero if (argc > 1) {
361*10465441SEvalZero cmd_echo(argc, argv);
362*10465441SEvalZero }
363*10465441SEvalZero
364*10465441SEvalZero m_abort = TRUE;
365*10465441SEvalZero
366*10465441SEvalZero return 0;
367*10465441SEvalZero }
368*10465441SEvalZero
369*10465441SEvalZero /** run local file system's script
370*10465441SEvalZero * script <filename>
371*10465441SEvalZero */
cmd_script(int argc,char * argv[])372*10465441SEvalZero static int cmd_script(int argc, char *argv[])
373*10465441SEvalZero {
374*10465441SEvalZero char line_buf[256];
375*10465441SEvalZero char *p;
376*10465441SEvalZero FILE *fp;
377*10465441SEvalZero const char *name;
378*10465441SEvalZero int ret = 0;
379*10465441SEvalZero static int stack = 0;
380*10465441SEvalZero
381*10465441SEvalZero CHK_ARGC(2, 0);
382*10465441SEvalZero
383*10465441SEvalZero if (stack++ == 0)
384*10465441SEvalZero m_abort = FALSE;
385*10465441SEvalZero
386*10465441SEvalZero name = argv[1];
387*10465441SEvalZero fp = fopen(name, "r");
388*10465441SEvalZero
389*10465441SEvalZero if (fp) {
390*10465441SEvalZero memset(line_buf, 0, sizeof(line_buf));
391*10465441SEvalZero while (!m_abort && fgets(line_buf, sizeof(line_buf) - 1, fp)) {
392*10465441SEvalZero p = line_buf + sizeof(line_buf) - 1;
393*10465441SEvalZero while (*p == 0 && p > line_buf)
394*10465441SEvalZero p--;
395*10465441SEvalZero while ((*p == '\r' || *p == '\n') && p > line_buf) {
396*10465441SEvalZero *p-- = 0;
397*10465441SEvalZero }
398*10465441SEvalZero p = cli_process_line(line_buf);
399*10465441SEvalZero if (*p)
400*10465441SEvalZero ret = cli_interpret(p);
401*10465441SEvalZero memset(line_buf, 0, sizeof(line_buf));
402*10465441SEvalZero }
403*10465441SEvalZero fclose(fp);
404*10465441SEvalZero }
405*10465441SEvalZero else {
406*10465441SEvalZero MSG("Can't open host script file '%s' for read\n", name);
407*10465441SEvalZero ret = -1;
408*10465441SEvalZero }
409*10465441SEvalZero
410*10465441SEvalZero stack--;
411*10465441SEvalZero
412*10465441SEvalZero return ret;
413*10465441SEvalZero }
414*10465441SEvalZero
415*10465441SEvalZero
416*10465441SEvalZero
417*10465441SEvalZero static const struct cli_command default_cmds[] =
418*10465441SEvalZero {
419*10465441SEvalZero { cmd_help, "help|?", "[<command>]", "show commands or help on one command" },
420*10465441SEvalZero { cmd_exit, "exit", NULL, "exit command line" },
421*10465441SEvalZero { cmd_exec, "*", "<n> <cmd> [...]>", "run <cmd> <n> times" },
422*10465441SEvalZero { cmd_failed, "!", "<cmd> [...]", "run <cmd> if last command failed" },
423*10465441SEvalZero { cmd_echo, "echo", "[...]", "print messages" },
424*10465441SEvalZero { cmd_set, "set", "<env> <val>", "set env variable" },
425*10465441SEvalZero { cmd_evl, "evl", "<val> <op> <val>", "evaluation expresstion" },
426*10465441SEvalZero { cmd_test, "test", "<a> <op> <b>", "test expression: <a> <op> <b>" },
427*10465441SEvalZero { cmd_script, "script", "<file>", "run host script <file>" },
428*10465441SEvalZero { cmd_abort, "abort", NULL, "abort from the running script" },
429*10465441SEvalZero { NULL, NULL, NULL, NULL }
430*10465441SEvalZero };
431*10465441SEvalZero
432*10465441SEvalZero static struct cli_commandset default_cmdset = {
433*10465441SEvalZero default_cmds,
434*10465441SEvalZero };
435*10465441SEvalZero
match_cmd(const char * src,int start,int end,const char * des)436*10465441SEvalZero static BOOL match_cmd(const char *src, int start, int end, const char *des)
437*10465441SEvalZero {
438*10465441SEvalZero while (src[start] == ' ' && start < end)
439*10465441SEvalZero start++;
440*10465441SEvalZero
441*10465441SEvalZero while (src[end] == ' ' && start < end)
442*10465441SEvalZero end--;
443*10465441SEvalZero
444*10465441SEvalZero if ((int)strlen(des) == (end - start + 1)) {
445*10465441SEvalZero if (memcmp(src + start, des, end - start + 1) == 0) {
446*10465441SEvalZero return TRUE;
447*10465441SEvalZero }
448*10465441SEvalZero }
449*10465441SEvalZero
450*10465441SEvalZero return FALSE;
451*10465441SEvalZero }
452*10465441SEvalZero
check_cmd(const char * cmds,const char * cmd)453*10465441SEvalZero static BOOL check_cmd(const char *cmds, const char *cmd)
454*10465441SEvalZero {
455*10465441SEvalZero int start, end;
456*10465441SEvalZero
457*10465441SEvalZero for (start = end = 0; cmds[end] != 0 && cmds[end] != '|'; end++);
458*10465441SEvalZero
459*10465441SEvalZero while (end > start) {
460*10465441SEvalZero if (match_cmd(cmds, start, end - 1, cmd) == TRUE)
461*10465441SEvalZero return TRUE;
462*10465441SEvalZero if (cmds[end] == 0)
463*10465441SEvalZero break;
464*10465441SEvalZero if (cmds[end] == '|') {
465*10465441SEvalZero end++;
466*10465441SEvalZero for (start = end; cmds[end] != 0 && cmds[end] != '|'; end++);
467*10465441SEvalZero }
468*10465441SEvalZero }
469*10465441SEvalZero
470*10465441SEvalZero return FALSE;
471*10465441SEvalZero }
472*10465441SEvalZero
cli_find(const char * cmd)473*10465441SEvalZero static const struct cli_command * cli_find(const char *cmd)
474*10465441SEvalZero {
475*10465441SEvalZero struct cli_commandset *work;
476*10465441SEvalZero const struct cli_command *s;
477*10465441SEvalZero
478*10465441SEvalZero FOR_EACH_CLI_CMD(work, s) {
479*10465441SEvalZero if (check_cmd(s->cmd, cmd) == TRUE)
480*10465441SEvalZero return s;
481*10465441SEvalZero }
482*10465441SEvalZero
483*10465441SEvalZero return NULL;
484*10465441SEvalZero }
485*10465441SEvalZero
show_cmd_usage(const struct cli_command * cmd)486*10465441SEvalZero static void show_cmd_usage(const struct cli_command *cmd)
487*10465441SEvalZero {
488*10465441SEvalZero MSG("%s: %s\n", cmd->cmd, cmd->descr);
489*10465441SEvalZero MSG("Usage: %s %s\n", cmd->cmd, cmd->args ? cmd->args : "");
490*10465441SEvalZero }
491*10465441SEvalZero
cmd_help(int argc,char * argv[])492*10465441SEvalZero static int cmd_help(int argc, char *argv[])
493*10465441SEvalZero {
494*10465441SEvalZero const struct cli_command *cmd;
495*10465441SEvalZero struct cli_commandset *cmdset;
496*10465441SEvalZero int i, n;
497*10465441SEvalZero
498*10465441SEvalZero if (argc < 2) {
499*10465441SEvalZero MSG("Available commands:\n");
500*10465441SEvalZero n = 0;
501*10465441SEvalZero FOR_EACH_CLI_CMD(cmdset, cmd) {
502*10465441SEvalZero MSG("%s", cmd->cmd);
503*10465441SEvalZero for (i = strlen(cmd->cmd); i%10; i++, MSG(" "));
504*10465441SEvalZero if ((++n % 5) == 0) MSG("\n");
505*10465441SEvalZero }
506*10465441SEvalZero MSG("\n");
507*10465441SEvalZero }
508*10465441SEvalZero else {
509*10465441SEvalZero cmd = cli_find(argv[1]);
510*10465441SEvalZero if (cmd == NULL) {
511*10465441SEvalZero MSG("No such command\n");
512*10465441SEvalZero return -1;
513*10465441SEvalZero }
514*10465441SEvalZero else {
515*10465441SEvalZero show_cmd_usage(cmd);
516*10465441SEvalZero }
517*10465441SEvalZero }
518*10465441SEvalZero
519*10465441SEvalZero return 0;
520*10465441SEvalZero }
521*10465441SEvalZero
cli_parse_args(const char * cmd,struct cli_arg * arg)522*10465441SEvalZero static void cli_parse_args(const char *cmd, struct cli_arg *arg)
523*10465441SEvalZero {
524*10465441SEvalZero char *p;
525*10465441SEvalZero int val;
526*10465441SEvalZero
527*10465441SEvalZero if (arg) {
528*10465441SEvalZero arg->argc = 0;
529*10465441SEvalZero if (cmd) {
530*10465441SEvalZero p = arg->_buf;
531*10465441SEvalZero while (*cmd && arg->argc < MAX_CLI_ARGS_NUM && (p - arg->_buf < MAX_CLI_ARGS_BUF_LEN)) {
532*10465441SEvalZero while(*cmd && (*cmd == ' ' || *cmd == '\t'))
533*10465441SEvalZero cmd++;
534*10465441SEvalZero
535*10465441SEvalZero arg->argv[arg->argc] = p;
536*10465441SEvalZero while (*cmd && (*cmd != ' ' && *cmd != '\t') && (p - arg->_buf < MAX_CLI_ARGS_BUF_LEN)) {
537*10465441SEvalZero if (*cmd == '$') {
538*10465441SEvalZero // command env replacement
539*10465441SEvalZero cmd++;
540*10465441SEvalZero val = cli_env_get(*cmd++);
541*10465441SEvalZero if (p - arg->_buf < MAX_CLI_ARGS_BUF_LEN - 12) { // 12 is long enough for 32bit 'int'
542*10465441SEvalZero p += sprintf(p, "%d", val & 0xFFFFFFFF);
543*10465441SEvalZero }
544*10465441SEvalZero }
545*10465441SEvalZero else
546*10465441SEvalZero *p++ = *cmd++;
547*10465441SEvalZero }
548*10465441SEvalZero *p++ = '\0';
549*10465441SEvalZero
550*10465441SEvalZero if (*(arg->argv[arg->argc]) == '\0')
551*10465441SEvalZero break;
552*10465441SEvalZero arg->argc++;
553*10465441SEvalZero }
554*10465441SEvalZero }
555*10465441SEvalZero }
556*10465441SEvalZero }
557*10465441SEvalZero
cli_interpret(const char * line)558*10465441SEvalZero int cli_interpret(const char *line)
559*10465441SEvalZero {
560*10465441SEvalZero struct cli_arg arg = {0};
561*10465441SEvalZero const struct cli_command *cmd;
562*10465441SEvalZero int ret = -1;
563*10465441SEvalZero
564*10465441SEvalZero cli_parse_args(line, &arg);
565*10465441SEvalZero
566*10465441SEvalZero if (arg.argc > 0) {
567*10465441SEvalZero cmd = cli_find(arg.argv[0]);
568*10465441SEvalZero if (cmd == NULL) {
569*10465441SEvalZero MSG("Unknown command '%s'\n", arg.argv[0]);
570*10465441SEvalZero }
571*10465441SEvalZero else {
572*10465441SEvalZero ret = cmd->handler(arg.argc, arg.argv);
573*10465441SEvalZero if (ret == CLI_INVALID_ARG) {
574*10465441SEvalZero MSG("\n");
575*10465441SEvalZero show_cmd_usage(cmd);
576*10465441SEvalZero }
577*10465441SEvalZero }
578*10465441SEvalZero }
579*10465441SEvalZero
580*10465441SEvalZero cli_env_set('?', ret); // $? = last command return code
581*10465441SEvalZero
582*10465441SEvalZero return ret;
583*10465441SEvalZero }
584*10465441SEvalZero
cli_add_commandset(struct cli_commandset * set)585*10465441SEvalZero void cli_add_commandset(struct cli_commandset *set)
586*10465441SEvalZero {
587*10465441SEvalZero if (set) {
588*10465441SEvalZero set->next = m_cmdset_head;
589*10465441SEvalZero m_cmdset_head = set;
590*10465441SEvalZero }
591*10465441SEvalZero }
592*10465441SEvalZero
cli_main_entry()593*10465441SEvalZero void cli_main_entry()
594*10465441SEvalZero {
595*10465441SEvalZero char line[80];
596*10465441SEvalZero int linelen = 0;
597*10465441SEvalZero char *p;
598*10465441SEvalZero
599*10465441SEvalZero MSG("$ ");
600*10465441SEvalZero cli_add_commandset(&default_cmdset);
601*10465441SEvalZero
602*10465441SEvalZero while (!m_exit) {
603*10465441SEvalZero char ch;
604*10465441SEvalZero if (linelen >= sizeof(line))
605*10465441SEvalZero continue;
606*10465441SEvalZero ch = getc(stdin);
607*10465441SEvalZero switch (ch) {
608*10465441SEvalZero case 8:
609*10465441SEvalZero case 127:
610*10465441SEvalZero if (linelen > 0) {
611*10465441SEvalZero --linelen;
612*10465441SEvalZero MSG("\x08 \x08");
613*10465441SEvalZero }
614*10465441SEvalZero break;
615*10465441SEvalZero
616*10465441SEvalZero case '\r':
617*10465441SEvalZero case '\n':
618*10465441SEvalZero //MSG("\r\n");
619*10465441SEvalZero if (linelen > 0) {
620*10465441SEvalZero line[linelen] = 0;
621*10465441SEvalZero p = cli_process_line(line);
622*10465441SEvalZero if (*p)
623*10465441SEvalZero cli_interpret(p);
624*10465441SEvalZero linelen = 0;
625*10465441SEvalZero }
626*10465441SEvalZero MSG("$ ");
627*10465441SEvalZero break;
628*10465441SEvalZero
629*10465441SEvalZero case 21:
630*10465441SEvalZero while (linelen > 0) {
631*10465441SEvalZero --linelen;
632*10465441SEvalZero MSG("\x08 \x08");
633*10465441SEvalZero }
634*10465441SEvalZero break;
635*10465441SEvalZero
636*10465441SEvalZero default:
637*10465441SEvalZero if (ch >= ' ' && ch < 127 && linelen < sizeof(line) - 1) {
638*10465441SEvalZero line[linelen++] = ch;
639*10465441SEvalZero //MSG("%c", ch);
640*10465441SEvalZero }
641*10465441SEvalZero }
642*10465441SEvalZero }
643*10465441SEvalZero }
644