]> Git Repo - J-u-boot.git/blob - common/cli_simple.c
spl: Rename SPL_TPL_NAME and SPL_TPL_PROMPT
[J-u-boot.git] / common / cli_simple.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2000
4  * Wolfgang Denk, DENX Software Engineering, [email protected].
5  *
6  * Add to readline cmdline-editing by
7  * (C) Copyright 2005
8  * JinHua Luo, GuangDong Linux Center, <[email protected]>
9  */
10
11 #include <bootretry.h>
12 #include <cli.h>
13 #include <command.h>
14 #include <console.h>
15 #include <env.h>
16 #include <log.h>
17 #include <linux/ctype.h>
18
19 #define DEBUG_PARSER    0       /* set to 1 to debug */
20
21 #define debug_parser(fmt, args...)              \
22         debug_cond(DEBUG_PARSER, fmt, ##args)
23
24 int cli_simple_process_macros(const char *input, char *output, int max_size)
25 {
26         char c, prev;
27         const char *varname_start = NULL;
28         int inputcnt = strlen(input);
29         int outputcnt = max_size;
30         int state = 0;          /* 0 = waiting for '$'  */
31         int ret;
32
33         /* 1 = waiting for '(' or '{' */
34         /* 2 = waiting for ')' or '}' */
35         /* 3 = waiting for '''  */
36         char __maybe_unused *output_start = output;
37
38         debug_parser("[PROCESS_MACROS] INPUT len %zd: \"%s\"\n", strlen(input),
39                      input);
40
41         prev = '\0';            /* previous character   */
42
43         while (inputcnt && outputcnt) {
44                 c = *input++;
45                 inputcnt--;
46
47                 if (state != 3) {
48                         /* remove one level of escape characters */
49                         if ((c == '\\') && (prev != '\\')) {
50                                 if (inputcnt-- == 0)
51                                         break;
52                                 prev = c;
53                                 c = *input++;
54                         }
55                 }
56
57                 switch (state) {
58                 case 0: /* Waiting for (unescaped) $    */
59                         if ((c == '\'') && (prev != '\\')) {
60                                 state = 3;
61                                 break;
62                         }
63                         if ((c == '$') && (prev != '\\')) {
64                                 state++;
65                         } else {
66                                 *(output++) = c;
67                                 outputcnt--;
68                         }
69                         break;
70                 case 1: /* Waiting for (        */
71                         if (c == '(' || c == '{') {
72                                 state++;
73                                 varname_start = input;
74                         } else {
75                                 state = 0;
76                                 *(output++) = '$';
77                                 outputcnt--;
78
79                                 if (outputcnt) {
80                                         *(output++) = c;
81                                         outputcnt--;
82                                 }
83                         }
84                         break;
85                 case 2: /* Waiting for )        */
86                         if (c == ')' || c == '}') {
87                                 int i;
88                                 char envname[CONFIG_SYS_CBSIZE], *envval;
89                                 /* Varname # of chars */
90                                 int envcnt = input - varname_start - 1;
91
92                                 /* Get the varname */
93                                 for (i = 0; i < envcnt; i++)
94                                         envname[i] = varname_start[i];
95                                 envname[i] = 0;
96
97                                 /* Get its value */
98                                 envval = env_get(envname);
99
100                                 /* Copy into the line if it exists */
101                                 if (envval != NULL)
102                                         while ((*envval) && outputcnt) {
103                                                 *(output++) = *(envval++);
104                                                 outputcnt--;
105                                         }
106                                 /* Look for another '$' */
107                                 state = 0;
108                         }
109                         break;
110                 case 3: /* Waiting for '        */
111                         if ((c == '\'') && (prev != '\\')) {
112                                 state = 0;
113                         } else {
114                                 *(output++) = c;
115                                 outputcnt--;
116                         }
117                         break;
118                 }
119                 prev = c;
120         }
121
122         ret = inputcnt ? -ENOSPC : 0;
123         if (outputcnt) {
124                 *output = 0;
125         } else {
126                 *(output - 1) = 0;
127                 ret = -ENOSPC;
128         }
129
130         debug_parser("[PROCESS_MACROS] OUTPUT len %zd: \"%s\"\n",
131                      strlen(output_start), output_start);
132
133         return ret;
134 }
135
136 #ifdef CONFIG_CMDLINE
137 int cli_simple_parse_line(char *line, char *argv[])
138 {
139         int nargs = 0;
140
141         debug_parser("%s: \"%s\"\n", __func__, line);
142         while (nargs < CONFIG_SYS_MAXARGS) {
143                 /* skip any white space */
144                 while (isblank(*line))
145                         ++line;
146
147                 if (*line == '\0') {    /* end of line, no more args    */
148                         argv[nargs] = NULL;
149                         debug_parser("%s: nargs=%d\n", __func__, nargs);
150                         return nargs;
151                 }
152
153                 argv[nargs++] = line;   /* begin of argument string     */
154
155                 /* find end of string */
156                 while (*line && !isblank(*line))
157                         ++line;
158
159                 if (*line == '\0') {    /* end of line, no more args    */
160                         argv[nargs] = NULL;
161                         debug_parser("parse_line: nargs=%d\n", nargs);
162                         return nargs;
163                 }
164
165                 *line++ = '\0';         /* terminate current arg         */
166         }
167
168         printf("** Too many args (max. %d) **\n", CONFIG_SYS_MAXARGS);
169
170         debug_parser("%s: nargs=%d\n", __func__, nargs);
171         return nargs;
172 }
173
174  /*
175  * WARNING:
176  *
177  * We must create a temporary copy of the command since the command we get
178  * may be the result from env_get(), which returns a pointer directly to
179  * the environment data, which may change magicly when the command we run
180  * creates or modifies environment variables (like "bootp" does).
181  */
182 int cli_simple_run_command(const char *cmd, int flag)
183 {
184         char cmdbuf[CONFIG_SYS_CBSIZE]; /* working copy of cmd          */
185         char *token;                    /* start of token in cmdbuf     */
186         char *sep;                      /* end of token (separator) in cmdbuf */
187         char finaltoken[CONFIG_SYS_CBSIZE];
188         char *str = cmdbuf;
189         char *argv[CONFIG_SYS_MAXARGS + 1];     /* NULL terminated      */
190         int argc, inquotes;
191         int repeatable = 1;
192         int rc = 0;
193
194         debug_parser("[RUN_COMMAND] cmd[%p]=\"", cmd);
195         if (DEBUG_PARSER) {
196                 /* use puts - string may be loooong */
197                 puts(cmd ? cmd : "NULL");
198                 puts("\"\n");
199         }
200         clear_ctrlc();          /* forget any previous Control C */
201
202         if (!cmd || !*cmd)
203                 return -1;      /* empty command */
204
205         if (strlen(cmd) >= CONFIG_SYS_CBSIZE) {
206                 puts("## Command too long!\n");
207                 return -1;
208         }
209
210         strcpy(cmdbuf, cmd);
211
212         /* Process separators and check for invalid
213          * repeatable commands
214          */
215
216         debug_parser("[PROCESS_SEPARATORS] %s\n", cmd);
217         while (*str) {
218                 /*
219                  * Find separator, or string end
220                  * Allow simple escape of ';' by writing "\;"
221                  */
222                 for (inquotes = 0, sep = str; *sep; sep++) {
223                         if ((*sep == '\'') &&
224                             (*(sep - 1) != '\\'))
225                                 inquotes = !inquotes;
226
227                         if (!inquotes &&
228                             (*sep == ';') &&    /* separator            */
229                             (sep != str) &&     /* past string start    */
230                             (*(sep - 1) != '\\'))       /* and NOT escaped */
231                                 break;
232                 }
233
234                 /*
235                  * Limit the token to data between separators
236                  */
237                 token = str;
238                 if (*sep) {
239                         str = sep + 1;  /* start of command for next pass */
240                         *sep = '\0';
241                 } else {
242                         str = sep;      /* no more commands for next pass */
243                 }
244                 debug_parser("token: \"%s\"\n", token);
245
246                 /* find macros in this token and replace them */
247                 cli_simple_process_macros(token, finaltoken,
248                                           sizeof(finaltoken));
249
250                 /* Extract arguments */
251                 argc = cli_simple_parse_line(finaltoken, argv);
252                 if (argc == 0) {
253                         rc = -1;        /* no command at all */
254                         continue;
255                 }
256
257                 if (cmd_process(flag, argc, argv, &repeatable, NULL))
258                         rc = -1;
259
260                 /* Did the user stop this? */
261                 if (had_ctrlc())
262                         return -1;      /* if stopped then not repeatable */
263         }
264
265         return rc ? rc : repeatable;
266 }
267
268 void cli_simple_loop(void)
269 {
270         static char lastcommand[CONFIG_SYS_CBSIZE + 1] = { 0, };
271
272         int len;
273         int flag;
274         int rc = 1;
275
276         for (;;) {
277                 if (rc >= 0) {
278                         /* Saw enough of a valid command to
279                          * restart the timeout.
280                          */
281                         bootretry_reset_cmd_timeout();
282                 }
283                 len = cli_readline(CONFIG_SYS_PROMPT);
284
285                 flag = 0;       /* assume no special flags for now */
286                 if (len > 0)
287                         strlcpy(lastcommand, console_buffer,
288                                 CONFIG_SYS_CBSIZE + 1);
289                 else if (len == 0)
290                         flag |= CMD_FLAG_REPEAT;
291 #ifdef CONFIG_BOOT_RETRY_TIME
292                 else if (len == -2) {
293                         /* -2 means timed out, retry autoboot
294                          */
295                         puts("\nTimed out waiting for command\n");
296 # ifdef CONFIG_RESET_TO_RETRY
297                         /* Reinit board to run initialization code again */
298                         do_reset(NULL, 0, 0, NULL);
299 # else
300                         return;         /* retry autoboot */
301 # endif
302                 }
303 #endif
304
305                 if (len == -1)
306                         puts("<INTERRUPT>\n");
307                 else
308                         rc = run_command_repeatable(lastcommand, flag);
309
310                 if (rc <= 0) {
311                         /* invalid command or not repeatable, forget it */
312                         lastcommand[0] = 0;
313                 }
314         }
315 }
316
317 int cli_simple_run_command_list(char *cmd, int flag)
318 {
319         char *line, *next;
320         int rcode = 0;
321
322         /*
323          * Break into individual lines, and execute each line; terminate on
324          * error.
325          */
326         next = cmd;
327         line = cmd;
328         while (*next) {
329                 if (*next == '\n') {
330                         *next = '\0';
331                         /* run only non-empty commands */
332                         if (*line) {
333                                 debug("** exec: \"%s\"\n", line);
334                                 if (cli_simple_run_command(line, 0) < 0) {
335                                         rcode = 1;
336                                         break;
337                                 }
338                         }
339                         line = next + 1;
340                 }
341                 ++next;
342         }
343         if (rcode == 0 && *line)
344                 rcode = (cli_simple_run_command(line, 0) < 0);
345
346         return rcode;
347 }
348 #endif
This page took 0.043407 seconds and 4 git commands to generate.