1

I'm trying to parse unregistered options in any number of files provided at command line. Let's say I have files:

configs0.ini configs1.ini configs2.ini 

And I wanted to support any number of these.

My code (simplified):

namespace po = boost::program_options; po::options_description cmd_opts{"Options"}; po::options_description config_file_opts; po::variables_map vm; cmd_opts.add_options() ("help,h", "Help message") ("config_files", po::value<std::vector<std::string>>()->multitoken(), "Configuration files to get settings from") po::parser.options(reg_config_file_opts).allow_unregistered(); po::store(parse_command_line(argc, argv, cmd_opts), vm); config_files = vm["config_files"].as<std::vector<std::string>>(); po::parsed_options parsed_opts; for(auto file : config_files) { std::ifstream ifs(file, std::ifstream::in); if(ifs.fail()) { std::cerr << "Error opening config file: " << file << std::endl; return false; } ifs.close(); <NEED HELP HERE> parsed_opt.add(parse_config_file(ifs, reg_config_file_opts)); } po::store(parsed_opts, vm); 

Does parsed_options have some sort of .add ability?

1 Answer 1

3

The library distinguishes three layers:

  • the description component
  • the parsers component
  • the storage component

The design assumes that you will be using one or more sets of descriptions with one or more parsers, and combine the results into one storage.

In practice this means you will store into the same variable map, and notify to update any value-semantics with side-effects.

Live Demo

  • File main.cpp

    #include <boost/program_options.hpp> #include <boost/program_options/cmdline.hpp> #include <boost/program_options/config.hpp> #include <fmt/format.h> #include <fmt/ranges.h> #include <fstream> namespace po = boost::program_options; int main() { for (auto args : { std::vector{"test.exe"}, std::vector{"test.exe", "--config_files", "a.cfg", "b.cfg", "c.cfg"}, }) { int const argc = args.size(); char const** argv = args.data(); po::options_description cmd_opts{"Options"}; using values = std::vector<std::string>; cmd_opts.add_options() ("help,h", "Help message") ("config_files", po::value<values>()->multitoken(), "Configuration files to get settings from") ; po::variables_map vm; po::variables_map cfg_vm; // can also reuse vm po::store(parse_command_line(argc, argv, cmd_opts), vm); auto& config_files = vm["config_files"]; if (!config_files.empty()) { po::options_description config_file_opts; config_file_opts.add_options() ("foo", po::value<values>()->composing()) ("bar_a", po::value<values>()->composing()) ("bar_b", po::value<values>()->composing()) ("bar_c", po::value<values>()->composing()) ; for(auto file : config_files.as<values>()) try { std::ifstream ifs(file); po::store(parse_config_file(ifs, config_file_opts), cfg_vm); } catch(std::exception const& e) { fmt::print(stderr, "{}: {}\n", file, e.what()); } fmt::print("Cmdline opts\n"); for (auto& [k, v] : vm) { fmt::print("{}={}\n", k, v.as<values>()); } fmt::print("Combined configs\n"); for (auto& [k, v] : cfg_vm) { fmt::print("{}={}\n", k, v.as<values>()); } } } } 
  • File a.cfg

    foo=foo_val_a bar_a=bar_val_a 
  • File b.cfg

    foo=foo_val_b bar_b=bar_val_b 
  • File c.cfg

    foo=foo_val_c bar_c=bar_val_c 

Prints:

Cmdline opts config_files={"a.cfg", "b.cfg", "c.cfg"} Combined configs bar_a={"bar_val_a"} bar_b={"bar_val_b"} bar_c={"bar_val_c"} foo={"foo_val_a", "foo_val_b", "foo_val_c"} 
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.