- convert all files to unix line-ending
[fw/openocd] / src / helper / command.c
index f13a86c15da1e2f5928f1f1a589642c981612ff0..15cddcdc40d197650a8896d934f14b9c7a8e22d9 100644 (file)
-/***************************************************************************\r
- *   Copyright (C) 2005 by Dominic Rath                                    *\r
- *   Dominic.Rath@gmx.de                                                   *\r
- *                                                                         *\r
- *   part of this file is taken from libcli (libcli.sourceforge.net)       *\r
- *   Copyright (C) David Parrish (david@dparrish.com)                      *\r
- *                                                                         *\r
- *   This program is free software; you can redistribute it and/or modify  *\r
- *   it under the terms of the GNU General Public License as published by  *\r
- *   the Free Software Foundation; either version 2 of the License, or     *\r
- *   (at your option) any later version.                                   *\r
- *                                                                         *\r
- *   This program is distributed in the hope that it will be useful,       *\r
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\r
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\r
- *   GNU General Public License for more details.                          *\r
- *                                                                         *\r
- *   You should have received a copy of the GNU General Public License     *\r
- *   along with this program; if not, write to the                         *\r
- *   Free Software Foundation, Inc.,                                       *\r
- *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *\r
- ***************************************************************************/\r
-#ifdef HAVE_CONFIG_H\r
-#include "config.h"\r
-#endif\r
-\r
-#include "replacements.h"\r
-\r
-#include "command.h"\r
-\r
-#include "log.h"\r
-#include "time_support.h"\r
-\r
-#include <stdlib.h>\r
-#include <string.h>\r
-#include <ctype.h>\r
-#include <stdarg.h>\r
-#include <stdio.h>\r
-#include <unistd.h>\r
-\r
-void command_print_help_line(command_context_t* context, struct command_s *command, int indent);\r
-\r
-int handle_sleep_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
-int handle_time_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
-\r
-int build_unique_lengths(command_context_t *context, command_t *commands)\r
-{\r
-       command_t *c, *p;\r
-\r
-       /* iterate through all commands */\r
-       for (c = commands; c; c = c->next)\r
-       {\r
-               /* find out how many characters are required to uniquely identify a command */\r
-               for (c->unique_len = 1; c->unique_len <= strlen(c->name); c->unique_len++)\r
-               {\r
-                       int foundmatch = 0;\r
-                       \r
-                       /* for every command, see if the current length is enough */\r
-                       for (p = commands; p; p = p->next)\r
-                       {\r
-                               /* ignore the command itself */\r
-                               if (c == p)\r
-                                       continue;\r
-                               \r
-                               /* compare commands up to the current length */\r
-                               if (strncmp(p->name, c->name, c->unique_len) == 0)\r
-                                       foundmatch++;\r
-                       }\r
-                       \r
-                       /* when none of the commands matched, we've found the minimum length required */\r
-                       if (!foundmatch)\r
-                               break;\r
-               }\r
-               \r
-               /* if the current command has children, build the unique lengths for them */\r
-               if (c->children)\r
-                       build_unique_lengths(context, c->children);\r
-       }\r
-       \r
-       return ERROR_OK;\r
-}\r
-\r
-/* Avoid evaluating this each time we add a command. Reduces overhead from O(n^2) to O(n). \r
- * Makes a difference on ARM7 types machines and is not observable on GHz machines.\r
- */\r
-static int unique_length_dirty = 1; \r
-\r
-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)\r
-{\r
-       command_t *c, *p;\r
-       unique_length_dirty = 1;\r
-       \r
-       if (!context || !name)\r
-               return NULL;\r
-                               \r
-       c = malloc(sizeof(command_t));\r
-       \r
-       c->name = strdup(name);\r
-       c->parent = parent;\r
-       c->children = NULL;\r
-       c->handler = handler;\r
-       c->mode = mode;\r
-       if (help)\r
-               c->help = strdup(help);\r
-       else\r
-               c->help = NULL;\r
-       c->unique_len = 0;\r
-       c->next = NULL;\r
-       \r
-       /* place command in tree */\r
-       if (parent)\r
-       {\r
-               if (parent->children)\r
-               {\r
-                       /* find last child */\r
-                       for (p = parent->children; p && p->next; p = p->next);\r
-                       if (p)\r
-                               p->next = c;\r
-               }\r
-               else\r
-               {\r
-                       parent->children = c;\r
-               }\r
-       }\r
-       else\r
-       {\r
-               if (context->commands)\r
-               {\r
-                       /* find last command */\r
-                       for (p = context->commands; p && p->next; p = p->next);\r
-                       if (p)\r
-                               p->next = c;\r
-               }\r
-               else\r
-               {\r
-                       context->commands = c;\r
-               }\r
-       }\r
-       \r
-       return c;\r
-}\r
-\r
-int unregister_command(command_context_t *context, char *name)\r
-{\r
-       unique_length_dirty = 1;\r
-       \r
-       command_t *c, *p = NULL, *c2;\r
-       \r
-       if ((!context) || (!name))\r
-               return ERROR_INVALID_ARGUMENTS;\r
-       \r
-       /* find command */\r
-       for (c = context->commands; c; c = c->next)\r
-       {\r
-               if (strcmp(name, c->name) == 0)\r
-               {\r
-                       /* unlink command */\r
-                       if (p)\r
-                       {\r
-                               p->next = c->next;\r
-                       }\r
-                       else\r
-                       {\r
-                               context->commands = c->next;\r
-                       }\r
-                       \r
-                       /* unregister children */\r
-                       if (c->children)\r
-                       {\r
-                               for (c2 = c->children; c2; c2 = c2->next)\r
-                               {\r
-                                       free(c2->name);\r
-                                       if (c2->help)\r
-                                               free(c2->help);\r
-                                       free(c2);\r
-                               }\r
-                       }\r
-                       \r
-                       /* delete command */\r
-                       free(c->name);\r
-                       if (c->help)\r
-                               free(c->help);\r
-                       free(c);\r
-               }\r
-               \r
-               /* remember the last command for unlinking */\r
-               p = c;\r
-       }\r
-       \r
-       return ERROR_OK;\r
-}\r
-\r
-int parse_line(char *line, char *words[], int max_words)\r
-{\r
-       int nwords = 0;\r
-       char *p = line;\r
-       char *word_start = line;\r
-       int inquote = 0;\r
-\r
-       while (nwords < max_words - 1)\r
-       {\r
-               /* check if we reached\r
-                * a terminating NUL\r
-                * a matching closing quote character " or '\r
-                * we're inside a word but not a quote, and the current character is whitespace\r
-                */\r
-               if (!*p || *p == inquote || (word_start && !inquote && isspace(*p)))\r
-               {\r
-                       /* we're inside a word or quote, and reached its end*/\r
-                       if (word_start)\r
-                       {\r
-                               int len;\r
-                               char *word_end=p;\r
-                               \r
-                               /* This will handle extra whitespace within quotes */\r
-                               while (isspace(*word_start)&&(word_start<word_end))\r
-                                       word_start++;\r
-                               while (isspace(*(word_end-1))&&(word_start<word_end))\r
-                                       word_end--;\r
-                               len = word_end - word_start;\r
-                               \r
-                               if (len>0)\r
-                               {\r
-                                       /* copy the word */\r
-                                       memcpy(words[nwords] = malloc(len + 1), word_start, len);\r
-                                       /* add terminating NUL */\r
-                                       words[nwords++][len] = 0;\r
-                               }\r
-                       }\r
-                       /* we're done parsing the line */\r
-                       if (!*p)\r
-                               break;\r
-\r
-                       /* skip over trailing quote or whitespace*/\r
-                       if (inquote || isspace(*p))\r
-                               p++;\r
-                       while (isspace(*p))\r
-                               p++;\r
-                       \r
-                       inquote = 0;\r
-                       word_start = 0;\r
-               }\r
-               else if (*p == '"' || *p == '\'')\r
-               {\r
-                       /* we've reached the beginning of a quote */\r
-                       inquote = *p++;\r
-                       word_start = p;\r
-               }\r
-               else\r
-               {\r
-                       /* we've reached the beginning of a new word */\r
-                       if (!word_start)\r
-                               word_start = p;\r
-                       \r
-                       /* normal character, skip */\r
-                       p++;\r
-               }\r
-       }\r
-       \r
-       return nwords;\r
-}\r
-\r
-void command_print(command_context_t *context, char *format, ...)\r
-{\r
-       char *buffer = NULL;\r
-       int n, size = 0;\r
-       char *p;\r
-\r
-       /* process format string */\r
-       for (;;)\r
-       {\r
-               va_list ap;\r
-               va_start(ap, format);\r
-               if (!buffer || (n = vsnprintf(buffer, size, format, ap)) >= size)\r
-               {\r
-                       /* increase buffer until it fits the whole string */\r
-                       if (!(p = realloc(buffer, size += 4096)))\r
-                       {\r
-                               /* gotta free up */\r
-                               if (buffer)\r
-                                       free(buffer);\r
-                               va_end(ap);\r
-                               return;\r
-                       }\r
-       \r
-                       buffer = p;\r
-                       \r
-                       va_end(ap);\r
-                       continue;\r
-               }\r
-               va_end(ap);\r
-               break;\r
-       }\r
-       \r
-       /* vsnprintf failed */\r
-       if (n < 0)\r
-       {\r
-               if (buffer)\r
-                       free(buffer);\r
-               return;\r
-       }\r
-\r
-       p = buffer;\r
-       \r
-       /* process lines in buffer */\r
-       do {\r
-               char *next = strchr(p, '\n');\r
-               \r
-               if (next)\r
-                       *next++ = 0;\r
-\r
-               if (context->output_handler)\r
-                       context->output_handler(context, p);\r
-\r
-               p = next;\r
-       } while (p);\r
-       \r
-       if (buffer)\r
-               free(buffer);\r
-}\r
-\r
-int find_and_run_command(command_context_t *context, command_t *commands, char *words[], int num_words, int start_word)\r
-{\r
-       command_t *c;\r
-       \r
-       if (unique_length_dirty)\r
-       {\r
-               unique_length_dirty = 0;\r
-               /* update unique lengths */\r
-               build_unique_lengths(context, context->commands);\r
-       }\r
-       \r
-       for (c = commands; c; c = c->next)\r
-       {\r
-               if (strncasecmp(c->name, words[start_word], c->unique_len))\r
-                       continue;\r
-\r
-               if (strncasecmp(c->name, words[start_word], strlen(words[start_word])))\r
-                       continue;\r
-               \r
-               if ((context->mode == COMMAND_CONFIG) || (c->mode == COMMAND_ANY) || (c->mode == context->mode) )\r
-               {\r
-                       if (!c->children)\r
-                       {\r
-                               if (!c->handler)\r
-                               {\r
-                                       command_print(context, "No handler for command");\r
-                                       break;\r
-                               }\r
-                               else\r
-                               {\r
-                                       int retval = c->handler(context, c->name, words + start_word + 1, num_words - start_word - 1);\r
-                                       if (retval == ERROR_COMMAND_SYNTAX_ERROR)\r
-                                       {\r
-                                               command_print(context, "Syntax error:");\r
-                                               command_print_help_line(context, c, 0);\r
-                                       }\r
-                                       return retval; \r
-                               }\r
-                       }\r
-                       else\r
-                       {\r
-                               if (start_word == num_words - 1)\r
-                               {\r
-                                       command_print(context, "Incomplete command");\r
-                                       break;\r
-                               }\r
-                               return find_and_run_command(context, c->children, words, num_words, start_word + 1);\r
-                       }\r
-               }\r
-       }\r
-       \r
-       command_print(context, "Command %s not found", words[start_word]);\r
-       return ERROR_OK;\r
-}\r
-\r
-int command_run_line(command_context_t *context, char *line)\r
-{\r
-       int nwords;\r
-       char *words[128] = {0};\r
-       int retval;\r
-       int i;\r
-       \r
-       if ((!context) || (!line))\r
-               return ERROR_INVALID_ARGUMENTS;\r
-       \r
-       /* skip preceding whitespace */\r
-       while (isspace(*line))\r
-               line++;\r
-       \r
-       /* empty line, ignore */\r
-       if (!*line)\r
-               return ERROR_OK;\r
-       \r
-       /* ignore comments */\r
-       if (*line && (line[0] == '#'))\r
-               return ERROR_OK;\r
-       \r
-       if (context->echo)\r
-       {\r
-               command_print(context, "%s", line);\r
-       }\r
-\r
-       nwords = parse_line(line, words, sizeof(words) / sizeof(words[0]));\r
-       \r
-       if (nwords > 0)\r
-               retval = find_and_run_command(context, context->commands, words, nwords, 0);\r
-       else\r
-               return ERROR_INVALID_ARGUMENTS;\r
-       \r
-       for (i = 0; i < nwords; i++)\r
-               free(words[i]);\r
-       \r
-       return retval;\r
-}\r
-\r
-int command_run_file(command_context_t *context, FILE *file, enum command_mode mode)\r
-{\r
-       int retval = ERROR_OK;\r
-       int old_command_mode;\r
-       char *buffer=malloc(4096);\r
-       if (buffer==NULL)\r
-       {\r
-               return ERROR_INVALID_ARGUMENTS;\r
-       }\r
-       \r
-       old_command_mode = context->mode;\r
-       context->mode = mode;\r
-       \r
-       while (fgets(buffer, 4096, file))\r
-       {\r
-               char *p;\r
-               char *cmd, *end;\r
-               \r
-               /* stop processing line after a comment (#, !) or a LF, CR were encountered */\r
-               if ((p = strpbrk(buffer, "#!\r\n")))\r
-                       *p = 0;\r
-\r
-               /* skip over leading whitespace */\r
-               cmd = buffer;\r
-               while (isspace(*cmd))\r
-                       cmd++;\r
-\r
-               /* empty (all whitespace) line? */\r
-               if (!*cmd)\r
-                       continue;\r
-               \r
-               /* search the end of the current line, ignore trailing whitespace */\r
-               for (p = end = cmd; *p; p++)\r
-                       if (!isspace(*p))\r
-                               end = p;\r
-               \r
-               /* terminate end */\r
-               *++end = 0;\r
-               if (strcasecmp(cmd, "quit") == 0)\r
-                       break;\r
-\r
-               /* run line */\r
-               if ((retval = command_run_line(context, cmd)) == ERROR_COMMAND_CLOSE_CONNECTION)\r
-                       break;\r
-       }\r
-       \r
-       context->mode = old_command_mode;\r
-\r
-       \r
-       free(buffer);\r
-       \r
-       return retval;\r
-}\r
-\r
-void command_print_help_line(command_context_t* context, struct command_s *command, int indent)\r
-{\r
-       command_t *c;\r
-       char indents[32] = {0};\r
-       char *help = "no help available";\r
-       char name_buf[64];\r
-       int i;\r
-       \r
-       for (i = 0; i < indent; i+=2)\r
-       {\r
-               indents[i*2] = ' ';\r
-               indents[i*2+1] = '-';\r
-       }\r
-       indents[i*2] = 0;\r
-       \r
-       if (command->help)\r
-               help = command->help;\r
-               \r
-       snprintf(name_buf, 64, command->name);\r
-       strncat(name_buf, indents, 64);\r
-       command_print(context, "%20s\t%s", name_buf, help);\r
-       \r
-       if (command->children)\r
-       {\r
-               for (c = command->children; c; c = c->next)\r
-               {\r
-                       command_print_help_line(context, c, indent + 1);\r
-               }\r
-       }\r
-}\r
-\r
-int command_print_help(command_context_t* context, char* name, char** args, int argc)\r
-{\r
-       command_t *c;\r
-\r
-       for (c = context->commands; c; c = c->next)\r
-       {\r
-               if (argc == 1)\r
-               {\r
-                        if (strncasecmp(c->name, args[0], c->unique_len))\r
-                                continue;\r
-\r
-                        if (strncasecmp(c->name, args[0], strlen(args[0])))\r
-                                continue;\r
-               } \r
-\r
-               command_print_help_line(context, c, 0);\r
-       }\r
-       \r
-       return ERROR_OK;\r
-}\r
-\r
-void command_set_output_handler(command_context_t* context, int (*output_handler)(struct command_context_s *context, char* line), void *priv)\r
-{\r
-       context->output_handler = output_handler;\r
-       context->output_handler_priv = priv;\r
-}\r
-\r
-command_context_t* copy_command_context(command_context_t* context)\r
-{\r
-       command_context_t* copy_context = malloc(sizeof(command_context_t));\r
-\r
-       *copy_context = *context;\r
-       \r
-       return copy_context;\r
-}\r
-\r
-int command_done(command_context_t *context)\r
-{\r
-       free(context);\r
-       context = NULL;\r
-       \r
-       return ERROR_OK;\r
-}\r
-\r
-command_context_t* command_init()\r
-{\r
-       command_context_t* context = malloc(sizeof(command_context_t));\r
-       \r
-       context->mode = COMMAND_EXEC;\r
-       context->commands = NULL;\r
-       context->current_target = 0;\r
-       context->echo = 0;\r
-       context->output_handler = NULL;\r
-       context->output_handler_priv = NULL;\r
-       \r
-       register_command(context, NULL, "help", command_print_help,\r
-                                        COMMAND_EXEC, "display this help");\r
-       \r
-       register_command(context, NULL, "sleep", handle_sleep_command,\r
-                                        COMMAND_ANY, "sleep for <n> milliseconds");\r
-       \r
-       register_command(context, NULL, "time", handle_time_command,\r
-                                        COMMAND_ANY, "time <cmd + args> - execute <cmd + args> and print time it took");\r
-       \r
-       return context;\r
-}\r
-\r
-/* sleep command sleeps for <n> miliseconds\r
- * this is useful in target startup scripts\r
- */\r
-int handle_sleep_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
-{\r
-       unsigned long duration = 0;\r
-       \r
-       if (argc == 1)\r
-       {\r
-               duration = strtoul(args[0], NULL, 0);\r
-               usleep(duration * 1000);\r
-       }\r
-\r
-       return ERROR_OK;\r
-}\r
-\r
-int handle_time_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
-{\r
-       if (argc<1)\r
-               return ERROR_COMMAND_SYNTAX_ERROR;\r
-       \r
-       duration_t duration;\r
-       char *duration_text;\r
-       int retval;\r
-       \r
-       duration_start_measure(&duration);\r
-       \r
-       retval = find_and_run_command(cmd_ctx, cmd_ctx->commands, args, argc, 0);\r
-       \r
-       duration_stop_measure(&duration, &duration_text);\r
-       \r
-       float t=duration.duration.tv_sec;\r
-       t+=((float)duration.duration.tv_usec / 1000000.0);\r
-       command_print(cmd_ctx, "%s took %fs", args[0], t);\r
-       \r
-       free(duration_text);\r
-\r
-       return retval;\r
-}\r
+/***************************************************************************
+ *   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;
+}