add command private data setter/accessor
[openocd.git] / src / helper / command.c
index 62fb48791c771dee0cacddbb2bcc3391c2228e1b..b2aa76b0b9e0ba00e0236f94913e975e29f35464 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,
@@ -185,8 +188,12 @@ static int script_command(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
        return script_command_run(interp, argc, argv, c, true);
 }
 
-/* nice short description of source file */
-#define __THIS__FILE__ "command.c"
+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.
@@ -289,35 +296,32 @@ static void command_free(struct command *c)
        free(c);
 }
 
+static int command_unknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
+
 static int register_command_handler(struct command *c)
 {
-       int retval = -ENOMEM;
-       const char *full_name = command_name(c, '_');
-       if (NULL == full_name)
-               return retval;
+       const char *ocd_name = alloc_printf("ocd_%s", c->name);
+       if (NULL == ocd_name)
+               return JIM_ERR;
 
-       const char *ocd_name = alloc_printf("ocd_%s", full_name);
-       if (NULL == full_name)
-               goto free_full_name;
+       LOG_DEBUG("registering '%s'...", ocd_name);
 
-       Jim_CreateCommand(interp, ocd_name, script_command, c, NULL);
+       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} {"
-                       "if {[catch {eval ocd_%s $args}] == 0} "
-                       "{return \"\"} else {return -code error}}",
-                       full_name, full_name);
-       if (NULL == full_name)
-               goto free_full_name;
-
-       Jim_Eval_Named(interp, override_name, __THIS__FILE__, __LINE__);
-       free((void *)override_name);
+       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;
 
-       retval = ERROR_OK;
+       retval = Jim_Eval_Named(interp, override_name, __FILE__, __LINE__);
+       free((void *)override_name);
 
-free_full_name:
-       free((void *)full_name);
        return retval;
 }
 
@@ -341,19 +345,20 @@ struct command* register_command(struct command_context *context,
        if (NULL == c)
                return NULL;
 
-       if (NULL != c->handler)
+       int retval = ERROR_OK;
+       if (NULL != cr->jim_handler && NULL == parent)
        {
-               int retval = register_command_handler(c);
-               if (ERROR_OK != retval)
-               {
-                       unregister_command(context, parent, name);
-                       return NULL;
-               }
+               retval = Jim_CreateCommand(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));
 
-       if (NULL != cr->jim_handler && NULL == parent)
-               Jim_CreateCommand(interp, cr->name, cr->jim_handler, cr->jim_handler_data, NULL);
-
+       if (ERROR_OK != retval)
+       {
+               unregister_command(context, parent, name);
+               c = NULL;
+       }
        return c;
 }
 
@@ -434,6 +439,14 @@ int unregister_command(struct command_context *context,
        return ERROR_OK;
 }
 
+void command_set_handler_data(struct command *c, void *p)
+{
+       if (NULL != c->handler || NULL != c->jim_handler)
+               c->jim_handler_data = p;
+       for (struct command *cc = c->children; NULL != cc; cc = cc->next)
+               command_set_handler_data(cc, p);
+}
+
 void command_output_text(struct command_context *context, const char *data)
 {
        if (context && context->output_handler && data) {
@@ -792,6 +805,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)
@@ -875,29 +890,39 @@ 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)
 {
        const char *cmd_name = Jim_GetString(argv[0], NULL);
-       script_debug(interp, cmd_name, argc - 1, argv + 1);
+       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();
        struct command *c = cmd_ctx->commands;
-       int remaining = command_unknown_find(argc - 1, argv + 1, c, &c);
+       int remaining = command_unknown_find(argc, argv, c, &c, true);
        // if nothing could be consumed, then it's really an unknown command
-       if (remaining == argc - 1)
+       if (remaining == argc)
        {
-               const char *cmd = Jim_GetString(argv[1], NULL);
+               const char *cmd = Jim_GetString(argv[0], NULL);
                LOG_ERROR("Unknown command:\n  %s", cmd);
                return JIM_OK;
        }
@@ -933,6 +958,61 @@ static int command_unknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
        return script_command_run(interp, count, start, c, found);
 }
 
+static int jim_command_mode(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+       struct command_context *cmd_ctx = current_command_context();
+       enum command_mode mode;
+       if (argc > 1)
+       {
+               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;
+               }
+               mode = c->mode;
+       }
+       else
+               mode = cmd_ctx->mode;
+
+       const char *mode_str;
+       switch (mode) {
+       case COMMAND_ANY: mode_str = "any"; break;
+       case COMMAND_CONFIG: mode_str = "config"; break;
+       case COMMAND_EXEC: mode_str = "exec"; break;
+       default: mode_str = "unknown"; break;
+       }
+       Jim_SetResultString(interp, mode_str, -1);
+       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();
+       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)
 {
@@ -1054,6 +1134,27 @@ COMMAND_HANDLER(handle_sleep_command)
        return ERROR_OK;
 }
 
+static const struct command_registration command_subcommand_handlers[] = {
+       {
+               .name = "mode",
+               .mode = COMMAND_ANY,
+               .jim_handler = &jim_command_mode,
+               .usage = "[<name> ...]",
+               .help = "Returns the command modes allowed by a  command:"
+                       "'any', 'config', or 'exec'.  If no command is"
+                       "specified, returns the current command mode.",
+       },
+       {
+               .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",
@@ -1091,6 +1192,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
 };
 
@@ -1139,7 +1246,6 @@ struct command_context* command_init(const char *startup_tcl)
        Jim_SetGlobalVariableStr(interp, "ocd_HOSTOS",
                        Jim_NewStringObj(interp, HostOs , strlen(HostOs)));
 
-       Jim_CreateCommand(interp, "unknown", &command_unknown, NULL, NULL);
        Jim_CreateCommand(interp, "ocd_find", jim_find, NULL, NULL);
        Jim_CreateCommand(interp, "echo", jim_echo, NULL, NULL);
        Jim_CreateCommand(interp, "capture", jim_capture, NULL, NULL);

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)