X-Git-Url: https://review.openocd.org/gitweb?a=blobdiff_plain;f=src%2Fhelper%2Fcommand.c;h=d65766842a5f23357d7108190c214d161f11e07e;hb=896ac8d4ef3212f80887bf009d626c5becb1240a;hp=b2aa76b0b9e0ba00e0236f94913e975e29f35464;hpb=933b4579f06d25e349e6648ec4aff114e634164d;p=openocd.git diff --git a/src/helper/command.c b/src/helper/command.c index b2aa76b0b9..d65766842a 100644 --- a/src/helper/command.c +++ b/src/helper/command.c @@ -47,35 +47,54 @@ /* nice short description of source file */ #define __THIS__FILE__ "command.c" -Jim_Interp *interp = NULL; static int run_command(struct command_context *context, struct command *c, const char *words[], unsigned num_words); +struct log_capture_state { + Jim_Interp *interp; + Jim_Obj *output; +}; + static void tcl_output(void *privData, const char *file, unsigned line, const char *function, const char *string) { - Jim_Obj *tclOutput = (Jim_Obj *)privData; - Jim_AppendString(interp, tclOutput, string, strlen(string)); + struct log_capture_state *state = (struct log_capture_state *)privData; + Jim_AppendString(state->interp, state->output, string, strlen(string)); } -static Jim_Obj *command_log_capture_start(Jim_Interp *interp) +static struct log_capture_state *command_log_capture_start(Jim_Interp *interp) { /* capture log output and return it. A garbage collect can * happen, so we need a reference count to this object */ Jim_Obj *tclOutput = Jim_NewStringObj(interp, "", 0); if (NULL == tclOutput) return NULL; + + struct log_capture_state *state = malloc(sizeof(*state)); + if (NULL == state) + return NULL; + + state->interp = interp; Jim_IncrRefCount(tclOutput); - log_add_callback(tcl_output, tclOutput); - return tclOutput; + state->output = tclOutput; + + log_add_callback(tcl_output, state); + + return state; } -static void command_log_capture_finish(Jim_Interp *interp, Jim_Obj *tclOutput) +static void command_log_capture_finish(struct log_capture_state *state) { - log_remove_callback(tcl_output, tclOutput); - Jim_SetResult(interp, tclOutput); - Jim_DecrRefCount(interp, tclOutput); + if (NULL == state) + return; + + log_remove_callback(tcl_output, state); + + Jim_SetResult(state->interp, state->output); + Jim_DecrRefCount(state->interp, state->output); + + free(state); } static int command_retval_set(Jim_Interp *interp, int retval) @@ -139,7 +158,7 @@ static const char **script_command_args_alloc( return words; } -static struct command_context *current_command_context(void) +static struct command_context *current_command_context(Jim_Interp *interp) { /* grab the command context from the associated data */ struct command_context *cmd_ctx = Jim_GetAssocData(interp, "context"); @@ -164,15 +183,14 @@ static int script_command_run(Jim_Interp *interp, if (NULL == words) return JIM_ERR; - Jim_Obj *tclOutput = NULL; + struct log_capture_state *state = NULL; if (capture) - tclOutput = command_log_capture_start(interp); + state = command_log_capture_start(interp); - struct command_context *cmd_ctx = current_command_context(); + struct command_context *cmd_ctx = current_command_context(interp); int retval = run_command(cmd_ctx, c, (const char **)words, nwords); - if (capture) - command_log_capture_finish(interp, tclOutput); + command_log_capture_finish(state); script_command_args_free(words, nwords); return command_retval_set(interp, retval); @@ -253,19 +271,44 @@ static struct command **command_list_for_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); + } + + if (c->name) + free(c->name); + if (c->help) + free((void*)c->help); + if (c->usage) + free((void*)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); - struct command *c = malloc(sizeof(struct command)); - memset(c, 0, sizeof(struct command)); + 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; @@ -275,31 +318,18 @@ static struct command *command_new(struct command_context *cmd_ctx, command_add_child(command_list_for_parent(cmd_ctx, parent), c); 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); - if (c->usage) - free((void*)c->usage); - free(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 *c) +static int register_command_handler(struct command_context *cmd_ctx, + struct command *c) { + Jim_Interp *interp = cmd_ctx->interp; const char *ocd_name = alloc_printf("ocd_%s", c->name); if (NULL == ocd_name) return JIM_ERR; @@ -348,11 +378,11 @@ struct command* register_command(struct command_context *context, int retval = ERROR_OK; if (NULL != cr->jim_handler && NULL == parent) { - retval = Jim_CreateCommand(interp, cr->name, + 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(command_root(c)); + retval = register_command_handler(context, command_root(c)); if (ERROR_OK != retval) { @@ -525,13 +555,26 @@ 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) +{ + return c->mode == COMMAND_ANY || c->mode == cmd_ctx->mode; +} + static int run_command(struct command_context *context, struct command *c, const char *words[], unsigned num_words) { - if (!((context->mode == COMMAND_CONFIG) || (c->mode == COMMAND_ANY) || (c->mode == context->mode))) + if (!command_can_run(context, c)) { - /* Config commands can not run after the config stage */ - LOG_ERROR("Command '%s' only runs during configuration stage", c->name); + /* Many commands may be run only before/after 'init' */ + const char *when; + switch (c->mode) { + case COMMAND_CONFIG: when = "before"; break; + case COMMAND_EXEC: when = "after"; break; + // handle the impossible with humor; it guarantees a bug report! + default: when = "if Cthulhu is summoned by"; break; + } + LOG_ERROR("The '%s' command must be used %s 'init'.", + c->name, when); return ERROR_FAIL; } @@ -547,7 +590,7 @@ static int run_command(struct command_context *context, /* Print help for command */ char *full_name = command_name(c, ' '); if (NULL != full_name) { - command_run_linef(context, "help %s", full_name); + command_run_linef(context, "usage %s", full_name); free(full_name); } else retval = -ENOMEM; @@ -581,6 +624,7 @@ int command_run_line(struct command_context *context, char *line) * happen when the Jim Tcl interpreter is provided by eCos for * instance. */ + Jim_Interp *interp = context->interp; Jim_DeleteAssocData(interp, "context"); retcode = Jim_SetAssocData(interp, "context", NULL, context); if (retcode == JIM_OK) @@ -668,12 +712,12 @@ struct command_context* copy_command_context(struct command_context* context) return copy_context; } -int command_done(struct command_context *context) +void command_done(struct command_context *cmd_ctx) { - free(context); - context = NULL; + if (NULL == cmd_ctx) + return; - return ERROR_OK; + free(cmd_ctx); } /* find full path to file */ @@ -789,12 +833,12 @@ static int jim_capture(Jim_Interp *interp, int argc, Jim_Obj *const *argv) if (argc != 2) return JIM_ERR; - Jim_Obj *tclOutput = command_log_capture_start(interp); + struct log_capture_state *state = command_log_capture_start(interp); const char *str = Jim_GetString(argv[1], NULL); int retcode = Jim_Eval_Named(interp, str, __THIS__FILE__, __LINE__); - command_log_capture_finish(interp, tclOutput); + command_log_capture_finish(state); return retcode; } @@ -857,16 +901,43 @@ static void command_help_show_wrap(const char *str, unsigned n, unsigned n2) static COMMAND_HELPER(command_help_show, struct command *c, unsigned n, bool show_help) { + if (!command_can_run(CMD_CTX, c)) + return ERROR_OK; + + char *cmd_name = command_name(c, ' '); + if (NULL == cmd_name) + return -ENOMEM; + command_help_show_indent(n); - LOG_USER_N("%s", command_name(c, ' ')); + LOG_USER_N("%s", cmd_name); + free(cmd_name); + if (c->usage) { LOG_USER_N(" "); command_help_show_wrap(c->usage, 0, n + 5); } else LOG_USER_N("\n"); - if (show_help && c->help) - command_help_show_wrap(c->help, n + 3, n + 3); + + if (show_help) + { + const char *stage_msg; + switch (c->mode) { + case COMMAND_CONFIG: stage_msg = "CONFIG"; break; + case COMMAND_EXEC: stage_msg = "EXEC"; break; + case COMMAND_ANY: stage_msg = "CONFIG or EXEC"; break; + default: stage_msg = "***UNKNOWN***"; break; + } + char *msg = alloc_printf("%s%sValid Modes: %s", + c->help ? : "", c->help ? " " : "", stage_msg); + if (NULL != msg) + { + command_help_show_wrap(msg, n + 3, n + 3); + free(msg); + } else + return -ENOMEM; + } + if (++n >= 2) return ERROR_OK; @@ -916,7 +987,7 @@ static int command_unknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv) } script_debug(interp, cmd_name, argc, argv); - struct command_context *cmd_ctx = current_command_context(); + struct command_context *cmd_ctx = current_command_context(interp); struct command *c = cmd_ctx->commands; int remaining = command_unknown_find(argc, argv, c, &c, true); // if nothing could be consumed, then it's really an unknown command @@ -938,10 +1009,10 @@ static int command_unknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv) } else { - c = command_find(cmd_ctx->commands, "help"); + c = command_find(cmd_ctx->commands, "usage"); if (NULL == c) { - LOG_ERROR("unknown command, but help is missing too"); + LOG_ERROR("unknown command, but usage is missing too"); return JIM_ERR; } count = argc - remaining; @@ -960,7 +1031,7 @@ static int command_unknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv) static int jim_command_mode(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { - struct command_context *cmd_ctx = current_command_context(); + struct command_context *cmd_ctx = current_command_context(interp); enum command_mode mode; if (argc > 1) { @@ -993,7 +1064,7 @@ static int jim_command_type(Jim_Interp *interp, int argc, Jim_Obj *const *argv) if (1 == argc) return JIM_ERR; - struct command_context *cmd_ctx = current_command_context(); + struct command_context *cmd_ctx = current_command_context(interp); struct command *c = cmd_ctx->commands; int remaining = command_unknown_find(argc - 1, argv + 1, c, &c, true); // if nothing could be consumed, then it's an unknown command @@ -1201,7 +1272,7 @@ static const struct command_registration command_builtin_handlers[] = { COMMAND_REGISTRATION_DONE }; -struct command_context* command_init(const char *startup_tcl) +struct command_context* command_init(const char *startup_tcl, Jim_Interp *interp) { struct command_context* context = malloc(sizeof(struct command_context)); const char *HostOs; @@ -1213,12 +1284,17 @@ struct command_context* command_init(const char *startup_tcl) context->output_handler_priv = NULL; #if !BUILD_ECOSBOARD - Jim_InitEmbedded(); - /* Create an interpreter */ - interp = Jim_CreateInterp(); - /* Add all the Jim core commands */ - Jim_RegisterCoreCommands(interp); + /* Create a jim interpreter if we were not handed one */ + if (interp == NULL) + { + Jim_InitEmbedded(); + /* Create an interpreter */ + interp = Jim_CreateInterp(); + /* Add all the Jim core commands */ + Jim_RegisterCoreCommands(interp); + } #endif + context->interp = interp; #if defined(_MSC_VER) /* WinXX - is generic, the forward @@ -1286,17 +1362,16 @@ int command_context_mode(struct command_context *cmd_ctx, enum command_mode mode return ERROR_OK; } -void process_jim_events(void) +void process_jim_events(struct command_context *cmd_ctx) { #if !BUILD_ECOSBOARD static int recursion = 0; + if (recursion) + return; - if (!recursion) - { - recursion++; - Jim_ProcessEvents (interp, JIM_ALL_EVENTS | JIM_DONT_WAIT); - recursion--; - } + recursion++; + Jim_ProcessEvents(cmd_ctx->interp, JIM_ALL_EVENTS | JIM_DONT_WAIT); + recursion--; #endif }