mirror of
https://github.com/openvswitch/ovs
synced 2025-08-30 13:58:14 +00:00
db-ctl-base: Librarize code in parse_options().
This commit extracts general code from parse_options() and puts it into db-ctl-base module. Signed-off-by: Alex Wang <alexw@nicira.com> Acked-by: Ben Pfaff <blp@nicira.com>
This commit is contained in:
parent
07ff77ccb8
commit
51a73ff06e
@ -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.) */
|
||||
|
@ -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[],
|
||||
|
@ -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 {
|
||||
|
Loading…
x
Reference in New Issue
Block a user