#include "jim-eventloop.h"
+/* nice short description of source file */
+#define __THIS__FILE__ "command.c"
+
Jim_Interp *interp = NULL;
static int run_command(struct command_context *context,
return cmd_ctx;
}
-static int script_command(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+static int script_command_run(Jim_Interp *interp,
+ int argc, Jim_Obj *const *argv, struct command *c, bool capture)
{
- /* the private data is stashed in the interp structure */
-
- struct command *c = interp->cmdPrivData;
- assert(c);
-
target_call_timer_callbacks_now();
LOG_USER_N("%s", ""); /* Keep GDB connection alive*/
- script_debug(interp, c->name, argc, argv);
-
unsigned nwords;
const char **words = script_command_args_alloc(argc, argv, &nwords);
if (NULL == words)
return JIM_ERR;
- Jim_Obj *tclOutput = command_log_capture_start(interp);
+ Jim_Obj *tclOutput = NULL;
+ if (capture)
+ tclOutput = command_log_capture_start(interp);
struct command_context *cmd_ctx = current_command_context();
int retval = run_command(cmd_ctx, c, (const char **)words, nwords);
- command_log_capture_finish(interp, tclOutput);
+ if (capture)
+ command_log_capture_finish(interp, tclOutput);
+
script_command_args_free(words, nwords);
return command_retval_set(interp, retval);
}
-/* nice short description of source file */
-#define __THIS__FILE__ "command.c"
+static int script_command(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ /* the private data is stashed in the interp structure */
+
+ struct command *c = interp->cmdPrivData;
+ assert(c);
+ script_debug(interp, c->name, argc, argv);
+ return script_command_run(interp, argc, argv, c, true);
+}
+
+static struct command *command_root(struct command *c)
+{
+ while (NULL != c->parent)
+ c = c->parent;
+ return c;
+}
/**
* Find a command by name from a list of commands.
free(c);
}
+static int command_unknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
+
static int register_command_handler(struct command *c)
{
- int retval = -ENOMEM;
- const char *full_name = command_name(c, '_');
- if (NULL == full_name)
- return retval;
+ const char *ocd_name = alloc_printf("ocd_%s", c->name);
+ if (NULL == ocd_name)
+ return JIM_ERR;
- const char *ocd_name = alloc_printf("ocd_%s", full_name);
- if (NULL == full_name)
- goto free_full_name;
+ LOG_DEBUG("registering '%s'...", ocd_name);
- Jim_CreateCommand(interp, ocd_name, script_command, c, NULL);
+ Jim_CmdProc func = c->handler ? &script_command : &command_unknown;
+ int retval = Jim_CreateCommand(interp, ocd_name, func, c, NULL);
free((void *)ocd_name);
+ if (JIM_OK != retval)
+ return retval;
/* we now need to add an overrideable proc */
- const char *override_name = alloc_printf("proc %s {args} {"
- "if {[catch {eval ocd_%s $args}] == 0} "
- "{return \"\"} else {return -code error}}",
- full_name, full_name);
- if (NULL == full_name)
- goto free_full_name;
-
- Jim_Eval_Named(interp, override_name, __THIS__FILE__, __LINE__);
- free((void *)override_name);
+ const char *override_name = alloc_printf(
+ "proc %s {args} {eval ocd_bouncer %s $args}",
+ c->name, c->name);
+ if (NULL == override_name)
+ return JIM_ERR;
- retval = ERROR_OK;
+ retval = Jim_Eval_Named(interp, override_name, __FILE__, __LINE__);
+ free((void *)override_name);
-free_full_name:
- free((void *)full_name);
return retval;
}
if (NULL == c)
return NULL;
- if (NULL != c->handler)
+ int retval = ERROR_OK;
+ if (NULL != cr->jim_handler && NULL == parent)
{
- int retval = register_command_handler(c);
- if (ERROR_OK != retval)
- {
- unregister_command(context, parent, name);
- return NULL;
- }
+ retval = Jim_CreateCommand(interp, cr->name,
+ cr->jim_handler, cr->jim_handler_data, NULL);
}
+ else if (NULL != cr->handler || NULL != parent)
+ retval = register_command_handler(command_root(c));
- if (NULL != cr->jim_handler && NULL == parent)
- Jim_CreateCommand(interp, cr->name, cr->jim_handler, cr->jim_handler_data, NULL);
-
+ if (ERROR_OK != retval)
+ {
+ unregister_command(context, parent, name);
+ c = NULL;
+ }
return c;
}
return ERROR_OK;
}
+void command_set_handler_data(struct command *c, void *p)
+{
+ if (NULL != c->handler || NULL != c->jim_handler)
+ c->jim_handler_data = p;
+ for (struct command *cc = c->children; NULL != cc; cc = cc->next)
+ command_set_handler_data(cc, p);
+}
+
void command_output_text(struct command_context *context, const char *data)
{
if (context && context->output_handler && data) {
if (0 == CMD_ARGC)
return ERROR_INVALID_ARGUMENTS;
*out = command_find(head, CMD_ARGV[0]);
+ if (NULL == *out && strncmp(CMD_ARGV[0], "ocd_", 4) == 0)
+ *out = command_find(head, CMD_ARGV[0] + 4);
if (NULL == *out)
return ERROR_INVALID_ARGUMENTS;
if (--CMD_ARGC == 0)
}
static int command_unknown_find(unsigned argc, Jim_Obj *const *argv,
- struct command *head, struct command **out)
+ struct command *head, struct command **out, bool top_level)
{
if (0 == argc)
return argc;
- struct command *c = command_find(head, Jim_GetString(argv[0], NULL));
+ const char *cmd_name = Jim_GetString(argv[0], NULL);
+ struct command *c = command_find(head, cmd_name);
+ if (NULL == c && top_level && strncmp(cmd_name, "ocd_", 4) == 0)
+ c = command_find(head, cmd_name + 4);
if (NULL == c)
return argc;
*out = c;
- return command_unknown_find(--argc, ++argv, (*out)->children, out);
+ return command_unknown_find(--argc, ++argv, (*out)->children, out, false);
}
static int command_unknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
const char *cmd_name = Jim_GetString(argv[0], NULL);
- script_debug(interp, cmd_name, argc - 1, argv + 1);
+ if (strcmp(cmd_name, "unknown") == 0)
+ {
+ if (argc == 1)
+ return JIM_OK;
+ argc--;
+ argv++;
+ }
+ script_debug(interp, cmd_name, argc, argv);
struct command_context *cmd_ctx = current_command_context();
struct command *c = cmd_ctx->commands;
- int remaining = command_unknown_find(argc - 1, argv + 1, c, &c);
+ int remaining = command_unknown_find(argc, argv, c, &c, true);
// if nothing could be consumed, then it's really an unknown command
- if (remaining == argc - 1)
+ if (remaining == argc)
{
- const char *cmd = Jim_GetString(argv[1], NULL);
+ const char *cmd = Jim_GetString(argv[0], NULL);
LOG_ERROR("Unknown command:\n %s", cmd);
return JIM_OK;
}
return (*c->jim_handler)(interp, count, start);
}
- unsigned nwords;
- const char **words = script_command_args_alloc(count, start, &nwords);
- if (NULL == words)
- return JIM_ERR;
+ return script_command_run(interp, count, start, c, found);
+}
- Jim_Obj *tclOutput = command_log_capture_start(interp);
+static int jim_command_mode(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ struct command_context *cmd_ctx = current_command_context();
+ enum command_mode mode;
+ if (argc > 1)
+ {
+ struct command *c = cmd_ctx->commands;
+ int remaining = command_unknown_find(argc - 1, argv + 1, c, &c, true);
+ // if nothing could be consumed, then it's an unknown command
+ if (remaining == argc - 1)
+ {
+ Jim_SetResultString(interp, "unknown", -1);
+ return JIM_OK;
+ }
+ mode = c->mode;
+ }
+ else
+ mode = cmd_ctx->mode;
+
+ const char *mode_str;
+ switch (mode) {
+ case COMMAND_ANY: mode_str = "any"; break;
+ case COMMAND_CONFIG: mode_str = "config"; break;
+ case COMMAND_EXEC: mode_str = "exec"; break;
+ default: mode_str = "unknown"; break;
+ }
+ Jim_SetResultString(interp, mode_str, -1);
+ return JIM_OK;
+}
- int retval = run_command(cmd_ctx, c, words, nwords);
+static int jim_command_type(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ if (1 == argc)
+ return JIM_ERR;
- command_log_capture_finish(interp, tclOutput);
- script_command_args_free(words, nwords);
+ struct command_context *cmd_ctx = current_command_context();
+ struct command *c = cmd_ctx->commands;
+ int remaining = command_unknown_find(argc - 1, argv + 1, c, &c, true);
+ // if nothing could be consumed, then it's an unknown command
+ if (remaining == argc - 1)
+ {
+ Jim_SetResultString(interp, "unknown", -1);
+ return JIM_OK;
+ }
- if (!found && ERROR_OK == retval)
- retval = ERROR_FAIL;
+ if (c->jim_handler)
+ Jim_SetResultString(interp, "native", -1);
+ else if (c->handler)
+ Jim_SetResultString(interp, "simple", -1);
+ else
+ Jim_SetResultString(interp, "group", -1);
- return command_retval_set(interp, retval);
+ return JIM_OK;
}
int help_add_command(struct command_context *cmd_ctx, struct command *parent,
return ERROR_OK;
}
+static const struct command_registration command_subcommand_handlers[] = {
+ {
+ .name = "mode",
+ .mode = COMMAND_ANY,
+ .jim_handler = &jim_command_mode,
+ .usage = "[<name> ...]",
+ .help = "Returns the command modes allowed by a command:"
+ "'any', 'config', or 'exec'. If no command is"
+ "specified, returns the current command mode.",
+ },
+ {
+ .name = "type",
+ .mode = COMMAND_ANY,
+ .jim_handler = &jim_command_type,
+ .usage = "<name> ...",
+ .help = "Returns the type of built-in command:"
+ "'native', 'simple', 'group', or 'unknown'",
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
static const struct command_registration command_builtin_handlers[] = {
{
.name = "add_help_text",
.help = "show basic command usage",
.usage = "[<command> ...]",
},
+ {
+ .name = "command",
+ .mode= COMMAND_ANY,
+ .help = "core command group (introspection)",
+ .chain = command_subcommand_handlers,
+ },
COMMAND_REGISTRATION_DONE
};
Jim_SetGlobalVariableStr(interp, "ocd_HOSTOS",
Jim_NewStringObj(interp, HostOs , strlen(HostOs)));
- Jim_CreateCommand(interp, "unknown", &command_unknown, NULL, NULL);
Jim_CreateCommand(interp, "ocd_find", jim_find, NULL, NULL);
Jim_CreateCommand(interp, "echo", jim_echo, NULL, NULL);
Jim_CreateCommand(interp, "capture", jim_capture, NULL, NULL);