diff --git a/README.md b/README.md index 1591774..a430fae 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,6 @@ C-code generator for docopt language ==================================== -Note, *at this point the code generator handles only options* -(positional arguments, commands and pattern matching will follow). - ### Step 1. Describe your CLI in docopt language ``` @@ -55,6 +52,7 @@ int main(int argc, char *argv[]) printf(" ship == %s\n", args.ship ? "true" : "false"); printf(" shoot == %s\n", args.shoot ? "true" : "false"); printf("Arguments\n"); + printf(" name == %s\n", args.name); printf(" x == %s\n", args.x); printf(" y == %s\n", args.y); printf("Flags\n"); @@ -82,6 +80,7 @@ Commands ship == false shoot == false Arguments + name == (null) x == (null) y == (null) Flags diff --git a/docopt.c b/docopt.c index bb3392b..c0f7d26 100644 --- a/docopt.c +++ b/docopt.c @@ -9,9 +9,47 @@ #include #endif +#ifdef DOCOPT_DEBUG +#define DOCOPT_DPRINTF(...) fprintf(stderr, __VA_ARGS__) +#else +#define DOCOPT_DPRINTF(...) +#endif +#if 0 + /* docopt parsed pattern */ +Required +(Either(Required +(Command('ship', False), + Command('create', False), + OneOrMore(Argument('', None))), + Required(Command('ship', False), + Argument('', None), + Command('move', False), + Argument('', None), + Argument('', None), + Optional(Option(None, '--speed', 1, '10'))), + Required(Command('ship', False), + Command('shoot', False), + Argument('', None), + Argument('', None)), + Required(Command('mine', False), + Required(Either +(Command('set', False), + Command('remove', False))), + Argument('', None), + Argument('', None), + Optional(Either +(Option(None, '--moored', 0, False), + Option(None, '--drifting', 0, False)))), + Required(Command('anchor', False), + Optional(Option(None, '--up', 0, False)), + Optional(Argument('', None))), + Required(Option('-h', '--help', 0, False)), + Required(Option(None, '--version', 0, False)))) +#endif typedef struct { /* commands */ + int anchor; int create; int mine; int move; @@ -21,12 +59,14 @@ typedef struct { int shoot; /* arguments */ char *name; + char *number; char *x; char *y; /* options without arguments */ int drifting; int help; int moored; + int up; int version; /* options with arguments */ char *speed; @@ -43,6 +83,7 @@ const char help_message[] = " naval_fate.py ship move [--speed=]\n" " naval_fate.py ship shoot \n" " naval_fate.py mine (set|remove) [--moored|--drifting]\n" +" naval_fate.py anchor [--up] []\n" " naval_fate.py --help\n" " naval_fate.py --version\n" "\n" @@ -61,20 +102,23 @@ const char usage_pattern[] = " naval_fate.py ship move [--speed=]\n" " naval_fate.py ship shoot \n" " naval_fate.py mine (set|remove) [--moored|--drifting]\n" +" naval_fate.py anchor [--up] []\n" " naval_fate.py --help\n" " naval_fate.py --version"; -typedef struct { - const char *name; - bool value; -} Command; - typedef struct { const char *name; char *value; + int count; char **array; } Argument; +typedef struct { + const char *name; + bool value; + Argument *args; +} Command; + typedef struct { const char *oshort; const char *olong; @@ -119,6 +163,54 @@ Tokens* tokens_move(Tokens *ts) { return ts; } +/* + * Positional Arguments + */ + + +static Argument docopt_ship[] = { + {"", NULL, 0, NULL}, + {NULL, NULL, 0, NULL} +}; + +static Argument docopt_create[] = { + {"", NULL, 0, NULL}, + {NULL, NULL, 0, NULL} +}; + +static Argument docopt_move[] = { + {"", NULL, 0, NULL}, + {"", NULL, 0, NULL}, + {NULL, NULL, 0, NULL} +}; + +static Argument docopt_shoot[] = { + {"", NULL, 0, NULL}, + {"", NULL, 0, NULL}, + {NULL, NULL, 0, NULL} +}; + +static Argument docopt_mine[] = { + {NULL, NULL, 0, NULL} +}; + +static Argument docopt_set[] = { + {"", NULL, 0, NULL}, + {"", NULL, 0, NULL}, + {NULL, NULL, 0, NULL} +}; + +static Argument docopt_remove[] = { + {"", NULL, 0, NULL}, + {"", NULL, 0, NULL}, + {NULL, NULL, 0, NULL} +}; + +static Argument docopt_anchor[] = { + {"", NULL, 0, NULL}, + {NULL, NULL, 0, NULL} +}; + /* * ARGV parsing functions @@ -137,13 +229,18 @@ int parse_doubledash(Tokens *ts, Elements *elements) { int parse_long(Tokens *ts, Elements *elements) { int i; - int len_prefix; + size_t len_prefix; int n_options = elements->n_options; char *eq = strchr(ts->current, '='); - Option *option; + Option *option = NULL; Option *options = elements->options; - len_prefix = (eq-(ts->current))/sizeof(char); + if (eq) { + len_prefix = (eq-(ts->current))/sizeof(char); + } + else { + len_prefix = strlen(ts->current); + } for (i=0; i < n_options; i++) { option = &options[i]; if (!strncmp(ts->current, option->olong, len_prefix)) @@ -166,12 +263,14 @@ int parse_long(Tokens *ts, Elements *elements) { } else { option->argument = eq + 1; } + DOCOPT_DPRINTF("option %s = %s\n", option->olong, option->argument); } else { if (eq != NULL) { fprintf(stderr, "%s must not have an argument\n", option->olong); return 1; } option->value = true; + DOCOPT_DPRINTF("option %s=true\n", option->olong); } return 0; } @@ -180,7 +279,7 @@ int parse_shorts(Tokens *ts, Elements *elements) { char *raw; int i; int n_options = elements->n_options; - Option *option; + Option *option = NULL; Option *options = elements->options; raw = &ts->current[1]; @@ -215,34 +314,77 @@ int parse_shorts(Tokens *ts, Elements *elements) { return 0; } -int parse_argcmd(Tokens *ts, Elements *elements) { +int elems_to_args(Elements *elements, DocoptArgs *args, bool help, + const char *version); + +int parse_argcmd(Tokens *ts, Elements *elements, DocoptArgs *args) { int i; int n_commands = elements->n_commands; - //int n_arguments = elements->n_arguments; + int n_arguments = elements->n_arguments; Command *command; Command *commands = elements->commands; - //Argument *arguments = elements->arguments; + Argument *arguments = elements->arguments; for (i=0; i < n_commands; i++) { command = &commands[i]; - if (!strcmp(command->name, ts->current)){ + if (!strcmp(command->name, ts->current)) { + DOCOPT_DPRINTF("! matched command '%s'\n", command->name); command->value = true; tokens_move(ts); + + if (command->args) { + /* Get the subset of arguments for this command */ + int n_args = 0; + + elems_to_args(elements, args, false, NULL); + /* Count and clear the positional arguments in the subset + * TODO: Add the number of arguments to command (ie. ->n_args) + */ + for (;command->args[n_args].name; n_args++) { + command->args[n_args].value = 0; + command->args[n_args].count = 0; + command->args[n_args].array = NULL; + }; + + /* replace the argument set with the subset */ + elements->n_arguments = n_args; + elements->arguments = command->args; + } /* if command arguments */ return 0; + } /* if current token is a command */ + } /* for commands */ + + if (n_arguments) { + /* Parse positional argument */ + /* find first argument position we haven't parsed yet */ + for (i=0; i < n_arguments; i++) { + if (!arguments[i].array) { + break; + } + } + if (i < n_arguments) { + /* a new argument */ + arguments[i].value = ts->current; + arguments[i].count = 1; + arguments[i].array = &ts->argv[ts->i]; + DOCOPT_DPRINTF("argument[%d]->name %s value %s count 1\n", i, arguments[i].name, arguments[i].value); } + else { /* i == n_arguments */ + /* count as number of OneOrMore arguments */ + arguments[i-1].count++; + DOCOPT_DPRINTF("argument[%d]->name %s value %s count %u\n", i-1, arguments[i-1].name, ts->current, arguments[i-1].count); + } + tokens_move(ts); } - // not implemented yet, just skip for now - // parsed.append(Argument(None, tokens.move())) - /*fprintf(stderr, "! argument '%s' has been ignored\n", ts->current); - fprintf(stderr, " '"); - for (i=0; iargc ; i++) - fprintf(stderr, "%s ", ts->argv[i]); - fprintf(stderr, "'\n");*/ - tokens_move(ts); + else { + /* Skip unknown or unexpected tokens */ + tokens_move(ts); + } + return 0; } -int parse_args(Tokens *ts, Elements *elements) { +int parse_args(Tokens *ts, Elements *elements, DocoptArgs *args) { int ret; while (ts->current != NULL) { @@ -254,7 +396,7 @@ int parse_args(Tokens *ts, Elements *elements) { } else if (ts->current[0] == '-' && ts->current[1] != '\0') { ret = parse_shorts(ts, elements); } else - ret = parse_argcmd(ts, elements); + ret = parse_argcmd(ts, elements, args); if (ret) return ret; } return 0; @@ -267,6 +409,10 @@ int elems_to_args(Elements *elements, DocoptArgs *args, bool help, Option *option; int i; + // fix gcc-related compiler warnings (unused) + (void)command; + (void)argument; + /* options */ for (i=0; i < elements->n_options; i++) { option = &elements->options[i]; @@ -283,6 +429,8 @@ int elems_to_args(Elements *elements, DocoptArgs *args, bool help, args->help = option->value; } else if (!strcmp(option->olong, "--moored")) { args->moored = option->value; + } else if (!strcmp(option->olong, "--up")) { + args->up = option->value; } else if (!strcmp(option->olong, "--version")) { args->version = option->value; } else if (!strcmp(option->olong, "--speed")) { @@ -293,7 +441,9 @@ int elems_to_args(Elements *elements, DocoptArgs *args, bool help, /* commands */ for (i=0; i < elements->n_commands; i++) { command = &elements->commands[i]; - if (!strcmp(command->name, "create")) { + if (!strcmp(command->name, "anchor")) { + args->anchor = command->value; + } else if (!strcmp(command->name, "create")) { args->create = command->value; } else if (!strcmp(command->name, "mine")) { args->mine = command->value; @@ -312,8 +462,11 @@ int elems_to_args(Elements *elements, DocoptArgs *args, bool help, /* arguments */ for (i=0; i < elements->n_arguments; i++) { argument = &elements->arguments[i]; + if (!argument->name) {return 0;} if (!strcmp(argument->name, "")) { args->name = argument->value; + } else if (!strcmp(argument->name, "")) { + args->number = argument->value; } else if (!strcmp(argument->name, "")) { args->x = argument->value; } else if (!strcmp(argument->name, "")) { @@ -330,35 +483,40 @@ int elems_to_args(Elements *elements, DocoptArgs *args, bool help, DocoptArgs docopt(int argc, char *argv[], bool help, const char *version) { DocoptArgs args = { - 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, 0, 0, 0, 0, (char*) "10", + 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0, (char*) + "10", usage_pattern, help_message }; Tokens ts; Command commands[] = { - {"create", 0}, - {"mine", 0}, - {"move", 0}, - {"remove", 0}, - {"set", 0}, - {"ship", 0}, - {"shoot", 0} + {"anchor", 0, docopt_anchor}, + {"create", 0, docopt_create}, + {"mine", 0, docopt_mine}, + {"move", 0, docopt_move}, + {"remove", 0, docopt_remove}, + {"set", 0, docopt_set}, + {"ship", 0, docopt_ship}, + {"shoot", 0, docopt_shoot} }; Argument arguments[] = { - {"", NULL, NULL}, - {"", NULL, NULL}, - {"", NULL, NULL} + {"", NULL, 0, NULL}, + {"", NULL, 0, NULL}, + {"", NULL, 0, NULL}, + {"", NULL, 0, NULL}, + {NULL, NULL, 0, NULL} }; Option options[] = { {NULL, "--drifting", 0, 0, NULL}, {"-h", "--help", 0, 0, NULL}, {NULL, "--moored", 0, 0, NULL}, + {NULL, "--up", 0, 0, NULL}, {NULL, "--version", 0, 0, NULL}, {NULL, "--speed", 1, 0, NULL} }; - Elements elements = {7, 3, 5, commands, arguments, options}; + Elements elements = {8, 4, 6, commands, arguments, options}; ts = tokens_new(argc, argv); - if (parse_args(&ts, &elements)) + if (parse_args(&ts, &elements, &args)) exit(EXIT_FAILURE); if (elems_to_args(&elements, &args, help, version)) exit(EXIT_SUCCESS); diff --git a/docopt_c.py b/docopt_c.py index c317e68..a690b36 100755 --- a/docopt_c.py +++ b/docopt_c.py @@ -33,9 +33,12 @@ import textwrap import numbers +docopt_prefix = 'docopt_' def to_c(s): if type(s) is str: + if (s.startswith(docopt_prefix)): + return s; return ('"%s"' % s.replace('\\', r'\\')\ .replace('"', r'\"')\ .replace('\n', '\\n"\n"')) @@ -51,11 +54,12 @@ def to_c(s): def c_command(o): - return '{%s}' % ', '.join(to_c(v) for v in (o.name, o.value)) + s = docopt_prefix + o.name + return '{%s}' % ', '.join(to_c(v) for v in (o.name, o.value, s)) def c_argument(o): - return '{%s}' % ', '.join(to_c(v) for v in (o.name, o.value, None)) + return '{%s}' % ', '.join(to_c(v) for v in (o.name, o.value, 0, None)) def c_option(o): @@ -115,6 +119,7 @@ def parse_leafs(pattern, all_options): else: if node not in leafs: leafs.append(node) + sort_by_name = lambda e: e.name leafs.sort(key=sort_by_name) commands = [leaf for leaf in leafs if type(leaf) == docopt.Command] @@ -129,6 +134,67 @@ def parse_leafs(pattern, all_options): leafs = [i for sl in [commands, arguments, flags, options] for i in sl] return leafs, commands, arguments, flags, options +def append_argument_set(positional_str, cmd_set, arg_set): + if len(cmd_set): + cmd_arg = '' + for cmd in cmd_set: + cmd_arg = "\nstatic Argument " + docopt_prefix + cmd.name + '[] = {' + for arg in arg_set: + cmd_arg += "\n " + c_argument(arg) + "," + cmd_arg += '\n {NULL, NULL, 0, NULL}\n};\n' + positional_str += cmd_arg + cmd_set = [] + arg_set = [] + return positional_str, cmd_set, arg_set + +def parse_positionals(pattern): + c_positional = '' + cmd_set = [] + arg_set = [] + seen_set = [] + options_shortcut = False + leafs = [] + queue = [(0, pattern)] + while queue: + level, node = queue.pop(-1) # depth-first search + if not options_shortcut and type(node) == docopt.OptionsShortcut: + options_shortcut = True + elif hasattr(node, 'children'): + children = [((level + 1), child) for child in node.children] + children.reverse() + queue.extend(children) + else: + if node not in leafs: + leafs.append(node) + + # print("Node " + str(node)) + + if (type(node) == docopt.Command): + if (node) not in seen_set: + cmd_set.append(node) + seen_set.append(node) + + elif (type(node) == docopt.Argument): + if len(cmd_set) != 0: + arg_set.append(node) + + elif (type(node) == docopt.Required): + c_positional, cmd_set, arg_set = append_argument_set(c_positional, cmd_set, arg_set) + elif (type(node) == docopt.Either): + continue + elif (type(node) == docopt.OneOrMore): + continue + elif (type(node) == docopt.Optional): + continue + elif (type(node) == docopt.Option): + continue + else: + c_positional, cmd_set, arg_set = append_argument_set(c_positional, cmd_set, arg_set) + + c_positional, cmd_set, arg_set = append_argument_set(c_positional, cmd_set, arg_set) + + return c_positional + if __name__ == '__main__': args = docopt.docopt(__doc__) @@ -161,6 +227,12 @@ def parse_leafs(pattern, all_options): pattern = docopt.parse_pattern(docopt.formal_usage(usage), all_options) leafs, commands, arguments, flags, options = parse_leafs(pattern, all_options) + # t_pattern = '' + t_pattern = ('#if 0\n /* docopt parsed pattern */\n' + + re.sub(r'([ \(])([A-Za-z]*\()', r'\n\1\2', str(pattern)) + + '\n#endif') + + c_positional = parse_positionals(pattern) t_commands = ';\n '.join('int %s' % c_name(cmd.name) for cmd in commands) t_commands = (('\n /* commands */\n ' + t_commands + ';') @@ -184,7 +256,7 @@ def parse_leafs(pattern, all_options): t_elems_cmds = ',\n '.join([c_command(cmd) for cmd in (commands)]) t_elems_cmds = ('\n ' + t_elems_cmds) if t_elems_cmds != '' else '' t_elems_args = ',\n '.join([c_argument(arg) for arg in (arguments)]) - t_elems_args = ('\n ' + t_elems_args) if t_elems_args != '' else '' + t_elems_args = ('\n ' + t_elems_args + ',') if t_elems_args != '' else '' t_elems_opts = ',\n '.join([c_option(o) for o in (flags + options)]) t_elems_opts = ('\n ' + t_elems_opts) if t_elems_opts != '' else '' t_elems_n = ', '.join([str(len(l)) @@ -198,6 +270,8 @@ def parse_leafs(pattern, all_options): t_if_option = ''.join(c_if_option(opt) for opt in options) out = Template(args['--template']).safe_substitute( + parsed_pattern=t_pattern, + positional=c_positional, commands=t_commands, arguments=t_arguments, flags=t_flags, diff --git a/example.c b/example.c index 9b544a0..368dc3a 100644 --- a/example.c +++ b/example.c @@ -2,7 +2,7 @@ int main(int argc, char *argv[]) { - DocoptArgs args = docopt(argc, argv, /* help */ 1, /* version */ "2.0rc2"); + DocoptArgs args = docopt(--argc, ++argv, /* help */ 1, /* version */ "2.0rc2"); printf("Commands\n"); printf(" mine == %s\n", args.mine ? "true" : "false"); @@ -12,13 +12,17 @@ int main(int argc, char *argv[]) printf(" set == %s\n", args.set ? "true" : "false"); printf(" ship == %s\n", args.ship ? "true" : "false"); printf(" shoot == %s\n", args.shoot ? "true" : "false"); + printf(" anchor == %s\n", args.anchor ? "true" : "false"); printf("Arguments\n"); + printf(" name == %s\n", args.name); printf(" x == %s\n", args.x); printf(" y == %s\n", args.y); + printf(" number == %s\n", args.number); printf("Flags\n"); printf(" --drifting == %s\n", args.drifting ? "true" : "false"); printf(" --help == %s\n", args.help ? "true" : "false"); printf(" --moored == %s\n", args.moored ? "true" : "false"); + printf(" --up == %s\n", args.up ? "true" : "false"); printf(" --version == %s\n", args.version ? "true" : "false"); printf("Options\n"); printf(" --speed == %s\n", args.speed); diff --git a/example.docopt b/example.docopt index 13a7684..08e7192 100644 --- a/example.docopt +++ b/example.docopt @@ -5,6 +5,7 @@ Usage: naval_fate.py ship move [--speed=] naval_fate.py ship shoot naval_fate.py mine (set|remove) [--moored|--drifting] + naval_fate.py anchor [--up] [] naval_fate.py --help naval_fate.py --version diff --git a/template.c b/template.c index ef03505..422f09e 100644 --- a/template.c +++ b/template.c @@ -9,6 +9,12 @@ #include #endif +#ifdef DOCOPT_DEBUG +#define DOCOPT_DPRINTF(...) fprintf(stderr, __VA_ARGS__) +#else +#define DOCOPT_DPRINTF(...) +#endif +$parsed_pattern typedef struct {$commands$arguments$flags$options /* special */ @@ -22,17 +28,19 @@ const char help_message[] = const char usage_pattern[] = $usage_pattern; -typedef struct { - const char *name; - bool value; -} Command; - typedef struct { const char *name; char *value; + int count; char **array; } Argument; +typedef struct { + const char *name; + bool value; + Argument *args; +} Command; + typedef struct { const char *oshort; const char *olong; @@ -77,6 +85,11 @@ Tokens* tokens_move(Tokens *ts) { return ts; } +/* + * Positional Arguments + */ + +$positional /* * ARGV parsing functions @@ -95,13 +108,18 @@ int parse_doubledash(Tokens *ts, Elements *elements) { int parse_long(Tokens *ts, Elements *elements) { int i; - int len_prefix; + size_t len_prefix; int n_options = elements->n_options; char *eq = strchr(ts->current, '='); - Option *option; + Option *option = NULL; Option *options = elements->options; - len_prefix = (eq-(ts->current))/sizeof(char); + if (eq) { + len_prefix = (eq-(ts->current))/sizeof(char); + } + else { + len_prefix = strlen(ts->current); + } for (i=0; i < n_options; i++) { option = &options[i]; if (!strncmp(ts->current, option->olong, len_prefix)) @@ -124,12 +142,14 @@ int parse_long(Tokens *ts, Elements *elements) { } else { option->argument = eq + 1; } + DOCOPT_DPRINTF("option %s = %s\n", option->olong, option->argument); } else { if (eq != NULL) { fprintf(stderr, "%s must not have an argument\n", option->olong); return 1; } option->value = true; + DOCOPT_DPRINTF("option %s=true\n", option->olong); } return 0; } @@ -138,7 +158,7 @@ int parse_shorts(Tokens *ts, Elements *elements) { char *raw; int i; int n_options = elements->n_options; - Option *option; + Option *option = NULL; Option *options = elements->options; raw = &ts->current[1]; @@ -173,34 +193,77 @@ int parse_shorts(Tokens *ts, Elements *elements) { return 0; } -int parse_argcmd(Tokens *ts, Elements *elements) { +int elems_to_args(Elements *elements, DocoptArgs *args, bool help, + const char *version); + +int parse_argcmd(Tokens *ts, Elements *elements, DocoptArgs *args) { int i; int n_commands = elements->n_commands; - //int n_arguments = elements->n_arguments; + int n_arguments = elements->n_arguments; Command *command; Command *commands = elements->commands; - //Argument *arguments = elements->arguments; + Argument *arguments = elements->arguments; for (i=0; i < n_commands; i++) { command = &commands[i]; - if (!strcmp(command->name, ts->current)){ + if (!strcmp(command->name, ts->current)) { + DOCOPT_DPRINTF("! matched command '%s'\n", command->name); command->value = true; tokens_move(ts); + + if (command->args) { + /* Get the subset of arguments for this command */ + int n_args = 0; + + elems_to_args(elements, args, false, NULL); + /* Count and clear the positional arguments in the subset + * TODO: Add the number of arguments to command (ie. ->n_args) + */ + for (;command->args[n_args].name; n_args++) { + command->args[n_args].value = 0; + command->args[n_args].count = 0; + command->args[n_args].array = NULL; + }; + + /* replace the argument set with the subset */ + elements->n_arguments = n_args; + elements->arguments = command->args; + } /* if command arguments */ return 0; + } /* if current token is a command */ + } /* for commands */ + + if (n_arguments) { + /* Parse positional argument */ + /* find first argument position we haven't parsed yet */ + for (i=0; i < n_arguments; i++) { + if (!arguments[i].array) { + break; + } + } + if (i < n_arguments) { + /* a new argument */ + arguments[i].value = ts->current; + arguments[i].count = 1; + arguments[i].array = &ts->argv[ts->i]; + DOCOPT_DPRINTF("argument[%d]->name %s value %s count 1\n", i, arguments[i].name, arguments[i].value); + } + else { /* i == n_arguments */ + /* count as number of OneOrMore arguments */ + arguments[i-1].count++; + DOCOPT_DPRINTF("argument[%d]->name %s value %s count %u\n", i-1, arguments[i-1].name, ts->current, arguments[i-1].count); } + tokens_move(ts); } - // not implemented yet, just skip for now - // parsed.append(Argument(None, tokens.move())) - /*fprintf(stderr, "! argument '%s' has been ignored\n", ts->current); - fprintf(stderr, " '"); - for (i=0; iargc ; i++) - fprintf(stderr, "%s ", ts->argv[i]); - fprintf(stderr, "'\n");*/ - tokens_move(ts); + else { + /* Skip unknown or unexpected tokens */ + tokens_move(ts); + } + return 0; } -int parse_args(Tokens *ts, Elements *elements) { +int parse_args(Tokens *ts, Elements *elements, DocoptArgs *args) { int ret; while (ts->current != NULL) { @@ -212,7 +275,7 @@ int parse_args(Tokens *ts, Elements *elements) { } else if (ts->current[0] == '-' && ts->current[1] != '\0') { ret = parse_shorts(ts, elements); } else - ret = parse_argcmd(ts, elements); + ret = parse_argcmd(ts, elements, args); if (ret) return ret; } return 0; @@ -247,7 +310,8 @@ int elems_to_args(Elements *elements, DocoptArgs *args, bool help, } /* arguments */ for (i=0; i < elements->n_arguments; i++) { - argument = &elements->arguments[i];$if_argument + argument = &elements->arguments[i]; + if (!argument->name) {return 0;}$if_argument } return 0; } @@ -265,13 +329,14 @@ DocoptArgs docopt(int argc, char *argv[], bool help, const char *version) { Command commands[] = {$elems_cmds }; Argument arguments[] = {$elems_args + {NULL, NULL, 0, NULL} }; Option options[] = {$elems_opts }; Elements elements = {$elems_n, commands, arguments, options}; ts = tokens_new(argc, argv); - if (parse_args(&ts, &elements)) + if (parse_args(&ts, &elements, &args)) exit(EXIT_FAILURE); if (elems_to_args(&elements, &args, help, version)) exit(EXIT_SUCCESS);