diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2016-02-12 13:39:14 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2016-02-12 13:39:14 +0200 |
commit | 2c58968b94f348911372e8afb47626d33825757b (patch) | |
tree | 0116d87bc8f829c17f6e9644d2cf8534e67568c8 | |
parent | 4d606849c74a2effc05a595368d2d0b48acf880e (diff) |
Add support for mixing command line options and arguments
-rw-r--r-- | bpkg/bpkg.cli | 18 | ||||
-rw-r--r-- | bpkg/bpkg.cxx | 68 | ||||
-rw-r--r-- | bpkg/buildfile | 10 |
3 files changed, 61 insertions, 35 deletions
diff --git a/bpkg/bpkg.cli b/bpkg/bpkg.cli index f299eaf..107ef0a 100644 --- a/bpkg/bpkg.cli +++ b/bpkg/bpkg.cli @@ -26,11 +26,11 @@ namespace bpkg packages, and repositories using a set of commands that are summarized below. - For a detailed description of any command or help topic, use the \cb{help} - command or see the corresponding man page (the man pages have the - \cb{bpkg-} prefix, for example \l{bpkg-help(1)}). Note that the common - options can also be specified as part of the command-specific options, for - convenience." + For a detailed description of any command or help topic, use the + \cb{help} command or see the corresponding man page (the man pages have + the \cb{bpkg-} prefix, for example \l{bpkg-help(1)}). Note also that + <command-options> and <command-args> can be specified in any order and + <common-options> can be specified as part of <command-options>." } // For usage it's nice to see the list of commands on the first page. So @@ -152,9 +152,7 @@ namespace bpkg bool cfg-create|create { - "<dir>", - "\l{bpkg-cfg-create(1)} \- create configuration", - "" + "\l{bpkg-cfg-create(1)} \- create configuration" } bool cfg-add|add @@ -218,9 +216,7 @@ namespace bpkg bool pkg-fetch { - "<pkg>/<ver>", - "\l{bpkg-pkg-fetch(1)} \- fetch package archive", - "" + "\l{bpkg-pkg-fetch(1)} \- fetch package archive" } bool pkg-unpack diff --git a/bpkg/bpkg.cxx b/bpkg/bpkg.cxx index 35fb796..8d4d1fb 100644 --- a/bpkg/bpkg.cxx +++ b/bpkg/bpkg.cxx @@ -2,6 +2,7 @@ // copyright : Copyright (c) 2014-2016 Code Synthesis Ltd // license : MIT; see accompanying LICENSE file +#include <cstring> // strcmp() #include <iostream> #include <exception> @@ -41,18 +42,46 @@ using namespace std; using namespace bpkg; -// Initialize the command option class O with the common options -// and then parse the rest of the arguments. Once this is done, -// use the "final" values of the common options to do global -// initializations (verbosity level, etc). +// Initialize the command option class O with the common options and then +// parse the rest of the command line placing non-option arguments to args. +// Once this is done, use the "final" values of the common options to do +// global initializations (verbosity level, etc). // template <typename O> static O -parse (const common_options& co, cli::scanner& s) +parse (const common_options& co, cli::scanner& scan, strings& args) { O o; static_cast<common_options&> (o) = co; - o.parse (s); + + // We want to be able to specify options and arguments in any order (it is + // really handy to just add -v at the end of the command line). + // + for (bool opt (true); scan.more (); ) + { + if (opt) + { + // If we see first "--", then we are done parsing options. + // + if (strcmp (scan.peek (), "--") == 0) + { + scan.next (); + opt = false; + continue; + } + + // Parse the next chunk of options until we reach an argument (or eos). + // + o.parse (scan); + + if (!scan.more ()) + break; + + // Fall through. + } + + args.push_back (scan.next ()); + } // Global initializations. // @@ -70,12 +99,12 @@ try { using namespace cli; - argv_file_scanner args (argc, argv, "--options-file"); + argv_file_scanner scan (argc, argv, "--options-file"); // First parse common options and --version/--help. // options o; - o.parse (args, unknown_mode::stop); + o.parse (scan, unknown_mode::stop); if (o.version ()) { @@ -87,19 +116,22 @@ try return 0; } - if (o.help ()) - return help (help_options (), "", nullptr); + strings argsv; // To be filled by parse() above. + vector_scanner args (argsv); const common_options& co (o); + if (o.help ()) + return help (parse<help_options> (co, scan, argsv), "", nullptr); + // The next argument should be a command. // - if (!args.more ()) + if (!scan.more ()) fail << "bpkg command expected" << info << "run 'bpkg help' for more information"; int cmd_argc (2); - char* cmd_argv[] {argv[0], const_cast<char*> (args.next ())}; + char* cmd_argv[] {argv[0], const_cast<char*> (scan.next ())}; commands cmd; cmd.parse (cmd_argc, cmd_argv, true, unknown_mode::stop); @@ -116,7 +148,7 @@ try if (h) { - ho = parse<help_options> (co, args); + ho = parse<help_options> (co, scan, argsv); if (args.more ()) { @@ -158,9 +190,9 @@ try // if (h) // r = help (ho, "pkg-verify", print_bpkg_pkg_verify_usage); // else - // r = pkg_verify (parse<pkg_verify_options> (co, args), args); + // r = pkg_verify (parse<pkg_verify_options> (co, scan, argsv), args); // - // return 0; + // break; // } // #define COMMAND_IMPL(NP, SP, CMD) \ @@ -169,7 +201,7 @@ try if (h) \ r = help (ho, SP#CMD, print_bpkg_##NP##CMD##_usage); \ else \ - r = NP##CMD (parse<NP##CMD##_options> (co, args), args); \ + r = NP##CMD (parse<NP##CMD##_options> (co, scan, argsv), args); \ \ break; \ } @@ -234,9 +266,7 @@ catch (const failed&) } catch (const cli::exception& e) { - *diag_stream << "error: "; - e.print (*diag_stream); - *diag_stream << endl; + error << e; return 1; } /* diff --git a/bpkg/buildfile b/bpkg/buildfile index 4effcaf..50a68e6 100644 --- a/bpkg/buildfile +++ b/bpkg/buildfile @@ -101,11 +101,11 @@ if! $cli.loaded # Option length must be the same to get commands/topics/options aligned. # -cli.options += -I $src_root --include-with-brackets --include-prefix bpkg \ ---guard-prefix BPKG --cxx-prologue "#include <bpkg/types-parsers>" \ ---cli-namespace bpkg::cli --generate-file-scanner --generate-specifier \ ---generate-parse --ansi-color --page-usage 'bpkg::print_$name$_' \ ---include-base-last --option-length 23 +cli.options += -I $src_root --include-with-brackets --include-prefix bpkg \ +--guard-prefix BPKG --cxx-prologue "#include <bpkg/types-parsers>" \ +--cli-namespace bpkg::cli --generate-vector-scanner --generate-file-scanner \ +--generate-specifier --generate-parse --page-usage 'bpkg::print_$name$_' \ +--ansi-color --include-base-last --option-length 23 cli.cxx{common-options}: cli.options += --short-usage --long-usage # Both. cli.cxx{bpkg-options}: cli.options += --short-usage --suppress-undocumented |