helper/command: remove dead code in command_unknown()
[openocd.git] / src / helper / command.c
index a0aa9e857e38bd81ffbd371f3dc001ec152c6503..ab0654b6ebe1981bef9187bfd7c4d01d8e5fe4e4 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.,                                       *
- *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.           *
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
  ***************************************************************************/
 
 #ifdef HAVE_CONFIG_H
@@ -192,7 +190,7 @@ 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*/
@@ -202,15 +200,9 @@ static int script_command_run(Jim_Interp *interp,
        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)
@@ -318,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 ? " " : "",
@@ -359,27 +351,11 @@ 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);
+       LOG_DEBUG("registering '%s'...", c->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);
+       int retval = Jim_CreateCommand(interp, c->name, func, c, NULL);
 
        return retval;
 }
@@ -504,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;
 
@@ -512,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);
@@ -527,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;
 
@@ -535,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
@@ -543,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);
@@ -559,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 */
@@ -577,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,
@@ -610,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;
 }
@@ -645,6 +652,8 @@ int command_run_line(struct command_context *context, char *line)
         * happen when the Jim Tcl interpreter is provided by eCos for
         * instance.
         */
+       context->current_target_override = NULL;
+
        Jim_Interp *interp = context->interp;
        Jim_DeleteAssocData(interp, "context");
        retcode = Jim_SetAssocData(interp, "context", NULL, context);
@@ -665,18 +674,8 @@ int command_run_line(struct command_context *context, char *line)
 
                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) {
@@ -686,6 +685,7 @@ int command_run_line(struct command_context *context, char *line)
                return retcode;
        } else {
                Jim_MakeErrorMessage(interp);
+               /* error is broadcast */
                LOG_USER("%s", Jim_GetString(Jim_GetResult(interp), NULL));
 
                if (retval == ERROR_OK) {
@@ -801,8 +801,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)
@@ -854,7 +852,7 @@ static COMMAND_HELPER(command_help_show, struct command *c, unsigned n,
 {
        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. */
@@ -956,34 +954,85 @@ COMMAND_HANDLER(handle_help_command)
 }
 
 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);
@@ -991,7 +1040,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) {
@@ -999,22 +1047,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)
@@ -1024,7 +1071,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);
@@ -1053,32 +1100,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 if (remaining == 0)
-               Jim_SetResultString(interp, "group", -1);
-       else
-               Jim_SetResultString(interp, "unknown", -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 +1111,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) {
@@ -1115,8 +1136,9 @@ int help_add_command(struct command_context *cmd_ctx, struct command *parent,
        if (usage) {
                bool replaced = false;
                if (nc->usage) {
+                       if (*nc->usage)
+                               replaced = true;
                        free(nc->usage);
-                       replaced = true;
                }
                nc->usage = strdup(usage);
                if (replaced)
@@ -1175,8 +1197,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 +1220,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 +1278,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 +1351,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)
@@ -1412,6 +1431,8 @@ 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_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)
@@ -1456,8 +1477,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)