Question

I am using boost::program_options to pass configuration files for my program. In particular I use often command line overriding of some of the options. For example if I register two options "opt1" and "opt2" I can successfully override the default values by running my program with

 myProgram.exe --opt1=option_value_1 --opt2=option_value_2

All good, but it happened already few times that I run my program mistakenly as

 myProgram.exe --opt1=option_value_1 opt2=option_value_2

In such a case (missing double hyphen) no error is thrown. In fact I can apparently run myProgram as

 myProgram.exe list of any unregistered and unknown values

and it still runs correctly. I would expect to at least get informed that something unexpected happened. Is there a solution to my problem?

Était-ce utile?

La solution

You should remove allow_unregistered() from your parse command. You command should simply be

po::store(parse_command_line(argc, argv, desc), vm);

then exception will be thrown on unknown options.

http://www.boost.org/doc/libs/1_54_0/doc/html/program_options/howto.html#idp123440592

If you want exception/error, if option has no "--" you should write extra parser, something like this, can help you

std::pair<std::string, std::string> fix_option(const std::string& value)
{
   std::string name = value;
   std::string val;
   std::string::size_type pos = name.find("=");
   if (pos != std::string::npos)
   {
      val = name.substr(pos + 1);
      name = name.substr(0, pos);
   }
   if (name.substr(0, 2) != "--")
   {
      throw std::logic_error(std::string("invalid command, no -- in command: ") + name);
   }
   return std::make_pair(name.substr(2), val);
}

code example

results:

./new --help=j

output: j

./new help=j

output: 
terminate called after throwing an instance of 'std::logic_error'
  what():  invalid command, no -- in command: help

Autres conseils

It seems that boost::program_options does not recognize positional arguments per default. This means that non-option arguments like opt2=option_value_2 are ignored. However, the documentation is not clear about it. You can enable handling of positional arguments with basic_command_line_parser::positional().

By Example

try {
    po::variables_map vm;
    po::store(po::command_line_parser(argc, argv).
                options(desc).positional({}).run(),
              vm);
    po::notify(vm);
} catch (po::too_many_positional_options_error &e) {
    // A positional argument like `opt2=option_value_2` was given
    cerr << e.what() << endl;
    exit(1);
} catch (po::error_with_option_name &e) {
    // Another usage error occurred
    cerr << e.what() << endl;
    exit(1);
}

Explanation

Basically,

po::store(po::parse_command_line(argc, argv, desc), vm);

has been replaced with

po::store(po::command_line_parser(argc, argv)
            .options(desc).positional({}).run(),
          vm);

As I understand the documentation, parse_command_line(argc, argv, desc) is a shorthand for command_line_parser(argc, argv).options(desc).run(). Through adding a call to positional(), we are enabling handling of positional arguments. Through specifying {}, no positional arguments are allowed. An instance of too_many_positional_options_error is thrown when too many positional arguments are given.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top