#include "jim-eventloop.h"
-int fast_and_dangerous = 0;
Jim_Interp *interp = NULL;
-static int run_command(command_context_t *context,
- command_t *c, const char *words[], unsigned num_words);
+static int run_command(struct command_context *context,
+ struct command *c, const char *words[], unsigned num_words);
static void tcl_output(void *privData, const char *file, unsigned line,
const char *function, const char *string)
Jim_AppendString(interp, tclOutput, string, strlen(string));
}
-extern command_context_t *global_cmd_ctx;
+extern struct command_context *global_cmd_ctx;
void script_debug(Jim_Interp *interp, const char *name,
unsigned argc, Jim_Obj *const *argv)
}
}
+static void script_command_args_free(const char **words, unsigned nwords)
+{
+ for (unsigned i = 0; i < nwords; i++)
+ free((void *)words[i]);
+ free(words);
+}
+static const char **script_command_args_alloc(
+ unsigned argc, Jim_Obj *const *argv, unsigned *nwords)
+{
+ const char **words = malloc(argc * sizeof(char *));
+ if (NULL == words)
+ return NULL;
+
+ unsigned i;
+ for (i = 0; i < argc; i++)
+ {
+ int len;
+ const char *w = Jim_GetString(argv[i], &len);
+ /* a comment may end the line early */
+ if (*w == '#')
+ break;
+
+ words[i] = strdup(w);
+ if (words[i] == NULL)
+ {
+ script_command_args_free(words, i);
+ return NULL;
+ }
+ }
+ *nwords = i;
+ return words;
+}
+
+static struct command_context *current_command_context(void)
+{
+ /* grab the command context from the associated data */
+ struct command_context *cmd_ctx = Jim_GetAssocData(interp, "context");
+ if (NULL == cmd_ctx)
+ {
+ /* Tcl can invoke commands directly instead of via command_run_line(). This would
+ * happen when the Jim Tcl interpreter is provided by eCos.
+ */
+ cmd_ctx = global_cmd_ctx;
+ }
+ return cmd_ctx;
+}
+
static int script_command(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
/* the private data is stashed in the interp structure */
- command_t *c;
- command_context_t *context;
+ struct command *c;
int retval;
- int i;
- int nwords;
- char **words;
/* DANGER!!!! be careful what we invoke here, since interp->cmdPrivData might
* get overwritten by running other Jim commands! Treat it as an
script_debug(interp, c->name, argc, argv);
- words = malloc(sizeof(char *) * argc);
- for (i = 0; i < argc; i++)
- {
- int len;
- const char *w = Jim_GetString(argv[i], &len);
- if (*w=='#')
- {
- /* hit an end of line comment */
- break;
- }
- words[i] = strdup(w);
- if (words[i] == NULL)
- {
- int j;
- for (j = 0; j < i; j++)
- free(words[j]);
- free(words);
- return JIM_ERR;
- }
- }
- nwords = i;
-
- /* grab the command context from the associated data */
- context = Jim_GetAssocData(interp, "context");
- if (context == NULL)
- {
- /* Tcl can invoke commands directly instead of via command_run_line(). This would
- * happen when the Jim Tcl interpreter is provided by eCos.
- */
- context = global_cmd_ctx;
- }
+ unsigned nwords;
+ const char **words = script_command_args_alloc(argc, argv, &nwords);
+ if (NULL == words)
+ return JIM_ERR;
/* capture log output and return it */
Jim_Obj *tclOutput = Jim_NewStringObj(interp, "", 0);
log_add_callback(tcl_output, tclOutput);
- retval = run_command(context, c, (const char **)words, nwords);
+ struct command_context *cmd_ctx = current_command_context();
+ retval = run_command(cmd_ctx, c, (const char **)words, nwords);
log_remove_callback(tcl_output, tclOutput);
Jim_SetResult(interp, tclOutput);
Jim_DecrRefCount(interp, tclOutput);
- for (i = 0; i < nwords; i++)
- free(words[i]);
- free(words);
+ script_command_args_free(words, nwords);
int *return_retval = Jim_GetAssocData(interp, "retval");
if (return_retval != NULL)
return (retval == ERROR_OK)?JIM_OK:JIM_ERR;
}
-static Jim_Obj *command_name_list(struct command_s *c)
-{
- Jim_Obj *cmd_list = c->parent ?
- command_name_list(c->parent) :
- Jim_NewListObj(interp, NULL, 0);
- Jim_ListAppendElement(interp, cmd_list,
- Jim_NewStringObj(interp, c->name, -1));
-
- return cmd_list;
-}
-
-static void command_helptext_add(Jim_Obj *cmd_list, const char *help)
-{
- Jim_Obj *cmd_entry = Jim_NewListObj(interp, NULL, 0);
- Jim_ListAppendElement(interp, cmd_entry, cmd_list);
- Jim_ListAppendElement(interp, cmd_entry,
- Jim_NewStringObj(interp, help ? : "", -1));
-
- /* accumulate help text in Tcl helptext list. */
- Jim_Obj *helptext = Jim_GetGlobalVariableStr(interp,
- "ocd_helptext", JIM_ERRMSG);
- if (Jim_IsShared(helptext))
- helptext = Jim_DuplicateObj(interp, helptext);
- Jim_ListAppendElement(interp, helptext, cmd_entry);
-}
-
/* nice short description of source file */
#define __THIS__FILE__ "command.c"
/**
* Find a command by name from a list of commands.
- * @returns The named command if found, or NULL.
+ * @returns Returns the named command if it exists in the list.
+ * Returns NULL otherwise.
*/
-static struct command_s *command_find(struct command_s **head, const char *name)
+static struct command *command_find(struct command *head, const char *name)
{
- assert(head);
- for (struct command_s *cc = *head; cc; cc = cc->next)
+ for (struct command *cc = head; cc; cc = cc->next)
{
if (strcmp(cc->name, name) == 0)
return cc;
}
return NULL;
}
+struct command *command_find_in_context(struct command_context *cmd_ctx,
+ const char *name)
+{
+ return command_find(cmd_ctx->commands, name);
+}
+struct command *command_find_in_parent(struct command *parent,
+ const char *name)
+{
+ return command_find(parent->children, name);
+}
/**
- * Add the command to the end of linked list.
- * @returns Returns false if the named command already exists in the list.
- * Returns true otherwise.
+ * Add the command into the linked list, sorted by name.
+ * @param head Address to head of command list pointer, which may be
+ * updated if @c c gets inserted at the beginning of the list.
+ * @param c The command to add to the list pointed to by @c head.
*/
-static void command_add_child(struct command_s **head, struct command_s *c)
+static void command_add_child(struct command **head, struct command *c)
{
assert(head);
if (NULL == *head)
*head = c;
return;
}
- struct command_s *cc = *head;
- while (cc->next) cc = cc->next;
- cc->next = c;
+
+ while ((*head)->next && (strcmp(c->name, (*head)->name) > 0))
+ head = &(*head)->next;
+
+ if (strcmp(c->name, (*head)->name) > 0) {
+ c->next = (*head)->next;
+ (*head)->next = c;
+ } else {
+ c->next = *head;
+ *head = c;
+ }
}
-command_t* register_command(command_context_t *context,
- command_t *parent, char *name, command_handler_t handler,
- enum command_mode mode, char *help)
+static struct command **command_list_for_parent(
+ struct command_context *cmd_ctx, struct command *parent)
{
- if (!context || !name)
- return NULL;
+ return parent ? &parent->children : &cmd_ctx->commands;
+}
- struct command_s **head = parent ? &parent->children : &context->commands;
- struct command_s *c = command_find(head, name);
- if (NULL != c)
- return c;
+static struct command *command_new(struct command_context *cmd_ctx,
+ struct command *parent, const struct command_registration *cr)
+{
+ assert(cr->name);
- c = malloc(sizeof(command_t));
+ struct command *c = malloc(sizeof(struct command));
+ memset(c, 0, sizeof(struct command));
- c->name = strdup(name);
+ c->name = strdup(cr->name);
+ if (cr->help)
+ c->help = strdup(cr->help);
+ if (cr->usage)
+ c->usage = strdup(cr->usage);
c->parent = parent;
- c->children = NULL;
- c->handler = handler;
- c->mode = mode;
- c->next = NULL;
+ c->handler = cr->handler;
+ c->jim_handler = cr->jim_handler;
+ c->jim_handler_data = cr->jim_handler_data;
+ c->mode = cr->mode;
- command_add_child(head, c);
+ command_add_child(command_list_for_parent(cmd_ctx, parent), c);
- command_helptext_add(command_name_list(c), help);
+ return c;
+}
+static void command_free(struct command *c)
+{
+ /// @todo if command has a handler, unregister its jim command!
- /* just a placeholder, no handler */
- if (c->handler == NULL)
- return c;
+ while (NULL != c->children)
+ {
+ struct command *tmp = c->children;
+ c->children = tmp->next;
+ command_free(tmp);
+ }
+ if (c->name)
+ free(c->name);
+ if (c->help)
+ free((void*)c->help);
+ if (c->usage)
+ free((void*)c->usage);
+ free(c);
+}
+
+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", full_name);
+ if (NULL == full_name)
+ goto free_full_name;
+
Jim_CreateCommand(interp, ocd_name, script_command, c, NULL);
free((void *)ocd_name);
"if {[catch {eval ocd_%s $args}] == 0} "
"{return \"\"} else {return -code error}}",
full_name, full_name);
+ if (NULL == full_name)
+ goto free_full_name;
+
Jim_Eval_Named(interp, override_name, __THIS__FILE__, __LINE__);
free((void *)override_name);
- free((void *)full_name);
+ retval = ERROR_OK;
- return c;
+free_full_name:
+ free((void *)full_name);
+ return retval;
}
-int unregister_all_commands(command_context_t *context)
+struct command* register_command(struct command_context *context,
+ struct command *parent, const struct command_registration *cr)
{
- command_t *c, *c2;
+ if (!context || !cr->name)
+ return NULL;
- if (context == NULL)
- return ERROR_OK;
+ const char *name = cr->name;
+ struct command **head = command_list_for_parent(context, parent);
+ struct command *c = command_find(*head, name);
+ if (NULL != c)
+ {
+ LOG_ERROR("command '%s' is already registered in '%s' context",
+ name, parent ? parent->name : "<global>");
+ return c;
+ }
+
+ c = command_new(context, parent, cr);
+ if (NULL == c)
+ return NULL;
+
+ if (NULL != c->handler)
+ {
+ int retval = register_command_handler(c);
+ if (ERROR_OK != retval)
+ {
+ unregister_command(context, parent, name);
+ return NULL;
+ }
+ }
+
+ if (NULL != cr->jim_handler && NULL == parent)
+ Jim_CreateCommand(interp, cr->name, cr->jim_handler, cr->jim_handler_data, NULL);
- while (NULL != context->commands)
+ return c;
+}
+
+int register_commands(struct command_context *cmd_ctx, struct command *parent,
+ const struct command_registration *cmds)
+{
+ int retval = ERROR_OK;
+ unsigned i;
+ for (i = 0; cmds[i].name || cmds[i].chain; i++)
{
- c = context->commands;
+ const struct command_registration *cr = cmds + i;
- while (NULL != c->children)
+ struct command *c = NULL;
+ if (NULL != cr->name)
{
- c2 = c->children;
- c->children = c->children->next;
- free(c2->name);
- c2->name = NULL;
- free(c2);
- c2 = NULL;
+ c = register_command(cmd_ctx, parent, cr);
+ if (NULL == c)
+ {
+ retval = ERROR_FAIL;
+ break;
+ }
+ }
+ if (NULL != cr->chain)
+ {
+ struct command *p = c ? : parent;
+ retval = register_commands(cmd_ctx, p, cr->chain);
+ if (ERROR_OK != retval)
+ break;
}
+ }
+ if (ERROR_OK != retval)
+ {
+ for (unsigned j = 0; j < i; j++)
+ unregister_command(cmd_ctx, parent, cmds[j].name);
+ }
+ return retval;
+}
- context->commands = context->commands->next;
+int unregister_all_commands(struct command_context *context,
+ struct command *parent)
+{
+ if (context == NULL)
+ return ERROR_OK;
- free(c->name);
- c->name = NULL;
- free(c);
- c = NULL;
+ struct command **head = command_list_for_parent(context, parent);
+ while (NULL != *head)
+ {
+ struct command *tmp = *head;
+ *head = tmp->next;
+ command_free(tmp);
}
return ERROR_OK;
}
-int unregister_command(command_context_t *context, char *name)
+int unregister_command(struct command_context *context,
+ struct command *parent, const char *name)
{
- command_t *c, *p = NULL, *c2;
-
if ((!context) || (!name))
return ERROR_INVALID_ARGUMENTS;
- /* find command */
- c = context->commands;
-
- while (NULL != c)
+ struct command *p = NULL;
+ struct command **head = command_list_for_parent(context, parent);
+ for (struct command *c = *head; NULL != c; p = c, c = c->next)
{
- if (strcmp(name, c->name) == 0)
- {
- /* unlink command */
- if (p)
- {
- p->next = c->next;
- }
- else
- {
- /* first element in command list */
- context->commands = c->next;
- }
-
- /* unregister children */
- while (NULL != c->children)
- {
- c2 = c->children;
- c->children = c->children->next;
- free(c2->name);
- c2->name = NULL;
- free(c2);
- c2 = NULL;
- }
+ if (strcmp(name, c->name) != 0)
+ continue;
- /* delete command */
- free(c->name);
- c->name = NULL;
- free(c);
- c = NULL;
- return ERROR_OK;
- }
+ if (p)
+ p->next = c->next;
+ else
+ *head = c->next;
- /* remember the last command for unlinking */
- p = c;
- c = c->next;
+ command_free(c);
+ return ERROR_OK;
}
return ERROR_OK;
}
-void command_output_text(command_context_t *context, const char *data)
+void command_output_text(struct command_context *context, const char *data)
{
if (context && context->output_handler && data) {
context->output_handler(context, data);
}
}
-void command_print_sameline(command_context_t *context, const char *format, ...)
+void command_print_sameline(struct command_context *context, const char *format, ...)
{
char *string;
va_end(ap);
}
-void command_print(command_context_t *context, const char *format, ...)
+void command_print(struct command_context *context, const char *format, ...)
{
char *string;
va_end(ap);
}
-static char *__command_name(struct command_s *c, char delim, unsigned extra)
+static char *__command_name(struct command *c, char delim, unsigned extra)
{
char *name;
unsigned len = strlen(c->name);
}
return name;
}
-char *command_name(struct command_s *c, char delim)
+char *command_name(struct command *c, char delim)
{
return __command_name(c, delim, 0);
}
-static int run_command(command_context_t *context,
- command_t *c, const char *words[], unsigned num_words)
+static int run_command(struct command_context *context,
+ struct command *c, const char *words[], unsigned num_words)
{
- int start_word = 0;
if (!((context->mode == COMMAND_CONFIG) || (c->mode == COMMAND_ANY) || (c->mode == context->mode)))
{
/* Config commands can not run after the config stage */
return ERROR_FAIL;
}
- unsigned argc = num_words - start_word - 1;
- const char **args = words + start_word + 1;
- int retval = c->handler(context, c->name, args, argc);
+ struct command_invocation cmd = {
+ .ctx = context,
+ .name = c->name,
+ .argc = num_words - 1,
+ .argv = words + 1,
+ };
+ int retval = c->handler(&cmd);
if (retval == ERROR_COMMAND_SYNTAX_ERROR)
{
/* Print help for command */
return retval;
}
-int command_run_line(command_context_t *context, char *line)
+int command_run_line(struct command_context *context, char *line)
{
/* all the parent commands have been registered with the interpreter
* so, can just evaluate the line as a script and check for
return retval;
}
-int command_run_linef(command_context_t *context, const char *format, ...)
+int command_run_linef(struct command_context *context, const char *format, ...)
{
int retval = ERROR_FAIL;
char *string;
return retval;
}
-void command_set_output_handler(command_context_t* context,
+void command_set_output_handler(struct command_context* context,
command_output_handler_t output_handler, void *priv)
{
context->output_handler = output_handler;
context->output_handler_priv = priv;
}
-command_context_t* copy_command_context(command_context_t* context)
+struct command_context* copy_command_context(struct command_context* context)
{
- command_context_t* copy_context = malloc(sizeof(command_context_t));
+ struct command_context* copy_context = malloc(sizeof(struct command_context));
*copy_context = *context;
return copy_context;
}
-int command_done(command_context_t *context)
+int command_done(struct command_context *context)
{
free(context);
context = NULL;
return retcode;
}
+static COMMAND_HELPER(command_help_find, struct command *head,
+ struct command **out)
+{
+ if (0 == CMD_ARGC)
+ return ERROR_INVALID_ARGUMENTS;
+ *out = command_find(head, CMD_ARGV[0]);
+ if (NULL == *out)
+ return ERROR_INVALID_ARGUMENTS;
+ if (--CMD_ARGC == 0)
+ return ERROR_OK;
+ CMD_ARGV++;
+ return CALL_COMMAND_HANDLER(command_help_find, (*out)->children, out);
+}
+
+static COMMAND_HELPER(command_help_show, struct command *c, unsigned n,
+ bool show_help);
+
+static COMMAND_HELPER(command_help_show_list, struct command *head, unsigned n,
+ bool show_help)
+{
+ for (struct command *c = head; NULL != c; c = c->next)
+ CALL_COMMAND_HANDLER(command_help_show, c, n, show_help);
+ return ERROR_OK;
+}
+static COMMAND_HELPER(command_help_show, struct command *c, unsigned n,
+ bool show_help)
+{
+ const char *usage = c->usage ? : "";
+ const char *help = "";
+ const char *sep = "";
+ if (show_help && c->help)
+ {
+ help = c->help ? : "";
+ sep = c->usage ? " | " : "";
+ }
+ command_run_linef(CMD_CTX, "cmd_help {%s} {%s%s%s} %d",
+ command_name(c, ' '), usage, sep, help, n);
+
+ if (++n >= 2)
+ return ERROR_OK;
+
+ return CALL_COMMAND_HANDLER(command_help_show_list,
+ c->children, n, show_help);
+}
+COMMAND_HANDLER(handle_help_command)
+{
+ struct command *c = CMD_CTX->commands;
+
+ if (0 == CMD_ARGC)
+ return CALL_COMMAND_HANDLER(command_help_show_list, c, 0, true);
+
+ int retval = CALL_COMMAND_HANDLER(command_help_find, c, &c);
+ if (ERROR_OK != retval)
+ return retval;
+
+ return CALL_COMMAND_HANDLER(command_help_show, c, 0, true);
+}
+
+COMMAND_HANDLER(handle_usage_command)
+{
+ struct command *c = CMD_CTX->commands;
+
+ if (0 == CMD_ARGC)
+ return CALL_COMMAND_HANDLER(command_help_show_list, c, 0, false);
+
+ int retval = CALL_COMMAND_HANDLER(command_help_find, c, &c);
+ if (ERROR_OK != retval)
+ return retval;
+
+ 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 || c->jim_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;
+ }
+ // pass the command through to the intended handler
+ if (c->jim_handler)
+ {
+ interp->cmdPrivData = c->jim_handler_data;
+ return (*c->jim_handler)(interp, count, start);
+ }
+
+ 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,
+ const char *cmd_name, const char *help_text, const char *usage)
+{
+ struct command **head = command_list_for_parent(cmd_ctx, parent);
+ struct command *nc = command_find(*head, cmd_name);
+ if (NULL == nc)
+ {
+ // add a new command with help text
+ struct command_registration cr = {
+ .name = cmd_name,
+ .mode = COMMAND_ANY,
+ .help = help_text,
+ .usage = usage,
+ };
+ nc = register_command(cmd_ctx, parent, &cr);
+ if (NULL == nc)
+ {
+ LOG_ERROR("failed to add '%s' help text", cmd_name);
+ return ERROR_FAIL;
+ }
+ LOG_DEBUG("added '%s' help text", cmd_name);
+ }
+ else
+ {
+ bool replaced = false;
+ if (nc->help)
+ {
+ free((void *)nc->help);
+ replaced = true;
+ }
+ nc->help = strdup(help_text);
+
+ if (replaced)
+ LOG_INFO("replaced existing '%s' help", cmd_name);
+ else
+ LOG_DEBUG("added '%s' help text", cmd_name);
+ }
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_help_add_command)
+{
+ if (CMD_ARGC < 2)
+ {
+ LOG_ERROR("%s: insufficient arguments", CMD_NAME);
+ return ERROR_INVALID_ARGUMENTS;
+ }
+
+ // save help text and remove it from argument list
+ const char *help_text = CMD_ARGV[--CMD_ARGC];
+ // likewise for the leaf command name
+ const char *cmd_name = CMD_ARGV[--CMD_ARGC];
+
+ struct command *c = NULL;
+ if (CMD_ARGC > 0)
+ {
+ c = CMD_CTX->commands;
+ int retval = CALL_COMMAND_HANDLER(command_help_find, c, &c);
+ if (ERROR_OK != retval)
+ return retval;
+ }
+ return help_add_command(CMD_CTX, c, cmd_name, help_text, NULL);
+}
+
/* sleep command sleeps for <n> miliseconds
* this is useful in target startup scripts
*/
COMMAND_HANDLER(handle_sleep_command)
{
bool busy = false;
- if (argc == 2)
+ if (CMD_ARGC == 2)
{
- if (strcmp(args[1], "busy") == 0)
+ if (strcmp(CMD_ARGV[1], "busy") == 0)
busy = true;
else
return ERROR_COMMAND_SYNTAX_ERROR;
}
- else if (argc < 1 || argc > 2)
+ else if (CMD_ARGC < 1 || CMD_ARGC > 2)
return ERROR_COMMAND_SYNTAX_ERROR;
unsigned long duration = 0;
- int retval = parse_ulong(args[0], &duration);
+ int retval = parse_ulong(CMD_ARGV[0], &duration);
if (ERROR_OK != retval)
return retval;
return ERROR_OK;
}
-COMMAND_HANDLER(handle_fast_command)
-{
- if (argc != 1)
- return ERROR_COMMAND_SYNTAX_ERROR;
-
- fast_and_dangerous = strcmp("enable", args[0]) == 0;
-
- return ERROR_OK;
-}
-
-
-command_context_t* command_init()
+static const struct command_registration command_builtin_handlers[] = {
+ {
+ .name = "add_help_text",
+ .handler = &handle_help_add_command,
+ .mode = COMMAND_ANY,
+ .help = "add new command help text",
+ .usage = "<command> [...] <help_text>]",
+ },
+ {
+ .name = "sleep",
+ .handler = &handle_sleep_command,
+ .mode = COMMAND_ANY,
+ .help = "sleep for n milliseconds. "
+ "\"busy\" will busy wait",
+ .usage = "<n> [busy]",
+ },
+ {
+ .name = "help",
+ .handler = &handle_help_command,
+ .mode = COMMAND_ANY,
+ .help = "show built-in command help",
+ .usage = "[<command_name> ...]",
+ },
+ {
+ .name = "usage",
+ .handler = &handle_usage_command,
+ .mode = COMMAND_ANY,
+ .help = "show command usage",
+ .usage = "[<command_name> ...]",
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+struct command_context* command_init(const char *startup_tcl)
{
- command_context_t* context = malloc(sizeof(command_context_t));
- extern const char startup_tcl[];
+ struct command_context* context = malloc(sizeof(struct command_context));
const char *HostOs;
context->mode = COMMAND_EXEC;
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);
interp->cb_fflush = openocd_jim_fflush;
interp->cb_fgets = openocd_jim_fgets;
+ register_commands(context, NULL, command_builtin_handlers);
+
#if !BUILD_ECOSBOARD
Jim_EventLoopOnLoad(interp);
#endif
+ Jim_SetAssocData(interp, "context", NULL, context);
if (Jim_Eval_Named(interp, startup_tcl, "embedded:startup.tcl",1) == JIM_ERR)
{
LOG_ERROR("Failed to run startup.tcl (embedded into OpenOCD)");
Jim_PrintErrorMessage(interp);
exit(-1);
}
-
- register_command(context, NULL, "sleep",
- handle_sleep_command, COMMAND_ANY,
- "<n> [busy] - sleep for n milliseconds. "
- "\"busy\" means busy wait");
- register_command(context, NULL, "fast",
- handle_fast_command, COMMAND_ANY,
- "fast <enable/disable> - place at beginning of "
- "config files. Sets defaults to fast and dangerous.");
+ Jim_DeleteAssocData(interp, "context");
return context;
}
-int command_context_mode(command_context_t *cmd_ctx, enum command_mode mode)
+int command_context_mode(struct command_context *cmd_ctx, enum command_mode mode)
{
if (!cmd_ctx)
return ERROR_INVALID_ARGUMENTS;
#endif
}
-void register_jim(struct command_context_s *cmd_ctx, const char *name, int (*cmd)(Jim_Interp *interp, int argc, Jim_Obj *const *argv), const char *help)
-{
- Jim_CreateCommand(interp, name, cmd, NULL, NULL);
-
- Jim_Obj *cmd_list = Jim_NewListObj(interp, NULL, 0);
- Jim_ListAppendElement(interp, cmd_list,
- Jim_NewStringObj(interp, name, -1));
-
- command_helptext_add(cmd_list, help);
-}
-
-/* return global variable long value or 0 upon failure */
-long jim_global_long(const char *variable)
-{
- Jim_Obj *objPtr = Jim_GetGlobalVariableStr(interp, variable, JIM_ERRMSG);
- long t;
- if (Jim_GetLong(interp, objPtr, &t) == JIM_OK)
- {
- return t;
- }
- return 0;
-}
-
#define DEFINE_PARSE_NUM_TYPE(name, type, func, min, max) \
int parse##name(const char *str, type *ul) \
{ \
DEFINE_PARSE_LONG(_s32, int32_t, n < INT32_MIN, INT32_MAX)
DEFINE_PARSE_LONG(_s16, int16_t, n < INT16_MIN, INT16_MAX)
DEFINE_PARSE_LONG(_s8, int8_t, n < INT8_MIN, INT8_MAX)
+
+static int command_parse_bool(const char *in, bool *out,
+ const char *on, const char *off)
+{
+ if (strcasecmp(in, on) == 0)
+ *out = true;
+ else if (strcasecmp(in, off) == 0)
+ *out = false;
+ else
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ return ERROR_OK;
+}
+
+int command_parse_bool_arg(const char *in, bool *out)
+{
+ if (command_parse_bool(in, out, "on", "off") == ERROR_OK)
+ return ERROR_OK;
+ if (command_parse_bool(in, out, "enable", "disable") == ERROR_OK)
+ return ERROR_OK;
+ if (command_parse_bool(in, out, "true", "false") == ERROR_OK)
+ return ERROR_OK;
+ if (command_parse_bool(in, out, "yes", "no") == ERROR_OK)
+ return ERROR_OK;
+ if (command_parse_bool(in, out, "1", "0") == ERROR_OK)
+ return ERROR_OK;
+ return ERROR_INVALID_ARGUMENTS;
+}
+
+COMMAND_HELPER(handle_command_parse_bool, bool *out, const char *label)
+{
+ switch (CMD_ARGC) {
+ case 1: {
+ const char *in = CMD_ARGV[0];
+ if (command_parse_bool_arg(in, out) != ERROR_OK)
+ {
+ LOG_ERROR("%s: argument '%s' is not valid", CMD_NAME, in);
+ return ERROR_INVALID_ARGUMENTS;
+ }
+ // fall through
+ }
+ case 0:
+ LOG_INFO("%s is %s", label, *out ? "enabled" : "disabled");
+ break;
+ default:
+ return ERROR_INVALID_ARGUMENTS;
+ }
+ return ERROR_OK;
+}