helper/command: unregister commands through their full-name
authorAntonio Borneo <borneo.antonio@gmail.com>
Wed, 13 May 2020 13:35:19 +0000 (15:35 +0200)
committerAntonio Borneo <borneo.antonio@gmail.com>
Sun, 18 Apr 2021 14:34:43 +0000 (15:34 +0100)
While keeping the struct command in place, unregister the jim
commands by scanning the list of jim commands through their
full-name.

Change-Id: I0e903fbc31172858b703d67ccd471809c7949e86
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/5674
Tested-by: jenkins
Reviewed-by: Oleksij Rempel <linux@rempel-privat.de>
src/helper/command.c
src/helper/command.h

index 5cddf2150e4ba401165157efaf731ef33d21031a..d79d7f464771d483f350c6cdd3ccb4ec2a1aff4e 100644 (file)
@@ -243,6 +243,26 @@ struct command_context *current_command_context(Jim_Interp *interp)
        return cmd_ctx;
 }
 
+/**
+ * Find a openocd command from fullname.
+ * @returns Returns the named command if it is registred in interp.
+ * Returns NULL otherwise.
+ */
+static struct command *command_find_from_name(Jim_Interp *interp, const char *name)
+{
+       if (!name)
+               return NULL;
+
+       Jim_Obj *jim_name = Jim_NewStringObj(interp, name, -1);
+       Jim_IncrRefCount(jim_name);
+       Jim_Cmd *cmd = Jim_GetCommand(interp, jim_name, JIM_NONE);
+       Jim_DecrRefCount(interp, jim_name);
+       if (!cmd || jimcmd_is_proc(cmd) || !jimcmd_is_ocd_command(cmd))
+               return NULL;
+
+       return jimcmd_privdata(cmd);
+}
+
 /**
  * Find a command by name from a list of commands.
  * @returns Returns the named command if it exists in the list.
@@ -429,12 +449,80 @@ int __register_commands(struct command_context *cmd_ctx, const char *cmd_prefix,
        return ___register_commands(cmd_ctx, parent, cmds, data, override_target);
 }
 
+static __attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT, 2, 3)))
+int unregister_commands_match(struct command_context *cmd_ctx, const char *format, ...)
+{
+       Jim_Interp *interp = cmd_ctx->interp;
+       va_list ap;
+
+       va_start(ap, format);
+       char *query = alloc_vprintf(format, ap);
+       va_end(ap);
+       if (!query)
+               return ERROR_FAIL;
+
+       char *query_cmd = alloc_printf("info commands {%s}", query);
+       free(query);
+       if (!query_cmd)
+               return ERROR_FAIL;
+
+       int retval = Jim_EvalSource(interp, __THIS__FILE__, __LINE__, query_cmd);
+       free(query_cmd);
+       if (retval != JIM_OK)
+               return ERROR_FAIL;
+
+       Jim_Obj *list = Jim_GetResult(interp);
+       Jim_IncrRefCount(list);
+
+       int len = Jim_ListLength(interp, list);
+       for (int i = 0; i < len; i++) {
+               Jim_Obj *elem = Jim_ListGetIndex(interp, list, i);
+               Jim_IncrRefCount(elem);
+
+               const char *name = Jim_GetString(elem, NULL);
+               struct command *c = command_find_from_name(interp, name);
+               if (!c) {
+                       /* not openocd command */
+                       Jim_DecrRefCount(interp, elem);
+                       continue;
+               }
+               LOG_DEBUG("delete command \"%s\"", name);
+               Jim_DeleteCommand(interp, elem);
+
+               help_del_command(cmd_ctx, name);
+
+               Jim_DecrRefCount(interp, elem);
+       }
+
+       Jim_DecrRefCount(interp, list);
+       return ERROR_OK;
+}
+
 int unregister_all_commands(struct command_context *context,
-       struct command *parent)
+       const char *cmd_prefix)
 {
-       if (context == NULL)
+       struct command *parent = NULL;
+
+       if (!context)
                return ERROR_OK;
 
+       if (!cmd_prefix || !*cmd_prefix) {
+               int retval = unregister_commands_match(context, "*");
+               if (retval != ERROR_OK)
+                       return retval;
+       } else {
+               Jim_Cmd *cmd = Jim_GetCommand(context->interp, Jim_NewStringObj(context->interp, cmd_prefix, -1), JIM_NONE);
+               if (cmd && jimcmd_is_ocd_command(cmd))
+                       parent = jimcmd_privdata(cmd);
+
+               int retval = unregister_commands_match(context, "%s *", cmd_prefix);
+               if (retval != ERROR_OK)
+                       return retval;
+               retval = unregister_commands_match(context, "%s", cmd_prefix);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+
        struct command **head = command_list_for_parent(context, parent);
        while (NULL != *head) {
                struct command *tmp = *head;
@@ -458,7 +546,11 @@ static int unregister_command(struct command_context *context,
                        continue;
 
                char *full_name = command_name(c, ' ');
-               help_del_command(context, full_name);
+
+               int retval = unregister_commands_match(context, "%s", full_name);
+               if (retval != ERROR_OK)
+                       return retval;
+
                free(full_name);
 
                if (p)
index db095972af3725fa0921ad90799408cfa4572ce2..4d1928c5a9630ecd03d249e607bebaac7041978e 100644 (file)
@@ -311,11 +311,11 @@ static inline int register_commands_with_data(struct command_context *cmd_ctx,
 /**
  * Unregisters all commands from the specified context.
  * @param cmd_ctx The context that will be cleared of registered commands.
- * @param parent If given, only clear commands from under this one command.
+ * @param cmd_prefix If given, only clear commands from under this one command.
  * @returns ERROR_OK on success, or an error code.
  */
 int unregister_all_commands(struct command_context *cmd_ctx,
-               struct command *parent);
+               const char *cmd_prefix);
 
 /**
  * Unregisters the help for all commands. Used at exit to remove the help