return words;
}
+static struct command_context *current_command_context(void)
+{
+ /* grab the command context from the associated data */
+ struct command_context *cmd_ctx = Jim_GetAssocData(interp, "context");
+ if (NULL == cmd_ctx)
+ {
+ /* Tcl can invoke commands directly instead of via command_run_line(). This would
+ * happen when the Jim Tcl interpreter is provided by eCos.
+ */
+ cmd_ctx = global_cmd_ctx;
+ }
+ return cmd_ctx;
+}
+
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;
- struct command_context *context;
int retval;
/* DANGER!!!! be careful what we invoke here, since interp->cmdPrivData might
if (NULL == words)
return JIM_ERR;
- /* grab the command context from the associated data */
- context = Jim_GetAssocData(interp, "context");
- if (context == NULL)
- {
- /* Tcl can invoke commands directly instead of via command_run_line(). This would
- * happen when the Jim Tcl interpreter is provided by eCos.
- */
- context = global_cmd_ctx;
- }
-
/* capture log output and return it */
Jim_Obj *tclOutput = Jim_NewStringObj(interp, "", 0);
/* a garbage collect can happen, so we need a reference count to this object */
log_add_callback(tcl_output, tclOutput);
- retval = run_command(context, c, (const char **)words, nwords);
+ struct command_context *cmd_ctx = current_command_context();
+ retval = run_command(cmd_ctx, c, (const char **)words, nwords);
log_remove_callback(tcl_output, tclOutput);
}
return NULL;
}
+struct command *command_find_in_context(struct command_context *cmd_ctx,
+ const char *name)
+{
+ return command_find(cmd_ctx->commands, name);
+}
+struct command *command_find_in_parent(struct command *parent,
+ const char *name)
+{
+ return command_find(parent->children, name);
+}
/**
* Add the command into the linked list, sorted by name.
}
static struct command *command_new(struct command_context *cmd_ctx,
- struct command *parent, const char *name,
- command_handler_t handler, enum command_mode mode,
- const char *help, const char *usage)
+ struct command *parent, const struct command_registration *cr)
{
- assert(name);
+ assert(cr->name);
struct command *c = malloc(sizeof(struct command));
memset(c, 0, sizeof(struct command));
- c->name = strdup(name);
- if (help)
- c->help = strdup(help);
- if (usage)
- c->usage = strdup(usage);
+ c->name = strdup(cr->name);
+ if (cr->help)
+ c->help = strdup(cr->help);
+ if (cr->usage)
+ c->usage = strdup(cr->usage);
c->parent = parent;
- c->handler = handler;
- c->mode = mode;
+ c->handler = cr->handler;
+ c->jim_handler = cr->jim_handler;
+ c->jim_handler_data = cr->jim_handler_data;
+ c->mode = cr->mode;
command_add_child(command_list_for_parent(cmd_ctx, parent), c);
free(c);
}
+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", full_name);
+ if (NULL == full_name)
+ goto free_full_name;
+
+ Jim_CreateCommand(interp, ocd_name, script_command, c, NULL);
+ free((void *)ocd_name);
+
+ /* 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);
+
+ retval = ERROR_OK;
+
+free_full_name:
+ free((void *)full_name);
+ return retval;
+}
+
struct command* register_command(struct command_context *context,
struct command *parent, const struct command_registration *cr)
{
return c;
}
- c = command_new(context, parent, name, cr->handler, cr->mode, cr->help, cr->usage);
- /* if allocation failed or it is a placeholder (no handler), we're done */
- if (NULL == c || NULL == c->handler)
- return c;
-
- const char *full_name = command_name(c, '_');
-
- const char *ocd_name = alloc_printf("ocd_%s", full_name);
- Jim_CreateCommand(interp, ocd_name, script_command, c, NULL);
- free((void *)ocd_name);
+ c = command_new(context, parent, cr);
+ if (NULL == c)
+ return NULL;
- /* 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);
- Jim_Eval_Named(interp, override_name, __THIS__FILE__, __LINE__);
- free((void *)override_name);
+ if (NULL != c->handler)
+ {
+ int retval = register_command_handler(c);
+ if (ERROR_OK != retval)
+ {
+ unregister_command(context, parent, name);
+ return NULL;
+ }
+ }
- free((void *)full_name);
+ if (NULL != cr->jim_handler && NULL == parent)
+ Jim_CreateCommand(interp, cr->name, cr->jim_handler, cr->jim_handler_data, NULL);
return c;
}
int register_commands(struct command_context *cmd_ctx, struct command *parent,
const struct command_registration *cmds)
{
+ int retval = ERROR_OK;
unsigned i;
- for (i = 0; cmds[i].name; i++)
+ for (i = 0; cmds[i].name || cmds[i].chain; i++)
{
- struct command *c = register_command(cmd_ctx, parent, cmds + i);
- if (NULL != c)
- continue;
+ const struct command_registration *cr = cmds + i;
+ struct command *c = NULL;
+ if (NULL != cr->name)
+ {
+ c = register_command(cmd_ctx, parent, cr);
+ if (NULL == c)
+ {
+ retval = ERROR_FAIL;
+ break;
+ }
+ }
+ if (NULL != cr->chain)
+ {
+ struct command *p = c ? : parent;
+ retval = register_commands(cmd_ctx, p, cr->chain);
+ if (ERROR_OK != retval)
+ break;
+ }
+ }
+ if (ERROR_OK != retval)
+ {
for (unsigned j = 0; j < i; j++)
unregister_command(cmd_ctx, parent, cmds[j].name);
- return ERROR_FAIL;
}
- return ERROR_OK;
+ return retval;
}
int unregister_all_commands(struct command_context *context,
return CALL_COMMAND_HANDLER(command_help_show, c, 0, false);
}
+static int command_unknown_find(unsigned argc, Jim_Obj *const *argv,
+ struct command *head, struct command **out)
+{
+ if (0 == argc)
+ return argc;
+ struct command *c = command_find(head, Jim_GetString(argv[0], NULL));
+ if (NULL == c)
+ return argc;
+ *out = c;
+ return command_unknown_find(--argc, ++argv, (*out)->children, out);
+}
+
+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);
+
+ 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);
+ // if nothing could be consumed, then it's really an unknown command
+ if (remaining == argc - 1)
+ {
+ const char *cmd = Jim_GetString(argv[1], NULL);
+ LOG_ERROR("Unknown command:\n %s", cmd);
+ return JIM_OK;
+ }
+
+ bool found = true;
+ Jim_Obj *const *start;
+ unsigned count;
+ if (c->handler || c->jim_handler)
+ {
+ // include the command name in the list
+ count = remaining + 1;
+ start = argv + (argc - remaining - 1);
+ }
+ else
+ {
+ c = command_find(cmd_ctx->commands, "help");
+ if (NULL == c)
+ {
+ LOG_ERROR("unknown command, but help is missing too");
+ return JIM_ERR;
+ }
+ count = argc - remaining;
+ start = argv;
+ found = false;
+ }
+ // pass the command through to the intended handler
+ if (c->jim_handler)
+ {
+ interp->cmdPrivData = c->jim_handler_data;
+ 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;
+
+ int retval = run_command(cmd_ctx, c, words, nwords);
+
+ script_command_args_free(words, nwords);
+
+ if (!found && ERROR_OK == retval)
+ retval = ERROR_FAIL;
+
+ return retval;
+}
int help_add_command(struct command_context *cmd_ctx, struct command *parent,
const char *cmd_name, const char *help_text, const char *usage)
return ERROR_OK;
}
+static const struct command_registration command_builtin_handlers[] = {
+ {
+ .name = "add_help_text",
+ .handler = &handle_help_add_command,
+ .mode = COMMAND_ANY,
+ .help = "add new command help text",
+ .usage = "<command> [...] <help_text>]",
+ },
+ {
+ .name = "sleep",
+ .handler = &handle_sleep_command,
+ .mode = COMMAND_ANY,
+ .help = "sleep for n milliseconds. "
+ "\"busy\" will busy wait",
+ .usage = "<n> [busy]",
+ },
+ {
+ .name = "help",
+ .handler = &handle_help_command,
+ .mode = COMMAND_ANY,
+ .help = "show built-in command help",
+ .usage = "[<command_name> ...]",
+ },
+ {
+ .name = "usage",
+ .handler = &handle_usage_command,
+ .mode = COMMAND_ANY,
+ .help = "show command usage",
+ .usage = "[<command_name> ...]",
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
struct command_context* command_init(const char *startup_tcl)
{
struct command_context* context = malloc(sizeof(struct command_context));
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);
interp->cb_fflush = openocd_jim_fflush;
interp->cb_fgets = openocd_jim_fgets;
- COMMAND_REGISTER(context, NULL, "add_help_text",
- handle_help_add_command, COMMAND_ANY,
- "<command> [...] <help_text>] - "
- "add new command help text");
+ register_commands(context, NULL, command_builtin_handlers);
#if !BUILD_ECOSBOARD
Jim_EventLoopOnLoad(interp);
}
Jim_DeleteAssocData(interp, "context");
- COMMAND_REGISTER(context, NULL, "sleep",
- handle_sleep_command, COMMAND_ANY,
- "<n> [busy] - sleep for n milliseconds. "
- "\"busy\" means busy wait");
-
- COMMAND_REGISTER(context, NULL, "help",
- &handle_help_command, COMMAND_ANY,
- "[<command_name> ...] - show built-in command help");
- COMMAND_REGISTER(context, NULL, "usage",
- &handle_usage_command, COMMAND_ANY,
- "[<command_name> ...] | "
- "show command usage");
-
return context;
}
#endif
}
-void register_jim(struct command_context *cmd_ctx, const char *name,
- Jim_CmdProc cmd, const char *help)
-{
- Jim_CreateCommand(interp, name, cmd, NULL, NULL);
-
- Jim_Obj *cmd_list = Jim_NewListObj(interp, NULL, 0);
- Jim_ListAppendElement(interp, cmd_list,
- Jim_NewStringObj(interp, name, -1));
-
- help_add_command(cmd_ctx, NULL, name, help, NULL);
-}
-
#define DEFINE_PARSE_NUM_TYPE(name, type, func, min, max) \
int parse##name(const char *str, type *ul) \
{ \