-/***************************************************************************\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)
+{
+ command_t *c, *p = NULL, *c2;
+
+ unique_length_dirty = 1;
+
+ 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_n(command_context_t *context, char *format, ...)
+{
+ char *string;
+
+ va_list ap;
+ va_start(ap, format);
+
+ string = alloc_vprintf(format, ap);
+ if (string != NULL)
+ {
+ context->output_handler(context, string);
+ free(string);
+ }
+
+ va_end(ap);
+}
+
+void command_print(command_context_t *context, char *format, ...)
+{
+ char *string;
+
+ va_list ap;
+ va_start(ap, format);
+
+ string = alloc_vprintf(format, ap);
+ if (string != NULL)
+ {
+ strcat(string, "\n"); /* alloc_vprintf guaranteed the buffer to be at least one char longer */
+ context->output_handler(context, string);
+ free(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 *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))
+ 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;
+ }
+ 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;
+ }
+ }
+ 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 retval;
+}
+
+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;
+
+ LOG_DEBUG("%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 *indent_text=malloc(indent + 2);
+
+ char *help = "no help available";
+ char name_buf[64];
+
+ if (indent)
+ {
+ indent_text[0] = ' ';
+ memset(indent_text + 1, '-', indent);
+ indent_text[indent + 1] = 0;
+ }
+
+ if (command->help)
+ help = command->help;
+
+ snprintf(name_buf, 64, command->name);
+
+ if (indent)
+ strncat(name_buf, indent_text, 64);
+
+ command_print(context, "%20s\t%s", name_buf, help, indent);
+
+ if (command->children)
+ {
+ for (c = command->children; c; c = c->next)
+ {
+ 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)
+{
+ command_t * c;
+
+ for (c = c_first; c; c = c->next)
+ {
+ if (argc > 0)
+ {
+ if (strncasecmp(c->name, args[0], c->unique_len))
+ continue;
+
+ if (strncasecmp(c->name, args[0], strlen(args[0])))
+ continue;
+
+ if (argc > 1)
+ {
+ command_print_help_match(context, c->children, name, args + 1, argc - 1);
+ continue;
+ }
+ }
+
+ command_print_help_line(context, c, 0);
+ }
+
+ return ERROR_OK;
+}
+
+int command_print_help(command_context_t* context, char* name, char** args, int argc)
+{
+ 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)
+{
+ 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->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)
+{
+ 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);
+
+ duration_stop_measure(&duration, &duration_text);
+
+ 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;
+}