[Spice-devel] [PATCH v4 x11spice 2/3] Simplify the expression of option handling.

Jeremy White jwhite at codeweavers.com
Tue Jul 23 21:28:57 UTC 2019


This fixes a bug with --config=<filename> handling.

Add expanded test code courtesy of Frediano Ziglio <fziglio at redhat.com>.

Signed-off-by: Jeremy White <jwhite at codeweavers.com>
---
 src/main.c    |  8 +++--
 src/options.c | 93 ++++++++++++++++++++++++++++++++++++++++++---------
 src/options.h |  1 -
 3 files changed, 83 insertions(+), 19 deletions(-)

diff --git a/src/main.c b/src/main.c
index f18311c9..da6d4882 100644
--- a/src/main.c
+++ b/src/main.c
@@ -67,9 +67,13 @@ int main(int argc, char *argv[])
     **  Parse arguments
     **----------------------------------------------------------------------*/
     options_init(&session.options);
-    options_handle_user_config(argc, argv, &session.options);
-    options_from_config(&session.options);
     rc = options_parse_arguments(argc, argv, &session.options);
+    if (rc == 0) {
+        options_from_config(&session.options);
+        /* We parse command line arguments a second time to ensure
+        **  that command line options take precedence over config files */
+        rc = options_parse_arguments(argc, argv, &session.options);
+    }
     if (rc)
         goto exit;
 
diff --git a/src/options.c b/src/options.c
index bc7cd631..6620b853 100644
--- a/src/options.c
+++ b/src/options.c
@@ -214,16 +214,6 @@ void options_handle_ssl_file_options(options_t *options,
     string_option(&options->ssl.ciphersuite, userkey, systemkey, "ssl", "ciphersuite");
 }
 
-void options_handle_user_config(int argc, char *argv[], options_t *options)
-{
-    int i;
-    for (i = 1; i < argc - 1; i++)
-        if (strcmp(argv[i], "--config") == 0 || strcmp(argv[i], "-config") == 0) {
-            str_replace(&options->user_config_file, argv[i + 1]);
-            i++;
-        }
-}
-
 int options_parse_arguments(int argc, char *argv[], options_t *options)
 {
     int rc;
@@ -254,6 +244,7 @@ int options_parse_arguments(int argc, char *argv[], options_t *options)
         {0, 0, 0, 0}
     };
 
+    optind = 1; /* Allow reuse of this function */
     while (1) {
         rc = getopt_long_only(argc, argv, "", long_options, &longindex);
         if (rc == -1) {
@@ -287,7 +278,7 @@ int options_parse_arguments(int argc, char *argv[], options_t *options)
                 break;
 
             case OPTION_CONFIG:
-                /* This was handled previously; we can ignore */
+                str_replace(&options->user_config_file, optarg);
                 break;
 
             case OPTION_SSL:
@@ -501,15 +492,85 @@ int options_impossible_config(options_t *options)
     return 1;
 }
 
-#if defined(OPTIONS_MAIN)
-int main(int argc, char *argv[])
+#if defined(MAIN_TEST)
+static int test_load_options(options_t *options, int argc, char **argv)
+{
+    int rc;
+    rc = options_parse_arguments(argc, argv, options);
+    if (rc == 0) {
+        options_from_config(options);
+        /* We parse command line arguments a second time to ensure
+        **  that command line options take precedence over config files */
+        rc = options_parse_arguments(argc, argv, options);
+    }
+    if (rc == 0) {
+        rc = options_process_io(options);
+    }
+    return rc;
+}
+
+static void test(const char *expected, char **argv)
 {
     options_t options;
+    int argc = 0;
+    int rc;
+    char buf[1000];
+
+    while (argv[argc]) {
+        ++argc;
+    }
 
     options_init(&options);
-    options_parse_arguments(argc, argv, &options);
-    options_from_config(&options);
-    g_message("Options parsed");
+    rc = test_load_options(&options, argc, argv);
+    if (rc == 0) {
+        snprintf(buf, sizeof(buf), "display %s allow_control %d listen %s ca_file %s",
+                 options.display, options.allow_control, options.listen, options.ssl.ca_cert_file);
+        if (strcmp(buf, expected) != 0) {
+            fprintf(stderr, "Unexpected results:\n\t%s\n%s\n",
+                    buf, expected);
+        }
+    }
+    else {
+        fprintf(stderr, "Unable to load options, rc %d\n", rc);
+    }
     options_free(&options);
 }
+
+#define TEST(exp, ...) do { \
+    char *argv[] = { "PROGRAM", __VA_ARGS__, NULL }; \
+    test(exp, argv); \
+} while(0)
+
+int main(int argc, char **argv)
+{
+    FILE *f = fopen("test.conf", "w");
+
+    if (argc > 1) {
+        options_t options;
+        options_init(&options);
+        printf("test_load_options returns %d\n",
+            test_load_options(&options, argc, argv));
+        options_free(&options);
+    }
+
+    fprintf(f, "[spice]\ndisplay=config_display\nlisten=8765\nallow-control=true");
+    fclose(f);
+
+    TEST("display (null) allow_control 0 listen 5900 ca_file (null)",
+         "--hide");
+    TEST("display (null) allow_control 0 listen 1234 ca_file (null)",
+         "1234");
+    TEST("display config_display allow_control 1 listen 8765 ca_file (null)",
+         "--config=test.conf");
+    TEST("display config_display allow_control 1 listen 123 ca_file (null)",
+         "--config=test.conf", "123");
+    TEST("display config_display allow_control 0 listen 123 ca_file (null)",
+         "--no-allow-control", "--config=test.conf", "123");
+    TEST("display DISPLAY allow_control 1 listen 123 ca_file (null)",
+         "--display", "DISPLAY", "--config=test.conf", "123");
+    TEST("display (null) allow_control 0 listen 5900 ca_file foo",
+         "--ssl=foo");
+    unlink("test.conf");
+    return 0;
+}
 #endif
diff --git a/src/options.h b/src/options.h
index 6155984b..2302c85b 100644
--- a/src/options.h
+++ b/src/options.h
@@ -73,7 +73,6 @@ typedef struct {
 **  Prototypes
 **--------------------------------------------------------------------------*/
 void options_init(options_t *options);
-void options_handle_user_config(int argc, char *argv[], options_t *options);
 int options_parse_arguments(int argc, char *argv[], options_t *options);
 int options_process_io(options_t *options);
 void options_free(options_t *options);
-- 
2.20.1



More information about the Spice-devel mailing list