remove unknown handler
authorZachary T Welch <zw@superlucidity.net>
Sat, 28 Nov 2009 05:47:54 +0000 (21:47 -0800)
committerZachary T Welch <zw@superlucidity.net>
Sat, 28 Nov 2009 21:00:39 +0000 (13:00 -0800)
Updates command registration to provide top-level handlers for all
commands, rather than falling back onto the 'unknown' command. Instead,
that same handler is registered for placeholders, providing the same
functionality under the root verb command name instead.  This permits
users to implement their own 'unknown' function, and it resolves some
mind-bending breakage related to function object lookup while recursing.

Changes 'ocd_bounce' to call 'ocd_command' and 'ocd_help' from the
wrapper directly, rather than bouncing through their wrappers. This
prevents endless recursion caused by the above changes, whereby the
'command' wrapper's type check would blow the stack to hell and gone.

src/helper/command.c
src/helper/startup.tcl

index ba0415719acc10b0eee09e6cc38d88f8343fa9be..2b299568e33849074e2e043c831042011980db02 100644 (file)
@@ -296,37 +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;
 
-       if (NULL != c->handler)
-       {
-               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);
-               free((void *)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}",
-                       full_name, full_name);
+                       c->name, c->name);
        if (NULL == override_name)
-               goto free_full_name;
+               return JIM_ERR;
 
-       Jim_Eval_Named(interp, override_name, __THIS__FILE__, __LINE__);
+       retval = Jim_Eval_Named(interp, override_name, __FILE__, __LINE__);
        free((void *)override_name);
 
-       retval = ERROR_OK;
-
-free_full_name:
-       free((void *)full_name);
        return retval;
 }
 
@@ -350,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(command_root(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;
 }
 
@@ -903,15 +899,22 @@ static int command_unknown_find(unsigned argc, Jim_Obj *const *argv,
 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, true);
+       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;
        }
@@ -1196,7 +1199,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);
index cb5fb026205d603f9916af615e6cd1d638b7f11e..dda89c8adc6cccf09f2c427d1dff99159aae0076 100644 (file)
@@ -15,7 +15,7 @@ proc exit {} {
 # to discard 'handler' command output,
 proc ocd_bouncer {name args} {
        set cmd [format "ocd_%s" $name]
-       set type [eval command type $cmd $args]
+       set type [eval ocd_command type $cmd $args]
        if {$type == "native"} {
                return [eval $cmd $args]
        } else {if {$type == "simple"} {
@@ -25,7 +25,7 @@ proc ocd_bouncer {name args} {
                        set errmsg "Command handler execution failed"
                }
        } else {if {$type == "group"} {
-               catch {eval help $name $args}
+               catch {eval ocd_help $name $args}
                set errmsg [format "%s: command requires more arguments" \
                        [concat $name " " $args]]
        } else {

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)