helper/command: clear errno before calling parser
[openocd.git] / src / helper / command.c
index bb04fb6a0708562b4e70b53be6a1620199fe4d36..d969933e2dba0bc9c8f8c554c83def7c97c9d20b 100644 (file)
@@ -22,9 +22,7 @@
  *   GNU General Public License for more details.                          *
  *                                                                         *
  *   You should have received a copy of the GNU General Public License     *
- *   along with this program; if not, write to the                         *
- *   Free Software Foundation, Inc.,                                       *
- *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
  ***************************************************************************/
 
 #ifdef HAVE_CONFIG_H
@@ -57,7 +55,7 @@ struct log_capture_state {
 static void tcl_output(void *privData, const char *file, unsigned line,
        const char *function, const char *string)
 {
-       struct log_capture_state *state = (struct log_capture_state *)privData;
+       struct log_capture_state *state = privData;
        Jim_AppendString(state->interp, state->output, string, strlen(string));
 }
 
@@ -121,7 +119,7 @@ static int command_retval_set(Jim_Interp *interp, int retval)
        if (return_retval != NULL)
                *return_retval = retval;
 
-       return (retval == ERROR_OK) ? JIM_OK : JIM_ERR;
+       return (retval == ERROR_OK) ? JIM_OK : retval;
 }
 
 extern struct command_context *global_cmd_ctx;
@@ -146,17 +144,17 @@ void script_debug(Jim_Interp *interp, const char *name,
        free(dbg);
 }
 
-static void script_command_args_free(const char **words, unsigned nwords)
+static void script_command_args_free(char **words, unsigned nwords)
 {
        for (unsigned i = 0; i < nwords; i++)
-               free((void *)words[i]);
+               free(words[i]);
        free(words);
 }
 
-static const char **script_command_args_alloc(
+static char **script_command_args_alloc(
        unsigned argc, Jim_Obj * const *argv, unsigned *nwords)
 {
-       const char **words = malloc(argc * sizeof(char *));
+       char **words = malloc(argc * sizeof(char *));
        if (NULL == words)
                return NULL;
 
@@ -192,25 +190,19 @@ struct command_context *current_command_context(Jim_Interp *interp)
 }
 
 static int script_command_run(Jim_Interp *interp,
-       int argc, Jim_Obj * const *argv, struct command *c, bool capture)
+       int argc, Jim_Obj * const *argv, struct command *c)
 {
        target_call_timer_callbacks_now();
        LOG_USER_N("%s", "");   /* Keep GDB connection alive*/
 
        unsigned nwords;
-       const char **words = script_command_args_alloc(argc, argv, &nwords);
+       char **words = script_command_args_alloc(argc, argv, &nwords);
        if (NULL == words)
                return JIM_ERR;
 
-       struct log_capture_state *state = NULL;
-       if (capture)
-               state = command_log_capture_start(interp);
-
        struct command_context *cmd_ctx = current_command_context(interp);
        int retval = run_command(cmd_ctx, c, (const char **)words, nwords);
 
-       command_log_capture_finish(state);
-
        script_command_args_free(words, nwords);
        return command_retval_set(interp, retval);
 }
@@ -222,7 +214,7 @@ static int script_command(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
        struct command *c = interp->cmdPrivData;
        assert(c);
        script_debug(interp, c->name, argc, argv);
-       return script_command_run(interp, argc, argv, c, true);
+       return script_command_run(interp, argc, argv, c);
 }
 
 static struct command *command_root(struct command *c)
@@ -299,12 +291,9 @@ static void command_free(struct command *c)
                command_free(tmp);
        }
 
-       if (c->name)
-               free((void *)c->name);
-       if (c->help)
-               free((void *)c->help);
-       if (c->usage)
-               free((void *)c->usage);
+       free(c->name);
+       free(c->help);
+       free(c->usage);
        free(c);
 }
 
