Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Parsing a configuration file with boost::program_options

Good day,

i wrote a class to parse a configuration file via boost::program_options. Here is what I have (shortened):

namespace nsProOp = boost::program_options;
nsProOp::variables_map m_variableMap;
nsProOp::options_description m_description;



// To add options to the variableMap, e.g. "addOption<int>("money_amount");"
template <class T>
    void addOption(const std::string& option, const std::string& helpDescription = "") {
        m_description.add_options()(option.c_str(), nsProOp::value<T > (), helpDescription.c_str());
    }



// And this is how i actually read the file:
void ConfigFile::parse() {
    std::ifstream file;
    file.open(m_pathToFile.c_str());

    nsProOp::store(nsProOp::parse_config_file(file, m_description, true), m_variableMap);
    nsProOp::notify(m_variableMap);      
}

Okay, this works fine. But i want to be able to parse the same file again so that I always use the latest entries provided by the user! The boost documentation says about "store":

"Stores in 'm' all options that are defined in 'options'. If 'm' already has a non-defaulted value of an option, that value is not changed, even if 'options' specify some value."

So, if I call "parse()" again nothing happens, because m_variableMap is filled. My attempt to call m_variableMap.clear() does not solve my problem, so store only works the first time.

Has anybody an advice for me? If my question is unclear, just tell me. Thanks!

like image 995
Anonymous Avatar asked Dec 20 '22 19:12

Anonymous


1 Answers

In at least boost 1.50, variables_map::clear() will allow the variable map to be properly refilled via store. An alternative solution that works as far back as at least boost 1.37 is to assign a default constructed variable map into the variable map before calling store.

void ConfigFile::parse() {
  std::ifstream file;
  file.open(m_pathToFile.c_str());
  m_variableMap = nsProOp::variables_map(); // Clear m_variableMap.
  nsProOp::store(nsProOp::parse_config_file(file, m_description, true), 
                 m_variableMap);
  nsProOp::notify(m_variableMap);      
}

Here is a sample program:

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

namespace po = boost::program_options;

void write_settings(const char* value)
{
  std::ofstream settings_file("settings.ini");
  settings_file << "name = " << value;
}

void read_settings(po::options_description& desc,
                   po::variables_map& vm)
{
  std::ifstream settings_file("settings.ini");

  // Clear the map.
  vm = po::variables_map();

  po::store(po::parse_config_file(settings_file , desc), vm);
  po::notify(vm);    
}

int main()
{
  std::string name;

  // Setup options.
  po::options_description desc("Options");
  desc.add_options()
    ("name", po::value<std::string>(&name), "name");
  po::variables_map vm;

  // Write, read, and print settings.
  write_settings("test");
  read_settings(desc, vm);
  std::cout << "name = " << name << std::endl;

  // Write, read, and print newer settings.
  write_settings("another test");
  read_settings(desc, vm);
  std::cout << "name = " << name << std::endl;
}

Which produces the following output:

name = test
name = another test
like image 179
Tanner Sansbury Avatar answered Dec 24 '22 02:12

Tanner Sansbury