#define debug_parser(fmt, args...) \
debug_cond(DEBUG_PARSER, fmt, ##args)
+
+static bool opt_xtrace;
+static bool opt_verbose;
+static int_least8_t command_level;
+
+static void cli_trace_cmd(int_fast8_t level, int argc, char *argv[])
+{
+ while (level-- > 0)
+ putchar('+');
+ for (int_fast8_t i = 0; i < argc; i++)
+ printf_P(PSTR(" %s"), argv[i]);
+ putchar('\n');
+}
+
+
+
+
static int cli_parse_line(char *line, char *argv[])
{
uint_fast8_t state = 0;
if (c == '}') {
/* Terminate variable name */
*(inp-1) = '\0';
- const char *envval = getenv_char(varname);
+ const char *envval = getenv_str(varname);
*(inp-1) = '}';
/* Copy into the line if it exists */
if (envval != NULL)
* WARNING:
*
* We must create a temporary copy of the command since the command we get
- * may be the result from getenv_char(), which returns a pointer directly to
+ * may be the result from getenv_str(), which returns a pointer directly to
* the environment data, which may change magicly when the command we run
* creates or modifies environment variables (like "bootp" does).
*
uint_fast8_t inquotes, repeatable = 1;
int rc = 0;
+ opt_verbose = 0;
+ opt_xtrace = 0;
+ char *optenv = getenv_str(PSTR("cli"));
+ if (optenv) {
+ opt_verbose = (strstr_P(optenv, PSTR("verbose")) != NULL);
+ opt_xtrace = (strstr_P(optenv, PSTR("xtrace")) != NULL);
+ }
+
debug_parser("[RUN_COMMAND] cmd[%p]=\"%s\"\n",
cmd, cmd ? cmd : "NULL");
+ if (opt_verbose)
+ printf_P(PSTR("%s\n"), cmd, cmd ? cmd : "");
+
clear_ctrlc(); /* forget any previous Control C */
if (!cmd || !*cmd)
if (!cmdbuf)
return -1; /* not enough memory */
+ ++command_level;
str = cmdbuf;
/* Process separators and check for invalid
*/
for (inquotes = 0, sep = str; *sep; sep++) {
if ((*sep == '\'') &&
- (sep != str) && /* past string start */
- (*(sep - 1) != '\\')) /* and NOT escaped */
+ (sep != str) && /* past string start */
+ (*(sep - 1) != '\\')) /* and NOT escaped */
inquotes = !inquotes;
if (!inquotes &&
- (*sep == ';' || *sep == '\n') && /* separator */
- (sep != str) && /* past string start */
- (*(sep - 1) != '\\')) /* and NOT escaped */
+ (*sep == ';' || *sep == '\n' /* separator */
+ || *sep == '#') && /* or start of comment */
+ ((sep == str) || /* string start */
+ (*(sep - 1) != '\\'))) /* or NOT escaped */
break;
}
- /*
- * Limit the token to data between separators
- */
+ /* no more commands after unescaped '#' token */
+ if (*sep == '#')
+ *sep = '\0';
+
+ /* Limit the token to data between separators */
token = str;
if (*sep) {
- str = sep + 1; /* start of command for next pass */
+ str = sep + 1; /* start of command for next pass */
*sep = '\0';
} else {
- str = sep; /* no more commands for next pass */
+ str = sep; /* no more commands for next pass */
}
debug_parser("token: \"%s\"\n", token);
continue;
}
- if (cmd_process(flag, argc, argv, &repeatable) != CMD_RET_SUCCESS)
+ if (opt_xtrace)
+ cli_trace_cmd(command_level, argc, argv);
+
+ rc = cmd_process(flag, argc, argv, &repeatable);
+ if (rc != CMD_RET_SUCCESS) {
+ if (opt_verbose)
+ printf_P(PSTR("Command failed, result=%d\n"), rc);
rc = -1;
+ }
/* Did the user stop this? */
if (had_ctrlc()) {
free(cmdbuf);
free(finaltoken);
+ --command_level;
return rc ? rc : repeatable;
}
} else if (len == 0)
flag |= CMD_FLAG_REPEAT;
- if (len == -1)
- my_puts_P(PSTR("<INTERRUPT>\n"));
- else
+ if (len == -1) {
+ if (opt_verbose)
+ my_puts_P(PSTR("<INTERRUPT>\n"));
+ } else
rc = run_command_repeatable(lastcommand, flag);
if (rc <= 0) {