rewrite 'unknown' command dispatching in C

Rewrite the magical 'unknown' command in C as a Jim handler, allowing
it to dispatch commands to any level in the tree.
__archive__
Zachary T Welch 2009-11-21 19:55:50 -08:00
parent 769fbfa058
commit 62e5649600
2 changed files with 65 additions and 17 deletions

View File

@ -853,6 +853,70 @@ COMMAND_HANDLER(handle_usage_command)
return CALL_COMMAND_HANDLER(command_help_show, c, 0, false); return CALL_COMMAND_HANDLER(command_help_show, c, 0, false);
} }
static int command_unknown_find(unsigned argc, Jim_Obj *const *argv,
struct command *head, struct command **out)
{
if (0 == argc)
return argc;
struct command *c = command_find(head, Jim_GetString(argv[0], NULL));
if (NULL == c)
return argc;
*out = c;
return command_unknown_find(--argc, ++argv, (*out)->children, out);
}
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);
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);
// if nothing could be consumed, then it's really an unknown command
if (remaining == argc - 1)
{
const char *cmd = Jim_GetString(argv[1], NULL);
LOG_ERROR("Unknown command:\n %s", cmd);
return JIM_OK;
}
bool found = true;
Jim_Obj *const *start;
unsigned count;
if (c->handler)
{
// include the command name in the list
count = remaining + 1;
start = argv + (argc - remaining - 1);
}
else
{
c = command_find(cmd_ctx->commands, "help");
if (NULL == c)
{
LOG_ERROR("unknown command, but help is missing too");
return JIM_ERR;
}
count = argc - remaining;
start = argv;
found = false;
}
unsigned nwords;
const char **words = script_command_args_alloc(count, start, &nwords);
if (NULL == words)
return JIM_ERR;
int retval = run_command(cmd_ctx, c, words, nwords);
script_command_args_free(words, nwords);
if (!found && ERROR_OK == retval)
retval = ERROR_FAIL;
return retval;
}
int help_add_command(struct command_context *cmd_ctx, struct command *parent, int help_add_command(struct command_context *cmd_ctx, struct command *parent,
const char *cmd_name, const char *help_text, const char *usage) const char *cmd_name, const char *help_text, const char *usage)
@ -1032,6 +1096,7 @@ struct command_context* command_init(const char *startup_tcl)
Jim_SetGlobalVariableStr(interp, "ocd_HOSTOS", Jim_SetGlobalVariableStr(interp, "ocd_HOSTOS",
Jim_NewStringObj(interp, HostOs , strlen(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, "ocd_find", jim_find, NULL, NULL);
Jim_CreateCommand(interp, "echo", jim_echo, NULL, NULL); Jim_CreateCommand(interp, "echo", jim_echo, NULL, NULL);
Jim_CreateCommand(interp, "capture", jim_capture, NULL, NULL); Jim_CreateCommand(interp, "capture", jim_capture, NULL, NULL);

View File

@ -44,23 +44,6 @@ proc cmd_help {cmdname h indent} {
} }
} }
# If a fn is unknown to Tcl, we try to execute it as an OpenOCD command
#
# We also support two level commands. "flash banks" is translated to
# flash_banks
proc unknown {args} {
# do the name mangling from "flash banks" to "flash_banks"
if {[llength $args]>=2} {
set cmd_name "[lindex $args 0]_[lindex $args 1]"
if {[catch {info body $cmd_name}]==0} {
# the command exists, try it...
return [eval "$cmd_name [lrange $args 2 end]"]
}
}
# This really is an unknown command.
return -code error "Unknown command: $args"
}
# Try flipping / and \ to find file if the filename does not # Try flipping / and \ to find file if the filename does not
# match the precise spelling # match the precise spelling
proc find {filename} { proc find {filename} {