Creating a simple configuration file and parser in C++

As others have pointed out, it will probably be less work to make use of an existing configuration-file parser library rather than re-invent the wheel.

For example, if you decide to use the Config4Cpp library (which I maintain), then your configuration file syntax will be slightly different (put double quotes around values and terminate assignment statements with a semicolon) as shown in the example below:

# File: someFile.cfg
url = "http://mysite.com";
file = "main.exe";
true_false = "true";

The following program parses the above configuration file, copies the desired values into variables and prints them:

#include <config4cpp/Configuration.h>
#include <iostream>
using namespace config4cpp;
using namespace std;

int main(int argc, char ** argv)
{
    Configuration *  cfg = Configuration::create();
    const char *     scope = "";
    const char *     configFile = "someFile.cfg";
    const char *     url;
    const char *     file;
    bool             true_false;

    try {
        cfg->parse(configFile);
        url        = cfg->lookupString(scope, "url");
        file       = cfg->lookupString(scope, "file");
        true_false = cfg->lookupBoolean(scope, "true_false");
    } catch(const ConfigurationException & ex) {
        cerr << ex.c_str() << endl;
        cfg->destroy();
        return 1;
    }
    cout << "url=" << url << "; file=" << file
         << "; true_false=" << true_false
         << endl;
    cfg->destroy();
    return 0;
}

The Config4Cpp website provides comprehensive documentation, but reading just Chapters 2 and 3 of the "Getting Started Guide" should be more than sufficient for your needs.


libconfig is very easy, and what's better, it uses a pseudo json notation for better readability.

Easy to install on Ubuntu: sudo apt-get install libconfig++8-dev

and link: -lconfig++


A naive approach could look like this:

#include <map>
#include <sstream>
#include <stdexcept>
#include <string>

std::map<std::string, std::string> options; // global?

void parse(std::istream & cfgfile)
{
    for (std::string line; std::getline(cfgfile, line); )
    {
        std::istringstream iss(line);
        std::string id, eq, val;

        bool error = false;

        if (!(iss >> id))
        {
            error = true;
        }
        else if (id[0] == '#')
        {
            continue;
        }
        else if (!(iss >> eq >> val >> std::ws) || eq != "=" || iss.get() != EOF)
        {
            error = true;
        }

        if (error)
        {
            // do something appropriate: throw, skip, warn, etc.
        }
        else
        {
            options[id] = val;
        }
    }
}

Now you can access each option value from the global options map anywhere in your program. If you want castability, you could make the mapped type a boost::variant.


In general, it's easiest to parse such typical config files in two stages: first read the lines, and then parse those one by one.
In C++, lines can be read from a stream using std::getline(). While by default it will read up to the next '\n' (which it will consume, but not return), you can pass it some other delimiter, too, which makes it a good candidate for reading up-to-some-char, like = in your example.

For simplicity, the following presumes that the = are not surrounded by whitespace. If you want to allow whitespaces at these positions, you will have to strategically place is >> std::ws before reading the value and remove trailing whitespaces from the keys. However, IMO the little added flexibility in the syntax is not worth the hassle for a config file reader.

const char config[] = "url=http://example.com\n"
                      "file=main.exe\n"
                      "true=0";

std::istringstream is_file(config);

std::string line;
while( std::getline(is_file, line) )
{
  std::istringstream is_line(line);
  std::string key;
  if( std::getline(is_line, key, '=') )
  {
    std::string value;
    if( std::getline(is_line, value) ) 
      store_line(key, value);
  }
}

(Adding error handling is left as an exercise to the reader.)