X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Fhelper%2Fcommand.c;h=0958147ea116e3183ef13eda30acec6ec2f4b230;hp=538c07bb917392981622af66327d30c6774fe649;hb=e5b0a69ba99f58991ebb5d07ad947592f09728f1;hpb=73c6e3bb18326050acc8908b561443a7b37549bb diff --git a/src/helper/command.c b/src/helper/command.c index 538c07bb91..0958147ea1 100644 --- a/src/helper/command.c +++ b/src/helper/command.c @@ -233,33 +233,73 @@ static void command_add_child(struct command **head, struct command *c) cc->next = c; } -struct command* register_command(struct command_context *context, - struct command *parent, char *name, command_handler_t handler, - enum command_mode mode, char *help) +static struct command **command_list_for_parent( + struct command_context *cmd_ctx, struct command *parent) { - if (!context || !name) - return NULL; + return parent ? &parent->children : &cmd_ctx->commands; +} - struct command **head = parent ? &parent->children : &context->commands; - struct command *c = command_find(*head, name); - if (NULL != c) - return c; +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) +{ + assert(name); - c = malloc(sizeof(struct command)); + struct command *c = malloc(sizeof(struct command)); + memset(c, 0, sizeof(struct command)); c->name = strdup(name); + if (help) + c->help = strdup(help); c->parent = parent; - c->children = NULL; c->handler = handler; c->mode = mode; - c->next = NULL; - command_add_child(head, c); + command_add_child(command_list_for_parent(cmd_ctx, parent), c); command_helptext_add(command_name_list(c), help); - /* just a placeholder, no handler */ - if (c->handler == NULL) + return c; +} +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); + } + + if (c->name) + free(c->name); + if (c->help) + free((void*)c->help); + free(c); +} + +struct command* register_command(struct command_context *context, + struct command *parent, const char *name, + command_handler_t handler, enum command_mode mode, + const char *help) +{ + if (!context || !name) + return NULL; + + struct command **head = command_list_for_parent(context, parent); + struct command *c = command_find(*head, name); + if (NULL != c) + { + LOG_ERROR("command '%s' is already registered in '%s' context", + name, parent ? parent->name : ""); + return c; + } + + c = command_new(context, parent, name, handler, mode, help); + /* 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, '_'); @@ -281,85 +321,43 @@ struct command* register_command(struct command_context *context, return c; } -int unregister_all_commands(struct command_context *context) +int unregister_all_commands(struct command_context *context, + struct command *parent) { - struct command *c, *c2; - if (context == NULL) return ERROR_OK; - while (NULL != context->commands) + struct command **head = command_list_for_parent(context, parent); + while (NULL != *head) { - c = context->commands; - - while (NULL != c->children) - { - c2 = c->children; - c->children = c->children->next; - free(c2->name); - c2->name = NULL; - free(c2); - c2 = NULL; - } - - context->commands = context->commands->next; - - free(c->name); - c->name = NULL; - free(c); - c = NULL; + struct command *tmp = *head; + *head = tmp->next; + command_free(tmp); } return ERROR_OK; } -int unregister_command(struct command_context *context, char *name) +int unregister_command(struct command_context *context, + struct command *parent, const char *name) { - struct command *c, *p = NULL, *c2; - if ((!context) || (!name)) return ERROR_INVALID_ARGUMENTS; - /* find command */ - c = context->commands; - - while (NULL != c) + struct command *p = NULL; + struct command **head = command_list_for_parent(context, parent); + for (struct command *c = *head; NULL != c; p = c, c = c->next) { - if (strcmp(name, c->name) == 0) - { - /* unlink command */ - if (p) - { - p->next = c->next; - } - else - { - /* first element in command list */ - context->commands = c->next; - } + if (strcmp(name, c->name) != 0) + continue; - /* unregister children */ - while (NULL != c->children) - { - c2 = c->children; - c->children = c->children->next; - free(c2->name); - c2->name = NULL; - free(c2); - c2 = NULL; - } - - /* delete command */ - free(c->name); - c->name = NULL; - free(c); - c = NULL; - return ERROR_OK; - } + if (p) + p->next = c->next; + else + *head = c->next; - /* remember the last command for unlinking */ - p = c; - c = c->next; + command_free(c); + return ERROR_OK; } return ERROR_OK; @@ -727,6 +725,52 @@ static int jim_capture(Jim_Interp *interp, int argc, Jim_Obj *const *argv) return retcode; } +static COMMAND_HELPER(command_help_find, struct command *head, + struct command **out) +{ + if (0 == CMD_ARGC) + return ERROR_INVALID_ARGUMENTS; + *out = command_find(head, CMD_ARGV[0]); + if (NULL == *out) + return ERROR_INVALID_ARGUMENTS; + if (--CMD_ARGC == 0) + return ERROR_OK; + CMD_ARGV++; + 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_list, struct command *head, unsigned n) +{ + for (struct command *c = head; NULL != c; c = c->next) + CALL_COMMAND_HANDLER(command_help_show, c, n); + return ERROR_OK; +} +static COMMAND_HELPER(command_help_show, struct command *c, unsigned n) +{ + command_run_linef(CMD_CTX, "cmd_help {%s} {%s} %d", command_name(c, ' '), + c->help ? : "no help available", n); + + if (++n >= 2) + return ERROR_OK; + + return CALL_COMMAND_HANDLER(command_help_show_list, c->children, n); +} +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); + + 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); +} + /* sleep command sleeps for miliseconds * this is useful in target startup scripts */ @@ -825,18 +869,24 @@ struct command_context* command_init(const char *startup_tcl) #if !BUILD_ECOSBOARD Jim_EventLoopOnLoad(interp); #endif + Jim_SetAssocData(interp, "context", NULL, context); if (Jim_Eval_Named(interp, startup_tcl, "embedded:startup.tcl",1) == JIM_ERR) { LOG_ERROR("Failed to run startup.tcl (embedded into OpenOCD)"); Jim_PrintErrorMessage(interp); exit(-1); } + Jim_DeleteAssocData(interp, "context"); register_command(context, NULL, "sleep", handle_sleep_command, COMMAND_ANY, " [busy] - sleep for n milliseconds. " "\"busy\" means busy wait"); + register_command(context, NULL, "help", + &handle_help_command, COMMAND_ANY, + "[ ...] - show built-in command help"); + return context; } @@ -983,5 +1033,3 @@ COMMAND_HELPER(handle_command_parse_bool, bool *out, const char *label) } return ERROR_OK; } - -