diff --git a/CHANGELOG.md b/CHANGELOG.md index ce1f6fa0..10781310 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ ## Version 1.1 (in progress) * Added support for basic enumerations [#12](https://github.com/CLIUtils/CLI11/issues/12) +* Added `app.parse_order()` with original parse order ## Version 1.0 * Cleanup using `clang-tidy` and `clang-format` diff --git a/README.md b/README.md index a23b1d8a..402d5efb 100644 --- a/README.md +++ b/README.md @@ -31,15 +31,25 @@ An acceptable CLI parser library should be all of the following: * Work with standard types, simple custom types, and extendible to exotic types. * Permissively licenced. -The major CLI parsers for C++ include: +The major CLI parsers for C++ include (with my biased opinions): -* [Boost Program Options]: A great library if you already depend on Boost, but its pre-C++11 syntax is really odd and setting up the correct call in the main function is poorly documented (and is nearly a page of code). A simple wrapper for the Boost library was originally developed, but was discarded as CLI11 became more powerful. The idea of capturing a value and setting it originated with Boost PO. -* [The Lean Mean C++ Option Parser]: One header file is great, but the syntax is atrocious, in my opinion. It was quite impractical to wrap the syntax or to use in a complex project. It seems to handle standard parsing quite well. -* [TCLAP]: The not-quite-standard command line parsing causes common shortcuts to fail. It also seems to be poorly supported, with only minimal bugfixes accepted. Header only, but in quite a few files. Has not managed to get enough support to move to GitHub yet. No subcommands. Produces wrapped values. -* [Cxxopts]: C++11, single file, and nice CMake support, but requires regex, therefore GCC 4.8 (CentOS 7 default) does not work. Syntax closely based on Boost PO, so not ideal but familiar. -* [DocOpt]: Completely different approach to program options in C++11, you write the docs and the interface is generated. Too fragile and specialized. -* [GFlags]: The Google Commandline Flags library. Uses macros heavily, and is limited in scope, missing things like subcommands. It provides a simple syntax and supports config files/env vars. -* [GetOpt]: Very limited C solution with long, convoluted syntax. Does not support much of anything, like help generation. Always available on UNIX, though (but in different flavors). +| Library | My biased opinion | +|---------|-------------------| +| [Boost Program Options] | A great library if you already depend on Boost, but its pre-C++11 syntax is really odd and setting up the correct call in the main function is poorly documented (and is nearly a page of code). A simple wrapper for the Boost library was originally developed, but was discarded as CLI11 became more powerful. The idea of capturing a value and setting it originated with Boost PO. | +| [The Lean Mean C++ Option Parser] | One header file is great, but the syntax is atrocious, in my opinion. It was quite impractical to wrap the syntax or to use in a complex project. It seems to handle standard parsing quite well. | +| [TCLAP] | The not-quite-standard command line parsing causes common shortcuts to fail. It also seems to be poorly supported, with only minimal bugfixes accepted. Header only, but in quite a few files. Has not managed to get enough support to move to GitHub yet. No subcommands. Produces wrapped values. | +| [Cxxopts] | C++11, single file, and nice CMake support, but requires regex, therefore GCC 4.8 (CentOS 7 default) does not work. Syntax closely based on Boost PO, so not ideal but familiar. | +| [DocOpt] | Completely different approach to program options in C++11, you write the docs and the interface is generated. Too fragile and specialized. | + +After I wrote this, I also found the following libraries: + +| Library | My biased opinion | +|---------|-------------------| +| [GFlags] | The Google Commandline Flags library. Uses macros heavily, and is limited in scope, missing things like subcommands. It provides a simple syntax and supports config files/env vars. | +| [GetOpt] | Very limited C solution with long, convoluted syntax. Does not support much of anything, like help generation. Always available on UNIX, though (but in different flavors). | +| [ProgramOptions.hxx] | Intresting library, less powerful and no subcommands. | +| [Args] | Also interesting, and supports subcommands. I like the optional-like design, but CLI11 is cleaner and provides direct value access, and is less verbose. | +| [Argument Aggregator] | I'm a big fan of the [fmt] library, and the try-catch statement looks familiar. :thumbsup: Doesn't seem to support subcommands. | None of these libraries fulfill all the above requirements. As you probably have already guessed, CLI11 does. So, this library was designed to provide a great syntax, good compiler compatibility, and minimal installation fuss. @@ -154,7 +164,7 @@ On the command line, options can be given as: * `--file=filename` (equals) Extra positional arguments will cause the program to exit, so at least one positional option with a vector is recommended if you want to allow extraneous arguments. -If you set `.allow_extras()` on the main `App`, the parse function will return the left over arguments instead of throwing an error. +If you set `.allow_extras()` on the main `App`, the parse function will return the left over arguments instead of throwing an error. You can access a vector of pointers to the parsed options in the original order using `parse_order()`. If `--` is present in the command line, everything after that is positional only. @@ -306,4 +316,8 @@ CLI11 was developed at the [University of Cincinnati] to support of the [GooFit] [DIANA/HEP]: http://diana-hep.org [NSF Award 1414736]: https://nsf.gov/awardsearch/showAward?AWD_ID=1414736 [University of Cincinnati]: http://www.uc.edu -[GitBook]: https://henryiii.gitbooks.io/cli11/content +[GitBook]: https://henryiii.gitbooks.io/cli11/content +[ProgramOptions.hxx]: https://github.com/Fytch/ProgramOptions.hxx +[Argument Aggregator]: https://github.com/vietjtnguyen/argagg +[Args]: https://github.com/Taywee/args +[fmt]: https://github.com/fmtlib/fmt diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index d08459ad..f41d948e 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -14,6 +14,7 @@ function(add_cli_exe T) endif() endfunction() -add_cli_exe(try try.cpp) -add_cli_exe(try1 try1.cpp) -add_cli_exe(try2 try2.cpp) +add_cli_exe(simple simple.cpp) +add_cli_exe(subcommands subcommands.cpp) +add_cli_exe(groups groups.cpp) +add_cli_exe(inter_argument_order inter_argument_order.cpp) diff --git a/examples/try2.cpp b/examples/groups.cpp similarity index 100% rename from examples/try2.cpp rename to examples/groups.cpp diff --git a/examples/inter_argument_order.cpp b/examples/inter_argument_order.cpp new file mode 100644 index 00000000..6d570e1b --- /dev/null +++ b/examples/inter_argument_order.cpp @@ -0,0 +1,48 @@ +#include +#include +#include +#include + +int main(int argc, char **argv) { + CLI::App app; + + std::vector foos; + auto foo = app.add_option("--foo,-f", foos); + + std::vector bars; + auto bar = app.add_option("--bar", bars); + + app.add_flag("--z,--x"); // Random other flags + + // Standard parsing lines (copy and paste in) + try { + app.parse(argc, argv); + } catch(const CLI::ParseError &e) { + return app.exit(e); + } + + // I perfer using the back and popping + std::reverse(std::begin(foos), std::end(foos)); + std::reverse(std::begin(bars), std::end(bars)); + + std::vector> keyval; + for(auto option : app.parse_order()) { + if(option == foo) { + keyval.emplace_back("foo", foos.back()); + foos.pop_back(); + } + if(option == bar) { + keyval.emplace_back("bar", bars.back()); + bars.pop_back(); + } + } + + // Prove the vector is correct + std::string name; + int value; + + for(auto &tuple : keyval) { + std::tie(name, value) = tuple; + std::cout << name << " : " << value << std::endl; + } +} diff --git a/examples/try.cpp b/examples/simple.cpp similarity index 100% rename from examples/try.cpp rename to examples/simple.cpp diff --git a/examples/try1.cpp b/examples/subcommands.cpp similarity index 100% rename from examples/try1.cpp rename to examples/subcommands.cpp diff --git a/include/CLI/App.hpp b/include/CLI/App.hpp index a76b6f3f..02d20751 100644 --- a/include/CLI/App.hpp +++ b/include/CLI/App.hpp @@ -81,6 +81,9 @@ class App { /// This is faster and cleaner than storing just a list of strings and reparsing. This may contain the -- separator. missing_t missing_; + /// This is a list of pointers to options with the orignal parse order + std::vector