aboutsummaryrefslogtreecommitdiff
path: root/src/helper
diff options
context:
space:
mode:
authoroharboe <oharboe@b42882b7-edfa-0310-969c-e2dbd0fdcd60>2008-02-25 17:32:53 +0000
committeroharboe <oharboe@b42882b7-edfa-0310-969c-e2dbd0fdcd60>2008-02-25 17:32:53 +0000
commit7f1944a47823fc48eef244257b80675a226f86b8 (patch)
treef070f312502705475fd5cb7918fcd4a124487ae5 /src/helper
parent375c5f85d2871921b10125e2bc54eba0c338a67b (diff)
Pavel Chromy
- multiple log listeners - added OUTPUT() to replace printf - fix formatting git-svn-id: svn://svn.berlios.de/openocd/trunk@346 b42882b7-edfa-0310-969c-e2dbd0fdcd60
Diffstat (limited to 'src/helper')
-rw-r--r--src/helper/command.c1225
-rw-r--r--src/helper/log.c79
-rw-r--r--src/helper/log.h212
-rw-r--r--src/helper/options.c14
4 files changed, 790 insertions, 740 deletions
diff --git a/src/helper/command.c b/src/helper/command.c
index 4b6de26c..f13a86c1 100644
--- a/src/helper/command.c
+++ b/src/helper/command.c
@@ -1,618 +1,607 @@
-/***************************************************************************
- * Copyright (C) 2005 by Dominic Rath *
- * Dominic.Rath@gmx.de *
- * *
- * part of this file is taken from libcli (libcli.sourceforge.net) *
- * Copyright (C) David Parrish (david@dparrish.com) *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the *
- * Free Software Foundation, Inc., *
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
- ***************************************************************************/
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "replacements.h"
-
-#include "command.h"
-
-#include "log.h"
-#include "time_support.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <unistd.h>
-
-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 build_unique_lengths(command_context_t *context, command_t *commands)
-{
- command_t *c, *p;
-
- /* 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 = malloc(sizeof(command_t));
-
- c->name = strdup(name);
- c->parent = parent;
- c->children = NULL;
- c->handler = handler;
- c->mode = mode;
- if (help)
- c->help = strdup(help);
- else
- c->help = NULL;
- c->unique_len = 0;
- c->next = NULL;
-
- /* place command in tree */
- if (parent)
- {
- if (parent->children)
- {
- /* find last child */
- for (p = parent->children; p && p->next; p = p->next);
- if (p)
- p->next = c;
- }
- else
- {
- parent->children = c;
- }
- }
- else
- {
- if (context->commands)
- {
- /* find last command */
- for (p = context->commands; p && p->next; p = p->next);
- if (p)
- p->next = c;
- }
- else
- {
- context->commands = c;
- }
- }
-
- return c;
-}
-
-int unregister_command(command_context_t *context, char *name)
-{
- unique_length_dirty = 1;
-
- command_t *c, *p = NULL, *c2;
-
- if ((!context) || (!name))
- return ERROR_INVALID_ARGUMENTS;
-
- /* find command */
- for (c = context->commands; c; c = c->next)
- {
- if (strcmp(name, c->name) == 0)
- {
- /* unlink command */
- if (p)
- {
- p->next = c->next;
- }
- else
- {
- context->commands = c->next;
- }
-
- /* unregister children */
- if (c->children)
- {
- for (c2 = c->children; c2; c2 = c2->next)
- {
- free(c2->name);
- if (c2->help)
- free(c2->help);
- free(c2);
- }
- }
-
- /* delete command */
- free(c->name);
- if (c->help)
- free(c->help);
- free(c);
- }
-
- /* remember the last command for unlinking */
- p = c;
- }
-
- return ERROR_OK;
-}
-
-int parse_line(char *line, char *words[], int max_words)
-{
- int nwords = 0;
- char *p = line;
- char *word_start = line;
- int inquote = 0;
-
- while (nwords < max_words - 1)
- {
- /* check if we reached
- * a terminating NUL
- * a matching closing quote character " or '
- * we're inside a word but not a quote, and the current character is whitespace
- */
- if (!*p || *p == inquote || (word_start && !inquote && isspace(*p)))
- {
- /* we're inside a word or quote, and reached its end*/
- if (word_start)
- {
- int len;
- char *word_end=p;
-
- /* This will handle extra whitespace within quotes */
- while (isspace(*word_start)&&(word_start<word_end))
- word_start++;
- while (isspace(*(word_end-1))&&(word_start<word_end))
- word_end--;
- len = word_end - word_start;
-
- if (len>0)
- {
- /* copy the word */
- memcpy(words[nwords] = malloc(len + 1), word_start, len);
- /* add terminating NUL */
- words[nwords++][len] = 0;
- }
- }
- /* we're done parsing the line */
- if (!*p)
- break;
-
- /* skip over trailing quote or whitespace*/
- if (inquote || isspace(*p))
- p++;
- while (isspace(*p))
- p++;
-
- inquote = 0;
- word_start = 0;
- }
- else if (*p == '"' || *p == '\'')
- {
- /* we've reached the beginning of a quote */
- inquote = *p++;
- word_start = p;
- }
- else
- {
- /* we've reached the beginning of a new word */
- if (!word_start)
- word_start = p;
-
- /* normal character, skip */
- p++;
- }
- }
-
- return nwords;
-}
-
-void command_print(command_context_t *context, char *format, ...)
-{
- char *buffer = NULL;
- int n, size = 0;
- char *p;
-
- /* process format string */
- for (;;)
- {
- va_list ap;
- va_start(ap, format);
- if (!buffer || (n = vsnprintf(buffer, size, format, ap)) >= size)
- {
- /* increase buffer until it fits the whole string */
- if (!(p = realloc(buffer, size += 4096)))
- {
- /* gotta free up */
- if (buffer)
- free(buffer);
- va_end(ap);
- return;
- }
-
- buffer = p;
-
- va_end(ap);
- continue;
- }
- va_end(ap);
- break;
- }
-
- /* vsnprintf failed */
- if (n < 0)
- {
- if (buffer)
- free(buffer);
- return;
- }
-
- p = buffer;
-
- /* process lines in buffer */
- do {
- char *next = strchr(p, '\n');
-
- if (next)
- *next++ = 0;
-
- if (context->output_handler)
- context->output_handler(context, p);
-
- p = next;
- } while (p);
-
- if (buffer)
- free(buffer);
-}
-
-int find_and_run_command(command_context_t *context, command_t *commands, char *words[], int num_words, int start_word)
-{
- command_t *c;
-
- 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))
- 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");
- break;
- }
- 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);
- }
- return retval;
- }
- }
- else
- {
- if (start_word == num_words - 1)
- {
- command_print(context, "Incomplete command");
- break;
- }
- return find_and_run_command(context, c->children, words, num_words, start_word + 1);
- }
- }
- }
-
- command_print(context, "Command %s not found", words[start_word]);
- return ERROR_OK;
-}
-
-static int command_run_line_inner(command_context_t *context, char *line)
-{
- int nwords;
- char *words[128] = {0};
- int retval;
- int i;
-
- if ((!context) || (!line))
- return ERROR_INVALID_ARGUMENTS;
-
- /* skip preceding whitespace */
- while (isspace(*line))
- line++;
-
- /* empty line, ignore */
- if (!*line)
- return ERROR_OK;
-
- /* ignore comments */
- if (*line && (line[0] == '#'))
- return ERROR_OK;
-
- if (context->echo)
- {
- command_print(context, "%s", 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);
- else
- return ERROR_INVALID_ARGUMENTS;
-
- for (i = 0; i < nwords; i++)
- free(words[i]);
-
- return retval;
-}
-
-int command_run_line(command_context_t *context, char *line)
-{
- int retval=command_run_line_inner(context, line);
- // we don't want any dangling callbacks!
- //
- // Capturing output from logging is *very* loosly modeled on C/C++ exceptions.
- // the capture must be set up at function entry and
- // stops when the function call returns
- log_setCallback(NULL, NULL);
- return retval;
-}
-int command_run_file(command_context_t *context, FILE *file, enum command_mode mode)
-{
- 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;
-
- /* 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_inner(context, cmd)) == ERROR_COMMAND_CLOSE_CONNECTION)
- break;
- }
-
- context->mode = old_command_mode;
-
-
- free(buffer);
-
- return retval;
-}
-
-void command_print_help_line(command_context_t* context, struct command_s *command, int indent)
-{
- command_t *c;
- char indents[32] = {0};
- char *help = "no help available";
- char name_buf[64];
- int i;
-
- for (i = 0; i < indent; i+=2)
- {
- indents[i*2] = ' ';
- indents[i*2+1] = '-';
- }
- indents[i*2] = 0;
-
- if (command->help)
- help = command->help;
-
- snprintf(name_buf, 64, command->name);
- strncat(name_buf, indents, 64);
- command_print(context, "%20s\t%s", name_buf, help);
-
- if (command->children)
- {
- for (c = command->children; c; c = c->next)
- {
- command_print_help_line(context, c, indent + 1);
- }
- }
-}
-
-int command_print_help(command_context_t* context, char* name, char** args, int argc)
-{
- command_t *c;
-
- for (c = context->commands; c; c = c->next)
- {
- if (argc == 1)
- {
- if (strncasecmp(c->name, args[0], c->unique_len))
- continue;
-
- if (strncasecmp(c->name, args[0], strlen(args[0])))
- continue;
- }
-
- command_print_help_line(context, c, 0);
- }
-
- return ERROR_OK;
-}
-
-void command_set_output_handler(command_context_t* context, int (*output_handler)(struct command_context_s *context, char* line), void *priv)
-{
- context->output_handler = output_handler;
- context->output_handler_priv = priv;
-}
-
-command_context_t* copy_command_context(command_context_t* context)
-{
- command_context_t* copy_context = malloc(sizeof(command_context_t));
-
- *copy_context = *context;
-
- return copy_context;
-}
-
-int command_done(command_context_t *context)
-{
- free(context);
- context = NULL;
-
- return ERROR_OK;
-}
-
-command_context_t* command_init()
-{
- command_context_t* context = malloc(sizeof(command_context_t));
-
- context->mode = COMMAND_EXEC;
- context->commands = NULL;
- context->current_target = 0;
- context->echo = 0;
- context->output_handler = NULL;
- context->output_handler_priv = NULL;
-
- register_command(context, NULL, "help", command_print_help,
- COMMAND_EXEC, "display this help");
-
- register_command(context, NULL, "sleep", handle_sleep_command,
- COMMAND_ANY, "sleep for <n> milliseconds");
-
- register_command(context, NULL, "time", handle_time_command,
- COMMAND_ANY, "time <cmd + args> - execute <cmd + args> and print time it took");
-
- return context;
-}
-
-/* sleep command sleeps for <n> miliseconds
- * this is useful in target startup scripts
- */
-int handle_sleep_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- unsigned long duration = 0;
-
- if (argc == 1)
- {
- duration = strtoul(args[0], NULL, 0);
- usleep(duration * 1000);
- }
-
- return ERROR_OK;
-}
-
-int handle_time_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- if (argc<1)
- return ERROR_COMMAND_SYNTAX_ERROR;
-
- duration_t duration;
- char *duration_text;
- int retval;
-
- duration_start_measure(&duration);
-
- retval = find_and_run_command(cmd_ctx, cmd_ctx->commands, args, argc, 0);
-
- duration_stop_measure(&duration, &duration_text);
-
- float t=duration.duration.tv_sec;
- t+=((float)duration.duration.tv_usec / 1000000.0);
- command_print(cmd_ctx, "%s took %fs", args[0], t);
-
- free(duration_text);
-
- return retval;
-}
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * part of this file is taken from libcli (libcli.sourceforge.net) *
+ * Copyright (C) David Parrish (david@dparrish.com) *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "replacements.h"
+
+#include "command.h"
+
+#include "log.h"
+#include "time_support.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <unistd.h>
+
+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 build_unique_lengths(command_context_t *context, command_t *commands)
+{
+ command_t *c, *p;
+
+ /* 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 = malloc(sizeof(command_t));
+
+ c->name = strdup(name);
+ c->parent = parent;
+ c->children = NULL;
+ c->handler = handler;
+ c->mode = mode;
+ if (help)
+ c->help = strdup(help);
+ else
+ c->help = NULL;
+ c->unique_len = 0;
+ c->next = NULL;
+
+ /* place command in tree */
+ if (parent)
+ {
+ if (parent->children)
+ {
+ /* find last child */
+ for (p = parent->children; p && p->next; p = p->next);
+ if (p)
+ p->next = c;
+ }
+ else
+ {
+ parent->children = c;
+ }
+ }
+ else
+ {
+ if (context->commands)
+ {
+ /* find last command */
+ for (p = context->commands; p && p->next; p = p->next);
+ if (p)
+ p->next = c;
+ }
+ else
+ {
+ context->commands = c;
+ }
+ }
+
+ return c;
+}
+
+int unregister_command(command_context_t *context, char *name)
+{
+ unique_length_dirty = 1;
+
+ command_t *c, *p = NULL, *c2;
+
+ if ((!context) || (!name))
+ return ERROR_INVALID_ARGUMENTS;
+
+ /* find command */
+ for (c = context->commands; c; c = c->next)
+ {
+ if (strcmp(name, c->name) == 0)
+ {
+ /* unlink command */
+ if (p)
+ {
+ p->next = c->next;
+ }
+ else
+ {
+ context->commands = c->next;
+ }
+
+ /* unregister children */
+ if (c->children)
+ {
+ for (c2 = c->children; c2; c2 = c2->next)
+ {
+ free(c2->name);
+ if (c2->help)
+ free(c2->help);
+ free(c2);
+ }
+ }
+
+ /* delete command */
+ free(c->name);
+ if (c->help)
+ free(c->help);
+ free(c);
+ }
+
+ /* remember the last command for unlinking */
+ p = c;
+ }
+
+ return ERROR_OK;
+}
+
+int parse_line(char *line, char *words[], int max_words)
+{
+ int nwords = 0;
+ char *p = line;
+ char *word_start = line;
+ int inquote = 0;
+
+ while (nwords < max_words - 1)
+ {
+ /* check if we reached
+ * a terminating NUL
+ * a matching closing quote character " or '
+ * we're inside a word but not a quote, and the current character is whitespace
+ */
+ if (!*p || *p == inquote || (word_start && !inquote && isspace(*p)))
+ {
+ /* we're inside a word or quote, and reached its end*/
+ if (word_start)
+ {
+ int len;
+ char *word_end=p;
+
+ /* This will handle extra whitespace within quotes */
+ while (isspace(*word_start)&&(word_start<word_end))
+ word_start++;
+ while (isspace(*(word_end-1))&&(word_start<word_end))
+ word_end--;
+ len = word_end - word_start;
+
+ if (len>0)
+ {
+ /* copy the word */
+ memcpy(words[nwords] = malloc(len + 1), word_start, len);
+ /* add terminating NUL */
+ words[nwords++][len] = 0;
+ }
+ }
+ /* we're done parsing the line */
+ if (!*p)
+ break;
+
+ /* skip over trailing quote or whitespace*/
+ if (inquote || isspace(*p))
+ p++;
+ while (isspace(*p))
+ p++;
+
+ inquote = 0;
+ word_start = 0;
+ }
+ else if (*p == '"' || *p == '\'')
+ {
+ /* we've reached the beginning of a quote */
+ inquote = *p++;
+ word_start = p;
+ }
+ else
+ {
+ /* we've reached the beginning of a new word */
+ if (!word_start)
+ word_start = p;
+
+ /* normal character, skip */
+ p++;
+ }
+ }
+
+ return nwords;
+}
+
+void command_print(command_context_t *context, char *format, ...)
+{
+ char *buffer = NULL;
+ int n, size = 0;
+ char *p;
+
+ /* process format string */
+ for (;;)
+ {
+ va_list ap;
+ va_start(ap, format);
+ if (!buffer || (n = vsnprintf(buffer, size, format, ap)) >= size)
+ {
+ /* increase buffer until it fits the whole string */
+ if (!(p = realloc(buffer, size += 4096)))
+ {
+ /* gotta free up */
+ if (buffer)
+ free(buffer);
+ va_end(ap);
+ return;
+ }
+
+ buffer = p;
+
+ va_end(ap);
+ continue;
+ }
+ va_end(ap);
+ break;
+ }
+
+ /* vsnprintf failed */
+ if (n < 0)
+ {
+ if (buffer)
+ free(buffer);
+ return;
+ }
+
+ p = buffer;
+
+ /* process lines in buffer */
+ do {
+ char *next = strchr(p, '\n');
+
+ if (next)
+ *next++ = 0;
+
+ if (context->output_handler)
+ context->output_handler(context, p);
+
+ p = next;
+ } while (p);
+
+ if (buffer)
+ free(buffer);
+}
+
+int find_and_run_command(command_context_t *context, command_t *commands, char *words[], int num_words, int start_word)
+{
+ command_t *c;
+
+ 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))
+ 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");
+ break;
+ }
+ 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);
+ }
+ return retval;
+ }
+ }
+ else
+ {
+ if (start_word == num_words - 1)
+ {
+ command_print(context, "Incomplete command");
+ break;
+ }
+ return find_and_run_command(context, c->children, words, num_words, start_word + 1);
+ }
+ }
+ }
+
+ command_print(context, "Command %s not found", words[start_word]);
+ return ERROR_OK;
+}
+
+int command_run_line(command_context_t *context, char *line)
+{
+ int nwords;
+ char *words[128] = {0};
+ int retval;
+ int i;
+
+ if ((!context) || (!line))
+ return ERROR_INVALID_ARGUMENTS;
+
+ /* skip preceding whitespace */
+ while (isspace(*line))
+ line++;
+
+ /* empty line, ignore */
+ if (!*line)
+ return ERROR_OK;
+
+ /* ignore comments */
+ if (*line && (line[0] == '#'))
+ return ERROR_OK;
+
+ if (context->echo)
+ {
+ command_print(context, "%s", 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);
+ else
+ return ERROR_INVALID_ARGUMENTS;
+
+ for (i = 0; i < nwords; i++)
+ free(words[i]);
+
+ return retval;
+}
+
+int command_run_file(command_context_t *context, FILE *file, enum command_mode mode)
+{
+ 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;
+
+ /* 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;
+ }
+
+ context->mode = old_command_mode;
+
+
+ free(buffer);
+
+ return retval;
+}
+
+void command_print_help_line(command_context_t* context, struct command_s *command, int indent)
+{
+ command_t *c;
+ char indents[32] = {0};
+ char *help = "no help available";
+ char name_buf[64];
+ int i;
+
+ for (i = 0; i < indent; i+=2)
+ {
+ indents[i*2] = ' ';
+ indents[i*2+1] = '-';
+ }
+ indents[i*2] = 0;
+
+ if (command->help)
+ help = command->help;
+
+ snprintf(name_buf, 64, command->name);
+ strncat(name_buf, indents, 64);
+ command_print(context, "%20s\t%s", name_buf, help);
+
+ if (command->children)
+ {
+ for (c = command->children; c; c = c->next)
+ {
+ command_print_help_line(context, c, indent + 1);
+ }
+ }
+}
+
+int command_print_help(command_context_t* context, char* name, char** args, int argc)
+{
+ command_t *c;
+
+ for (c = context->commands; c; c = c->next)
+ {
+ if (argc == 1)
+ {
+ if (strncasecmp(c->name, args[0], c->unique_len))
+ continue;
+
+ if (strncasecmp(c->name, args[0], strlen(args[0])))
+ continue;
+ }
+
+ command_print_help_line(context, c, 0);
+ }
+
+ return ERROR_OK;
+}
+
+void command_set_output_handler(command_context_t* context, int (*output_handler)(struct command_context_s *context, char* line), void *priv)
+{
+ context->output_handler = output_handler;
+ context->output_handler_priv = priv;
+}
+
+command_context_t* copy_command_context(command_context_t* context)
+{
+ command_context_t* copy_context = malloc(sizeof(command_context_t));
+
+ *copy_context = *context;
+
+ return copy_context;
+}
+
+int command_done(command_context_t *context)
+{
+ free(context);
+ context = NULL;
+
+ return ERROR_OK;
+}
+
+command_context_t* command_init()
+{
+ command_context_t* context = malloc(sizeof(command_context_t));
+
+ context->mode = COMMAND_EXEC;
+ context->commands = NULL;
+ context->current_target = 0;
+ context->echo = 0;
+ context->output_handler = NULL;
+ context->output_handler_priv = NULL;
+
+ register_command(context, NULL, "help", command_print_help,
+ COMMAND_EXEC, "display this help");
+
+ register_command(context, NULL, "sleep", handle_sleep_command,
+ COMMAND_ANY, "sleep for <n> milliseconds");
+
+ register_command(context, NULL, "time", handle_time_command,
+ COMMAND_ANY, "time <cmd + args> - execute <cmd + args> and print time it took");
+
+ return context;
+}
+
+/* sleep command sleeps for <n> miliseconds
+ * this is useful in target startup scripts
+ */
+int handle_sleep_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ unsigned long duration = 0;
+
+ if (argc == 1)
+ {
+ duration = strtoul(args[0], NULL, 0);
+ usleep(duration * 1000);
+ }
+
+ return ERROR_OK;
+}
+
+int handle_time_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ if (argc<1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ duration_t duration;
+ char *duration_text;
+ int retval;
+
+ duration_start_measure(&duration);
+
+ retval = find_and_run_command(cmd_ctx, cmd_ctx->commands, args, argc, 0);
+
+ duration_stop_measure(&duration, &duration_text);
+
+ float t=duration.duration.tv_sec;
+ t+=((float)duration.duration.tv_usec / 1000000.0);
+ command_print(cmd_ctx, "%s took %fs", args[0], t);
+
+ free(duration_text);
+
+ return retval;
+}
diff --git a/src/helper/log.c b/src/helper/log.c
index 8567c037..90077ea3 100644
--- a/src/helper/log.c
+++ b/src/helper/log.c
@@ -33,18 +33,11 @@
int debug_level = -1;
static FILE* log_output;
+static log_callback_t *log_callbacks = NULL;
-static void *privData;
-static logCallback callback;
static time_t start;
-void log_setCallback(logCallback c, void *p)
-{
- callback = c;
- privData = p;
-}
-
-static char *log_strings[5] =
+static char *log_strings[5] =
{
"User: ",
"Error: ",
@@ -59,12 +52,22 @@ void log_printf(enum log_levels level, const char *file, int line, const char *f
count++;
va_list args;
char buffer[512];
+ log_callback_t *cb;
if (level > debug_level)
return;
va_start(args, format);
vsnprintf(buffer, 512, format, args);
+ va_end(args);
+
+ if (level == LOG_OUTPUT)
+ {
+ /* do not prepend any headers, just print out what we were given and return */
+ fputs(buffer, log_output);
+ fflush(log_output);
+ return;
+ }
char *f = strrchr(file, '/');
if (f != NULL)
@@ -84,14 +87,15 @@ void log_printf(enum log_levels level, const char *file, int line, const char *f
fflush(log_output);
- va_end(args);
-
/* Never forward LOG_DEBUG, too verbose and they can be found in the log if need be */
- if (callback && (level <= LOG_INFO))
+ if (level <= LOG_INFO)
{
- va_start(args, format);
- callback(privData, file, line, function, format, args);
- va_end(args);
+ for (cb = log_callbacks; cb; cb = cb->next)
+ {
+ va_start(args, format);
+ cb->fn(cb->priv, file, line, function, format, args);
+ va_end(args);
+ }
}
}
@@ -164,8 +168,51 @@ int set_log_output(struct command_context_s *cmd_ctx, FILE *output)
return ERROR_OK;
}
+/* add/remove log callback handler */
+int log_add_callback(log_callback_fn fn, void *priv)
+{
+ log_callback_t *cb;
+
+ /* prevent the same callback to be registered more than once, just for sure */
+ for (cb = log_callbacks; cb; cb = cb->next)
+ {
+ if (cb->fn == fn && cb->priv == priv)
+ return ERROR_INVALID_ARGUMENTS;
+ }
+
+ /* alloc memory, it is safe just to return in case of an error, no need for the caller to check this */
+ if ((cb = malloc(sizeof(log_callback_t))) == NULL)
+ return ERROR_BUF_TOO_SMALL;
+
+ /* add item to the beginning of the linked list */
+ cb->fn = fn;
+ cb->priv = priv;
+ cb->next = log_callbacks;
+ log_callbacks = cb;
+
+ return ERROR_OK;
+}
+
+int log_remove_callback(log_callback_fn fn, void *priv)
+{
+ log_callback_t *cb, **p;
+
+ for (p = &log_callbacks; cb = *p; p = &(*p)->next)
+ {
+ if (cb->fn == fn && cb->priv == priv)
+ {
+ *p = cb->next;
+ free(cb);
+ return ERROR_OK;
+ }
+ }
+
+ /* no such item */
+ return ERROR_INVALID_ARGUMENTS;
+}
+
/* return allocated string w/printf() result */
-char *allocPrintf(const char *fmt, va_list ap)
+char *alloc_printf(const char *fmt, va_list ap)
{
char *string = NULL;
diff --git a/src/helper/log.h b/src/helper/log.h
index ab32760a..61050009 100644
--- a/src/helper/log.h
+++ b/src/helper/log.h
@@ -1,99 +1,113 @@
-/***************************************************************************
- * Copyright (C) 2005 by Dominic Rath *
- * Dominic.Rath@gmx.de *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the *
- * Free Software Foundation, Inc., *
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
- ***************************************************************************/
-#ifndef ERROR_H
-#define ERROR_H
-
-#include "replacements.h"
-#include "command.h"
-
-#include <stdarg.h>
-
-/* logging priorities
- * LOG_USER - user messages. Could be anything from information
- * to progress messags. These messages do not represent
- * incorrect or unexpected behaviour, just normal execution.
- * LOG_ERROR - fatal errors, that are likely to cause program abort
- * LOG_WARNING - non-fatal errors, that may be resolved later
- * LOG_INFO - state information, etc.
- * LOG_DEBUG - debug statements, execution trace
- */
-enum log_levels
-{
- LOG_USER = -1,
- LOG_ERROR = 0,
- LOG_WARNING = 1,
- LOG_INFO = 2,
- LOG_DEBUG = 3
-};
-
-extern void log_printf(enum log_levels level, const char *file, int line,
- const char *function, const char *format, ...)
- __attribute__ ((format (printf, 5, 6)));
-extern int log_register_commands(struct command_context_s *cmd_ctx);
-extern int log_init(struct command_context_s *cmd_ctx);
-extern int set_log_output(struct command_context_s *cmd_ctx, FILE *output);
-
-typedef void (*logCallback)(void *priv, const char *file, int line,
- const char *function, const char *format, va_list args);
-
-extern void log_setCallback(logCallback callback, void *priv);
-
-extern int debug_level;
-
-/* Avoid fn call and building parameter list if we're not outputting the information.
- * Matters on feeble CPUs for DEBUG/INFO statements that are involved frequently */
-
-#define DEBUG(expr ...) \
- do { if (debug_level >= LOG_DEBUG) \
- log_printf (LOG_DEBUG, __FILE__, __LINE__, __FUNCTION__, expr); \
- } while(0)
-
-#define INFO(expr ...) \
- do { if (debug_level >= LOG_INFO) \
- log_printf (LOG_INFO, __FILE__, __LINE__, __FUNCTION__, expr); \
- } while(0)
-
-#define WARNING(expr ...) \
- do { \
- log_printf (LOG_WARNING, __FILE__, __LINE__, __FUNCTION__, expr); \
- } while(0)
-
-#define ERROR(expr ...) \
- do { \
- log_printf (LOG_ERROR, __FILE__, __LINE__, __FUNCTION__, expr); \
- } while(0)
-
-#define USER(expr ...) \
- do { \
- log_printf (LOG_USER, __FILE__, __LINE__, __FUNCTION__, expr); \
- } while(0)
-
-
-/* general failures
- * error codes < 100
- */
-#define ERROR_OK (0)
-#define ERROR_INVALID_ARGUMENTS (-1)
-#define ERROR_NO_CONFIG_FILE (-2)
-#define ERROR_BUF_TOO_SMALL (-3)
-
-char *allocPrintf(const char *fmt, va_list ap);
-
-#endif /* LOG_H */
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef ERROR_H
+#define ERROR_H
+
+#include "replacements.h"
+#include "command.h"
+
+#include <stdarg.h>
+
+/* logging priorities
+ * LOG_USER - user messages. Could be anything from information
+ * to progress messags. These messages do not represent
+ * incorrect or unexpected behaviour, just normal execution.
+ * LOG_ERROR - fatal errors, that are likely to cause program abort
+ * LOG_WARNING - non-fatal errors, that may be resolved later
+ * LOG_INFO - state information, etc.
+ * LOG_DEBUG - debug statements, execution trace
+ */
+enum log_levels
+{
+ LOG_OUTPUT = -2,
+ LOG_USER = -1,
+ LOG_ERROR = 0,
+ LOG_WARNING = 1,
+ LOG_INFO = 2,
+ LOG_DEBUG = 3
+};
+
+extern void log_printf(enum log_levels level, const char *file, int line,
+ const char *function, const char *format, ...)
+ __attribute__ ((format (printf, 5, 6)));
+extern int log_register_commands(struct command_context_s *cmd_ctx);
+extern int log_init(struct command_context_s *cmd_ctx);
+extern int set_log_output(struct command_context_s *cmd_ctx, FILE *output);
+
+typedef void (*log_callback_fn)(void *priv, const char *file, int line,
+ const char *function, const char *format, va_list args);
+
+typedef struct log_callback_s
+{
+ log_callback_fn fn;
+ void *priv;
+ struct log_callback_s *next;
+} log_callback_t;
+
+extern int log_add_callback(log_callback_fn fn, void *priv);
+extern int log_remove_callback(log_callback_fn fn, void *priv);
+
+char *alloc_printf(const char *fmt, va_list ap);
+
+extern int debug_level;
+
+/* Avoid fn call and building parameter list if we're not outputting the information.
+ * Matters on feeble CPUs for DEBUG/INFO statements that are involved frequently */
+
+#define DEBUG(expr ...) \
+ do { if (debug_level >= LOG_DEBUG) \
+ log_printf (LOG_DEBUG, __FILE__, __LINE__, __FUNCTION__, expr); \
+ } while(0)
+
+#define INFO(expr ...) \
+ do { if (debug_level >= LOG_INFO) \
+ log_printf (LOG_INFO, __FILE__, __LINE__, __FUNCTION__, expr); \
+ } while(0)
+
+#define WARNING(expr ...) \
+ do { \
+ log_printf (LOG_WARNING, __FILE__, __LINE__, __FUNCTION__, expr); \
+ } while(0)
+
+#define ERROR(expr ...) \
+ do { \
+ log_printf (LOG_ERROR, __FILE__, __LINE__, __FUNCTION__, expr); \
+ } while(0)
+
+#define USER(expr ...) \
+ do { \
+ log_printf (LOG_USER, __FILE__, __LINE__, __FUNCTION__, expr); \
+ } while(0)
+
+#define OUTPUT(expr ...) \
+ do { \
+ log_printf (LOG_OUTPUT, __FILE__, __LINE__, __FUNCTION__, expr); \
+ } while(0)
+
+
+/* general failures
+ * error codes < 100
+ */
+#define ERROR_OK (0)
+#define ERROR_INVALID_ARGUMENTS (-1)
+#define ERROR_NO_CONFIG_FILE (-2)
+#define ERROR_BUF_TOO_SMALL (-3)
+
+#endif /* LOG_H */
diff --git a/src/helper/options.c b/src/helper/options.c
index 1e717be8..4232cb44 100644
--- a/src/helper/options.c
+++ b/src/helper/options.c
@@ -113,13 +113,13 @@ int parse_cmdline_args(struct command_context_s *cmd_ctx, int argc, char *argv[]
if (help_flag)
{
- printf("Open On-Chip Debugger\n(c) 2005 by Dominic Rath\n\n");
- printf("--help | -h\tdisplay this help\n");
- printf("--file | -f\tuse configuration file <name>\n");
- printf("--search | -s\tdir to search for config files and scripts.\n");
- printf("--debug | -d\tset debug level <0-3>\n");
- printf("--log_output | -l\tredirect log output to file <name>\n");
- printf("--command | -c\trun <command>\n");
+ OUTPUT("Open On-Chip Debugger\n(c) 2005 by Dominic Rath\n\n");
+ OUTPUT("--help | -h\tdisplay this help\n");
+ OUTPUT("--file | -f\tuse configuration file <name>\n");
+ OUTPUT("--search | -s\tdir to search for config files and scripts.\n");
+ OUTPUT("--debug | -d\tset debug level <0-3>\n");
+ OUTPUT("--log_output | -l\tredirect log output to file <name>\n");
+ OUTPUT("--command | -c\trun <command>\n");
exit(-1);
}