#include <stdio.h>
#include <unistd.h>
+#include <openocd_tcl.h>
+
+int fast_and_dangerous = 0;
+
void command_print_help_line(command_context_t* context, struct command_s *command, int indent);
int handle_sleep_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
int handle_time_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_fast_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int build_unique_lengths(command_context_t *context, command_t *commands)
-{
- command_t *c, *p;
+/* forward declaration of jim_command */
+extern int jim_command(command_context_t *context, char *line);
- /* iterate through all commands */
- for (c = commands; c; c = c->next)
- {
- /* find out how many characters are required to uniquely identify a command */
- for (c->unique_len = 1; c->unique_len <= strlen(c->name); c->unique_len++)
- {
- int foundmatch = 0;
-
- /* for every command, see if the current length is enough */
- for (p = commands; p; p = p->next)
- {
- /* ignore the command itself */
- if (c == p)
- continue;
-
- /* compare commands up to the current length */
- if (strncmp(p->name, c->name, c->unique_len) == 0)
- foundmatch++;
- }
-
- /* when none of the commands matched, we've found the minimum length required */
- if (!foundmatch)
- break;
- }
-
- /* if the current command has children, build the unique lengths for them */
- if (c->children)
- build_unique_lengths(context, c->children);
- }
-
- return ERROR_OK;
-}
-/* Avoid evaluating this each time we add a command. Reduces overhead from O(n^2) to O(n).
- * Makes a difference on ARM7 types machines and is not observable on GHz machines.
- */
-static int unique_length_dirty = 1;
command_t* register_command(command_context_t *context, command_t *parent, char *name, int (*handler)(struct command_context_s *context, char* name, char** args, int argc), enum command_mode mode, char *help)
{
command_t *c, *p;
- unique_length_dirty = 1;
if (!context || !name)
return NULL;
c->children = NULL;
c->handler = handler;
c->mode = mode;
- if (help)
- c->help = strdup(help);
- else
- c->help = NULL;
- c->unique_len = 0;
+ if (!help)
+ help="";
+ c->help = strdup(help);
c->next = NULL;
/* place command in tree */
context->commands = c;
}
}
+ /* accumulate help text in Tcl helptext list. */
+ Jim_Obj *helptext=Jim_GetGlobalVariableStr(interp, "ocd_helptext", JIM_ERRMSG);
+ Jim_Obj *cmd_entry=Jim_NewListObj(interp, NULL, 0);
+ Jim_Obj *cmd_list=Jim_NewListObj(interp, NULL, 0);
+
+ /* maximum of two levels :-) */
+ if (c->parent!=NULL)
+ {
+ Jim_ListAppendElement(interp, cmd_list, Jim_NewStringObj(interp, c->parent->name, -1));
+ }
+ Jim_ListAppendElement(interp, cmd_list, Jim_NewStringObj(interp, c->name, -1));
+
+ Jim_ListAppendElement(interp, cmd_entry, cmd_list);
+ Jim_ListAppendElement(interp, cmd_entry, Jim_NewStringObj(interp, c->help, -1));
+ Jim_ListAppendElement(interp, helptext, cmd_entry);
return c;
}
-int unregister_command(command_context_t *context, char *name)
+int unregister_all_commands(command_context_t *context)
{
- unique_length_dirty = 1;
+ command_t *c, *c2;
+ if (context == NULL)
+ return ERROR_OK;
+
+
+ while(NULL != context->commands)
+ {
+ c = context->commands;
+
+ while(NULL != c->children)
+ {
+ c2 = c->children;
+ c->children = c->children->next;
+ free(c2->name);
+ c2->name = NULL;
+ free(c2->help);
+ c2->help = NULL;
+ free(c2);
+ c2 = NULL;
+ }
+
+ context->commands = context->commands->next;
+
+ free(c->name);
+ c->name = NULL;
+ free(c->help);
+ c->help = NULL;
+ free(c);
+ c = NULL;
+ }
+
+ return ERROR_OK;
+}
+
+int unregister_command(command_context_t *context, char *name)
+{
command_t *c, *p = NULL, *c2;
if ((!context) || (!name))
return nwords;
}
+void command_output_text(command_context_t *context, const char *data)
+{
+ if( context && context->output_handler && data ){
+ context->output_handler( context, data );
+ }
+}
+
void command_print_n(command_context_t *context, char *format, ...)
{
char *string;
va_end(ap);
}
-int find_and_run_command(command_context_t *context, command_t *commands, char *words[], int num_words, int start_word)
+command_t *find_command(command_context_t *context, command_t *commands, char *words[], int num_words, int start_word, int *new_start_word)
{
command_t *c;
- int retval = ERROR_COMMAND_SYNTAX_ERROR;
-
- if (unique_length_dirty)
- {
- unique_length_dirty = 0;
- /* update unique lengths */
- build_unique_lengths(context, context->commands);
- }
for (c = commands; c; c = c->next)
{
- if (strncasecmp(c->name, words[start_word], c->unique_len))
+ if (strcasecmp(c->name, words[start_word]))
continue;
- if (strncasecmp(c->name, words[start_word], strlen(words[start_word])))
- continue;
-
if ((context->mode == COMMAND_CONFIG) || (c->mode == COMMAND_ANY) || (c->mode == context->mode) )
{
if (!c->children)
{
if (!c->handler)
{
- command_print(context, "No handler for command");
- retval = ERROR_COMMAND_SYNTAX_ERROR;
- break;
+ return NULL;
}
else
{
- int retval = c->handler(context, c->name, words + start_word + 1, num_words - start_word - 1);
- if (retval == ERROR_COMMAND_SYNTAX_ERROR)
- {
- command_print(context, "Syntax error:");
- command_print_help_line(context, c, 0);
- } else if (retval != ERROR_OK)
- {
- /* we do not print out an error message because the command *should*
- * have printed out an error
- */
- LOG_DEBUG("Command failed with error code %d", retval);
- }
- return retval;
+ *new_start_word=start_word;
+ return c;
}
}
else
{
if (start_word == num_words - 1)
{
- command_print(context, "Incomplete command");
- break;
+ return NULL;
}
- return find_and_run_command(context, c->children, words, num_words, start_word + 1);
+ return find_command(context, c->children, words, num_words, start_word + 1, new_start_word);
}
}
}
+ return NULL;
+}
+
+int find_and_run_command(command_context_t *context, command_t *commands, char *words[], int num_words)
+{
+ int start_word=0;
+ command_t *c;
+ c = find_command(context, commands, words, num_words, start_word, &start_word);
+ if (c == NULL)
+ {
+ /* just return command not found */
+ return ERROR_COMMAND_NOTFOUND;
+ }
- command_print(context, "Command %s not found", words[start_word]);
- return retval;
+ int retval = c->handler(context, c->name, words + start_word + 1, num_words - start_word - 1);
+ if (retval == ERROR_COMMAND_SYNTAX_ERROR)
+ {
+ command_print(context, "Syntax error:");
+ command_print_help_line(context, c, 0);
+ }
+ else if (retval == ERROR_COMMAND_CLOSE_CONNECTION)
+ {
+ /* just fall through for a shutdown request */
+ }
+ else if (retval != ERROR_OK)
+ {
+ /* we do not print out an error message because the command *should*
+ * have printed out an error
+ */
+ LOG_DEBUG("Command failed with error code %d", retval);
+ }
+
+ return retval;
}
-int command_run_line(command_context_t *context, char *line)
+int command_run_line_internal(command_context_t *context, char *line)
{
+ LOG_USER_N("%s", ""); /* Keep GDB connection alive*/
+
int nwords;
char *words[128] = {0};
int retval;
int i;
-
- if ((!context) || (!line))
- return ERROR_INVALID_ARGUMENTS;
-
+
/* skip preceding whitespace */
while (isspace(*line))
line++;
nwords = parse_line(line, words, sizeof(words) / sizeof(words[0]));
if (nwords > 0)
- retval = find_and_run_command(context, context->commands, words, nwords, 0);
+ {
+ retval = find_and_run_command(context, context->commands, words, nwords);
+ }
else
return ERROR_INVALID_ARGUMENTS;
return retval;
}
-int command_run_file(command_context_t *context, FILE *file, enum command_mode mode)
+int command_run_line(command_context_t *context, char *line)
{
- int retval = ERROR_OK;
- int old_command_mode;
- char *buffer=malloc(4096);
- if (buffer==NULL)
- {
- return ERROR_INVALID_ARGUMENTS;
- }
-
- old_command_mode = context->mode;
- context->mode = mode;
-
- while (fgets(buffer, 4096, file))
- {
- char *p;
- char *cmd, *end;
-
- /* stop processing line after a comment (#, !) or a LF, CR were encountered */
- if ((p = strpbrk(buffer, "#!\r\n")))
- *p = 0;
+ /* if a command is unknown to the "unknown" proc in tcl/commands.tcl will
+ * redirect it to OpenOCD.
+ *
+ * This avoids having to type the "openocd" prefix and makes OpenOCD
+ * commands "native" to Tcl.
+ */
+ return jim_command(context, line);
+}
- /* skip over leading whitespace */
- cmd = buffer;
- while (isspace(*cmd))
- cmd++;
- /* empty (all whitespace) line? */
- if (!*cmd)
- continue;
-
- /* search the end of the current line, ignore trailing whitespace */
- for (p = end = cmd; *p; p++)
- if (!isspace(*p))
- end = p;
-
- /* terminate end */
- *++end = 0;
- if (strcasecmp(cmd, "quit") == 0)
- break;
-
- /* run line */
- if ((retval = command_run_line(context, cmd)) == ERROR_COMMAND_CLOSE_CONNECTION)
- break;
+int command_run_linef(command_context_t *context, char *format, ...)
+{
+ int retval=ERROR_FAIL;
+ char *string;
+ va_list ap;
+ va_start(ap, format);
+ string = alloc_vprintf(format, ap);
+ if (string!=NULL)
+ {
+ retval=command_run_line(context, string);
}
-
- context->mode = old_command_mode;
-
-
- free(buffer);
-
+ va_end(ap);
return retval;
}
void command_print_help_line(command_context_t* context, struct command_s *command, int indent)
{
command_t *c;
- char indent_text[indent + 2];
+ char *indent_text=malloc(indent + 2);
+
char *help = "no help available";
char name_buf[64];
command_print_help_line(context, c, indent + 1);
}
}
+ free(indent_text);
}
int command_print_help_match(command_context_t* context, command_t* c_first, char* name, char** args, int argc)
{
if (argc > 0)
{
- if (strncasecmp(c->name, args[0], c->unique_len))
- continue;
-
- if (strncasecmp(c->name, args[0], strlen(args[0])))
+ if (strcasecmp(c->name, args[0]))
continue;
if (argc > 1)
return command_print_help_match(context, context->commands, name, args, argc);
}
-
-void command_set_output_handler(command_context_t* context, int (*output_handler)(struct command_context_s *context, char* line), void *priv)
+void command_set_output_handler(command_context_t* context, int (*output_handler)(struct command_context_s *context, const char* line), void *priv)
{
context->output_handler = output_handler;
context->output_handler_priv = priv;
register_command(context, NULL, "time", handle_time_command,
COMMAND_ANY, "time <cmd + args> - execute <cmd + args> and print time it took");
+ 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.");
+
return context;
}
return ERROR_OK;
}
-int handle_time_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+int handle_fast_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
{
- if (argc<1)
+ if (argc!=1)
return ERROR_COMMAND_SYNTAX_ERROR;
+ fast_and_dangerous = strcmp("enable", args[0])==0;
+
+ return ERROR_OK;
+}
+
+
+int handle_time_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
duration_t duration;
char *duration_text;
int retval;
+ float t;
+
+ if (argc<1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
duration_start_measure(&duration);
- retval = find_and_run_command(cmd_ctx, cmd_ctx->commands, args, argc, 0);
+ retval = find_and_run_command(cmd_ctx, cmd_ctx->commands, args, argc);
+ if (retval == ERROR_COMMAND_NOTFOUND)
+ {
+ command_print(cmd_ctx, "Command %s not found", args[0]);
+ }
duration_stop_measure(&duration, &duration_text);
- float t=duration.duration.tv_sec;
+ t=duration.duration.tv_sec;
t+=((float)duration.duration.tv_usec / 1000000.0);
command_print(cmd_ctx, "%s took %fs", args[0], t);