These changes all look good to me, I really like the unit32_t-as-a-stack idea.
---Peter On Tue, 03 Mar 2015 21:41:11 -0800: Ben Pfaff <b...@nicira.com> wrote: On Mon, Feb 23, 2015 at 08:48:59AM -0800, Alex Wang wrote: >> From: Peter Amidon <pe...@picnicpark.org> >> >> This patch adds bash command-line completion script for ovs-vsctl. >> Therein, codes are added to ovs-vsctl to allow it to print the >> options and command arguments. The ovs-vsctl-bashcomp.bash will >> parse the vsctl command and complete on the user input. >> >> The completion script can do the following:: >> >> - display available completion and complete on user input for >> global/local options, command, and argument. >> >> - query database and expand keywords like 'table/record/column/key' >> to available completions. >> >> - deal with argument relations like 'one and more', 'zero or one'. >> >> - complete multiple ovs-vsctl commands cascaded via '--'. >> >> To use the script, either copy it inside /etc/bash_completion.d/ >> or manually run it via . ovs-vsctl-bashcomp.bash. >> >> Signed-off-by: Alex Wang <al...@nicira.com> > Since I'm not a bash expert, I think I'll concentrate on the C code in > ovs-vsctl.c. Alex, have you reviewed the bash code? As long as you > have, I'm happy with it. > valgrind reports a buffer overrun when the length of command->argument > is 0. > It appears that print_command_arguments() uses a linked list to maintain > a stack of bools that will never get very deep. I think a single-word > bitmap would work just as well. > Here, you can omit the multiplication by sizeof(char), because the C > standard guarantees that sizeof(char) is 1: > char *simple_args = xzalloc(2 * length * sizeof(char)); > 'in_repeated' should be declared bool and assigned true and false (not 0 > and 1). > Please write a space around binary operators, e.g. arguments[length-i-1] > becomes arguments[length - i - 1]. > It took me a minute to figure out what was going on with the output > buffer, that it's actually being written backward byte-by-byte. That's > brilliant, but I found the actual bookkeeping method difficult to > follow. This is a case where I find it a lot easier to understand when > there's a pointer to the current position that we decrement as we go. > Pretty much the same for the input buffer, although that's not quite as > hard to understand at first glance. > I think there's a missing "free" of the output buffer too. > There are double blank lines between functions. We don't generally do > that. > strlen(item) > 0 is more efficiently written item[0] != '\0'. > I usually try to write "break;" after every case in a switch statement, > even the last one, because it makes it harder to forget to add one if > you add another case later. > s/surronds/surrounds/ in the comment here: > * We use 'whole_word_is_optional' value to decide whether or not a ! or > * + should be added on encountering a space: if the optional surronds > * the whole word then it shouldn't be, but if it is only a part of the > I got interested in this so I actually implemented these changes. > Here's an incremental diff. I verified that it produces the same output > as the original version. > diff --git a/utilities/ovs-vsctl.c b/utilities/ovs-vsctl.c > index 695ecd4..efd138c 100644 > --- a/utilities/ovs-vsctl.c > +++ b/utilities/ovs-vsctl.c > @@ -768,94 +768,75 @@ static void > print_command_arguments(const struct vsctl_command_syntax *command) > { > /* > - * The argument string is parsed in reverse. We use a stack 'oew_stack' > - * to keep track of nested optionals. Whenever a ']' is encountered, we > - * push an element to 'oew_stack'. The 'optional_ends_word' is set if > - * the ']' is not nested. Subsequently, we pop an entry everytime '[' is > - * met. > + * The argument string is parsed in reverse. We use a stack 'oew_stack' to > + * keep track of nested optionals. Whenever a ']' is encountered, we push > + * a bit to 'oew_stack'. The bit is set to 1 if the ']' is not nested. > + * Subsequently, we pop an entry everytime '[' is met. > * > - * We use 'whole_word_is_optional' value to decide whether or not a ! or > - * + should be added on encountering a space: if the optional surronds > - * the whole word then it shouldn't be, but if it is only a part of the > - * word (i.e. [key=]value), it should be. > + * We use 'whole_word_is_optional' value to decide whether or not a ! or + > + * should be added on encountering a space: if the optional surrounds the > + * whole word then it shouldn't be, but if it is only a part of the word > + * (i.e. [key=]value), it should be. > */ > - struct oew_stack_element { > - bool optional_ends_word; > - struct ovs_list node; > - }; > + uint32_t oew_stack = 0; > const char *arguments = command->arguments; > - struct ovs_list oew_stack; > int length = strlen(arguments); > - char *simple_args = xzalloc(2 * length * sizeof(char)); > - /* One char has already been written: \0 */ > - int chars_written = 1; > - int in_repeated = 0; > - bool whole_word_is_optional = false; > - int i; > + if (!length) { > + return; > + } > - list_init(&oew_stack); > + /* Output buffer, written backward from end. */ > + char *output = xmalloc(2 * length); > + char *outp = output + 2 * length; > + *--outp = '\0'; > - for (i = 1; i <= length; i++) { > - int simple_index = 2 * length - chars_written - 1; > - char current = arguments[length-i]; > - struct oew_stack_element *elem; > - int oew; > + bool in_repeated = false; > + bool whole_word_is_optional = false; > - switch(current) { > + for (const char *inp = arguments + length; inp > arguments; ) { > + switch (*--inp) { > case ']': > - elem = xmalloc(sizeof *elem); > - if (i == 1 > - || arguments[length-i+1] == ' ' > - || arguments[length-i+1] == '.') { > - elem->optional_ends_word = true; > - } else { > - elem->optional_ends_word = false; > + oew_stack <<= 1; > + if (inp[1] == '\0' || inp[1] == ' ' || inp[1] == '.') { > + oew_stack |= 1; > } > - list_push_back(&oew_stack, &elem->node); > break; > case '[': > - elem = CONTAINER_OF(list_pop_back(&oew_stack), > - struct oew_stack_element, > - node); > - oew = elem->optional_ends_word; > - free(elem); > /* Checks if the whole word is optional, and sets the > * 'whole_word_is_optional' accordingly. */ > - if ((i == length || arguments[length-i-1] == ' ') > - && oew) { > - simple_args[simple_index] = in_repeated ? '*' : '?'; > - whole_word_is_optional = oew; > + if ((inp == arguments || inp[-1] == ' ') && oew_stack & 1) { > + *--outp = in_repeated ? '*' : '?'; > + whole_word_is_optional = true; > } else { > - simple_args[simple_index] = '?'; > - whole_word_is_optional = 0; > + *--outp = '?'; > + whole_word_is_optional = false; > } > - chars_written++; > + oew_stack >>= 1; > break; > case ' ': > if (!whole_word_is_optional) { > - simple_args[simple_index] = in_repeated ? '+' : '!'; > - chars_written++; > + *--outp = in_repeated ? '+' : '!'; > } > - simple_args[2 * length - ++chars_written] = ' '; > - in_repeated = 0; > + *--outp = ' '; > + in_repeated = false; > whole_word_is_optional = false; > break; > case '.': > - in_repeated = 1; > + in_repeated = true; > break; > default: > - simple_args[simple_index] = current; > - chars_written++; > + *--outp = *inp; > + break; > } > } > - if (arguments[0] != '[' && chars_written > 1) { > - simple_args[2 * length - ++chars_written] = in_repeated ? '+' : '!'; > + if (arguments[0] != '[' && outp != output + 2 * length - 1) { > + *--outp = in_repeated ? '+' : '!'; > } > - printf("%s", simple_args + 2 * length - chars_written); > + printf("%s", outp); > + free(output); > } > - > static void > print_vsctl_commands(void) > { > @@ -866,10 +847,9 @@ print_vsctl_commands(void) > char *options_begin = options; > char *item; > - for (item = strsep(&options, ","); > - item != NULL; > + for (item = strsep(&options, ","); item != NULL; > item = strsep(&options, ",")) { > - if (strlen(item) > 0) { > + if (item[0] != '\0') { > printf("[%s] ", item); > } > } > @@ -883,7 +863,6 @@ print_vsctl_commands(void) > exit(EXIT_SUCCESS); > } > - > static void > print_vsctl_options(const struct option *options) > { > @@ -899,7 +878,6 @@ print_vsctl_options(const struct option *options) > exit(EXIT_SUCCESS); > } > - > static char * > default_db(void) > { _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev