xref: /nrf52832-nimble/rt-thread/components/dfs/filesystems/uffs/src/emu/cmdline.c (revision 104654410c56c573564690304ae786df310c91fc)
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