#include "command.h"
#include "log.h"
+#include "time_support.h"
#include <stdlib.h>
#include <string.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)
{
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;
}
}
- /* update unique lengths */
- build_unique_lengths(context, (parent) ? parent : context->commands);
-
return c;
}
{
command_t *c, *p = NULL, *c2;
+ unique_length_dirty = 1;
+
if ((!context) || (!name))
return ERROR_INVALID_ARGUMENTS;
/* 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;
- }
+ 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++;
-
+ while (isspace(*p))
+ p++;
+
inquote = 0;
word_start = 0;
}
return nwords;
}
-void command_print(command_context_t *context, char *format, ...)
+void command_print_n(command_context_t *context, char *format, ...)
{
+ char *string;
+
va_list ap;
- char *buffer = NULL;
- int n, size = 0;
- char *p;
-
va_start(ap, format);
-
- /* process format string */
- /* TODO: possible bug. va_list is undefined after the first call to vsnprintf */
- while (!buffer || (n = vsnprintf(buffer, size, format, ap)) >= size)
- {
- /* increase buffer until it fits the whole string */
- if (!(p = realloc(buffer, size += 4096)))
- return;
- buffer = p;
+ string = alloc_vprintf(format, ap);
+ if (string != NULL)
+ {
+ context->output_handler(context, string);
+ free(string);
}
-
- /* vsnprintf failed */
- if (n < 0)
- return;
- p = buffer;
-
- /* process lines in buffer */
- do {
- char *next = strchr(p, '\n');
-
- if (next)
- *next++ = 0;
+ va_end(ap);
+}
- if (context->output_handler)
- context->output_handler(context, p);
+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);
+ }
- p = next;
- } while (p);
-
- if (buffer)
- free(buffer);
-
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], strlen(words[start_word])))
continue;
- if ((c->mode == context->mode) || (c->mode == COMMAND_ANY))
+ 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
{
- return c->handler(context, c->name, words + start_word + 1, num_words - start_word - 1);
+ 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
}
command_print(context, "Command %s not found", words[start_word]);
- return ERROR_OK;
+ return retval;
}
int command_run_line(command_context_t *context, char *line)
if (!*line)
return ERROR_OK;
- if (context->echo)
- {
- command_print(context, "%s", line);
- }
+ /* ignore comments */
+ if (*line && (line[0] == '#'))
+ return ERROR_OK;
+
+ LOG_DEBUG("%s", line);
nwords = parse_line(line, words, sizeof(words) / sizeof(words[0]));
int command_run_file(command_context_t *context, FILE *file, enum command_mode mode)
{
- int retval;
+ int retval = ERROR_OK;
int old_command_mode;
- char buffer[4096];
+ char *buffer=malloc(4096);
+ if (buffer==NULL)
+ {
+ return ERROR_INVALID_ARGUMENTS;
+ }
old_command_mode = context->mode;
context->mode = mode;
}
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 *indent_text=malloc(indent + 2);
+
char *help = "no help available";
char name_buf[64];
- int i;
- for (i = 0; i < indent; i+=2)
+ if (indent)
{
- indents[i*2] = ' ';
- indents[i*2+1] = '-';
+ indent_text[0] = ' ';
+ memset(indent_text + 1, '-', indent);
+ indent_text[indent + 1] = 0;
}
- indents[i*2] = 0;
- if ((command->mode == COMMAND_EXEC) || (command->mode == COMMAND_ANY))
- {
- if (command->help)
- help = command->help;
+ 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);
- }
+ 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)
{
command_print_help_line(context, c, indent + 1);
}
}
+ free(indent_text);
}
-int command_print_help(command_context_t* context, char* name, char** args, int argc)
+int command_print_help_match(command_context_t* context, command_t* c_first, char* name, char** args, int argc)
{
- command_t *c;
+ command_t * c;
- for (c = context->commands; c; c = c->next)
+ for (c = c_first; c; c = c->next)
{
- if (argc == 1)
+ if (argc > 0)
{
- if (strncasecmp(c->name, args[0], c->unique_len))
- continue;
+ if (strncasecmp(c->name, args[0], c->unique_len))
+ continue;
- if (strncasecmp(c->name, args[0], strlen(args[0])))
- 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;
int command_done(command_context_t *context)
{
free(context);
+ context = NULL;
return ERROR_OK;
}
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, "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;
}
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;
+}