db-ctl-base: Librarize code in parse_options().
authorAlex Wang <alexw@nicira.com>
Thu, 11 Jun 2015 15:19:15 +0000 (08:19 -0700)
committerAlex Wang <alexw@nicira.com>
Tue, 23 Jun 2015 16:43:24 +0000 (09:43 -0700)
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>
lib/db-ctl-base.c
lib/db-ctl-base.h
utilities/ovs-vsctl.c

index f27d1bb..d1dc8f7 100644 (file)
@@ -49,6 +49,114 @@ struct ovsdb_idl_txn *the_idl_txn;
 static struct shash all_commands = SHASH_INITIALIZER(&all_commands);
 
 \f
+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,
 }
 
 \f
+/* 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.) */
index 85b5e26..eaa6bc6 100644 (file)
@@ -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[],
index b114a5a..6bc6818 100644 (file)
@@ -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;
-}
-
 \f
 /* ovs-vsctl specific context.  Inherits the 'struct ctl_context' as base. */
 struct vsctl_context {