2
0
mirror of https://github.com/openvswitch/ovs synced 2025-09-02 07:15:17 +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:
Alex Wang
2015-06-11 08:19:15 -07:00
parent 07ff77ccb8
commit 51a73ff06e
3 changed files with 231 additions and 214 deletions

View File

@@ -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.) */