add 'command type' introspective handler
[openocd.git] / src / helper / command.c
index 8b29ab4ac4b41a48ce1953adffb1ec2715d7bbf0..23175baf2cda31aab5ee563076a2145731b05b42 100644 (file)
@@ -44,6 +44,9 @@
 #include "jim-eventloop.h"
 
 
+/* nice short description of source file */
+#define __THIS__FILE__ "command.c"
+
 Jim_Interp *interp = NULL;
 
 static int run_command(struct command_context *context,
@@ -150,35 +153,47 @@ static struct command_context *current_command_context(void)
        return cmd_ctx;
 }
 
-static int script_command(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+static int script_command_run(Jim_Interp *interp,
+               int argc, Jim_Obj *const *argv, struct command *c, bool capture)
 {
-       /* the private data is stashed in the interp structure */
-
-       struct command *c = interp->cmdPrivData;
-       assert(c);
-
        target_call_timer_callbacks_now();
        LOG_USER_N("%s", ""); /* Keep GDB connection alive*/
 
-       script_debug(interp, c->name, argc, argv);
-
        unsigned nwords;
        const char **words = script_command_args_alloc(argc, argv, &nwords);
        if (NULL == words)
                return JIM_ERR;
 
-       Jim_Obj *tclOutput = command_log_capture_start(interp);
+       Jim_Obj *tclOutput = NULL;
+       if (capture)
+               tclOutput = command_log_capture_start(interp);
 
        struct command_context *cmd_ctx = current_command_context();
        int retval = run_command(cmd_ctx, c, (const char **)words, nwords);
 
-       command_log_capture_finish(interp, tclOutput);
+       if (capture)
+               command_log_capture_finish(interp, tclOutput);
+
        script_command_args_free(words, nwords);
        return command_retval_set(interp, retval);
 }
 
-/* nice short description of source file */
-#define __THIS__FILE__ "command.c"
+static int script_command(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+       /* the private data is stashed in the interp structure */
+
+       struct command *c = interp->cmdPrivData;
+       assert(c);
+       script_debug(interp, c->name, argc, argv);
+       return script_command_run(interp, argc, argv, c, true);
+}
+
+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.
@@ -288,19 +303,22 @@ static int register_command_handler(struct command *c)
        if (NULL == full_name)
                return retval;
 
-       const char *ocd_name = alloc_printf("ocd_%s", full_name);
-       if (NULL == full_name)
-               goto free_full_name;
+       if (NULL != c->handler)
+       {
+               const char *ocd_name = alloc_printf("ocd_%s", full_name);
+               if (NULL == full_name)
+                       goto free_full_name;
 
-       Jim_CreateCommand(interp, ocd_name, script_command, c, NULL);
-       free((void *)ocd_name);
+               Jim_CreateCommand(interp, ocd_name, script_command, c, NULL);
+               free((void *)ocd_name);
+       }
 
        /* we now need to add an overrideable proc */
        const char *override_name = alloc_printf("proc %s {args} {"
                        "if {[catch {eval ocd_%s $args}] == 0} "
                        "{return \"\"} else {return -code error}}",
                        full_name, full_name);
-       if (NULL == full_name)
+       if (NULL == override_name)
                goto free_full_name;
 
        Jim_Eval_Named(interp, override_name, __THIS__FILE__, __LINE__);
@@ -335,7 +353,7 @@ struct command* register_command(struct command_context *context,
 
        if (NULL != c->handler)
        {
-               int retval = register_command_handler(c);
+               int retval = register_command_handler(command_root(c));
                if (ERROR_OK != retval)
                {
                        unregister_command(context, parent, name);
@@ -784,6 +802,8 @@ static COMMAND_HELPER(command_help_find, struct command *head,
        if (0 == CMD_ARGC)
                return ERROR_INVALID_ARGUMENTS;
        *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_INVALID_ARGUMENTS;
        if (--CMD_ARGC == 0)
@@ -867,15 +887,18 @@ COMMAND_HANDLER(handle_help_command)
 }
 
 static int command_unknown_find(unsigned argc, Jim_Obj *const *argv,
-               struct command *head, struct command **out)
+               struct command *head, struct command **out, bool top_level)
 {
        if (0 == argc)
                return argc;
-       struct command *c = command_find(head, Jim_GetString(argv[0], NULL));
+       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);
+       return command_unknown_find(--argc, ++argv, (*out)->children, out, false);
 }
 
 static int command_unknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
@@ -885,7 +908,7 @@ static int command_unknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 
        struct command_context *cmd_ctx = current_command_context();
        struct command *c = cmd_ctx->commands;
-       int remaining = command_unknown_find(argc - 1, argv + 1, c, &c);
+       int remaining = command_unknown_find(argc - 1, argv + 1, c, &c, true);
        // if nothing could be consumed, then it's really an unknown command
        if (remaining == argc - 1)
        {
@@ -922,22 +945,32 @@ static int command_unknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
                return (*c->jim_handler)(interp, count, start);
        }
 
-       unsigned nwords;
-       const char **words = script_command_args_alloc(count, start, &nwords);
-       if (NULL == words)
-               return JIM_ERR;
-
-       Jim_Obj *tclOutput = command_log_capture_start(interp);
+       return script_command_run(interp, count, start, c, found);
+}
 
-       int retval = run_command(cmd_ctx, c, words, nwords);
+static int jim_command_type(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+       if (1 == argc)
+               return JIM_ERR;
 
-       command_log_capture_finish(interp, tclOutput);
-       script_command_args_free(words, nwords);
+       struct command_context *cmd_ctx = current_command_context();
+       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 (!found && ERROR_OK == retval)
-               retval = ERROR_FAIL;
+       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 command_retval_set(interp, retval);
+       return JIM_OK;
 }
 
 int help_add_command(struct command_context *cmd_ctx, struct command *parent,
@@ -1061,6 +1094,18 @@ COMMAND_HANDLER(handle_sleep_command)
        return ERROR_OK;
 }
 
+static const struct command_registration command_subcommand_handlers[] = {
+       {
+               .name = "type",
+               .mode = COMMAND_ANY,
+               .jim_handler = &jim_command_type,
+               .usage = "<name> ...",
+               .help = "Returns the type of built-in command:"
+                       "'native', 'simple', 'group', or 'unknown'",
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
 static const struct command_registration command_builtin_handlers[] = {
        {
                .name = "add_help_text",
@@ -1098,6 +1143,12 @@ static const struct command_registration command_builtin_handlers[] = {
                .help = "show basic command usage",
                .usage = "[<command> ...]",
        },
+       {
+               .name = "command",
+               .mode= COMMAND_ANY,
+               .help = "core command group (introspection)",
+               .chain = command_subcommand_handlers,
+       },
        COMMAND_REGISTRATION_DONE
 };
 

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)