Commit 34bd80971bbb35770909ecfa26acc7f146646c09

Authored by Philip Top
Committed by GitHub
1 parent 73e94b22

allow the use of `allow_extra_args(false)` to specify only a single argument at …

…a time with a container output. (#484)
README.md
... ... @@ -322,6 +322,7 @@ Before parsing, you can set the following options:
322 322 - `->ignore_case()`: Ignore the case on the command line (also works on subcommands, does not affect arguments).
323 323 - `->ignore_underscore()`: Ignore any underscores in the options names (also works on subcommands, does not affect arguments). For example "option_one" will match with "optionone". This does not apply to short form options since they only have one character
324 324 - `->disable_flag_override()`: From the command line long form flag options can be assigned a value on the command line using the `=` notation `--flag=value`. If this behavior is not desired, the `disable_flag_override()` disables it and will generate an exception if it is done on the command line. The `=` does not work with short form flag options.
  325 +- `->allow_extra_args(true/false)`: 🚧 If set to true the option will take an unlimited number of arguments like a vector, if false it will limit the number of arguments to the size of the type used in the option. Default value depends on the nature of the type use, containers default to true, others default to false.
325 326 - `->delimiter(char)`: Allows specification of a custom delimiter for separating single arguments into vector arguments, for example specifying `->delimiter(',')` on an option would result in `--opt=1,2,3` producing 3 elements of a vector and the equivalent of --opt 1 2 3 assuming opt is a vector value.
326 327 - `->description(str)`: Set/change the description.
327 328 - `->multi_option_policy(CLI::MultiOptionPolicy::Throw)`: Set the multi-option policy. Shortcuts available: `->take_last()`, `->take_first()`,`->take_all()`, and `->join()`. This will only affect options expecting 1 argument or bool flags (which do not inherit their default but always start with a specific policy).
... ...
include/CLI/App.hpp
... ... @@ -2761,7 +2761,12 @@ class App {
2761 2761 }
2762 2762 int min_num = (std::min)(op->get_type_size_min(), op->get_items_expected_min());
2763 2763 int max_num = op->get_items_expected_max();
2764   -
  2764 + // check container like options to limit the argument size to a single type if the allow_extra_flags argument is
  2765 + // set. 16 is somewhat arbitrary (needs to be at least 4)
  2766 + if(max_num >= detail::expected_max_vector_size / 16 && !op->get_allow_extra_args()) {
  2767 + auto tmax = op->get_type_size_max();
  2768 + max_num = detail::checked_multiply(tmax, op->get_expected_min()) ? tmax : detail::expected_max_vector_size;
  2769 + }
2765 2770 // Make sure we always eat the minimum for unlimited vectors
2766 2771 int collected = 0; // total number of arguments collected
2767 2772 int result_count = 0; // local variable for number of results in a single arg string
... ...
tests/OptionTypeTest.cpp
... ... @@ -838,3 +838,29 @@ TEST_F(TApp, tupleTwoVectors) {
838 838 EXPECT_EQ(std::get<0>(cv).size(), 2U);
839 839 EXPECT_EQ(std::get<1>(cv).size(), 3U);
840 840 }
  841 +
  842 +TEST_F(TApp, vectorSingleArg) {
  843 +
  844 + std::vector<int> cv;
  845 + app.add_option("-c", cv)->allow_extra_args(false);
  846 + std::string extra;
  847 + app.add_option("args", extra);
  848 + args = {"-c", "1", "-c", "2", "4"};
  849 +
  850 + run();
  851 + EXPECT_EQ(cv.size(), 2U);
  852 + EXPECT_EQ(extra, "4");
  853 +}
  854 +
  855 +TEST_F(TApp, vectorDoubleArg) {
  856 +
  857 + std::vector<std::pair<int, std::string>> cv;
  858 + app.add_option("-c", cv)->allow_extra_args(false);
  859 + std::vector<std::string> extras;
  860 + app.add_option("args", extras);
  861 + args = {"-c", "1", "bob", "-c", "2", "apple", "4", "key"};
  862 +
  863 + run();
  864 + EXPECT_EQ(cv.size(), 2U);
  865 + EXPECT_EQ(extras.size(), 2U);
  866 +}
... ...