3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
5 * Add to readline cmdline-editing by
7 * JinHua Luo, GuangDong Linux Center, <luo.jinhua@gd-linux.com>
9 * SPDX-License-Identifier: GPL-2.0+
14 #include <linux/ctype.h>
16 #define DEBUG_PARSER 0 /* set to 1 to debug */
18 #define debug_parser(fmt, args...) \
19 debug_cond(DEBUG_PARSER, fmt, ##args)
22 int cli_simple_parse_line(char *line, char *argv[])
26 debug_parser("%s: \"%s\"\n", __func__, line);
27 while (nargs < CONFIG_SYS_MAXARGS) {
28 /* skip any white space */
29 while (isblank(*line))
32 if (*line == '\0') { /* end of line, no more args */
34 debug_parser("%s: nargs=%d\n", __func__, nargs);
38 argv[nargs++] = line; /* begin of argument string */
40 /* find end of string */
41 while (*line && !isblank(*line))
44 if (*line == '\0') { /* end of line, no more args */
46 debug_parser("parse_line: nargs=%d\n", nargs);
50 *line++ = '\0'; /* terminate current arg */
53 printf("** Too many args (max. %d) **\n", CONFIG_SYS_MAXARGS);
55 debug_parser("%s: nargs=%d\n", __func__, nargs);
59 static void process_macros(const char *input, char *output)
62 const char *varname_start = NULL;
63 int inputcnt = strlen(input);
64 int outputcnt = CONFIG_SYS_CBSIZE;
65 int state = 0; /* 0 = waiting for '$' */
67 /* 1 = waiting for '(' or '{' */
68 /* 2 = waiting for ')' or '}' */
69 /* 3 = waiting for ''' */
70 char *output_start = output;
72 debug_parser("[PROCESS_MACROS] INPUT len %zd: \"%s\"\n", strlen(input),
75 prev = '\0'; /* previous character */
77 while (inputcnt && outputcnt) {
82 /* remove one level of escape characters */
83 if ((c == '\\') && (prev != '\\')) {
92 case 0: /* Waiting for (unescaped) $ */
93 if ((c == '\'') && (prev != '\\')) {
97 if ((c == '$') && (prev != '\\')) {
104 case 1: /* Waiting for ( */
105 if (c == '(' || c == '{') {
107 varname_start = input;
119 case 2: /* Waiting for ) */
120 if (c == ')' || c == '}') {
122 char envname[CONFIG_SYS_CBSIZE], *envval;
123 /* Varname # of chars */
124 int envcnt = input - varname_start - 1;
126 /* Get the varname */
127 for (i = 0; i < envcnt; i++)
128 envname[i] = varname_start[i];
132 envval = getenv(envname);
134 /* Copy into the line if it exists */
136 while ((*envval) && outputcnt) {
137 *(output++) = *(envval++);
140 /* Look for another '$' */
144 case 3: /* Waiting for ' */
145 if ((c == '\'') && (prev != '\\')) {
161 debug_parser("[PROCESS_MACROS] OUTPUT len %zd: \"%s\"\n",
162 strlen(output_start), output_start);
168 * We must create a temporary copy of the command since the command we get
169 * may be the result from getenv(), which returns a pointer directly to
170 * the environment data, which may change magicly when the command we run
171 * creates or modifies environment variables (like "bootp" does).
173 int cli_simple_run_command(const char *cmd, int flag)
175 char cmdbuf[CONFIG_SYS_CBSIZE]; /* working copy of cmd */
176 char *token; /* start of token in cmdbuf */
177 char *sep; /* end of token (separator) in cmdbuf */
178 char finaltoken[CONFIG_SYS_CBSIZE];
180 char *argv[CONFIG_SYS_MAXARGS + 1]; /* NULL terminated */
185 debug_parser("[RUN_COMMAND] cmd[%p]=\"", cmd);
187 /* use puts - string may be loooong */
188 puts(cmd ? cmd : "NULL");
191 clear_ctrlc(); /* forget any previous Control C */
194 return -1; /* empty command */
196 if (strlen(cmd) >= CONFIG_SYS_CBSIZE) {
197 puts("## Command too long!\n");
203 /* Process separators and check for invalid
204 * repeatable commands
207 debug_parser("[PROCESS_SEPARATORS] %s\n", cmd);
210 * Find separator, or string end
211 * Allow simple escape of ';' by writing "\;"
213 for (inquotes = 0, sep = str; *sep; sep++) {
214 if ((*sep == '\'') &&
215 (*(sep - 1) != '\\'))
216 inquotes = !inquotes;
219 (*sep == ';') && /* separator */
220 (sep != str) && /* past string start */
221 (*(sep - 1) != '\\')) /* and NOT escaped */
226 * Limit the token to data between separators
230 str = sep + 1; /* start of command for next pass */
233 str = sep; /* no more commands for next pass */
235 debug_parser("token: \"%s\"\n", token);
237 /* find macros in this token and replace them */
238 process_macros(token, finaltoken);
240 /* Extract arguments */
241 argc = cli_simple_parse_line(finaltoken, argv);
243 rc = -1; /* no command at all */
247 if (cmd_process(flag, argc, argv, &repeatable, NULL))
250 /* Did the user stop this? */
252 return -1; /* if stopped then not repeatable */
255 return rc ? rc : repeatable;
260 static char lastcommand[CONFIG_SYS_CBSIZE] = { 0, };
267 #ifdef CONFIG_BOOT_RETRY_TIME
269 /* Saw enough of a valid command to
270 * restart the timeout.
275 len = cli_readline(CONFIG_SYS_PROMPT);
277 flag = 0; /* assume no special flags for now */
279 strcpy(lastcommand, console_buffer);
281 flag |= CMD_FLAG_REPEAT;
282 #ifdef CONFIG_BOOT_RETRY_TIME
283 else if (len == -2) {
284 /* -2 means timed out, retry autoboot
286 puts("\nTimed out waiting for command\n");
287 # ifdef CONFIG_RESET_TO_RETRY
288 /* Reinit board to run initialization code again */
289 do_reset(NULL, 0, 0, NULL);
291 return; /* retry autoboot */
297 puts("<INTERRUPT>\n");
299 rc = run_command(lastcommand, flag);
302 /* invalid command or not repeatable, forget it */
308 int cli_simple_run_command_list(char *cmd, int flag)
314 * Break into individual lines, and execute each line; terminate on
322 /* run only non-empty commands */
324 debug("** exec: \"%s\"\n", line);
325 if (cli_simple_run_command(line, 0) < 0) {
334 if (rcode == 0 && *line)
335 rcode = (cli_simple_run_command(line, 0) >= 0);