From: OpenOCD-Gerrit <ope...@us...> - 2021-04-18 14:35:06
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "Main OpenOCD repository". The branch, master has been updated via f238337c9c2fdabb48992487e5243d03d32e215d (commit) via e216186fab59d71fdee24af926d1807a1d7fc950 (commit) via aacc26559e4984b649083ac046db2cbcb54e2f70 (commit) via cb83bc747ce1106c50d713f6d552da8c3e476e0f (commit) from 41c95aa4ea1506a951dad0147f6cd4b8d7043358 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit f238337c9c2fdabb48992487e5243d03d32e215d Author: Antonio Borneo <bor...@gm...> Date: Wed May 13 02:30:11 2020 +0200 helper/command: simplify run_command() Now that the commands are registered using their full-name, the full-name is in argv[0]. Don't rebuild the full-name but use directly argv[0]. Change-Id: Ic9e469ac39276367b8c47527e70791ff470fefbc Signed-off-by: Antonio Borneo <bor...@gm...> Reviewed-on: http://openocd.zylin.com/5672 Tested-by: jenkins Reviewed-by: Oleksij Rempel <li...@re...> diff --git a/src/helper/command.c b/src/helper/command.c index 41b86796a..1628b6ee7 100644 --- a/src/helper/command.c +++ b/src/helper/command.c @@ -586,20 +586,13 @@ static int run_command(struct command_context *context, int retval = c->handler(&cmd); if (retval == ERROR_COMMAND_SYNTAX_ERROR) { /* Print help for command */ - char *full_name = command_name(c, ' '); - if (NULL != full_name) { - command_run_linef(context, "usage %s", full_name); - free(full_name); - } + command_run_linef(context, "usage %s", words[0]); } else if (retval == ERROR_COMMAND_CLOSE_CONNECTION) { /* just fall through for a shutdown request */ } else { - if (retval != ERROR_OK) { - char *full_name = command_name(c, ' '); + if (retval != ERROR_OK) LOG_DEBUG("Command '%s' failed with error code %d", - full_name ? full_name : c->name, retval); - free(full_name); - } + words[0], retval); /* Use the command output as the Tcl result */ Jim_SetResult(context->interp, cmd.output); } commit e216186fab59d71fdee24af926d1807a1d7fc950 Author: Antonio Borneo <bor...@gm...> Date: Wed May 13 01:59:59 2020 +0200 helper/command: register full-name commands in jim While still keeping the tree of struct command, stop registering commands in jim by the root "word" only. Register the full-name of the command and pass as private data the struct command of the command itself. Still use the tree of struct command to un-register the commands. Some "native" commands (.jim_handler) share the same handler, then the handler checks the command name to run the right code. Now argv[0] returns the full-name of the command, so check the name by looking in the struct command passed as private data. Change-Id: I5623c61cceee8a75f5d5a551ef3fbf5a303af6be Signed-off-by: Antonio Borneo <bor...@gm...> Reviewed-on: http://openocd.zylin.com/5671 Tested-by: jenkins Reviewed-by: Oleksij Rempel <li...@re...> diff --git a/src/helper/command.c b/src/helper/command.c index 3b531807f..41b86796a 100644 --- a/src/helper/command.c +++ b/src/helper/command.c @@ -232,13 +232,6 @@ struct command_context *current_command_context(Jim_Interp *interp) return cmd_ctx; } -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. * @returns Returns the named command if it exists in the list. @@ -349,18 +342,6 @@ command_new_error: 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; - -#if 0 - LOG_DEBUG("registering '%s'...", c->name); -#endif - - return Jim_CreateCommand(interp, c->name, command_unknown, c, NULL); -} - static struct command *register_command(struct command_context *context, struct command *parent, const struct command_registration *cr) { @@ -383,12 +364,13 @@ static struct command *register_command(struct command_context *context, if (NULL == c) return NULL; - if (cr->jim_handler || cr->handler) { - int retval = register_command_handler(context, command_root(c)); - if (retval != JIM_OK) { - unregister_command(context, parent, name); - return NULL; - } + char *full_name = command_name(c, ' '); + LOG_DEBUG("registering '%s'...", full_name); + int retval = Jim_CreateCommand(context->interp, full_name, + command_unknown, c, NULL); + if (retval != JIM_OK) { + unregister_command(context, parent, name); + return NULL; } return c; } @@ -563,7 +545,7 @@ static char *command_name(struct command *c, char delim) return __command_name(c, delim, 0); } -static bool command_can_run(struct command_context *cmd_ctx, struct command *c) +static bool command_can_run(struct command_context *cmd_ctx, struct command *c, const char *full_name) { if (c->mode == COMMAND_ANY || c->mode == cmd_ctx->mode) return true; @@ -582,10 +564,8 @@ static bool command_can_run(struct command_context *cmd_ctx, struct command *c) when = "if Cthulhu is summoned by"; break; } - char *full_name = command_name(c, ' '); LOG_ERROR("The '%s' command must be used %s 'init'.", full_name ? full_name : c->name, when); - free(full_name); return false; } @@ -980,41 +960,8 @@ static char *alloc_concatenate_strings(int argc, Jim_Obj * const *argv) return all; } -static int run_usage(Jim_Interp *interp, int argc_valid, int argc, Jim_Obj * const *argv) -{ - struct command_context *cmd_ctx = current_command_context(interp); - char *command; - int retval; - - assert(argc_valid >= 1); - assert(argc >= argc_valid); - - command = alloc_concatenate_strings(argc_valid, argv); - if (!command) - return JIM_ERR; - - retval = command_run_linef(cmd_ctx, "usage %s", command); - if (retval != ERROR_OK) { - LOG_ERROR("unable to execute command \"usage %s\"", command); - return JIM_ERR; - } - - if (argc_valid == argc) - LOG_ERROR("%s: command requires more arguments", command); - else { - free(command); - command = alloc_concatenate_strings(argc - argc_valid, argv + argc_valid); - if (!command) - return JIM_ERR; - LOG_ERROR("invalid subcommand \"%s\"", command); - } - - free(command); - return retval; -} - static int exec_command(Jim_Interp *interp, struct command_context *cmd_ctx, - struct command *c, int argc, Jim_Obj *const *argv) + struct command *c, int argc, Jim_Obj * const *argv) { if (c->jim_handler) return c->jim_handler(interp, argc, argv); @@ -1034,30 +981,30 @@ static int command_unknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { script_debug(interp, argc, argv); - struct command_context *cmd_ctx = current_command_context(interp); - struct command *c = cmd_ctx->commands; - int remaining = command_unknown_find(argc, argv, c, &c); - /* if nothing could be consumed, then it's really an unknown command */ - if (remaining == argc) { - const char *cmd = Jim_GetString(argv[0], NULL); - LOG_ERROR("Unknown command:\n %s", cmd); - return JIM_OK; + /* check subcommands */ + if (argc > 1) { + char *s = alloc_printf("%s %s", Jim_GetString(argv[0], NULL), Jim_GetString(argv[1], NULL)); + Jim_Obj *js = Jim_NewStringObj(interp, s, -1); + Jim_IncrRefCount(js); + free(s); + Jim_Cmd *cmd = Jim_GetCommand(interp, js, JIM_NONE); + if (cmd) { + int retval = Jim_EvalObjPrefix(interp, js, argc - 2, argv + 2); + Jim_DecrRefCount(interp, js); + return retval; + } + Jim_DecrRefCount(interp, js); } - 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 { - count = argc - remaining; - start = argv; - run_usage(interp, count, argc, start); + struct command *c = jim_to_command(interp); + if (!c->jim_handler && !c->handler) { + Jim_EvalObjPrefix(interp, Jim_NewStringObj(interp, "usage", -1), 1, argv); return JIM_ERR; } - if (!command_can_run(cmd_ctx, c)) + struct command_context *cmd_ctx = current_command_context(interp); + + if (!command_can_run(cmd_ctx, c, Jim_GetString(argv[0], NULL))) return JIM_ERR; target_call_timer_callbacks_now(); @@ -1076,7 +1023,7 @@ static int command_unknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv) if (c->jim_override_target) cmd_ctx->current_target_override = c->jim_override_target; - int retval = exec_command(interp, cmd_ctx, c, count, start); + int retval = exec_command(interp, cmd_ctx, c, argc, argv); if (c->jim_override_target) cmd_ctx->current_target_override = saved_target_override; diff --git a/src/jtag/tcl.c b/src/jtag/tcl.c index 2fa162e56..bf65e8119 100644 --- a/src/jtag/tcl.c +++ b/src/jtag/tcl.c @@ -767,7 +767,8 @@ static bool jtag_tap_disable(struct jtag_tap *t) int jim_jtag_tap_enabler(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { - const char *cmd_name = Jim_GetString(argv[0], NULL); + struct command *c = jim_to_command(interp); + const char *cmd_name = c->name; Jim_GetOptInfo goi; Jim_GetOpt_Setup(&goi, interp, argc-1, argv + 1); if (goi.argc != 1) { @@ -804,7 +805,8 @@ int jim_jtag_tap_enabler(Jim_Interp *interp, int argc, Jim_Obj *const *argv) int jim_jtag_configure(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { - const char *cmd_name = Jim_GetString(argv[0], NULL); + struct command *c = jim_to_command(interp); + const char *cmd_name = c->name; Jim_GetOptInfo goi; Jim_GetOpt_Setup(&goi, interp, argc-1, argv + 1); goi.isconfigure = !strcmp(cmd_name, "configure"); diff --git a/src/target/aarch64.c b/src/target/aarch64.c index 46ed49f68..4ba92c8a0 100644 --- a/src/target/aarch64.c +++ b/src/target/aarch64.c @@ -2966,6 +2966,7 @@ COMMAND_HANDLER(aarch64_mask_interrupts_command) static int jim_mcrmrc(Jim_Interp *interp, int argc, Jim_Obj * const *argv) { + struct command *c = jim_to_command(interp); struct command_context *context; struct target *target; struct arm *arm; @@ -2973,7 +2974,7 @@ static int jim_mcrmrc(Jim_Interp *interp, int argc, Jim_Obj * const *argv) bool is_mcr = false; int arg_cnt = 0; - if (Jim_CompareStringImmediate(interp, argv[0], "mcr")) { + if (!strcmp(c->name, "mcr")) { is_mcr = true; arg_cnt = 7; } else { diff --git a/src/target/arm_tpiu_swo.c b/src/target/arm_tpiu_swo.c index 186ce5d0e..f93508622 100644 --- a/src/target/arm_tpiu_swo.c +++ b/src/target/arm_tpiu_swo.c @@ -550,16 +550,16 @@ err_no_params: static int jim_arm_tpiu_swo_configure(Jim_Interp *interp, int argc, Jim_Obj * const *argv) { + struct command *c = jim_to_command(interp); Jim_GetOptInfo goi; Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1); - goi.isconfigure = !strcmp(Jim_GetString(argv[0], NULL), "configure"); + goi.isconfigure = !strcmp(c->name, "configure"); if (goi.argc < 1) { Jim_WrongNumArgs(goi.interp, goi.argc, goi.argv, "missing: -option ..."); return JIM_ERR; } - struct command *c = jim_to_command(interp); struct arm_tpiu_swo_object *obj = c->jim_handler_data; return arm_tpiu_swo_configure(&goi, obj); } diff --git a/src/target/target.c b/src/target/target.c index fa033d351..e9d67702e 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -5197,10 +5197,11 @@ no_params: static int jim_target_configure(Jim_Interp *interp, int argc, Jim_Obj * const *argv) { + struct command *c = jim_to_command(interp); Jim_GetOptInfo goi; Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1); - goi.isconfigure = !strcmp(Jim_GetString(argv[0], NULL), "configure"); + goi.isconfigure = !strcmp(c->name, "configure"); if (goi.argc < 1) { Jim_WrongNumArgs(goi.interp, goi.argc, goi.argv, "missing: -option ..."); commit aacc26559e4984b649083ac046db2cbcb54e2f70 Author: Antonio Borneo <bor...@gm...> Date: Sat Mar 27 16:12:11 2021 +0100 help: re-implement 'help' independent from tree of struct command The current implementation of "help" related commands is tightly connected to the tree of struct command. The TCL commands 'add_usage_text' and 'add_help_text' have to add fake commands in the tree of struct command to handle the help of TCL procs. Move all the help texts in a list accessible from the struct command_context and register the commands through their full name. Keep the list sorted alphabetically by the command name, so the result of commands 'help' and 'usage' will be sorted too. Remove the associated help and usage during commands un-register, but call help_del_all_commands() for the text added through TCL commands 'add_usage_text' and 'add_help_text'. The resulting help and usage output is not changed by this patch (tested on all the help and usage strings in current master branch). Change-Id: Ifd37bb5bd374cba1a22cd7aac208505b4ae1e6fc Signed-off-by: Antonio Borneo <bor...@gm...> Reviewed-on: http://openocd.zylin.com/5670 Tested-by: jenkins Reviewed-by: Oleksij Rempel <li...@re...> diff --git a/src/helper/command.c b/src/helper/command.c index 288ba99aa..3b531807f 100644 --- a/src/helper/command.c +++ b/src/helper/command.c @@ -52,6 +52,9 @@ struct log_capture_state { static int unregister_command(struct command_context *context, struct command *parent, const char *name); static char *command_name(struct command *c, char delim); +static int help_add_command(struct command_context *cmd_ctx, + const char *cmd_name, const char *help_text, const char *usage_text); +static int help_del_command(struct command_context *cmd_ctx, const char *cmd_name); /* wrap jimtcl internal data */ static inline bool jimcmd_is_proc(Jim_Cmd *cmd) @@ -293,8 +296,6 @@ static void command_free(struct command *c) } free(c->name); - free(c->help); - free(c->usage); free(c); } @@ -323,12 +324,7 @@ static struct command *command_new(struct command_context *cmd_ctx, 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)) + if (!c->name) goto command_new_error; c->parent = parent; @@ -338,6 +334,12 @@ static struct command *command_new(struct command_context *cmd_ctx, command_add_child(command_list_for_parent(cmd_ctx, parent), c); + if (cr->help || cr->usage) { + char *full_name = command_name(c, ' '); + help_add_command(cmd_ctx, full_name, cr->help, cr->usage); + free(full_name); + } + return c; command_new_error: @@ -464,6 +466,10 @@ static int unregister_command(struct command_context *context, if (strcmp(name, c->name) != 0) continue; + char *full_name = command_name(c, ' '); + help_del_command(context, full_name); + free(full_name); + if (p) p->next = c->next; else @@ -785,28 +791,22 @@ 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_COMMAND_SYNTAX_ERROR; - *out = command_find(head, CMD_ARGV[0]); - if (NULL == *out) - return ERROR_COMMAND_SYNTAX_ERROR; - if (--CMD_ARGC == 0) - return ERROR_OK; - CMD_ARGV++; - return CALL_COMMAND_HANDLER(command_help_find, (*out)->children, out); -} +struct help_entry { + struct list_head lh; + char *cmd_name; + char *help; + char *usage; +}; -static COMMAND_HELPER(command_help_show, struct command *c, unsigned n, +static COMMAND_HELPER(command_help_show, struct help_entry *c, bool show_help, const char *cmd_match); -static COMMAND_HELPER(command_help_show_list, struct command *head, unsigned n, - bool show_help, const char *cmd_match) +static COMMAND_HELPER(command_help_show_list, bool show_help, const char *cmd_match) { - for (struct command *c = head; NULL != c; c = c->next) - CALL_COMMAND_HANDLER(command_help_show, c, n, show_help, cmd_match); + struct help_entry *entry; + + list_for_each_entry(entry, CMD_CTX->help_list, lh) + CALL_COMMAND_HANDLER(command_help_show, entry, show_help, cmd_match); return ERROR_OK; } @@ -837,26 +837,23 @@ static void command_help_show_wrap(const char *str, unsigned n, unsigned n2) } } -static COMMAND_HELPER(command_help_show, struct command *c, unsigned n, +static COMMAND_HELPER(command_help_show, struct help_entry *c, bool show_help, const char *cmd_match) { - char *cmd_name = command_name(c, ' '); - if (NULL == cmd_name) - return ERROR_FAIL; + unsigned int n = 0; + for (const char *s = strchr(c->cmd_name, ' '); s; s = strchr(s + 1, ' ')) + n++; /* If the match string occurs anywhere, we print out * stuff for this command. */ - bool is_match = (strstr(cmd_name, cmd_match) != NULL) || + bool is_match = (strstr(c->cmd_name, cmd_match) != NULL) || ((c->usage != NULL) && (strstr(c->usage, cmd_match) != NULL)) || ((c->help != NULL) && (strstr(c->help, cmd_match) != NULL)); if (is_match) { command_help_show_indent(n); - LOG_USER_N("%s", cmd_name); - } - free(cmd_name); + LOG_USER_N("%s", c->cmd_name); - if (is_match) { if (c->usage && strlen(c->usage) > 0) { LOG_USER_N(" "); command_help_show_wrap(c->usage, 0, n + 5); @@ -867,11 +864,30 @@ static COMMAND_HELPER(command_help_show, struct command *c, unsigned n, if (is_match && show_help) { char *msg; + /* TODO: factorize jim_command_mode() to avoid running jim command here */ + char *request = alloc_printf("command mode %s", c->cmd_name); + if (!request) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + int retval = Jim_Eval(CMD_CTX->interp, request); + free(request); + enum command_mode mode = COMMAND_UNKNOWN; + if (retval != JIM_ERR) { + const char *result = Jim_GetString(Jim_GetResult(CMD_CTX->interp), NULL); + if (!strcmp(result, "any")) + mode = COMMAND_ANY; + else if (!strcmp(result, "config")) + mode = COMMAND_CONFIG; + else if (!strcmp(result, "exec")) + mode = COMMAND_EXEC; + } + /* Normal commands are runtime-only; highlight exceptions */ - if (c->mode != COMMAND_EXEC) { + if (mode != COMMAND_EXEC) { const char *stage_msg = ""; - switch (c->mode) { + switch (mode) { case COMMAND_CONFIG: stage_msg = " (configuration command)"; break; @@ -893,20 +909,13 @@ static COMMAND_HELPER(command_help_show, struct command *c, unsigned n, return -ENOMEM; } - if (++n > 5) { - LOG_ERROR("command recursion exceeded"); - return ERROR_FAIL; - } - - return CALL_COMMAND_HANDLER(command_help_show_list, - c->children, n, show_help, cmd_match); + return ERROR_OK; } COMMAND_HANDLER(handle_help_command) { bool full = strcmp(CMD_NAME, "help") == 0; int retval; - struct command *c = CMD_CTX->commands; char *cmd_match; if (CMD_ARGC <= 0) @@ -926,8 +935,7 @@ COMMAND_HANDLER(handle_help_command) LOG_ERROR("unable to build search string"); return -ENOMEM; } - retval = CALL_COMMAND_HANDLER(command_help_show_list, - c, 0, full, cmd_match); + retval = CALL_COMMAND_HANDLER(command_help_show_list, full, cmd_match); free(cmd_match); return retval; @@ -1124,81 +1132,104 @@ static int jim_command_mode(Jim_Interp *interp, int argc, Jim_Obj *const *argv) return JIM_OK; } -int help_add_command(struct command_context *cmd_ctx, struct command *parent, - const char *cmd_name, const char *help_text, const char *usage) +int help_del_all_commands(struct command_context *cmd_ctx) +{ + struct help_entry *curr, *n; + + list_for_each_entry_safe(curr, n, cmd_ctx->help_list, lh) { + list_del(&curr->lh); + free(curr->cmd_name); + free(curr->help); + free(curr->usage); + free(curr); + } + return ERROR_OK; +} + +static int help_del_command(struct command_context *cmd_ctx, const char *cmd_name) { - struct command **head = command_list_for_parent(cmd_ctx, parent); - struct command *nc = command_find(*head, cmd_name); - if (NULL == nc) { - /* add a new command with help text */ - struct command_registration cr = { - .name = cmd_name, - .mode = COMMAND_ANY, - .help = help_text, - .usage = usage ? : "", - }; - nc = register_command(cmd_ctx, parent, &cr); - if (NULL == nc) { - LOG_ERROR("failed to add '%s' help text", cmd_name); + struct help_entry *curr; + + list_for_each_entry(curr, cmd_ctx->help_list, lh) { + if (!strcmp(cmd_name, curr->cmd_name)) { + list_del(&curr->lh); + free(curr->cmd_name); + free(curr->help); + free(curr->usage); + free(curr); + break; + } + } + + return ERROR_OK; +} + +static int help_add_command(struct command_context *cmd_ctx, + const char *cmd_name, const char *help_text, const char *usage_text) +{ + int cmp = -1; /* add after curr */ + struct help_entry *curr; + + list_for_each_entry_reverse(curr, cmd_ctx->help_list, lh) { + cmp = strcmp(cmd_name, curr->cmd_name); + if (cmp >= 0) + break; + } + + struct help_entry *entry; + if (cmp) { + entry = calloc(1, sizeof(*entry)); + if (!entry) { + LOG_ERROR("Out of memory"); return ERROR_FAIL; } - LOG_DEBUG("added '%s' help text", cmd_name); - return ERROR_OK; + entry->cmd_name = strdup(cmd_name); + if (!entry->cmd_name) { + LOG_ERROR("Out of memory"); + free(entry); + return ERROR_FAIL; + } + list_add(&entry->lh, &curr->lh); + } else { + entry = curr; } + if (help_text) { - bool replaced = false; - if (nc->help) { - free(nc->help); - replaced = true; + char *text = strdup(help_text); + if (!text) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; } - nc->help = strdup(help_text); - if (replaced) - LOG_INFO("replaced existing '%s' help", cmd_name); - else - LOG_DEBUG("added '%s' help text", cmd_name); + free(entry->help); + entry->help = text; } - if (usage) { - bool replaced = false; - if (nc->usage) { - if (*nc->usage) - replaced = true; - free(nc->usage); + + if (usage_text) { + char *text = strdup(usage_text); + if (!text) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; } - nc->usage = strdup(usage); - if (replaced) - LOG_INFO("replaced existing '%s' usage", cmd_name); - else - LOG_DEBUG("added '%s' usage text", cmd_name); + free(entry->usage); + entry->usage = text; } + return ERROR_OK; } COMMAND_HANDLER(handle_help_add_command) { - if (CMD_ARGC < 2) { - LOG_ERROR("%s: insufficient arguments", CMD_NAME); + if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; - } - /* save help text and remove it from argument list */ - const char *str = CMD_ARGV[--CMD_ARGC]; - const char *help = !strcmp(CMD_NAME, "add_help_text") ? str : NULL; - const char *usage = !strcmp(CMD_NAME, "add_usage_text") ? str : NULL; + const char *help = !strcmp(CMD_NAME, "add_help_text") ? CMD_ARGV[1] : NULL; + const char *usage = !strcmp(CMD_NAME, "add_usage_text") ? CMD_ARGV[1] : NULL; if (!help && !usage) { LOG_ERROR("command name '%s' is unknown", CMD_NAME); return ERROR_COMMAND_SYNTAX_ERROR; } - /* likewise for the leaf command name */ - const char *cmd_name = CMD_ARGV[--CMD_ARGC]; - - struct command *c = NULL; - if (CMD_ARGC > 0) { - c = CMD_CTX->commands; - int retval = CALL_COMMAND_HANDLER(command_help_find, c, &c); - if (ERROR_OK != retval) - return retval; - } - return help_add_command(CMD_CTX, c, cmd_name, help, usage); + const char *cmd_name = CMD_ARGV[0]; + return help_add_command(CMD_CTX, cmd_name, help, usage); } /* sleep command sleeps for <n> milliseconds @@ -1329,6 +1360,10 @@ struct command_context *command_init(const char *startup_tcl, Jim_Interp *interp context->mode = COMMAND_EXEC; + /* context can be duplicated. Put list head on separate mem-chunk to keep list consistent */ + context->help_list = malloc(sizeof(*context->help_list)); + INIT_LIST_HEAD(context->help_list); + /* Create a jim interpreter if we were not handed one */ if (interp == NULL) { /* Create an interpreter */ @@ -1393,6 +1428,7 @@ void command_exit(struct command_context *context) return; Jim_FreeInterp(context->interp); + free(context->help_list); command_done(context); } diff --git a/src/helper/command.h b/src/helper/command.h index 9a04e9fa1..db095972a 100644 --- a/src/helper/command.h +++ b/src/helper/command.h @@ -26,6 +26,7 @@ #include <stdbool.h> #include <jim-nvp.h> +#include <helper/list.h> #include <helper/types.h> /* To achieve C99 printf compatibility in MinGW, gnu_printf should be @@ -41,6 +42,7 @@ enum command_mode { COMMAND_EXEC, COMMAND_CONFIG, COMMAND_ANY, + COMMAND_UNKNOWN = -1, /* error condition */ }; struct command_context; @@ -64,6 +66,7 @@ struct command_context { */ command_output_handler_t output_handler; void *output_handler_priv; + struct list_head *help_list; }; struct command; @@ -179,8 +182,6 @@ typedef __COMMAND_HANDLER((*command_handler_t)); struct command { char *name; - char *help; - char *usage; struct command *parent; struct command *children; command_handler_t handler; @@ -316,6 +317,14 @@ static inline int register_commands_with_data(struct command_context *cmd_ctx, int unregister_all_commands(struct command_context *cmd_ctx, struct command *parent); +/** + * Unregisters the help for all commands. Used at exit to remove the help + * added through the commands 'add_help_text' and 'add_usage_text'. + * @param cmd_ctx The context that will be cleared of registered helps. + * @returns ERROR_OK on success, or an error code. + */ +int help_del_all_commands(struct command_context *cmd_ctx); + void command_set_output_handler(struct command_context *context, command_output_handler_t output_handler, void *priv); diff --git a/src/openocd.c b/src/openocd.c index fcefdbe70..32b68b6fc 100644 --- a/src/openocd.c +++ b/src/openocd.c @@ -361,6 +361,7 @@ int openocd_main(int argc, char *argv[]) server_free(); unregister_all_commands(cmd_ctx, NULL); + help_del_all_commands(cmd_ctx); /* free all DAP and CTI objects */ dap_cleanup_all(); commit cb83bc747ce1106c50d713f6d552da8c3e476e0f Author: Antonio Borneo <bor...@gm...> Date: Sat May 9 02:00:45 2020 +0200 command mode: return "any" for tcl proc A tcl proc can be executed anytime, in any command mode. Let the command "command mode" to detect a tcl proc and return the string "any". Change-Id: I0559076c3063632ee0ea9a57a25f91060209b77f Signed-off-by: Antonio Borneo <bor...@gm...> Reviewed-on: http://openocd.zylin.com/5669 Tested-by: jenkins Reviewed-by: Oleksij Rempel <li...@re...> diff --git a/src/helper/command.c b/src/helper/command.c index 114d07328..288ba99aa 100644 --- a/src/helper/command.c +++ b/src/helper/command.c @@ -53,6 +53,12 @@ static int unregister_command(struct command_context *context, struct command *parent, const char *name); static char *command_name(struct command *c, char delim); +/* wrap jimtcl internal data */ +static inline bool jimcmd_is_proc(Jim_Cmd *cmd) +{ + return cmd->isproc; +} + static void tcl_output(void *privData, const char *file, unsigned line, const char *function, const char *string) { @@ -1076,6 +1082,18 @@ static int jim_command_mode(Jim_Interp *interp, int argc, Jim_Obj *const *argv) enum command_mode mode; if (argc > 1) { + char *full_name = alloc_concatenate_strings(argc - 1, argv + 1); + if (!full_name) + return JIM_ERR; + Jim_Obj *s = Jim_NewStringObj(interp, full_name, -1); + Jim_IncrRefCount(s); + Jim_Cmd *cmd = Jim_GetCommand(interp, s, JIM_NONE); + Jim_DecrRefCount(interp, s); + free(full_name); + if (cmd && jimcmd_is_proc(cmd)) { + Jim_SetResultString(interp, "any", -1); + return JIM_OK; + } 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 an unknown command */ ----------------------------------------------------------------------- Summary of changes: src/helper/command.c | 382 +++++++++++++++++++++++----------------------- src/helper/command.h | 13 +- src/jtag/tcl.c | 6 +- src/openocd.c | 1 + src/target/aarch64.c | 3 +- src/target/arm_tpiu_swo.c | 4 +- src/target/target.c | 3 +- 7 files changed, 210 insertions(+), 202 deletions(-) hooks/post-receive -- Main OpenOCD repository |