René Nyffenegger's collection of things on the web
René Nyffenegger on Oracle - Most wanted - Feedback
 

A C++ Class to read Configuration Files

Note: I have started to move some scripts and source code from this website to GitHub.

This affects some or all of the scripts found on this page. They should be found under
github.com/ReneNyffenegger/development_misc/ ... c++/helpers.

I don't intend to maintain the scripts and or sources on this page any longer (so they might be outdated). But I will try to improve the code in the GitHub repository and accept Push Requests.

This class uses the class Chameleon. Chameleon is a string to/from double conversion class.
Here's ConfigFile.h
ConfigFile.h
#ifndef __CONFIG_FILE_H__
#define __CONFIG_FILE_H__

#include <string>
#include <map>

#include "Chameleon.h"

class ConfigFile {
  std::map<std::string,Chameleon> content_;

public:
  ConfigFile(std::string const& configFile);

  Chameleon const& Value(std::string const& section, std::string const& entry) const;

  Chameleon const& Value(std::string const& section, std::string const& entry, double value);
  Chameleon const& Value(std::string const& section, std::string const& entry, std::string const& value);
};

#endif
Here's ConfigFile.cpp
ConfigFile.cpp
#include "ConfigFile.h"

#include <fstream>

std::string trim(std::string const& source, char const* delims = " \t\r\n") {
  std::string result(source);
  std::string::size_type index = result.find_last_not_of(delims);
  if(index != std::string::npos)
    result.erase(++index);

  index = result.find_first_not_of(delims);
  if(index != std::string::npos)
    result.erase(0, index);
  else
    result.erase();
  return result;
}

ConfigFile::ConfigFile(std::string const& configFile) {
  std::ifstream file(configFile.c_str());

  std::string line;
  std::string name;
  std::string value;
  std::string inSection;
  int posEqual;
  while (std::getline(file,line)) {

    if (! line.length()) continue;

    if (line[0] == '#') continue;
    if (line[0] == ';') continue;

    if (line[0] == '[') {
      inSection=trim(line.substr(1,line.find(']')-1));
      continue;
    }

    posEqual=line.find('=');
    name  = trim(line.substr(0,posEqual));
    value = trim(line.substr(posEqual+1));

    content_[inSection+'/'+name]=Chameleon(value);
  }
}

Chameleon const& ConfigFile::Value(std::string const& section, std::string const& entry) const {

  std::map<std::string,Chameleon>::const_iterator ci = content_.find(section + '/' + entry);

  if (ci == content_.end()) throw "does not exist";

  return ci->second;
}

Chameleon const& ConfigFile::Value(std::string const& section, std::string const& entry, double value) {
  try {
    return Value(section, entry);
  } catch(const char *) {
    return content_.insert(std::make_pair(section+'/'+entry, Chameleon(value))).first->second;
  }
}

Chameleon const& ConfigFile::Value(std::string const& section, std::string const& entry, std::string const& value) {
  try {
    return Value(section, entry);
  } catch(const char *) {
    return content_.insert(std::make_pair(section+'/'+entry, Chameleon(value))).first->second;
  }
}

A test program

ConfigFileTest.cpp
ConfigFileTest.cpp
#include "ConfigFile.h"

#include <iostream>

int main() {
  ConfigFile cf("config.txt");

  std::string foo;
  std::string water;
  double      four;

  foo   = cf.Value("section_1","foo"  );
  water = cf.Value("section_2","water");
  four  = cf.Value("section_2","four" );

  std::cout << foo   << std::endl;
  std::cout << water << std::endl;
  std::cout << four  << std::endl;

  return 0;
}
Here's the configuration file that's being read by the test program:
config.txt
[section_1]
foo  = bar
water= h2o

[section_2]
foo  = foo
water= wet
four = 4.2
Compiling the test program with n:
g++ -Wall Chameleon.cpp ConfigFile.cpp ConfigFileTest.cpp -o ConfigFileTest.exe

Thanks

My special thanks go to Dieter Vrancken who improved this class, see also this entry in my blog.
Thanks also to Lars Schouw who pointed out an error on this page and Christian Decker who spotted an error in the code.