aboutsummaryrefslogtreecommitdiff
path: root/src/helper/command.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/helper/command.c')
-rw-r--r--src/helper/command.c256
1 files changed, 111 insertions, 145 deletions
diff --git a/src/helper/command.c b/src/helper/command.c
index a775c73..218f058 100644
--- a/src/helper/command.c
+++ b/src/helper/command.c
@@ -31,8 +31,7 @@
#define __THIS__FILE__ "command.c"
struct log_capture_state {
- Jim_Interp *interp;
- Jim_Obj *output;
+ char *output;
};
static int unregister_command(struct command_context *context,
@@ -41,6 +40,7 @@ static int jim_command_dispatch(Jim_Interp *interp, int argc, Jim_Obj * const *a
static int help_add_command(struct command_context *cmd_ctx,
const char *cmd_name, const char *help_text, const char *usage_text);
static int help_del_command(struct command_context *cmd_ctx, const char *cmd_name);
+static enum command_mode get_command_mode(Jim_Interp *interp, const char *cmd_name);
/* set of functions to wrap jimtcl internal data */
static inline bool jimcmd_is_proc(Jim_Cmd *cmd)
@@ -58,73 +58,6 @@ void *jimcmd_privdata(Jim_Cmd *cmd)
return cmd->isproc ? NULL : cmd->u.native.privData;
}
-static void tcl_output(void *privData, const char *file, unsigned line,
- const char *function, const char *string)
-{
- struct log_capture_state *state = privData;
- Jim_AppendString(state->interp, state->output, string, strlen(string));
-}
-
-static struct log_capture_state *command_log_capture_start(Jim_Interp *interp)
-{
- /* capture log output and return it. A garbage collect can
- * happen, so we need a reference count to this object */
- Jim_Obj *jim_output = Jim_NewStringObj(interp, "", 0);
- if (!jim_output)
- return NULL;
-
- Jim_IncrRefCount(jim_output);
-
- struct log_capture_state *state = malloc(sizeof(*state));
- if (!state) {
- LOG_ERROR("Out of memory");
- Jim_DecrRefCount(interp, jim_output);
- return NULL;
- }
-
- state->interp = interp;
- state->output = jim_output;
-
- log_add_callback(tcl_output, state);
-
- return state;
-}
-
-/* Classic openocd commands provide progress output which we
- * will capture and return as a Tcl return value.
- *
- * However, if a non-openocd command has been invoked, then it
- * makes sense to return the tcl return value from that command.
- *
- * The tcl return value is empty for openocd commands that provide
- * progress output.
- *
- * For other commands, we prepend the logs to the tcl return value.
- */
-static void command_log_capture_finish(struct log_capture_state *state)
-{
- if (!state)
- return;
-
- log_remove_callback(tcl_output, state);
-
- int loglen;
- const char *log_result = Jim_GetString(state->output, &loglen);
- int reslen;
- const char *cmd_result = Jim_GetString(Jim_GetResult(state->interp), &reslen);
-
- // Just in case the log doesn't end with a newline, we add it
- if (loglen != 0 && reslen != 0 && log_result[loglen - 1] != '\n')
- Jim_AppendString(state->interp, state->output, "\n", 1);
-
- Jim_AppendString(state->interp, state->output, cmd_result, reslen);
-
- Jim_SetResult(state->interp, state->output);
- Jim_DecrRefCount(state->interp, state->output);
-
- free(state);
-}
-
static int command_retval_set(Jim_Interp *interp, int retval)
{
int *return_retval = Jim_GetAssocData(interp, "retval");
@@ -144,7 +77,7 @@ static void script_debug(Jim_Interp *interp, unsigned int argc, Jim_Obj * const
return;
char *dbg = alloc_printf("command -");
- for (unsigned i = 0; i < argc; i++) {
+ for (unsigned int i = 0; i < argc; i++) {
const char *w = Jim_GetString(argv[i], NULL);
char *t = alloc_printf("%s %s", dbg, w);
free(dbg);
@@ -288,7 +221,7 @@ int __register_commands(struct command_context *cmd_ctx, const char *cmd_prefix,
struct target *override_target)
{
int retval = ERROR_OK;
- unsigned i;
+ unsigned int i;
for (i = 0; cmds[i].name || cmds[i].chain; i++) {
const struct command_registration *cr = cmds + i;
@@ -323,7 +256,7 @@ int __register_commands(struct command_context *cmd_ctx, const char *cmd_prefix,
}
}
if (retval != ERROR_OK) {
- for (unsigned j = 0; j < i; j++)
+ for (unsigned int j = 0; j < i; j++)
unregister_command(cmd_ctx, cmd_prefix, cmds[j].name);
}
return retval;
@@ -673,21 +606,34 @@ COMMAND_HANDLER(handle_echo)
}
if (CMD_ARGC != 1)
- return ERROR_FAIL;
+ return ERROR_COMMAND_SYNTAX_ERROR;
LOG_USER("%s", CMD_ARGV[0]);
return ERROR_OK;
}
-/* Return both the progress output (LOG_INFO and higher)
+static void tcl_output(void *privData, const char *file, unsigned int line,
+ const char *function, const char *string)
+{
+ struct log_capture_state *state = privData;
+ char *old = state->output;
+
+ state->output = alloc_printf("%s%s", old ? old : "", string);
+ free(old);
+ if (!state->output)
+ LOG_ERROR("Out of memory");
+}
+
+/*
+ * Return both the progress output (LOG_INFO and higher)
* and the tcl return value of a command.
*/
-static int jim_capture(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+COMMAND_HANDLER(handle_command_capture)
{
- if (argc != 2)
- return JIM_ERR;
+ struct log_capture_state state = {NULL};
- struct log_capture_state *state = command_log_capture_start(interp);
+ if (CMD_ARGC != 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
/* disable polling during capture. This avoids capturing output
* from polling.
@@ -697,14 +643,24 @@ static int jim_capture(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
*/
bool save_poll_mask = jtag_poll_mask();
- const char *str = Jim_GetString(argv[1], NULL);
- int retcode = Jim_Eval_Named(interp, str, __THIS__FILE__, __LINE__);
+ log_add_callback(tcl_output, &state);
+
+ int jimretval = Jim_EvalObj(CMD_CTX->interp, CMD_JIMTCL_ARGV[0]);
+ const char *cmd_result = Jim_GetString(Jim_GetResult(CMD_CTX->interp), NULL);
+
+ log_remove_callback(tcl_output, &state);
jtag_poll_unmask(save_poll_mask);
- command_log_capture_finish(state);
+ if (state.output && *state.output)
+ command_print(CMD, "%s", state.output);
+
+ if (cmd_result && *cmd_result)
+ command_print(CMD, "%s", cmd_result);
- return retcode;
+ free(state.output);
+
+ return (jimretval == JIM_OK) ? ERROR_OK : ERROR_FAIL;
}
struct help_entry {
@@ -728,12 +684,12 @@ static COMMAND_HELPER(command_help_show_list, bool show_help, const char *cmd_ma
#define HELP_LINE_WIDTH(_n) (int)(76 - (2 * _n))
-static void command_help_show_indent(unsigned n)
+static void command_help_show_indent(unsigned int n)
{
- for (unsigned i = 0; i < n; i++)
+ for (unsigned int i = 0; i < n; i++)
LOG_USER_N(" ");
}
-static void command_help_show_wrap(const char *str, unsigned n, unsigned n2)
+static void command_help_show_wrap(const char *str, unsigned int n, unsigned int n2)
{
const char *cp = str, *last = str;
while (*cp) {
@@ -779,24 +735,7 @@ static COMMAND_HELPER(command_help_show, struct help_entry *c,
if (is_match && show_help) {
char *msg;
- /* TODO: factorize jim_command_mode() to avoid running jim command here */
- char *request = alloc_printf("command mode %s", c->cmd_name);
- if (!request) {
- LOG_ERROR("Out of memory");
- return ERROR_FAIL;
- }
- int retval = Jim_Eval(CMD_CTX->interp, request);
- free(request);
- enum command_mode mode = COMMAND_UNKNOWN;
- if (retval != JIM_ERR) {
- const char *result = Jim_GetString(Jim_GetResult(CMD_CTX->interp), NULL);
- if (!strcmp(result, "any"))
- mode = COMMAND_ANY;
- else if (!strcmp(result, "config"))
- mode = COMMAND_CONFIG;
- else if (!strcmp(result, "exec"))
- mode = COMMAND_EXEC;
- }
+ enum command_mode mode = get_command_mode(CMD_CTX->interp, c->cmd_name);
/* Normal commands are runtime-only; highlight exceptions */
if (mode != COMMAND_EXEC) {
@@ -809,6 +748,7 @@ static COMMAND_HELPER(command_help_show, struct help_entry *c,
case COMMAND_ANY:
stage_msg = " (command valid any time)";
break;
+ case COMMAND_UNKNOWN:
default:
stage_msg = " (?mode error?)";
break;
@@ -817,11 +757,13 @@ static COMMAND_HELPER(command_help_show, struct help_entry *c,
} else
msg = alloc_printf("%s", c->help ? c->help : "");
- if (msg) {
- command_help_show_wrap(msg, n + 3, n + 3);
- free(msg);
- } else
- return -ENOMEM;
+ if (!msg) {
+ LOG_ERROR("Out of memory");
+ return ERROR_FAIL;
+ }
+
+ command_help_show_wrap(msg, n + 3, n + 3);
+ free(msg);
}
return ERROR_OK;
@@ -856,22 +798,19 @@ COMMAND_HANDLER(handle_help_command)
return retval;
}
-static char *alloc_concatenate_strings(int argc, Jim_Obj * const *argv)
+static char *alloc_concatenate_strings(int argc, const char **argv)
{
- char *prev, *all;
- int i;
-
assert(argc >= 1);
- all = strdup(Jim_GetString(argv[0], NULL));
+ char *all = strdup(argv[0]);
if (!all) {
LOG_ERROR("Out of memory");
return NULL;
}
- for (i = 1; i < argc; ++i) {
- prev = all;
- all = alloc_printf("%s %s", all, Jim_GetString(argv[i], NULL));
+ for (int i = 1; i < argc; ++i) {
+ char *prev = all;
+ all = alloc_printf("%s %s", all, argv[i]);
free(prev);
if (!all) {
LOG_ERROR("Out of memory");
@@ -936,35 +875,40 @@ static int jim_command_dispatch(Jim_Interp *interp, int argc, Jim_Obj * const *a
return retval;
}
-static int jim_command_mode(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+static enum command_mode get_command_mode(Jim_Interp *interp, const char *cmd_name)
{
- struct command_context *cmd_ctx = current_command_context(interp);
- enum command_mode mode;
+ if (!cmd_name)
+ return COMMAND_UNKNOWN;
- if (argc > 1) {
- char *full_name = alloc_concatenate_strings(argc - 1, argv + 1);
+ Jim_Obj *s = Jim_NewStringObj(interp, cmd_name, -1);
+ Jim_IncrRefCount(s);
+ Jim_Cmd *cmd = Jim_GetCommand(interp, s, JIM_NONE);
+ Jim_DecrRefCount(interp, s);
+
+ if (!cmd || !(jimcmd_is_proc(cmd) || jimcmd_is_oocd_command(cmd)))
+ return COMMAND_UNKNOWN;
+
+ /* tcl proc */
+ if (jimcmd_is_proc(cmd))
+ return COMMAND_ANY;
+
+ struct command *c = jimcmd_privdata(cmd);
+ return c->mode;
+}
+
+COMMAND_HANDLER(handle_command_mode)
+{
+ enum command_mode mode = CMD_CTX->mode;
+
+ if (CMD_ARGC) {
+ char *full_name = alloc_concatenate_strings(CMD_ARGC, CMD_ARGV);
if (!full_name)
- return JIM_ERR;
- Jim_Obj *s = Jim_NewStringObj(interp, full_name, -1);
- Jim_IncrRefCount(s);
- Jim_Cmd *cmd = Jim_GetCommand(interp, s, JIM_NONE);
- Jim_DecrRefCount(interp, s);
- free(full_name);
- if (!cmd || !(jimcmd_is_proc(cmd) || jimcmd_is_oocd_command(cmd))) {
- Jim_SetResultString(interp, "unknown", -1);
- return JIM_OK;
- }
+ return ERROR_FAIL;
- if (jimcmd_is_proc(cmd)) {
- /* tcl proc */
- mode = COMMAND_ANY;
- } else {
- struct command *c = jimcmd_privdata(cmd);
+ mode = get_command_mode(CMD_CTX->interp, full_name);
- mode = c->mode;
- }
- } else
- mode = cmd_ctx->mode;
+ free(full_name);
+ }
const char *mode_str;
switch (mode) {
@@ -977,12 +921,13 @@ static int jim_command_mode(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
case COMMAND_EXEC:
mode_str = "exec";
break;
+ case COMMAND_UNKNOWN:
default:
mode_str = "unknown";
break;
}
- Jim_SetResultString(interp, mode_str, -1);
- return JIM_OK;
+ command_print(CMD, "%s", mode_str);
+ return ERROR_OK;
}
int help_del_all_commands(struct command_context *cmd_ctx)
@@ -1121,7 +1066,7 @@ static const struct command_registration command_subcommand_handlers[] = {
{
.name = "mode",
.mode = COMMAND_ANY,
- .jim_handler = jim_command_mode,
+ .handler = handle_command_mode,
.usage = "[command_name ...]",
.help = "Returns the command modes allowed by a command: "
"'any', 'config', or 'exec'. If no command is "
@@ -1143,7 +1088,7 @@ static const struct command_registration command_builtin_handlers[] = {
{
.name = "capture",
.mode = COMMAND_ANY,
- .jim_handler = jim_capture,
+ .handler = handle_command_capture,
.help = "Capture progress output and return as tcl return value. If the "
"progress output was empty, return tcl return value.",
.usage = "command",
@@ -1317,7 +1262,7 @@ DEFINE_PARSE_NUM_TYPE(_llong, long long, strtoll, LLONG_MIN, LLONG_MAX)
#define DEFINE_PARSE_ULONGLONG(name, type, min, max) \
DEFINE_PARSE_WRAPPER(name, type, min, max, unsigned long long, _ullong)
-DEFINE_PARSE_ULONGLONG(_uint, unsigned, 0, UINT_MAX)
+DEFINE_PARSE_ULONGLONG(_uint, unsigned int, 0, UINT_MAX)
DEFINE_PARSE_ULONGLONG(_u64, uint64_t, 0, UINT64_MAX)
DEFINE_PARSE_ULONGLONG(_u32, uint32_t, 0, UINT32_MAX)
DEFINE_PARSE_ULONGLONG(_u16, uint16_t, 0, UINT16_MAX)
@@ -1360,6 +1305,27 @@ int command_parse_bool_arg(const char *in, bool *out)
return ERROR_COMMAND_SYNTAX_ERROR;
}
+COMMAND_HELPER(command_parse_str_to_buf, const char *str, void *buf, unsigned int buf_len)
+{
+ assert(str);
+ assert(buf);
+
+ int ret = str_to_buf(str, buf, buf_len);
+ if (ret == ERROR_OK)
+ return ret;
+
+ /* Provide a clear error message to the user */
+ if (ret == ERROR_INVALID_NUMBER) {
+ command_print(CMD, "'%s' is not a valid number", str);
+ } else if (ret == ERROR_NUMBER_EXCEEDS_BUFFER) {
+ command_print(CMD, "Number %s exceeds %u bits", str, buf_len);
+ } else {
+ command_print(CMD, "Could not parse number '%s'", str);
+ }
+
+ return ERROR_COMMAND_ARGUMENT_INVALID;
+}
+
COMMAND_HELPER(handle_command_parse_bool, bool *out, const char *label)
{
switch (CMD_ARGC) {