This commit extracts general code from parse_options() and puts it into db-ctl-base module.
Signed-off-by: Alex Wang <al...@nicira.com> --- lib/db-ctl-base.c | 220 +++++++++++++++++++++++++++++++++++++++++++++++++ lib/db-ctl-base.h | 5 ++ utilities/ovs-vsctl.c | 220 ++----------------------------------------------- 3 files changed, 231 insertions(+), 214 deletions(-) diff --git a/lib/db-ctl-base.c b/lib/db-ctl-base.c index f27d1bb..d1dc8f7 100644 --- a/lib/db-ctl-base.c +++ b/lib/db-ctl-base.c @@ -49,6 +49,114 @@ struct ovsdb_idl_txn *the_idl_txn; static struct shash all_commands = SHASH_INITIALIZER(&all_commands); +static struct option * +find_option(const char *name, struct option *options, size_t n_options) +{ + size_t i; + + for (i = 0; i < n_options; i++) { + if (!strcmp(options[i].name, name)) { + return &options[i]; + } + } + return NULL; +} + +static struct option * +add_option(struct option **optionsp, size_t *n_optionsp, + size_t *allocated_optionsp) +{ + if (*n_optionsp >= *allocated_optionsp) { + *optionsp = x2nrealloc(*optionsp, allocated_optionsp, + sizeof **optionsp); + } + return &(*optionsp)[(*n_optionsp)++]; +} + +/* Converts the command arguments into format that can be parsed by + * bash completion script. + * + * Therein, arguments will be attached with following prefixes: + * + * !argument :: The argument is required + * ?argument :: The argument is optional + * *argument :: The argument may appear any number (0 or more) times + * +argument :: The argument may appear one or more times + * + */ +static void +print_command_arguments(const struct ctl_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 + * 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 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. + */ + uint32_t oew_stack = 0; + + const char *arguments = command->arguments; + int length = strlen(arguments); + if (!length) { + return; + } + + /* Output buffer, written backward from end. */ + char *output = xmalloc(2 * length); + char *outp = output + 2 * length; + *--outp = '\0'; + + bool in_repeated = false; + bool whole_word_is_optional = false; + + for (const char *inp = arguments + length; inp > arguments; ) { + switch (*--inp) { + case ']': + oew_stack <<= 1; + if (inp[1] == '\0' || inp[1] == ' ' || inp[1] == '.') { + oew_stack |= 1; + } + break; + case '[': + /* Checks if the whole word is optional, and sets the + * 'whole_word_is_optional' accordingly. */ + if ((inp == arguments || inp[-1] == ' ') && oew_stack & 1) { + *--outp = in_repeated ? '*' : '?'; + whole_word_is_optional = true; + } else { + *--outp = '?'; + whole_word_is_optional = false; + } + oew_stack >>= 1; + break; + case ' ': + if (!whole_word_is_optional) { + *--outp = in_repeated ? '+' : '!'; + } + *--outp = ' '; + in_repeated = false; + whole_word_is_optional = false; + break; + case '.': + in_repeated = true; + break; + default: + *--outp = *inp; + break; + } + } + if (arguments[0] != '[' && outp != output + 2 * length - 1) { + *--outp = in_repeated ? '+' : '!'; + } + printf("%s", outp); + free(output); +} + static void die_if_error(char *error) { @@ -1388,6 +1496,63 @@ parse_command(int argc, char *argv[], struct shash *local_options, } +/* Given pointer to dynamic array 'options_p', array's current size + * 'allocated_options_p' and number of added options 'n_options_p', + * adds all command options to the array. Enlarges the array if + * necessary. */ +void +ctl_add_cmd_options(struct option **options_p, size_t *n_options_p, + size_t *allocated_options_p, int opt_val) +{ + struct option *o; + const struct shash_node *node; + size_t n_existing_options = *n_options_p; + + SHASH_FOR_EACH (node, ctl_get_all_commands()) { + const struct ctl_command_syntax *p = node->data; + + if (p->options[0]) { + char *save_ptr = NULL; + char *name; + char *s; + + s = xstrdup(p->options); + for (name = strtok_r(s, ",", &save_ptr); name != NULL; + name = strtok_r(NULL, ",", &save_ptr)) { + char *equals; + int has_arg; + + ovs_assert(name[0] == '-' && name[1] == '-' && name[2]); + name += 2; + + equals = strchr(name, '='); + if (equals) { + has_arg = required_argument; + *equals = '\0'; + } else { + has_arg = no_argument; + } + + o = find_option(name, *options_p, *n_options_p); + if (o) { + ovs_assert(o - *options_p >= n_existing_options); + ovs_assert(o->has_arg == has_arg); + } else { + o = add_option(options_p, n_options_p, allocated_options_p); + o->name = xstrdup(name); + o->has_arg = has_arg; + o->flag = NULL; + o->val = opt_val; + } + } + + free(s); + } + } + o = add_option(options_p, n_options_p, allocated_options_p); + memset(o, 0, sizeof *o); +} + /* Parses command-line input for commands. */ struct ctl_command * ctl_parse_commands(int argc, char *argv[], struct shash *local_options, @@ -1427,6 +1592,61 @@ ctl_parse_commands(int argc, char *argv[], struct shash *local_options, return commands; } +/* Prints all registered commands. */ +void +ctl_print_commands(void) +{ + const struct shash_node *node; + + SHASH_FOR_EACH (node, ctl_get_all_commands()) { + const struct ctl_command_syntax *p = node->data; + char *options = xstrdup(p->options); + char *options_begin = options; + char *item; + + for (item = strsep(&options, ","); item != NULL; + item = strsep(&options, ",")) { + if (item[0] != '\0') { + printf("[%s] ", item); + } + } + printf(",%s,", p->name); + print_command_arguments(p); + printf("\n"); + + free(options_begin); + } + + exit(EXIT_SUCCESS); +} + +/* Given array of options 'options', prints them. */ +void +ctl_print_options(const struct option *options) +{ + for (; options->name; options++) { + const struct option *o = options; + + printf("--%s%s\n", o->name, o->has_arg ? "=ARG" : ""); + if (o->flag == NULL && o->val > 0 && o->val <= UCHAR_MAX) { + printf("-%c%s\n", o->val, o->has_arg ? " ARG" : ""); + } + } + + exit(EXIT_SUCCESS); +} + +/* Returns the default local database path. */ +char * +ctl_default_db(void) +{ + static char *def; + if (!def) { + def = xasprintf("unix:%s/db.sock", ovs_rundir()); + } + return def; +} + /* Returns true if it looks like this set of arguments might modify the * database, otherwise false. (Not very smart, so it's prone to false * positives.) */ diff --git a/lib/db-ctl-base.h b/lib/db-ctl-base.h index 85b5e26..eaa6bc6 100644 --- a/lib/db-ctl-base.h +++ b/lib/db-ctl-base.h @@ -55,6 +55,7 @@ extern struct ovsdb_idl *the_idl; extern struct ovsdb_idl_txn *the_idl_txn; void ctl_init(void); +char *ctl_default_db(void); OVS_NO_RETURN void ctl_exit(int status); OVS_NO_RETURN void ctl_fatal(const char *, ...) OVS_PRINTF_FORMAT(1, 2); @@ -145,6 +146,10 @@ struct ctl_command { bool ctl_might_write_to_db(char **argv); const char *ctl_get_db_cmd_usage(void); +void ctl_print_commands(void); +void ctl_print_options(const struct option *); +void ctl_add_cmd_options(struct option **, size_t *n_options_p, + size_t *allocated_options_p, int opt_val); void ctl_register_commands(const struct ctl_command_syntax *); const struct shash *ctl_get_all_commands(void); struct ctl_command *ctl_parse_commands(int argc, char *argv[], diff --git a/utilities/ovs-vsctl.c b/utilities/ovs-vsctl.c index b114a5a..6bc6818 100644 --- a/utilities/ovs-vsctl.c +++ b/utilities/ovs-vsctl.c @@ -31,7 +31,6 @@ #include "command-line.h" #include "compiler.h" -#include "dirs.h" #include "dynamic-string.h" #include "fatal-signal.h" #include "hash.h" @@ -85,10 +84,7 @@ static bool retry; static struct table_style table_style = TABLE_STYLE_DEFAULT; static void vsctl_cmd_init(void); -static char *default_db(void); OVS_NO_RETURN static void usage(void); -OVS_NO_RETURN static void print_vsctl_commands(void); -OVS_NO_RETURN static void print_vsctl_options(const struct option *options); static void parse_options(int argc, char *argv[], struct shash *local_options); static void run_prerequisites(struct ctl_command[], size_t n_commands, struct ovsdb_idl *); @@ -188,30 +184,6 @@ main(int argc, char *argv[]) } } -static struct option * -find_option(const char *name, struct option *options, size_t n_options) -{ - size_t i; - - for (i = 0; i < n_options; i++) { - if (!strcmp(options[i].name, name)) { - return &options[i]; - } - } - return NULL; -} - -static struct option * -add_option(struct option **optionsp, size_t *n_optionsp, - size_t *allocated_optionsp) -{ - if (*n_optionsp >= *allocated_optionsp) { - *optionsp = x2nrealloc(*optionsp, allocated_optionsp, - sizeof **optionsp); - } - return &(*optionsp)[(*n_optionsp)++]; -} - static void parse_options(int argc, char *argv[], struct shash *local_options) { @@ -250,8 +222,7 @@ parse_options(int argc, char *argv[], struct shash *local_options) const int n_global_long_options = ARRAY_SIZE(global_long_options) - 1; char *tmp, *short_options; - const struct shash_node *node; - struct option *options, *o; + struct option *options; size_t allocated_options; size_t n_options; size_t i; @@ -267,50 +238,7 @@ parse_options(int argc, char *argv[], struct shash *local_options) options = xmemdup(global_long_options, sizeof global_long_options); allocated_options = ARRAY_SIZE(global_long_options); n_options = n_global_long_options; - SHASH_FOR_EACH (node, ctl_get_all_commands()) { - const struct ctl_command_syntax *p = node->data; - - if (p->options[0]) { - char *save_ptr = NULL; - char *name; - char *s; - - s = xstrdup(p->options); - for (name = strtok_r(s, ",", &save_ptr); name != NULL; - name = strtok_r(NULL, ",", &save_ptr)) { - char *equals; - int has_arg; - - ovs_assert(name[0] == '-' && name[1] == '-' && name[2]); - name += 2; - - equals = strchr(name, '='); - if (equals) { - has_arg = required_argument; - *equals = '\0'; - } else { - has_arg = no_argument; - } - - o = find_option(name, options, n_options); - if (o) { - ovs_assert(o - options >= n_global_long_options); - ovs_assert(o->has_arg == has_arg); - } else { - o = add_option(&options, &n_options, &allocated_options); - o->name = xstrdup(name); - o->has_arg = has_arg; - o->flag = NULL; - o->val = OPT_LOCAL; - } - } - - free(s); - } - } - o = add_option(&options, &n_options, &allocated_options); - memset(o, 0, sizeof *o); - + ctl_add_cmd_options(&options, &n_options, &allocated_options, OPT_LOCAL); table_style.format = TF_LIST; for (;;) { @@ -357,10 +285,10 @@ parse_options(int argc, char *argv[], struct shash *local_options) usage(); case OPT_COMMANDS: - print_vsctl_commands(); + ctl_print_commands(); case OPT_OPTIONS: - print_vsctl_options(global_long_options); + ctl_print_options(global_long_options); case 'V': ovs_print_version(0, 0); @@ -398,7 +326,7 @@ parse_options(int argc, char *argv[], struct shash *local_options) free(short_options); if (!db) { - db = default_db(); + db = ctl_default_db(); } for (i = n_global_long_options; options[i].name; i++) { @@ -479,7 +407,7 @@ Options:\n\ -t, --timeout=SECS wait at most SECS seconds for ovs-vswitchd\n\ --dry-run do not commit changes to database\n\ --oneline print exactly one line of output per command\n", - program_name, program_name, ctl_get_db_cmd_usage(), default_db()); + program_name, program_name, ctl_get_db_cmd_usage(), ctl_default_db()); vlog_usage(); printf("\ --no-syslog equivalent to --verbose=vsctl:syslog:warn\n"); @@ -491,142 +419,6 @@ Other options:\n\ exit(EXIT_SUCCESS); } -/* Converts the command arguments into format that can be parsed by - * bash completion script. - * - * Therein, arguments will be attached with following prefixes: - * - * !argument :: The argument is required - * ?argument :: The argument is optional - * *argument :: The argument may appear any number (0 or more) times - * +argument :: The argument may appear one or more times - * - */ -static void -print_command_arguments(const struct ctl_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 - * 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 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. - */ - uint32_t oew_stack = 0; - - const char *arguments = command->arguments; - int length = strlen(arguments); - if (!length) { - return; - } - - /* Output buffer, written backward from end. */ - char *output = xmalloc(2 * length); - char *outp = output + 2 * length; - *--outp = '\0'; - - bool in_repeated = false; - bool whole_word_is_optional = false; - - for (const char *inp = arguments + length; inp > arguments; ) { - switch (*--inp) { - case ']': - oew_stack <<= 1; - if (inp[1] == '\0' || inp[1] == ' ' || inp[1] == '.') { - oew_stack |= 1; - } - break; - case '[': - /* Checks if the whole word is optional, and sets the - * 'whole_word_is_optional' accordingly. */ - if ((inp == arguments || inp[-1] == ' ') && oew_stack & 1) { - *--outp = in_repeated ? '*' : '?'; - whole_word_is_optional = true; - } else { - *--outp = '?'; - whole_word_is_optional = false; - } - oew_stack >>= 1; - break; - case ' ': - if (!whole_word_is_optional) { - *--outp = in_repeated ? '+' : '!'; - } - *--outp = ' '; - in_repeated = false; - whole_word_is_optional = false; - break; - case '.': - in_repeated = true; - break; - default: - *--outp = *inp; - break; - } - } - if (arguments[0] != '[' && outp != output + 2 * length - 1) { - *--outp = in_repeated ? '+' : '!'; - } - printf("%s", outp); - free(output); -} - -static void -print_vsctl_commands(void) -{ - const struct shash_node *node; - - SHASH_FOR_EACH (node, ctl_get_all_commands()) { - const struct ctl_command_syntax *p = node->data; - char *options = xstrdup(p->options); - char *options_begin = options; - char *item; - - for (item = strsep(&options, ","); item != NULL; - item = strsep(&options, ",")) { - if (item[0] != '\0') { - printf("[%s] ", item); - } - } - printf(",%s,", p->name); - print_command_arguments(p); - printf("\n"); - - free(options_begin); - } - - exit(EXIT_SUCCESS); -} - -static void -print_vsctl_options(const struct option *options) -{ - for (; options->name; options++) { - const struct option *o = options; - - printf("--%s%s\n", o->name, o->has_arg ? "=ARG" : ""); - if (o->flag == NULL && o->val > 0 && o->val <= UCHAR_MAX) { - printf("-%c%s\n", o->val, o->has_arg ? " ARG" : ""); - } - } - - exit(EXIT_SUCCESS); -} - -static char * -default_db(void) -{ - static char *def; - if (!def) { - def = xasprintf("unix:%s/db.sock", ovs_rundir()); - } - return def; -} - /* ovs-vsctl specific context. Inherits the 'struct ctl_context' as base. */ struct vsctl_context { -- 1.7.9.5 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev