]>
git.ipfire.org Git - people/ms/u-boot.git/blob - common/cli_simple.c
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+
13 #include <bootretry.h>
16 #include <linux/ctype.h>
18 #define DEBUG_PARSER 0 /* set to 1 to debug */
20 #define debug_parser(fmt, args...) \
21 debug_cond(DEBUG_PARSER, fmt, ##args)
24 int cli_simple_parse_line(char *line
, char *argv
[])
28 debug_parser("%s: \"%s\"\n", __func__
, line
);
29 while (nargs
< CONFIG_SYS_MAXARGS
) {
30 /* skip any white space */
31 while (isblank(*line
))
34 if (*line
== '\0') { /* end of line, no more args */
36 debug_parser("%s: nargs=%d\n", __func__
, nargs
);
40 argv
[nargs
++] = line
; /* begin of argument string */
42 /* find end of string */
43 while (*line
&& !isblank(*line
))
46 if (*line
== '\0') { /* end of line, no more args */
48 debug_parser("parse_line: nargs=%d\n", nargs
);
52 *line
++ = '\0'; /* terminate current arg */
55 printf("** Too many args (max. %d) **\n", CONFIG_SYS_MAXARGS
);
57 debug_parser("%s: nargs=%d\n", __func__
, nargs
);
61 void cli_simple_process_macros(const char *input
, char *output
)
64 const char *varname_start
= NULL
;
65 int inputcnt
= strlen(input
);
66 int outputcnt
= CONFIG_SYS_CBSIZE
;
67 int state
= 0; /* 0 = waiting for '$' */
69 /* 1 = waiting for '(' or '{' */
70 /* 2 = waiting for ')' or '}' */
71 /* 3 = waiting for ''' */
72 char __maybe_unused
*output_start
= output
;
74 debug_parser("[PROCESS_MACROS] INPUT len %zd: \"%s\"\n", strlen(input
),
77 prev
= '\0'; /* previous character */
79 while (inputcnt
&& outputcnt
) {
84 /* remove one level of escape characters */
85 if ((c
== '\\') && (prev
!= '\\')) {
94 case 0: /* Waiting for (unescaped) $ */
95 if ((c
== '\'') && (prev
!= '\\')) {
99 if ((c
== '$') && (prev
!= '\\')) {
106 case 1: /* Waiting for ( */
107 if (c
== '(' || c
== '{') {
109 varname_start
= input
;
121 case 2: /* Waiting for ) */
122 if (c
== ')' || c
== '}') {
124 char envname
[CONFIG_SYS_CBSIZE
], *envval
;
125 /* Varname # of chars */
126 int envcnt
= input
- varname_start
- 1;
128 /* Get the varname */
129 for (i
= 0; i
< envcnt
; i
++)
130 envname
[i
] = varname_start
[i
];
134 envval
= getenv(envname
);
136 /* Copy into the line if it exists */
138 while ((*envval
) && outputcnt
) {
139 *(output
++) = *(envval
++);
142 /* Look for another '$' */
146 case 3: /* Waiting for ' */
147 if ((c
== '\'') && (prev
!= '\\')) {
163 debug_parser("[PROCESS_MACROS] OUTPUT len %zd: \"%s\"\n",
164 strlen(output_start
), output_start
);
170 * We must create a temporary copy of the command since the command we get
171 * may be the result from getenv(), which returns a pointer directly to
172 * the environment data, which may change magicly when the command we run
173 * creates or modifies environment variables (like "bootp" does).
175 int cli_simple_run_command(const char *cmd
, int flag
)
177 char cmdbuf
[CONFIG_SYS_CBSIZE
]; /* working copy of cmd */
178 char *token
; /* start of token in cmdbuf */
179 char *sep
; /* end of token (separator) in cmdbuf */
180 char finaltoken
[CONFIG_SYS_CBSIZE
];
182 char *argv
[CONFIG_SYS_MAXARGS
+ 1]; /* NULL terminated */
187 debug_parser("[RUN_COMMAND] cmd[%p]=\"", cmd
);
189 /* use puts - string may be loooong */
190 puts(cmd
? cmd
: "NULL");
193 clear_ctrlc(); /* forget any previous Control C */
196 return -1; /* empty command */
198 if (strlen(cmd
) >= CONFIG_SYS_CBSIZE
) {
199 puts("## Command too long!\n");
205 /* Process separators and check for invalid
206 * repeatable commands
209 debug_parser("[PROCESS_SEPARATORS] %s\n", cmd
);
212 * Find separator, or string end
213 * Allow simple escape of ';' by writing "\;"
215 for (inquotes
= 0, sep
= str
; *sep
; sep
++) {
216 if ((*sep
== '\'') &&
217 (*(sep
- 1) != '\\'))
218 inquotes
= !inquotes
;
221 (*sep
== ';') && /* separator */
222 (sep
!= str
) && /* past string start */
223 (*(sep
- 1) != '\\')) /* and NOT escaped */
228 * Limit the token to data between separators
232 str
= sep
+ 1; /* start of command for next pass */
235 str
= sep
; /* no more commands for next pass */
237 debug_parser("token: \"%s\"\n", token
);
239 /* find macros in this token and replace them */
240 cli_simple_process_macros(token
, finaltoken
);
242 /* Extract arguments */
243 argc
= cli_simple_parse_line(finaltoken
, argv
);
245 rc
= -1; /* no command at all */
249 if (cmd_process(flag
, argc
, argv
, &repeatable
, NULL
))
252 /* Did the user stop this? */
254 return -1; /* if stopped then not repeatable */
257 return rc
? rc
: repeatable
;
260 void cli_simple_loop(void)
262 static char lastcommand
[CONFIG_SYS_CBSIZE
+ 1] = { 0, };
270 /* Saw enough of a valid command to
271 * restart the timeout.
273 bootretry_reset_cmd_timeout();
275 len
= cli_readline(CONFIG_SYS_PROMPT
);
277 flag
= 0; /* assume no special flags for now */
279 strlcpy(lastcommand
, console_buffer
,
280 CONFIG_SYS_CBSIZE
+ 1);
282 flag
|= CMD_FLAG_REPEAT
;
283 #ifdef CONFIG_BOOT_RETRY_TIME
284 else if (len
== -2) {
285 /* -2 means timed out, retry autoboot
287 puts("\nTimed out waiting for command\n");
288 # ifdef CONFIG_RESET_TO_RETRY
289 /* Reinit board to run initialization code again */
290 do_reset(NULL
, 0, 0, NULL
);
292 return; /* retry autoboot */
298 puts("<INTERRUPT>\n");
300 rc
= run_command_repeatable(lastcommand
, flag
);
303 /* invalid command or not repeatable, forget it */
309 int cli_simple_run_command_list(char *cmd
, int flag
)
315 * Break into individual lines, and execute each line; terminate on
323 /* run only non-empty commands */
325 debug("** exec: \"%s\"\n", line
);
326 if (cli_simple_run_command(line
, 0) < 0) {
335 if (rcode
== 0 && *line
)
336 rcode
= (cli_simple_run_command(line
, 0) < 0);