X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Fhelper%2Fcommand.c;h=df12ffc1b43cde99d9e978c016c0b5f8c1e083f5;hp=00d4b356150abe31a5ea40b82847a8fa490617b0;hb=f2a5a1ce8125936f7d96254da7e1f77867b3cb7b;hpb=335f667d4433e8ca3a57e813fd128b78d8b364d2 diff --git a/src/helper/command.c b/src/helper/command.c index 00d4b35615..df12ffc1b4 100644 --- a/src/helper/command.c +++ b/src/helper/command.c @@ -20,6 +20,12 @@ * 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" @@ -70,9 +76,15 @@ 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; @@ -121,14 +133,13 @@ command_t* register_command(command_context_t *context, command_t *parent, char } } - /* update unique lengths */ - build_unique_lengths(context, (parent) ? parent : context->commands); - return c; } int unregister_command(command_context_t *context, char *name) { + unique_length_dirty = 1; + command_t *c, *p = NULL, *c2; if ((!context) || (!name)) @@ -194,14 +205,24 @@ int parse_line(char *line, char *words[], int max_words) /* we're inside a word or quote, and reached its end*/ if (word_start) { - int len = p - word_start; - - /* 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_start0) + { + /* 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; @@ -209,7 +230,9 @@ int parse_line(char *line, char *words[], int max_words) /* skip over trailing quote or whitespace*/ if (inquote || isspace(*p)) p++; - + while (isspace(*p)) + p++; + inquote = 0; word_start = 0; } @@ -235,27 +258,43 @@ int parse_line(char *line, char *words[], int max_words) void command_print(command_context_t *context, char *format, ...) { - 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) + for (;;) { - /* increase buffer until it fits the whole string */ - if (!(p = realloc(buffer, size += 4096))) - return; - - buffer = p; + 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; @@ -274,14 +313,19 @@ void command_print(command_context_t *context, char *format, ...) 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; + 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)) @@ -290,7 +334,7 @@ int find_and_run_command(command_context_t *context, command_t *commands, char * 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) { @@ -320,7 +364,7 @@ int find_and_run_command(command_context_t *context, command_t *commands, char * return ERROR_OK; } -int command_run_line(command_context_t *context, char *line) +static int command_run_line_inner(command_context_t *context, char *line) { int nwords; char *words[128] = {0}; @@ -338,6 +382,10 @@ int command_run_line(command_context_t *context, char *line) if (!*line) return ERROR_OK; + /* ignore comments */ + if (*line && (line[0] == '#')) + return ERROR_OK; + if (context->echo) { command_print(context, "%s", line); @@ -356,11 +404,26 @@ int command_run_line(command_context_t *context, char *line) 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; + 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; @@ -394,11 +457,14 @@ int command_run_file(command_context_t *context, FILE *file, enum command_mode m break; /* run line */ - if (command_run_line(context, cmd) == ERROR_COMMAND_CLOSE_CONNECTION) + if ((retval = command_run_line_inner(context, cmd)) == ERROR_COMMAND_CLOSE_CONNECTION) break; } context->mode = old_command_mode; + + + free(buffer); return retval; } @@ -418,15 +484,12 @@ void command_print_help_line(command_context_t* context, struct command_s *comma } 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); + strncat(name_buf, indents, 64); + command_print(context, "%20s\t%s", name_buf, help); if (command->children) { @@ -443,6 +506,15 @@ int command_print_help(command_context_t* context, char* name, char** args, int 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); } @@ -467,6 +539,7 @@ command_context_t* copy_command_context(command_context_t* context) int command_done(command_context_t *context) { free(context); + context = NULL; return ERROR_OK; }