Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Parsing unregistered options for config files in Boost program_options?

With command line options, I can do the following:

po::variables_map vm;
auto parsedOptions = po::command_line_parser(argc, argv).options(optionsDescription1).allow_unregistered().run();
po::store(parsedOptions, vm);
po::notify(vm);

auto unregistered = po::collect_unrecognized(parsedOptions.options, po::include_positional);
po::variables_map vm2;
auto parsedOptions2 = po::command_line_parser(unregistered).options(optionsDescription2).run();
po::store(parsedOptions2, vm2);
po::notify(vm2);

This works fine, because collect_unregistered() collects the command line tokens exactly as it appeared in the command line. However, it doesn't work for config files. I can parse a config file allowing unregistered options, but when I collect the unregistered options, I get a result that I cannot use.

po::variables_map vm;
auto parsedOptions = po::parse_config_file<char>(filename, optionsDescription1, true);
po::store(parsedOptions, vm);
po::notify(vm);
auto unregistered = po::collect_unrecognized(parsedOptions.options, po::include_positional);

In this case I get the names and values of the options listed. For example, if the config file contained the following options:

unregistered_option1=value1
unregistered_option2=value2

Then I get the values unregistered_option1, value1, unregistered_option2, value2 in the string vector unregistered. Boost's parser cannot do anything useful with this format. Is there any way to parse this list (i.e. parse all the options that were unrecognized by the first options_description with a different options_description)? Of course I can just parse the file again with the second options_description with allow_unregistered set, but then I can't check for options unknown to both descriptions.

like image 698
petersohn Avatar asked May 14 '14 20:05

petersohn


1 Answers

You don't have to rely on the imperfections of collect_unrecognized() return value, you can always detect, handle and reconstruct the options yourself, as the result of parse_config_file() keeps the observed relationship for the unknown options:

auto parsed_options = parse_config_file(ifs, config_file_options, true);
store(parsed_options, vm);
...
for (const auto& o : parsed_options.options) {
    if (vm.find(o.string_key) == vm.end()) {
        // an unknown option
        cout << o.string_key << "=" << o.value << "\n";
    }
}
like image 135
mockinterface Avatar answered Oct 21 '22 03:10

mockinterface