-/***************************************************************************
- * 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;
-}
+/***************************************************************************\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