@@ -321,7 +310,7 @@ static struct command *command_new(struct command_context *cmd_ctx,
         * arguments.
        */
        if ((cr->jim_handler == NULL) && (cr->usage == NULL)) {
-               LOG_DEBUG("BUG: command '%s%s%s' does not have the "
+               LOG_ERROR("BUG: command '%s%s%s' does not have the "
                        "'.usage' field filled out",
                        parent && parent->name ? parent->name : "",
                        parent && parent->name ? " " : "",
@@ -362,27 +351,11 @@ 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;
 
-       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((void *)ocd_name);
-       if (JIM_OK != retval)
-               return retval;
-
-       /* we now need to add an overrideable proc */
-       const char *override_name = alloc_printf(
-                       "proc %s {args} {eval ocd_bouncer %s $args}",
-                       c->name, c->name);
-       if (NULL == override_name)
-               return JIM_ERR;
+       LOG_DEBUG("registering '%s'...", c->name);
 
-       retval = Jim_Eval_Named(interp, override_name, 0, 0);
-       free((void *)override_name);
+       Jim_CmdProc *func = c->handler ? &script_command : &command_unknown;
+       int retval = Jim_CreateCommand(interp, c->name, func, c, NULL);
 
        return retval;
 }
@@ -507,7 +480,7 @@ void command_output_text(struct command_context *context, const char *data)
                context->output_handler(context, data);
 }
 
-void command_print_sameline(struct command_context *context, const char *format, ...)
+void command_print_sameline(struct command_invocation *cmd, const char *format, ...)
 {
        char *string;
 
@@ -515,13 +488,13 @@ void command_print_sameline(struct command_context *context, const char *format,
        va_start(ap, format);
 
        string = alloc_vprintf(format, ap);
-       if (string != NULL) {
+       if (string != NULL && cmd) {
                /* we want this collected in the log + we also want to pick it up as a tcl return
                 * value.
                 *
                 * The latter bit isn't precisely neat, but will do for now.
                 */
-               LOG_USER_N("%s", string);
+               Jim_AppendString(cmd->ctx->interp, cmd->output, string, -1);
                /* We already printed it above
                 * command_output_text(context, string); */
                free(string);
@@ -530,7 +503,7 @@ void command_print_sameline(struct command_context *context, const char *format,
        va_end(ap);
 }
 
-void command_print(struct command_context *context, const char *format, ...)
+void command_print(struct command_invocation *cmd, const char *format, ...)
 {
        char *string;
 
@@ -538,7 +511,7 @@ void command_print(struct command_context *context, const char *format, ...)
        va_start(ap, format);
 
        string = alloc_vprintf(format, ap);
-       if (string != NULL) {
+       if (string != NULL && cmd) {
                strcat(string, "\n");   /* alloc_vprintf guaranteed the buffer to be at least one
                                         *char longer */
                /* we want this collected in the log + we also want to pick it up as a tcl return
@@ -546,7 +519,7 @@ void command_print(struct command_context *context, const char *format, ...)
                 *
                 * The latter bit isn't precisely neat, but will do for now.
                 */
-               LOG_USER_N("%s", string);
+               Jim_AppendString(cmd->ctx->interp, cmd->output, string, -1);
                /* We already printed it above
                 * command_output_text(context, string); */
                free(string);
@@ -562,6 +535,10 @@ static char *__command_name(struct command *c, char delim, unsigned extra)
        if (NULL == c->parent) {
                /* allocate enough for the name, child names, and '\0' */
                name = malloc(len + extra + 1);
+               if (!name) {
+                       LOG_ERROR("Out of memory");
+                       return NULL;
+               }
                strcpy(name, c->name);
        } else {
                /* parent's extra must include both the space and name */
@@ -580,31 +557,35 @@ char *command_name(struct command *c, char delim)
 
 static bool command_can_run(struct command_context *cmd_ctx, struct command *c)
 {
-       return c->mode == COMMAND_ANY || c->mode == cmd_ctx->mode;
+       if (c->mode == COMMAND_ANY || c->mode == cmd_ctx->mode)
+               return true;
+
+       /* 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;
+       }
+       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;
 }
 
 static int run_command(struct command_context *context,
        struct command *c, const char *words[], unsigned num_words)
 {
-       if (!command_can_run(context, c)) {
-               /* 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);
+       if (!command_can_run(context, c))
                return ERROR_FAIL;
-       }
 
        struct command_invocation cmd = {
                .ctx = context,
@@ -613,23 +594,46 @@ static int run_command(struct command_context *context,
                .argc = num_words - 1,
                .argv = words + 1,
        };
+       /* Black magic of overridden current target:
+        * If the command we are going to handle has a target prefix,
+        * override the current target temporarily for the time
+        * of processing the command.
+        * current_target_override is used also for event handlers
+        * therefore we prevent touching it if command has no prefix.
+        * Previous override is saved and restored back to ensure
+        * correct work when run_command() is re-entered. */
+       struct target *saved_target_override = context->current_target_override;
+       if (c->jim_handler_data)
+               context->current_target_override = c->jim_handler_data;
+
+       cmd.output = Jim_NewEmptyStringObj(context->interp);
+       Jim_IncrRefCount(cmd.output);
+
        int retval = c->handler(&cmd);
+
+       if (c->jim_handler_data)
+               context->current_target_override = saved_target_override;
+
        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);
-               } else
-                       retval = -ENOMEM;
+               }
        } else if (retval == ERROR_COMMAND_CLOSE_CONNECTION) {
                /* just fall through for a shutdown request */
-       } else if (retval != ERROR_OK) {
-               /* we do not print out an error message because the command *should*
-                * have printed out an error
-                */
-               LOG_DEBUG("Command failed with error code %d", retval);
+       } else {
+               if (retval != ERROR_OK) {
+                       char *full_name = command_name(c, ' ');
+                       LOG_DEBUG("Command '%s' failed with error code %d",
+                                               full_name ? full_name : c->name, retval);
+                       free(full_name);
+               }
+               /* Use the command output as the Tcl result */
+               Jim_SetResult(context->interp, cmd.output);
        }
+       Jim_DecrRefCount(context->interp, cmd.output);
 
        return retval;
 }
@@ -648,7 +652,11 @@ int command_run_line(struct command_context *context, char *line)
         * happen when the Jim Tcl interpreter is provided by eCos for
         * instance.
         */
+       struct target *saved_target_override = context->current_target_override;
+       context->current_target_override = NULL;
+
        Jim_Interp *interp = context->interp;
+       struct command_context *old_context = Jim_GetAssocData(interp, "context");
        Jim_DeleteAssocData(interp, "context");
        retcode = Jim_SetAssocData(interp, "context", NULL, context);
        if (retcode == JIM_OK) {
@@ -661,42 +669,38 @@ int command_run_line(struct command_context *context, char *line)
                        Jim_DeleteAssocData(interp, "retval");
                }
                Jim_DeleteAssocData(interp, "context");
+               int inner_retcode = Jim_SetAssocData(interp, "context", NULL, old_context);
+               if (retcode == JIM_OK)
+                       retcode = inner_retcode;
        }
-       if (retcode == JIM_ERR) {
-               if (retval != ERROR_COMMAND_CLOSE_CONNECTION) {
-                       /* We do not print the connection closed error message */
-                       Jim_MakeErrorMessage(interp);
-                       LOG_USER("%s", Jim_GetString(Jim_GetResult(interp), NULL));
-               }
-               if (retval == ERROR_OK) {
-                       /* It wasn't a low level OpenOCD command that failed */
-                       return ERROR_FAIL;
-               }
-               return retval;
-       } else if (retcode == JIM_EXIT) {
-               /* ignore.
-                * exit(Jim_GetExitCode(interp)); */
-       } else {
+       context->current_target_override = saved_target_override;
+       if (retcode == JIM_OK) {
                const char *result;
                int reslen;
 
                result = Jim_GetString(Jim_GetResult(interp), &reslen);
                if (reslen > 0) {
-                       int i;
-                       char buff[256 + 1];
-                       for (i = 0; i < reslen; i += 256) {
-                               int chunk;
-                               chunk = reslen - i;
-                               if (chunk > 256)
-                                       chunk = 256;
-                               strncpy(buff, result + i, chunk);
-                               buff[chunk] = 0;
-                               LOG_USER_N("%s", buff);
-                       }
-                       LOG_USER_N("\n");
+                       command_output_text(context, result);
+                       command_output_text(context, "\n");
                }
                retval = ERROR_OK;
+       } else if (retcode == JIM_EXIT) {
+               /* ignore.
+                * exit(Jim_GetExitCode(interp)); */
+       } else if (retcode == ERROR_COMMAND_CLOSE_CONNECTION) {
+               return retcode;
+       } else {
+               Jim_MakeErrorMessage(interp);
+               /* error is broadcast */
+               LOG_USER("%s", Jim_GetString(Jim_GetResult(interp), NULL));
+
+               if (retval == ERROR_OK) {
+                       /* It wasn't a low level OpenOCD command that failed */
+                       return ERROR_FAIL;
+               }
+               return retval;
        }
+
        return retval;
 }
 
@@ -803,8 +807,6 @@ static COMMAND_HELPER(command_help_find, struct command *head,
        if (0 == CMD_ARGC)
                return ERROR_COMMAND_SYNTAX_ERROR;
        *out = command_find(head, CMD_ARGV[0]);
-       if (NULL == *out && strncmp(CMD_ARGV[0], "ocd_", 4) == 0)
-               *out = command_find(head, CMD_ARGV[0] + 4);
        if (NULL == *out)
                return ERROR_COMMAND_SYNTAX_ERROR;
        if (--CMD_ARGC == 0)
@@ -814,13 +816,13 @@ static COMMAND_HELPER(command_help_find, struct command *head,
 }
 
 static COMMAND_HELPER(command_help_show, struct command *c, unsigned n,
-       bool show_help, const char *match);
+       bool show_help, const char *cmd_match);
 
 static COMMAND_HELPER(command_help_show_list, struct command *head, unsigned n,
-       bool show_help, const char *match)
+       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, match);
+               CALL_COMMAND_HANDLER(command_help_show, c, n, show_help, cmd_match);
        return ERROR_OK;
 }
 
@@ -852,17 +854,17 @@ 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, const char *match)
+       bool show_help, const char *cmd_match)
 {
        char *cmd_name = command_name(c, ' ');
        if (NULL == cmd_name)
-               return -ENOMEM;
+               return ERROR_FAIL;
 
        /* If the match string occurs anywhere, we print out
         * stuff for this command. */
-       bool is_match = (strstr(cmd_name, match) != NULL) ||
-               ((c->usage != NULL) && (strstr(c->usage, match) != NULL)) ||
-               ((c->help != NULL) && (strstr(c->help, match) != NULL));
+       bool is_match = (strstr(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);
@@ -871,7 +873,7 @@ static COMMAND_HELPER(command_help_show, struct command *c, unsigned n,
        free(cmd_name);
 
        if (is_match) {
-               if (c->usage) {
+               if (c->usage && strlen(c->usage) > 0) {
                        LOG_USER_N(" ");
                        command_help_show_wrap(c->usage, 0, n + 5);
                } else
@@ -913,7 +915,7 @@ static COMMAND_HELPER(command_help_show, struct command *c, unsigned n,
        }
 
        return CALL_COMMAND_HANDLER(command_help_show_list,
-               c->children, n, show_help, match);
+               c->children, n, show_help, cmd_match);
 }
 
 COMMAND_HANDLER(handle_help_command)
@@ -921,26 +923,26 @@ COMMAND_HANDLER(handle_help_command)
        bool full = strcmp(CMD_NAME, "help") == 0;
        int retval;
        struct command *c = CMD_CTX->commands;
-       char *match = NULL;
+       char *cmd_match = NULL;
 
        if (CMD_ARGC == 0)
-               match = "";
+               cmd_match = "";
        else if (CMD_ARGC >= 1) {
                unsigned i;
 
                for (i = 0; i < CMD_ARGC; ++i) {
-                       if (NULL != match) {
-                               char *prev = match;
+                       if (NULL != cmd_match) {
+                               char *prev = cmd_match;
 
-                               match = alloc_printf("%s %s", match, CMD_ARGV[i]);
+                               cmd_match = alloc_printf("%s %s", cmd_match, CMD_ARGV[i]);
                                free(prev);
-                               if (NULL == match) {
+                               if (NULL == cmd_match) {
                                        LOG_ERROR("unable to build search string");
                                        return -ENOMEM;
                                }
                        } else {
-                               match = alloc_printf("%s", CMD_ARGV[i]);
-                               if (NULL == match) {
+                               cmd_match = alloc_printf("%s", CMD_ARGV[i]);
+                               if (NULL == cmd_match) {
                                        LOG_ERROR("unable to build search string");
                                        return -ENOMEM;
                                }
@@ -950,42 +952,93 @@ COMMAND_HANDLER(handle_help_command)
                return ERROR_COMMAND_SYNTAX_ERROR;
 
        retval = CALL_COMMAND_HANDLER(command_help_show_list,
-                       c, 0, full, match);
+                       c, 0, full, cmd_match);
 
        if (CMD_ARGC >= 1)
-               free(match);
+               free(cmd_match);
        return retval;
 }
 
 static int command_unknown_find(unsigned argc, Jim_Obj *const *argv,
-       struct command *head, struct command **out, bool top_level)
+       struct command *head, struct command **out)
 {
        if (0 == argc)
                return argc;
        const char *cmd_name = Jim_GetString(argv[0], NULL);
        struct command *c = command_find(head, cmd_name);
-       if (NULL == c && top_level && strncmp(cmd_name, "ocd_", 4) == 0)
-               c = command_find(head, cmd_name + 4);
        if (NULL == c)
                return argc;
        *out = c;
-       return command_unknown_find(--argc, ++argv, (*out)->children, out, false);
+       return command_unknown_find(--argc, ++argv, (*out)->children, out);
+}
+
+static char *alloc_concatenate_strings(int argc, Jim_Obj * const *argv)
+{
+       char *prev, *all;
+       int i;
+
+       assert(argc >= 1);
+
+       all = strdup(Jim_GetString(argv[0], NULL));
+       if (!all) {
+               LOG_ERROR("Out of memory");
+               return NULL;
+       }
+
+       for (i = 1; i < argc; ++i) {
+               prev = all;
+               all = alloc_printf("%s %s", all, Jim_GetString(argv[i], NULL));
+               free(prev);
+               if (!all) {
+                       LOG_ERROR("Out of memory");
+                       return NULL;
+               }
+       }
+
+       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 command_unknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
        const char *cmd_name = Jim_GetString(argv[0], NULL);
-       if (strcmp(cmd_name, "unknown") == 0) {
-               if (argc == 1)
-                       return JIM_OK;
-               argc--;
-               argv++;
-       }
        script_debug(interp, cmd_name, 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, true);
+       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);
@@ -993,7 +1046,6 @@ static int command_unknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
                return JIM_OK;
        }
 
-       bool found = true;
        Jim_Obj *const *start;
        unsigned count;
        if (c->handler || c->jim_handler) {
@@ -1001,22 +1053,21 @@ static int command_unknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
                count = remaining + 1;
                start = argv + (argc - remaining - 1);
        } else {
-               c = command_find(cmd_ctx->commands, "usage");
-               if (NULL == c) {
-                       LOG_ERROR("unknown command, but usage is missing too");
-                       return JIM_ERR;
-               }
                count = argc - remaining;
                start = argv;
-               found = false;
+               run_usage(interp, count, argc, start);
+               return JIM_ERR;
        }
        /* pass the command through to the intended handler */
        if (c->jim_handler) {
+               if (!command_can_run(cmd_ctx, c))
+                       return JIM_ERR;
+
                interp->cmdPrivData = c->jim_handler_data;
                return (*c->jim_handler)(interp, count, start);
        }
 
-       return script_command_run(interp, count, start, c, found);
+       return script_command_run(interp, count, start, c);
 }
 
 static int jim_command_mode(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
@@ -1026,7 +1077,7 @@ static int jim_command_mode(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 
        if (argc > 1) {
                struct command *c = cmd_ctx->commands;
-               int remaining = command_unknown_find(argc - 1, argv + 1, c, &c, true);
+               int remaining = command_unknown_find(argc - 1, argv + 1, c, &c);
                /* if nothing could be consumed, then it's an unknown command */
                if (remaining == argc - 1) {
                        Jim_SetResultString(interp, "unknown", -1);
@@ -1055,30 +1106,6 @@ static int jim_command_mode(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
        return JIM_OK;
 }
 
-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(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 */
-       if (remaining == argc - 1) {
-               Jim_SetResultString(interp, "unknown", -1);
-               return JIM_OK;
-       }
-
-       if (c->jim_handler)
-               Jim_SetResultString(interp, "native", -1);
-       else if (c->handler)
-               Jim_SetResultString(interp, "simple", -1);
-       else
-               Jim_SetResultString(interp, "group", -1);
-
-       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)
 {
@@ -1090,7 +1117,7 @@ int help_add_command(struct command_context *cmd_ctx, struct command *parent,
                        .name = cmd_name,
                        .mode = COMMAND_ANY,
                        .help = help_text,
-                       .usage = usage,
+                       .usage = usage ? : "",
                };
                nc = register_command(cmd_ctx, parent, &cr);
                if (NULL == nc) {
@@ -1103,7 +1130,7 @@ int help_add_command(struct command_context *cmd_ctx, struct command *parent,
        if (help_text) {
                bool replaced = false;
                if (nc->help) {
-                       free((void *)nc->help);
+                       free(nc->help);
                        replaced = true;
                }
                nc->help = strdup(help_text);
@@ -1115,8 +1142,9 @@ int help_add_command(struct command_context *cmd_ctx, struct command *parent,
        if (usage) {
                bool replaced = false;
                if (nc->usage) {
-                       free((void *)nc->usage);
-                       replaced = true;
+                       if (*nc->usage)
+                               replaced = true;
+                       free(nc->usage);
                }
                nc->usage = strdup(usage);
                if (replaced)
@@ -1175,8 +1203,8 @@ COMMAND_HANDLER(handle_sleep_command)
                return retval;
 
        if (!busy) {
-               long long then = timeval_ms();
-               while (timeval_ms() - then < (long long)duration) {
+               int64_t then = timeval_ms();
+               while (timeval_ms() - then < (int64_t)duration) {
                        target_call_timer_callbacks_now();
                        usleep(1000);
                }
@@ -1198,15 +1226,6 @@ static const struct command_registration command_subcommand_handlers[] = {
                        "Returns 'unknown' if an unknown command is given. "
                        "Command can be multiple tokens.",
        },
-       {
-               .name = "type",
-               .mode = COMMAND_ANY,
-               .jim_handler = jim_command_type,
-               .usage = "command_name [...]",
-               .help = "Returns the type of built-in command:"
-                       "'native', 'simple', 'group', or 'unknown'. "
-                       "Command can be multiple tokens.",
-       },
        COMMAND_REGISTRATION_DONE
 };
 
@@ -1265,20 +1284,17 @@ static const struct command_registration command_builtin_handlers[] = {
                .mode = COMMAND_ANY,
                .help = "core command group (introspection)",
                .chain = command_subcommand_handlers,
+               .usage = "",
        },
        COMMAND_REGISTRATION_DONE
 };
 
 struct command_context *command_init(const char *startup_tcl, Jim_Interp *interp)
 {
-       struct command_context *context = malloc(sizeof(struct command_context));
+       struct command_context *context = calloc(1, sizeof(struct command_context));
        const char *HostOs;
 
        context->mode = COMMAND_EXEC;
-       context->commands = NULL;
-       context->current_target = 0;
-       context->output_handler = NULL;
-       context->output_handler_priv = NULL;
 
        /* Create a jim interpreter if we were not handed one */
        if (interp == NULL) {
@@ -1341,6 +1357,15 @@ struct command_context *command_init(const char *startup_tcl, Jim_Interp *interp
        return context;
 }
 
+void command_exit(struct command_context *context)
+{
+       if (!context)
+               return;
+
+       Jim_FreeInterp(context->interp);
+       command_done(context);
+}
+
 int command_context_mode(struct command_context *cmd_ctx, enum command_mode mode)
 {
        if (!cmd_ctx)
@@ -1369,6 +1394,7 @@ void process_jim_events(struct command_context *cmd_ctx)
                        return ERROR_COMMAND_ARGUMENT_INVALID; \
                } \
                char *end; \
+               errno = 0; \
                *ul = func(str, &end, 0); \
                if (*end) { \
                        LOG_ERROR("Invalid command argument"); \
@@ -1404,19 +1430,23 @@ DEFINE_PARSE_NUM_TYPE(_llong, long long, strtoll, LLONG_MIN, LLONG_MAX)
                return ERROR_OK; \
        }
 
-#define DEFINE_PARSE_ULONG(name, type, min, max) \
-       DEFINE_PARSE_WRAPPER(name, type, min, max, unsigned long, _ulong)
-DEFINE_PARSE_ULONG(_uint, unsigned, 0, UINT_MAX)
-DEFINE_PARSE_ULONG(_u32, uint32_t, 0, UINT32_MAX)
-DEFINE_PARSE_ULONG(_u16, uint16_t, 0, UINT16_MAX)
-DEFINE_PARSE_ULONG(_u8, uint8_t, 0, UINT8_MAX)
+#define DEFINE_PARSE_ULONGLONG(name, type, min, max) \
+       DEFINE_PARSE_WRAPPER(name, type, min, max, unsigned long long, _ullong)
+DEFINE_PARSE_ULONGLONG(_uint, unsigned, 0, UINT_MAX)
+DEFINE_PARSE_ULONGLONG(_u64,  uint64_t, 0, UINT64_MAX)
+DEFINE_PARSE_ULONGLONG(_u32,  uint32_t, 0, UINT32_MAX)
+DEFINE_PARSE_ULONGLONG(_u16,  uint16_t, 0, UINT16_MAX)
+DEFINE_PARSE_ULONGLONG(_u8,   uint8_t,  0, UINT8_MAX)
+
+DEFINE_PARSE_ULONGLONG(_target_addr, target_addr_t, 0, TARGET_ADDR_MAX)
 
-#define DEFINE_PARSE_LONG(name, type, min, max)        \
-       DEFINE_PARSE_WRAPPER(name, type, min, max, long, _long)
-DEFINE_PARSE_LONG(_int, int, n < INT_MIN, INT_MAX)
-DEFINE_PARSE_LONG(_s32, int32_t, n < INT32_MIN, INT32_MAX)
-DEFINE_PARSE_LONG(_s16, int16_t, n < INT16_MIN, INT16_MAX)
-DEFINE_PARSE_LONG(_s8, int8_t, n < INT8_MIN, INT8_MAX)
+#define DEFINE_PARSE_LONGLONG(name, type, min, max) \
+       DEFINE_PARSE_WRAPPER(name, type, min, max, long long, _llong)
+DEFINE_PARSE_LONGLONG(_int, int,     n < INT_MIN,   INT_MAX)
+DEFINE_PARSE_LONGLONG(_s64, int64_t, n < INT64_MIN, INT64_MAX)
+DEFINE_PARSE_LONGLONG(_s32, int32_t, n < INT32_MIN, INT32_MAX)
+DEFINE_PARSE_LONGLONG(_s16, int16_t, n < INT16_MIN, INT16_MAX)
+DEFINE_PARSE_LONGLONG(_s8,  int8_t,  n < INT8_MIN,  INT8_MAX)
 
 static int command_parse_bool(const char *in, bool *out,
        const char *on, const char *off)
@@ -1454,8 +1484,8 @@ COMMAND_HELPER(handle_command_parse_bool, bool *out, const char *label)
                                LOG_ERROR("%s: argument '%s' is not valid", CMD_NAME, in);
                                return ERROR_COMMAND_SYNTAX_ERROR;
                        }
-                       /* fall through */
                }
+                       /* fallthrough */
                case 0:
                        LOG_INFO("%s is %s", label, *out ? "enabled" : "disabled");
                        break;

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)