]>
cloudbase.mooo.com Git - z180-stamp.git/blob - avr/cli.c
13 #include "cli_readline.h"
14 #include "con-utils.h"
17 #define DEBUG_PARSER 0 /* set to 1 to debug */
19 #define debug_parser(fmt, args...) \
20 debug_cond(DEBUG_PARSER, fmt, ##args)
22 static int cli_parse_line(char *line
, char *argv
[])
24 static const FLASH
char delim
[] = {" \t"};
27 uint_fast8_t nargs
= 0;
29 debug_parser("parse_line: \"%s\"\n", line
);
31 ptr
= strtok_P(line
, delim
);
32 while(nargs
< CONFIG_SYS_MAXARGS
&& ptr
!= NULL
) {
34 ptr
= strtok_P(NULL
, delim
);
38 printf_P(PSTR("** Too many args (max. %d) **\n"), CONFIG_SYS_MAXARGS
);
41 debug_parser("parse_line: nargs=%d\n", nargs
);
46 static void process_macros(const char *input
, char *output
)
49 const char *varname_start
= NULL
;
50 #if 0 && (CONFIG_SYS_CBSIZE < __UINT_FAST8_MAX__)
51 uint_fast8_t inputcnt
= strlen(input
);
52 uint_fast8_t outputcnt
= CONFIG_SYS_CBSIZE
;
54 int inputcnt
= strlen(input
);
55 int outputcnt
= CONFIG_SYS_CBSIZE
;
57 uint_fast8_t state
= 0; /* 0 = waiting for '$' */
59 /* 1 = waiting for '(' or '{' */
60 /* 2 = waiting for ')' or '}' */
61 /* 3 = waiting for ''' */
62 char *output_start
= output
;
64 debug_parser("[PROCESS_MACROS] INPUT len %d: \"%s\"\n", strlen(input
),
67 prev
= '\0'; /* previous character */
69 while (inputcnt
&& outputcnt
) {
74 /* remove one level of escape characters */
75 if ((c
== '\\') && (prev
!= '\\')) {
84 case 0: /* Waiting for (unescaped) $ */
85 if ((c
== '\'') && (prev
!= '\\')) {
89 if ((c
== '$') && (prev
!= '\\')) {
96 case 1: /* Waiting for ( */
97 if (c
== '(' || c
== '{') {
99 varname_start
= input
;
111 case 2: /* Waiting for ) */
112 if (c
== ')' || c
== '}') {
113 char envname
[CONFIG_SYS_ENV_NAMELEN
+1], *envval
;
114 /* Varname # of chars */
115 uint_fast8_t envcnt
= input
- varname_start
- 1;
116 if (envcnt
> CONFIG_SYS_ENV_NAMELEN
)
117 envcnt
= CONFIG_SYS_ENV_NAMELEN
;
119 memcpy(envname
, varname_start
, envcnt
);
120 envname
[envcnt
] = '\0';
123 envval
= getenv(envname
);
125 /* Copy into the line if it exists */
127 while ((*envval
) && outputcnt
) {
128 *(output
++) = *(envval
++);
131 /* Look for another '$' */
135 case 3: /* Waiting for ' */
136 if ((c
== '\'') && (prev
!= '\\')) {
152 debug_parser("[PROCESS_MACROS] OUTPUT len %d: \"%s\"\n",
153 strlen(output_start
), output_start
);
159 * We must create a temporary copy of the command since the command we get
160 * may be the result from getenv(), which returns a pointer directly to
161 * the environment data, which may change magicly when the command we run
162 * creates or modifies environment variables (like "bootp" does).
164 static int cli_run_command(const char *cmd
, int flag
)
166 char *cmdbuf
; /* working copy of cmd */
167 char *token
; /* start of token in cmdbuf */
168 char *sep
; /* end of token (separator) in cmdbuf */
171 char *argv
[CONFIG_SYS_MAXARGS
+ 1]; /* NULL terminated */
173 uint_fast8_t inquotes
, repeatable
= 1;
176 debug_parser("[RUN_COMMAND] cmd[%p]=\"%s\"\n",
177 cmd
, cmd
? cmd
: "NULL");
179 clear_ctrlc(); /* forget any previous Control C */
182 return -1; /* empty command */
185 cmdbuf
= xmalloc(strlen(cmd
) + 1);
186 finaltoken
= xmalloc(CONFIG_SYS_CBSIZE
);
191 /* Process separators and check for invalid
192 * repeatable commands
195 debug_parser("[PROCESS_SEPARATORS] %s\n", cmd
);
198 * Find separator, or string end
199 * Allow simple escape of ';' by writing "\;"
201 for (inquotes
= 0, sep
= str
; *sep
; sep
++) {
202 if ((*sep
== '\'') &&
203 (*(sep
- 1) != '\\'))
204 inquotes
= !inquotes
;
207 (*sep
== ';' || *sep
== '\n') && /* separator */
208 (sep
!= str
) && /* past string start */
209 (*(sep
- 1) != '\\')) /* and NOT escaped */
214 * Limit the token to data between separators
218 str
= sep
+ 1; /* start of command for next pass */
221 str
= sep
; /* no more commands for next pass */
223 debug_parser("token: \"%s\"\n", token
);
225 /* find macros in this token and replace them */
226 process_macros(token
, finaltoken
);
228 /* Extract arguments */
229 argc
= cli_parse_line(finaltoken
, argv
);
231 rc
= -1; /* no command at all */
235 if (cmd_process(flag
, argc
, argv
, &repeatable
))
238 /* Did the user stop this? */
240 rc
= -1; /* if stopped then not repeatable */
248 return rc
? rc
: repeatable
;
251 static int cli_run_command_list(const char *cmd
)
253 return (cli_run_command(cmd
, 0) < 0);
256 /******************************************************************************/
260 * Run a command using the selected parser.
262 * @param cmd Command to run
263 * @param flag Execution flags (CMD_FLAG_...)
264 * @return 0 on success, or != 0 on error.
266 int run_command(const char *cmd
, int flag
)
269 * cli_run_command can return 0 or 1 for success, so clean up
272 if (cli_run_command(cmd
, flag
) == -1)
279 * Run a command using the selected parser, and check if it is repeatable.
281 * @param cmd Command to run
282 * @param flag Execution flags (CMD_FLAG_...)
283 * @return 0 (not repeatable) or 1 (repeatable) on success, -1 on error.
285 static int run_command_repeatable(const char *cmd
, int flag
)
287 return cli_run_command(cmd
, flag
);
290 int run_command_list(const char *cmd
, int len
)
294 return cli_run_command_list(cmd
);
297 /****************************************************************************/
302 char *lastcommand
= NULL
;
308 len
= cli_readline(PSTR(CONFIG_SYS_PROMPT
));
310 flag
= 0; /* assume no special flags for now */
312 lastcommand
= (char *) xrealloc(lastcommand
, len
+1);
313 if (lastcommand
!= NULL
) {
314 strncpy(lastcommand
, console_buffer
, len
+1);
315 lastcommand
[len
] = '\0';
318 flag
|= CMD_FLAG_REPEAT
;
321 my_puts_P(PSTR("<INTERRUPT>\n"));
323 rc
= run_command_repeatable(lastcommand
, flag
);
326 /* invalid command or not repeatable, forget it */
334 int do_run(cmd_tbl_t
*cmdtp
, int flag
, int argc
, char * const argv
[])
340 return CMD_RET_USAGE
;
342 for (i
= 1; i
< argc
; ++i
) {
345 arg
= getenv(argv
[i
]);
347 printf_P(PSTR("## Error: \"%s\" not defined\n"), argv
[i
]);
351 if (run_command(arg
, flag
) != 0)