1

I want to write a program that parses a config file, and allows the command line to override what's written there. So I can have a config file that says:

[section1]
opt1=42

[section2]
opt2=17

And then, I can run the command with:

./so --opt2=3

And the program will get opt1 as 42 and opt2 and 3. I use the following program to try and do it:

#include <fstream>
#include <boost/program_options.hpp>

namespace po = boost::program_options;

int main(int argc, char *argv[]) {
    po::options_description options1("section1");
    options1.add_options()
            ("opt1", po::value<int>(), "Option 1");

    po::options_description options2("section2");
    options2.add_options()
            ("opt2", po::value<int>(), "Option 2");

    po::options_description options;
    options.add(options1);
    options.add(options2);

    po::variables_map values;
    po::store( po::command_line_parser( argc, argv ).options(options).run(), values );

    std::ifstream iniFile( "options.ini" );

    po::store(
            parse_config_file( iniFile, options ),
            values );
}

This, of course, doesn't work. Boost::program_options wants opt1 under section1 to be called section1.opt1. If I do that, however, my program becomes harder to maintain on two fronts:

  • I need to define two options_descriptions, one for the INI and one for the command line.
  • Since the options' keys are now different, I need to manually merge the two.

Is there a way achieve this without doing the work manually?

Shachar Shemesh
  • 8,193
  • 6
  • 25
  • 57

1 Answers1

-1

The trivial solution is, to not use the sections. There might be some confusion around "sections" in the options descriptions vs. sections in ini-files.

The sections in ini-files refer only to options named with embedded periods: "section1.opt1". So you can simply write the config file as:

opt1=42

# perhaps with a comment
opt2=17

See it Live On Coliru

#include <boost/program_options.hpp>
#include <fstream>
#include <iostream>

namespace po = boost::program_options;

int main(int argc, char* argv[]) {
    po::options_description options;
    options.add_options()
        ("opt1", po::value<int>(), "Option 1")
        ("section2.opt2", po::value<int>(), "Option 2");

    std::cout << options << "\n";

    po::variables_map values;
    po::store(po::parse_command_line(argc, argv, options), values);

    std::ifstream iniFile("options.ini");

    po::store(parse_config_file(iniFile, options), values);

    auto report = [&values](char const* name) {
        if (auto opt = values[name]; !opt.empty())
            std::cout << name << ": " << opt.as<int>() << "\n";
    };

    report("opt1");
    report("opt2");
    report("section1.opt1");
    report("section2.opt2");
}

Prints

echo "opt1=42" >> options.ini; ./a.out --section2.opt2 99
  --opt1 arg            Option 1
  --section2.opt2 arg   Option 2

opt1: 42
section2.opt2: 99
sehe
  • 374,641
  • 47
  • 450
  • 633
  • If you still requirethe sections, you **can** do some post-processing like I did [here](https://stackoverflow.com/questions/63780447/how-to-store-data-in-boostprogram-optionsvariable-map/63785686#63785686) or [here](https://stackoverflow.com/questions/62399047/boost-program-options-store-multiple-config-file-parse-results-into-one-parsed-o/62433436#62433436) or [here](https://stackoverflow.com/a/62396785/85371) – sehe Sep 23 '20 at 23:05
  • The answer completely ignores the question. An answer saying "you can't do that" would have been marginally helpful. You answer essentially says "the solution to getting sections is not to use sections". Your answer is _literally_ a repeat of the information in the question. – Shachar Shemesh Sep 24 '20 at 10:50
  • Okay. That's a harsh read, but I appreciate the explanation. – sehe Sep 24 '20 at 11:10
  • I parsed the question more as "this doesn't do what I expect/hoped", which is why I zoomed in on the possible source of confusion (description sections aren't "sections"). Since your question only centers on changing /one side/ (the descriptions), I elected to go the other way (changing the config file), which does meet all the stated requirements. I acknowledged that changing might not be your intent in [my comment](https://stackoverflow.com/questions/64002249/sane-way-to-use-boostprogram-options-with-ini-and-command-line/64037252?noredirect=1#comment113239277_64037252). – sehe Sep 24 '20 at 11:11
  • I guess the upshot is that the answer is, by your own evaluation, "marginally helpful". I submit that by [SO] etiquette that doesn't normally warrant a downvote. Sorry for any confusion I caused in the wording of my answer (communication is hard). Cheers. – sehe Sep 24 '20 at 11:11