+ 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.
+ * @param head Address to head of command list pointer, which may be
+ * updated if @c c gets inserted at the beginning of the list.
+ * @param c The command to add to the list pointed to by @c head.
+ */
+static void command_add_child(struct command **head, struct command *c)
+{
+ assert(head);
+ if (NULL == *head) {
+ *head = c;
+ return;
+ }
+
+ while ((*head)->next && (strcmp(c->name, (*head)->name) > 0))
+ head = &(*head)->next;
+
+ if (strcmp(c->name, (*head)->name) > 0) {
+ c->next = (*head)->next;
+ (*head)->next = c;
+ } else {
+ c->next = *head;
+ *head = c;
+ }
+}
+
+static struct command **command_list_for_parent(
+ struct command_context *cmd_ctx, struct command *parent)
+{
+ return parent ? &parent->children : &cmd_ctx->commands;
+}
+
+static void command_free(struct command *c)
+{
+ /** @todo if command has a handler, unregister its jim command! */
+
+ while (NULL != c->children) {
+ struct command *tmp = c->children;
+ c->children = tmp->next;
+ command_free(tmp);
+ }
+
+ free(c->name);
+ free(c->help);
+ free(c->usage);
+ free(c);
+}
+
+static struct command *command_new(struct command_context *cmd_ctx,
+ struct command *parent, const struct command_registration *cr)
+{
+ assert(cr->name);
+
+ /*
+ * If it is a non-jim command with no .usage specified,
+ * log an error.
+ *
+ * strlen(.usage) == 0 means that the command takes no
+ * arguments.
+ */
+ if ((cr->jim_handler == NULL) && (cr->usage == NULL)) {
+ LOG_DEBUG("BUG: command '%s%s%s' does not have the "
+ "'.usage' field filled out",
+ parent && parent->name ? parent->name : "",
+ parent && parent->name ? " " : "",
+ cr->name);
+ }
+
+ struct command *c = calloc(1, sizeof(struct command));
+ if (NULL == c)
+ return NULL;
+
+ c->name = strdup(cr->name);
+ if (cr->help)
+ c->help = strdup(cr->help);
+ if (cr->usage)
+ c->usage = strdup(cr->usage);
+
+ if (!c->name || (cr->help && !c->help) || (cr->usage && !c->usage))
+ goto command_new_error;
+
+ c->parent = parent;
+ 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);
+
+ return c;
+
+command_new_error:
+ command_free(c);
+ return NULL;
+}
+
+static int command_unknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
+
+static int register_command_handler(struct command_context *cmd_ctx,
+ struct command *c)
+{
+ Jim_Interp *interp = cmd_ctx->interp;
+ char *ocd_name = alloc_printf("ocd_%s", c->name);
+ if (NULL == ocd_name)
+ return JIM_ERR;
+
+ LOG_DEBUG("registering '%s'...", ocd_name);
+
+ Jim_CmdProc *func = c->handler ? &script_command : &command_unknown;
+ int retval = Jim_CreateCommand(interp, ocd_name, func, c, NULL);
+ free(ocd_name);
+ if (JIM_OK != retval)
+ return retval;
+
+ /* we now need to add an overrideable proc */
+ 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 = Jim_Eval_Named(interp, override_name, 0, 0);
+ free(override_name);
+
+ return retval;
+}
+
+struct command *register_command(struct command_context *context,
+ struct command *parent, const struct command_registration *cr)
+{
+ if (!context || !cr->name)
+ return NULL;
+
+ const char *name = cr->name;
+ struct command **head = command_list_for_parent(context, parent);
+ struct command *c = command_find(*head, name);
+ if (NULL != c) {
+ /* TODO: originally we treated attempting to register a cmd twice as an error
+ * Sometimes we need this behaviour, such as with flash banks.
+ * http://www.mail-archive.com/openocd-development@lists.berlios.de/msg11152.html */
+ LOG_DEBUG("command '%s' is already registered in '%s' context",
+ name, parent ? parent->name : "<global>");
+ return c;
+ }
+
+ c = command_new(context, parent, cr);
+ if (NULL == c)
+ return NULL;
+
+ int retval = ERROR_OK;
+ if (NULL != cr->jim_handler && NULL == parent) {
+ retval = Jim_CreateCommand(context->interp, cr->name,
+ cr->jim_handler, cr->jim_handler_data, NULL);
+ } else if (NULL != cr->handler || NULL != parent)
+ retval = register_command_handler(context, command_root(c));
+
+ if (ERROR_OK != retval) {
+ unregister_command(context, parent, name);
+ c = 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 || cmds[i].chain; i++) {
+ 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;