On 7/9/2013 3:47 AM, Quentin Glidic wrote:
> From: Quentin Glidic <[email protected]>
> 
> Long options with argument support two formats: equal ("--long=arg") and
> space ("--long arg")
> Short options now support three formats: short ("-sarg"), equal
> ("-s=arg") and space ("-s value")
> 
> Provide a test program
> 
> Signed-off-by: Quentin Glidic <[email protected]>
> ---
>  man/weston.man             |   4 +
>  shared/option-parser.c     | 111 ++++++++++++---
>  tests/Makefile.am          |   9 +-
>  tests/option-parser-test.c | 342 
> +++++++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 447 insertions(+), 19 deletions(-)
>  create mode 100644 tests/option-parser-test.c
> 
> diff --git a/man/weston.man b/man/weston.man
> index 39d854b..79d4588 100644
> --- a/man/weston.man
> +++ b/man/weston.man
> @@ -92,6 +92,10 @@ and
>  .\" ***************************************************************
>  .SH OPTIONS
>  .
> +Long options with an argument support two format: equal ("--long=arg") and
> +space ("--long arg"). Short options with argument support three format: short
> +("-sarg"), equal ("-s=arg") and space ("-s arg").
> +.
>  .SS Weston core options:
>  .TP
>  \fB\-\^B\fR\fIbackend.so\fR, \fB\-\-backend\fR=\fIbackend.so\fR
> diff --git a/shared/option-parser.c b/shared/option-parser.c
> index c00349a..da9c394 100644
> --- a/shared/option-parser.c
> +++ b/shared/option-parser.c
> @@ -30,22 +30,34 @@
>  
>  #include "config-parser.h"
>  
> -static void
> -handle_option(const struct weston_option *option, char *value)
> +enum state {
> +     OK,
> +     EATEN,
> +     ERROR
> +};
> +
> +static enum state
> +handle_option(const struct weston_option *option, const char *value)
>  {
>       switch (option->type) {
>       case WESTON_OPTION_INTEGER:
> +             if (value == NULL || value[0] == '\0')
> +                     return ERROR;
>               * (int32_t *) option->data = strtol(value, NULL, 0);
> -             return;
> +             return EATEN;
>       case WESTON_OPTION_UNSIGNED_INTEGER:
> +             if (value == NULL || value[0] == '\0')
> +                     return ERROR;
>               * (uint32_t *) option->data = strtoul(value, NULL, 0);
> -             return;
> +             return EATEN;

Can this be a fallthrough? Looks like both of the cases use the same logic.

>       case WESTON_OPTION_STRING:
> +             if (value == NULL)
> +                     return ERROR;
>               * (char **) option->data = strdup(value);
> -             return;
> +             return EATEN;
>       case WESTON_OPTION_BOOLEAN:
>               * (int32_t *) option->data = 1;
> -             return;
> +             return OK;
>       default:
>               assert(0);
>       }
> @@ -56,26 +68,89 @@ parse_options(const struct weston_option *options,
>             int count, int *argc, char *argv[])
>  {
>       int i, j, k, len = 0;
> +     const char *arg, *value;
>  
>       for (i = 1, j = 1; i < *argc; i++) {
> -             for (k = 0; k < count; k++) {
> -                     if (options[k].name)
> +             arg = argv[i];
> +             value = argv[i+1];
> +
> +             if (arg[0] != '-')
> +             {
> +                     /* Not an option, just skip it */
> +                     argv[j++] = argv[i];
> +                     continue;
> +             }
> +             ++arg; /* Skip the first dash */
> +
> +             /* We have an option, check for which one */
> +             if (arg[0] == '-') {
> +                     /* Long option */
> +                     ++arg; /* Skip the second dash */
> +                     for (k = 0; k < count; k++) {
> +                             if (!options[k].name)
> +                                     /* No long variant for this option */
> +                                     continue;
> +
>                               len = strlen(options[k].name);
> -                     if (options[k].name &&
> -                         argv[i][0] == '-' &&
> -                         argv[i][1] == '-' &&
> -                         strncmp(options[k].name, &argv[i][2], len) == 0 &&
> -                         (argv[i][len + 2] == '=' || argv[i][len + 2] == 
> '\0')) {
> -                             handle_option(&options[k], &argv[i][len + 3]);
> +                             if (strncmp(options[k].name, arg, len) != 0)
> +                                     /* Not matching */
> +                                     continue;
> +
> +                             switch (arg[len]) {
> +                             case '=': value = arg + (len+1);
> +                             case '\0': break;
> +                             default: continue; /* Not fully matching */
> +                             }
> +
> +                             switch (handle_option(&options[k], value)) {
> +                             case OK: break;
> +                             case EATEN:
> +                                     if (arg[len] == '\0')
> +                                             ++i;
> +                                     break;
> +                             case ERROR: return -1;
> +                             }
> +
>                               break;
> -                     } else if (options[k].short_name &&
> -                                argv[i][0] == '-' &&
> -                                options[k].short_name == argv[i][1]) {
> -                             handle_option(&options[k], &argv[i][2]);
> +                     }
> +             } else {
> +                     /* Short option */
> +                     for (k = 0; k < count; k++) {
> +                             if (!options[k].short_name)
> +                                     /* no short variant for this option */
> +                                     continue;
> +
> +                             if (options[k].short_name != arg[0])
> +                                     /* Not matching */
> +                                     continue;
> +
> +                             if (arg[1] != '\0')
> +                                     value = arg+1;
> +
> +                             switch (arg[1]) {
> +                             case '\0': break;
> +                             case '=': value = arg + 2; break;
> +                             default: value = arg + 1;
> +                             }
> +                             //fprintf(stderr, "arg = %s, value = '%s'\n", 
> arg, value);
> +
> +                             switch (handle_option(&options[k], value)) {
> +                             case OK:
> +                                     if (arg[1] != '\0')
> +                                             /* Do not support merged short 
> options */
> +                                             return -1;
> +                                     break;
> +                             case EATEN:
> +                                     if (arg[1] == '\0')
> +                                             ++i;
> +                                     break;
> +                             case ERROR: return -1;
> +                             }
>                               break;
>                       }
>               }
>               if (k == count)
> +                     /* None matched */
>                       argv[j++] = argv[i];
>       }
>       argv[j] = NULL;
> diff --git a/tests/Makefile.am b/tests/Makefile.am
> index d4aa909..29ebaef 100644
> --- a/tests/Makefile.am
> +++ b/tests/Makefile.am
> @@ -1,7 +1,8 @@
>  TESTS = $(shared_tests) $(module_tests) $(weston_tests)
>  
>  shared_tests = \
> -     config-parser.test
> +     config-parser.test              \
> +     option-parser.test
>  
>  module_tests =                               \
>       surface-test.la                 \
> @@ -57,6 +58,12 @@ config_parser_test_LDADD = \
>  config_parser_test_SOURCES = \
>       config-parser-test.c
>  
> +option_parser_test_SOURCES =         \
> +     option-parser-test.c            \
> +     $(weston_test_runner_src)
> +option_parser_test_LDADD =           \
> +     ../shared/libshared.la
> +
>  surface_global_test_la_SOURCES = surface-global-test.c
>  surface_test_la_SOURCES = surface-test.c
>  
> diff --git a/tests/option-parser-test.c b/tests/option-parser-test.c
> new file mode 100644
> index 0000000..0329122
> --- /dev/null
> +++ b/tests/option-parser-test.c
> @@ -0,0 +1,342 @@
> +/*
> + * Copyright © 2013 Quentin "Sardem FF7" Glidic
> + *
> + * Permission to use, copy, modify, distribute, and sell this software and
> + * its documentation for any purpose is hereby granted without fee, provided
> + * that the above copyright notice appear in all copies and that both that
> + * copyright notice and this permission notice appear in supporting
> + * documentation, and that the name of the copyright holders not be used in
> + * advertising or publicity pertaining to distribution of the software
> + * without specific, written prior permission.  The copyright holders make
> + * no representations about the suitability of this software for any
> + * purpose.  It is provided "as is" without express or implied warranty.
> + *
> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
> + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
> + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
> + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
> + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
> + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
> + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#include <stdlib.h>
> +#include <stdint.h>
> +#include <string.h>
> +#include <assert.h>
> +#include "weston-test-runner.h"
> +#include "config-parser.h"
> +
> +#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
> +
> +static char *str = NULL;
> +static int32_t i = 0;
> +static uint32_t u = 0;
> +static uint8_t b = 0;
> +
> +const struct weston_option test_options[] = {
> +     { WESTON_OPTION_STRING,           "string", 's', &str },
> +     { WESTON_OPTION_INTEGER,          "int",    'i', &i },
> +     { WESTON_OPTION_UNSIGNED_INTEGER, "uint",   'u', &u },
> +     { WESTON_OPTION_BOOLEAN,          "bool",   'b', &b },
> +};
> +
> +static void reset(void) {
> +     str = NULL;
> +     i = -1;
> +     u = 0;
> +     b = 0;
> +}
> +
> +TEST(option_parser_test_empty)
> +{
> +     reset();
> +     char *argv[] = {
> +             "test",
> +             NULL
> +     };
> +     int argc = ARRAY_LENGTH(argv) - 1;
> +
> +     int r = parse_options(test_options, ARRAY_LENGTH(test_options), &argc, 
> argv);
> +     assert(r == 1);
> +     assert(argc == r);
> +}
> +
> +TEST(option_parser_test_extra)
> +{
> +     reset();
> +     char *argv[] = {
> +             "test",
> +             "extra",
> +             NULL
> +     };
> +     int argc = ARRAY_LENGTH(argv) - 1;
> +
> +     int r = parse_options(test_options, ARRAY_LENGTH(test_options), &argc, 
> argv);
> +     assert(r == 2);
> +     assert(argc == r);
> +}
> +
> +TEST(option_parser_test_long_equal)
> +{
> +     reset();
> +     char *argv[] = {
> +             "test",
> +             "--string=s",
> +             "--int=-10",
> +             "--uint=10",
> +             "--bool",
> +             NULL
> +     };
> +     int argc = ARRAY_LENGTH(argv) - 1;
> +
> +     int r = parse_options(test_options, ARRAY_LENGTH(test_options), &argc, 
> argv);
> +     assert(r == 1);
> +     assert(argc == r);
> +     assert(strcmp(str, "s") == 0);
> +     assert(i == -10);
> +     assert(u == 10);
> +     assert(b);
> +}
> +
> +TEST(option_parser_test_long_equal_extra)
> +{
> +     reset();
> +     char *argv[] = {
> +             "test",
> +             "--string=s",
> +             "--int=-10",
> +             "--uint=10",
> +             "--bool",
> +             "extra",
> +             NULL
> +     };
> +     int argc = ARRAY_LENGTH(argv) - 1;
> +
> +     int r = parse_options(test_options, ARRAY_LENGTH(test_options), &argc, 
> argv);
> +     assert(r == 2);
> +     assert(argc == r);
> +     assert(strcmp(str, "s") == 0);
> +     assert(i == -10);
> +     assert(u == 10);
> +     assert(b);
> +}
> +
> +TEST(option_parser_test_long_space)
> +{
> +     reset();
> +     char *argv[] = {
> +             "test",
> +             "--string", "s",
> +             "--int", "-10",
> +             "--uint", "10",
> +             "--bool",
> +             NULL
> +     };
> +     int argc = ARRAY_LENGTH(argv) - 1;
> +
> +     int r = parse_options(test_options, ARRAY_LENGTH(test_options), &argc, 
> argv);
> +     assert(r == 1);
> +     assert(argc == r);
> +     assert(strcmp(str, "s") == 0);
> +     assert(i == -10);
> +     assert(u == 10);
> +     assert(b);
> +}
> +
> +TEST(option_parser_test_long_space_extra)
> +{
> +     reset();
> +     char *argv[] = {
> +             "test",
> +             "--string", "s",
> +             "--int", "-10",
> +             "--uint", "10",
> +             "--bool",
> +             "extra",
> +             NULL
> +     };
> +     int argc = ARRAY_LENGTH(argv) - 1;
> +
> +     int r = parse_options(test_options, ARRAY_LENGTH(test_options), &argc, 
> argv);
> +     assert(r == 2);
> +     assert(argc == r);
> +     assert(strcmp(str, "s") == 0);
> +     assert(i == -10);
> +     assert(u == 10);
> +     assert(b);
> +}
> +
> +TEST(option_parser_test_short)
> +{
> +     reset();
> +     char *argv[] = {
> +             "test",
> +             "-ss",
> +             "-i-10",
> +             "-u10",
> +             "-b",
> +             NULL
> +     };
> +     int argc = ARRAY_LENGTH(argv) - 1;
> +
> +     int r = parse_options(test_options, ARRAY_LENGTH(test_options), &argc, 
> argv);
> +     assert(r == 1);
> +     assert(argc == r);
> +     assert(strcmp(str, "s") == 0);
> +     assert(i == -10);
> +     assert(u == 10);
> +     assert(b);
> +}
> +
> +TEST(option_parser_test_short_equal)
> +{
> +     reset();
> +     char *argv[] = {
> +             "test",
> +             "-s=s",
> +             "-i=-10",
> +             "-u=10",
> +             "-b",
> +             NULL
> +     };
> +     int argc = ARRAY_LENGTH(argv) - 1;
> +
> +     int r = parse_options(test_options, ARRAY_LENGTH(test_options), &argc, 
> argv);
> +     assert(r == 1);
> +     assert(argc == r);
> +     assert(strcmp(str, "s") == 0);
> +     assert(i == -10);
> +     assert(u == 10);
> +     assert(b);
> +}
> +
> +TEST(option_parser_test_short_space)
> +{
> +     reset();
> +     char *argv[] = {
> +             "test",
> +             "-s", "s",
> +             "-i", "-10",
> +             "-u", "10",
> +             "-b",
> +             NULL
> +     };
> +     int argc = ARRAY_LENGTH(argv) - 1;
> +
> +     int r = parse_options(test_options, ARRAY_LENGTH(test_options), &argc, 
> argv);
> +     assert(r == 1);
> +     assert(argc == r);
> +     assert(strcmp(str, "s") == 0);
> +     assert(i == -10);
> +     assert(u == 10);
> +     assert(b);
> +}
> +
> +TEST(option_parser_test_long_equal_missing_right)
> +{
> +     reset();
> +     char *argv[] = {
> +             "test",
> +             "--string=",
> +             NULL
> +     };
> +     int argc = ARRAY_LENGTH(argv) - 1;
> +
> +     int r = parse_options(test_options, ARRAY_LENGTH(test_options), &argc, 
> argv);
> +     assert(r == 1);
> +     assert(argc == r);
> +     assert(strcmp(str, "") == 0);
> +     assert(i == -1);
> +     assert(u == 0);
> +     assert(!b);
> +}
> +
> +TEST(option_parser_test_long_equal_missing_wrong)
> +{
> +     reset();
> +     char *argv[] = {
> +             "test",
> +             "--int=",
> +             NULL
> +     };
> +     int argc = ARRAY_LENGTH(argv) - 1;
> +
> +     int r = parse_options(test_options, ARRAY_LENGTH(test_options), &argc, 
> argv);
> +     assert(r == -1);
> +}
> +
> +TEST(option_parser_test_long_space_missing)
> +{
> +     reset();
> +     char *argv[] = {
> +             "test",
> +             "--string",
> +             NULL
> +     };
> +     int argc = ARRAY_LENGTH(argv) - 1;
> +
> +     int r = parse_options(test_options, ARRAY_LENGTH(test_options), &argc, 
> argv);
> +     assert(r == -1);
> +}
> +
> +TEST(option_parser_test_short_space_missing)
> +{
> +     reset();
> +     char *argv[] = {
> +             "test",
> +             "-s",
> +             NULL
> +     };
> +     int argc = ARRAY_LENGTH(argv) - 1;
> +
> +     int r = parse_options(test_options, ARRAY_LENGTH(test_options), &argc, 
> argv);
> +     assert(r == -1);
> +}
> +
> +TEST(option_parser_test_short_equal_missing_right)
> +{
> +     reset();
> +     char *argv[] = {
> +             "test",
> +             "-s=",
> +             NULL
> +     };
> +     int argc = ARRAY_LENGTH(argv) - 1;
> +
> +     int r = parse_options(test_options, ARRAY_LENGTH(test_options), &argc, 
> argv);
> +     assert(r == 1);
> +     assert(argc == r);
> +     assert(strcmp(str, "") == 0);
> +     assert(i == -1);
> +     assert(u == 0);
> +     assert(!b);
> +}
> +
> +TEST(option_parser_test_short_equal_missing_wrong)
> +{
> +     reset();
> +     char *argv[] = {
> +             "test",
> +             "-i=",
> +             NULL
> +     };
> +     int argc = ARRAY_LENGTH(argv) - 1;
> +
> +     int r = parse_options(test_options, ARRAY_LENGTH(test_options), &argc, 
> argv);
> +     assert(r == -1);
> +}
> +
> +TEST(option_parser_test_short_concat)
> +{
> +     reset();
> +     char *argv[] = {
> +             "test",
> +             "-bcd",
> +             NULL
> +     };
> +     int argc = ARRAY_LENGTH(argv) - 1;
> +
> +     int r = parse_options(test_options, ARRAY_LENGTH(test_options), &argc, 
> argv);
> +     assert(r == -1);
> +}
> 

_______________________________________________
wayland-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/wayland-devel

Reply via email to