2007年9月16日星期日

A C++ Class to read Configuration Files

A C++ Class to read Configuration Files

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
#include

#include "Chameleon.h"

class ConfigFile {
std::map 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

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::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

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.

没有评论: