add command_name helper
The command_name function returns a malloced string for a given command and its parents. This can be used to display a message to the user, but it is used internally to handle registration and syntax errors. This helps permit arbitrary command nesting.
This commit is contained in:
parent
f93c98081f
commit
2d3cc1eac1
|
@ -217,32 +217,22 @@ command_t* register_command(command_context_t *context, command_t *parent, char
|
||||||
if (c->handler == NULL)
|
if (c->handler == NULL)
|
||||||
return c;
|
return c;
|
||||||
|
|
||||||
/* If this is a two level command, e.g. "flash banks", then the
|
const char *full_name = command_name(c, '_');
|
||||||
* "unknown" proc in startup.tcl must redirect to this command.
|
|
||||||
*
|
const char *ocd_name = alloc_printf("ocd_%s", full_name);
|
||||||
* "flash banks" is translated by "unknown" to "flash_banks"
|
Jim_CreateCommand(interp, ocd_name, script_command, c, NULL);
|
||||||
* if such a proc exists
|
free((void *)ocd_name);
|
||||||
*/
|
|
||||||
/* Print help for command */
|
|
||||||
const char *t1="";
|
|
||||||
const char *t2="";
|
|
||||||
const char *t3="";
|
|
||||||
/* maximum of two levels :-) */
|
|
||||||
if (c->parent != NULL)
|
|
||||||
{
|
|
||||||
t1 = c->parent->name;
|
|
||||||
t2="_";
|
|
||||||
}
|
|
||||||
t3 = c->name;
|
|
||||||
const char *full_name = alloc_printf("ocd_%s%s%s", t1, t2, t3);
|
|
||||||
Jim_CreateCommand(interp, full_name, script_command, c, NULL);
|
|
||||||
free((void *)full_name);
|
|
||||||
|
|
||||||
/* we now need to add an overrideable proc */
|
/* we now need to add an overrideable proc */
|
||||||
const char *override_name = alloc_printf("proc %s%s%s {args} {if {[catch {eval ocd_%s%s%s $args}]==0} {return \"\"} else { return -code error }", t1, t2, t3, t1, t2, t3);
|
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);
|
||||||
Jim_Eval_Named(interp, override_name, __THIS__FILE__, __LINE__);
|
Jim_Eval_Named(interp, override_name, __THIS__FILE__, __LINE__);
|
||||||
free((void *)override_name);
|
free((void *)override_name);
|
||||||
|
|
||||||
|
free((void *)full_name);
|
||||||
|
|
||||||
/* accumulate help text in Tcl helptext list. */
|
/* accumulate help text in Tcl helptext list. */
|
||||||
Jim_Obj *helptext = Jim_GetGlobalVariableStr(interp, "ocd_helptext", JIM_ERRMSG);
|
Jim_Obj *helptext = Jim_GetGlobalVariableStr(interp, "ocd_helptext", JIM_ERRMSG);
|
||||||
if (Jim_IsShared(helptext))
|
if (Jim_IsShared(helptext))
|
||||||
|
@ -404,6 +394,28 @@ void command_print(command_context_t *context, const char *format, ...)
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char *__command_name(struct command_s *c, char delim, unsigned extra)
|
||||||
|
{
|
||||||
|
char *name;
|
||||||
|
unsigned len = strlen(c->name);
|
||||||
|
if (NULL == c->parent) {
|
||||||
|
// allocate enough for the name, child names, and '\0'
|
||||||
|
name = malloc(len + extra + 1);
|
||||||
|
strcpy(name, c->name);
|
||||||
|
} else {
|
||||||
|
// parent's extra must include both the space and name
|
||||||
|
name = __command_name(c->parent, delim, 1 + len + extra);
|
||||||
|
char dstr[2] = { delim, 0 };
|
||||||
|
strcat(name, dstr);
|
||||||
|
strcat(name, c->name);
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
char *command_name(struct command_s *c, char delim)
|
||||||
|
{
|
||||||
|
return __command_name(c, delim, 0);
|
||||||
|
}
|
||||||
|
|
||||||
static int run_command(command_context_t *context,
|
static int run_command(command_context_t *context,
|
||||||
command_t *c, char *words[], unsigned num_words)
|
command_t *c, char *words[], unsigned num_words)
|
||||||
{
|
{
|
||||||
|
@ -419,17 +431,12 @@ static int run_command(command_context_t *context,
|
||||||
if (retval == ERROR_COMMAND_SYNTAX_ERROR)
|
if (retval == ERROR_COMMAND_SYNTAX_ERROR)
|
||||||
{
|
{
|
||||||
/* Print help for command */
|
/* Print help for command */
|
||||||
const char *t1="";
|
char *full_name = command_name(c, ' ');
|
||||||
const char *t2="";
|
if (NULL != full_name) {
|
||||||
const char *t3="";
|
command_run_linef(context, "help %s", full_name);
|
||||||
/* maximum of two levels :-) */
|
free(full_name);
|
||||||
if (c->parent != NULL)
|
} else
|
||||||
{
|
retval = -ENOMEM;
|
||||||
t1 = c->parent->name;
|
|
||||||
t2=" ";
|
|
||||||
}
|
|
||||||
t3 = c->name;
|
|
||||||
command_run_linef(context, "help {%s%s%s}", t1, t2, t3);
|
|
||||||
}
|
}
|
||||||
else if (retval == ERROR_COMMAND_CLOSE_CONNECTION)
|
else if (retval == ERROR_COMMAND_CLOSE_CONNECTION)
|
||||||
{
|
{
|
||||||
|
|
|
@ -84,6 +84,16 @@ typedef struct command_s
|
||||||
struct command_s *next;
|
struct command_s *next;
|
||||||
} command_t;
|
} command_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param c The command to be named.
|
||||||
|
* @param delim The character to place between command names.
|
||||||
|
* @returns A malloc'd string containing the full command name,
|
||||||
|
* which may include one or more ancestor components. Multiple names
|
||||||
|
* are separated by single spaces. The caller must free() the string
|
||||||
|
* when done with it.
|
||||||
|
*/
|
||||||
|
char *command_name(struct command_s *c, char delim);
|
||||||
|
|
||||||
command_t* register_command(command_context_t *context,
|
command_t* register_command(command_context_t *context,
|
||||||
command_t *parent, char *name,
|
command_t *parent, char *name,
|
||||||
int (*handler)(struct command_context_s *context,
|
int (*handler)(struct command_context_s *context,
|
||||||
|
|
Loading…
Reference in New Issue