[Spice-devel] [PATCH fixup1 x11spice 2/3] Simplify the expression of argument parsing.

Frediano Ziglio fziglio at redhat.com
Wed Jul 24 14:59:00 UTC 2019


> 
> This fixes a bug with --config=handling.
> 
> This also includes test code courtesy of Frediano Ziglio
> <fziglio at redhat.com>.

This was very experiment patch, just worked.
I would turn it in a real test as there's a tests directory.
It seems is using just exported APIs so maybe would be better
to put a new test (executable) in tests directory having a
main function and calling/linking options.c.

> 
> Signed-off-by: Jeremy White <jwhite at codeweavers.com>
> ---
>  src/main.c    |  8 +++--
>  src/options.c | 91 ++++++++++++++++++++++++++++++++++++++++++---------
>  src/options.h |  1 -
>  3 files changed, 82 insertions(+), 18 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);
> +    }

I personally find a bit complicated API to use, a simple call to
a single function would be IMHO better.

>      if (rc)
>          goto exit;
>  
> diff --git a/src/options.c b/src/options.c
> index cff4ac17..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) {
> -            options->user_config_file = g_strdup(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) {
> @@ -501,15 +492,85 @@ int options_impossible_config(options_t *options)
>      return 1;
>  }
>  
> -#if defined(OPTIONS_MAIN)

What was this 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);
> +    }

quite boring that every time you need to use options_parse_arguments
you have to repeat these step.

> +    if (rc == 0) {
> +        rc = options_process_io(options);

Is this always mandatory? Can the user of these API avoid to call it?

> +    }
> +    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);

Frediano


More information about the Spice-devel mailing list