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 *help, const char *usage)
{
assert(name);
c->name = strdup(name);
if (help)
c->help = strdup(help);
+ if (usage)
+ c->usage = strdup(usage);
c->parent = parent;
c->handler = handler;
c->mode = mode;
free(c->name);
if (c->help)
free((void*)c->help);
+ if (c->usage)
+ free((void*)c->usage);
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);
+ 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);
-
- /* 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);
+ int retval = register_command_handler(c);
+ if (ERROR_OK != retval)
+ {
+ unregister_command(context, parent, name);
+ c = NULL;
+ }
+ return c;
+}
- free((void *)full_name);
+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 || cmds[i].chain; i++)
+ {
+ const struct command_registration *cr = cmds + i;
- return c;
+ 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 retval;
}
int unregister_all_commands(struct command_context *context,
return CALL_COMMAND_HANDLER(command_help_find, (*out)->children, out);
}
-static COMMAND_HELPER(command_help_show, struct command *c, unsigned n);
+static COMMAND_HELPER(command_help_show, struct command *c, unsigned n,
+ bool show_help);
-static COMMAND_HELPER(command_help_show_list, struct command *head, unsigned n)
+static COMMAND_HELPER(command_help_show_list, struct command *head, unsigned n,
+ bool show_help)
{
for (struct command *c = head; NULL != c; c = c->next)
- CALL_COMMAND_HANDLER(command_help_show, c, n);
+ CALL_COMMAND_HANDLER(command_help_show, c, n, show_help);
return ERROR_OK;
}
-static COMMAND_HELPER(command_help_show, struct command *c, unsigned n)
+static COMMAND_HELPER(command_help_show, struct command *c, unsigned n,
+ bool show_help)
{
- command_run_linef(CMD_CTX, "cmd_help {%s} {%s} %d", command_name(c, ' '),
- c->help ? : "no help available", n);
+ const char *usage = c->usage ? : "";
+ const char *help = "";
+ const char *sep = "";
+ if (show_help && c->help)
+ {
+ help = c->help ? : "";
+ sep = c->usage ? " | " : "";
+ }
+ command_run_linef(CMD_CTX, "cmd_help {%s} {%s%s%s} %d",
+ command_name(c, ' '), usage, sep, help, n);
if (++n >= 2)
return ERROR_OK;
- return CALL_COMMAND_HANDLER(command_help_show_list, c->children, n);
+ return CALL_COMMAND_HANDLER(command_help_show_list,
+ c->children, n, show_help);
}
COMMAND_HANDLER(handle_help_command)
{
struct command *c = CMD_CTX->commands;
if (0 == CMD_ARGC)
- return CALL_COMMAND_HANDLER(command_help_show_list, c, 0);
+ return CALL_COMMAND_HANDLER(command_help_show_list, c, 0, true);
+
+ int retval = CALL_COMMAND_HANDLER(command_help_find, c, &c);
+ if (ERROR_OK != retval)
+ return retval;
+
+ return CALL_COMMAND_HANDLER(command_help_show, c, 0, true);
+}
+
+COMMAND_HANDLER(handle_usage_command)
+{
+ struct command *c = CMD_CTX->commands;
+
+ if (0 == CMD_ARGC)
+ return CALL_COMMAND_HANDLER(command_help_show_list, c, 0, false);
int retval = CALL_COMMAND_HANDLER(command_help_find, c, &c);
if (ERROR_OK != retval)
return retval;
- return CALL_COMMAND_HANDLER(command_help_show, c, 0);
+ return CALL_COMMAND_HANDLER(command_help_show, c, 0, false);
}
int help_add_command(struct command_context *cmd_ctx, struct command *parent,
- const char *cmd_name, const char *help_text)
+ const char *cmd_name, const char *help_text, const char *usage)
{
struct command **head = command_list_for_parent(cmd_ctx, parent);
struct command *nc = command_find(*head, cmd_name);
.name = cmd_name,
.mode = COMMAND_ANY,
.help = help_text,
+ .usage = usage,
};
nc = register_command(cmd_ctx, parent, &cr);
if (NULL == nc)
if (ERROR_OK != retval)
return retval;
}
- return help_add_command(CMD_CTX, c, cmd_name, help_text);
+ return help_add_command(CMD_CTX, c, cmd_name, help_text, NULL);
}
/* sleep command sleeps for <n> miliseconds
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));
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");
-
return context;
}
Jim_ListAppendElement(interp, cmd_list,
Jim_NewStringObj(interp, name, -1));
- help_add_command(cmd_ctx, NULL, name, help);
+ help_add_command(cmd_ctx, NULL, name, help, NULL);
}
#define DEFINE_PARSE_NUM_TYPE(name, type, func, min, max) \