static int unregister_command(struct command_context *context,
struct command *parent, const char *name);
static char *command_name(struct command *c, char delim);
+static int command_unknown(Jim_Interp *interp, int argc, Jim_Obj * const *argv);
static int help_add_command(struct command_context *cmd_ctx,
const char *cmd_name, const char *help_text, const char *usage_text);
static int help_del_command(struct command_context *cmd_ctx, const char *cmd_name);
-/* wrap jimtcl internal data */
+/* set of functions to wrap jimtcl internal data */
static inline bool jimcmd_is_proc(Jim_Cmd *cmd)
{
return cmd->isproc;
}
+static inline bool jimcmd_is_ocd_command(Jim_Cmd *cmd)
+{
+ return !cmd->isproc && cmd->u.native.cmdProc == command_unknown;
+}
+
+static inline void *jimcmd_privdata(Jim_Cmd *cmd)
+{
+ return cmd->isproc ? NULL : cmd->u.native.privData;
+}
+
static void tcl_output(void *privData, const char *file, unsigned line,
const char *function, const char *string)
{
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.
return NULL;
}
-static int command_unknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
-
static struct command *register_command(struct command_context *context,
struct command *parent, const struct command_registration *cr)
{
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;
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)
int retval = c->handler(&cmd);
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);
- }
+ command_run_linef(context, "usage %s", words[0]);
} else if (retval == ERROR_COMMAND_CLOSE_CONNECTION) {
/* just fall through for a shutdown request */
} else {
- if (retval != ERROR_OK) {
- char *full_name = command_name(c, ' ');
+ if (retval != ERROR_OK)
LOG_DEBUG("Command '%s' failed with error code %d",
- full_name ? full_name : c->name, retval);
- free(full_name);
- }
+ words[0], retval);
/* Use the command output as the Tcl result */
Jim_SetResult(context->interp, cmd.output);
}
return retval;
}
-static int command_unknown_find(unsigned argc, Jim_Obj *const *argv,
- 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)
- return argc;
- *out = c;
- return command_unknown_find(--argc, ++argv, (*out)->children, out);
-}
-
static char *alloc_concatenate_strings(int argc, Jim_Obj * const *argv)
{
char *prev, *all;
Jim_Cmd *cmd = Jim_GetCommand(interp, s, JIM_NONE);
Jim_DecrRefCount(interp, s);
free(full_name);
- if (cmd && jimcmd_is_proc(cmd)) {
- Jim_SetResultString(interp, "any", -1);
- return JIM_OK;
- }
- struct command *c = cmd_ctx->commands;
- 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) {
+ if (!cmd || !(jimcmd_is_proc(cmd) || jimcmd_is_ocd_command(cmd))) {
Jim_SetResultString(interp, "unknown", -1);
return JIM_OK;
}
- mode = c->mode;
+
+ if (jimcmd_is_proc(cmd)) {
+ /* tcl proc */
+ mode = COMMAND_ANY;
+ } else {
+ struct command *c = jimcmd_privdata(cmd);
+
+ mode = c->mode;
+ }
} else
mode = cmd_ctx->mode;