ConfigFile rewrite
This commit is contained in:
parent
77fcb0ad25
commit
b69f0daa1a
@ -17,8 +17,8 @@ IsCpp=1
|
|||||||
Icon=
|
Icon=
|
||||||
ExeOutput=..\lib
|
ExeOutput=..\lib
|
||||||
ObjectOutput=..\devcpp
|
ObjectOutput=..\devcpp
|
||||||
OverrideOutput=0
|
OverrideOutput=1
|
||||||
OverrideOutputName=photon.a
|
OverrideOutputName=libphoton.a
|
||||||
HostApplication=
|
HostApplication=
|
||||||
Folders=include,include/util,src,src/util
|
Folders=include,include/util,src,src/util
|
||||||
CommandLine=
|
CommandLine=
|
||||||
@ -27,7 +27,7 @@ CustomMakefile=
|
|||||||
IncludeVersionInfo=0
|
IncludeVersionInfo=0
|
||||||
SupportXPThemes=0
|
SupportXPThemes=0
|
||||||
CompilerSet=0
|
CompilerSet=0
|
||||||
CompilerSettings=0000000000000000000000
|
CompilerSettings=0000001000000000000000
|
||||||
|
|
||||||
[Unit1]
|
[Unit1]
|
||||||
FileName=..\include\types.h
|
FileName=..\include\types.h
|
||||||
|
@ -1,28 +1,247 @@
|
|||||||
//This file is part of Photon (http://photon.sourceforge.net)
|
//This file is part of Photon (http://photon.sourceforge.net)
|
||||||
//Copyright (C) 2004-2005 James Turk
|
//Copyright (C) 2004-2005 James Turk
|
||||||
//
|
//
|
||||||
// Author:
|
// Author:
|
||||||
// James Turk (jpt2433@rit.edu)
|
// James Turk (jpt2433@rit.edu)
|
||||||
//
|
//
|
||||||
// Version:
|
// Version:
|
||||||
// $Id: ConfigFile.h,v 1.1 2005/01/27 03:35:23 cozman Exp $
|
// $Id: ConfigFile.h,v 1.2 2005/01/31 15:44:13 cozman Exp $
|
||||||
//
|
//
|
||||||
// Revisions:
|
// Revisions:
|
||||||
// $Log: ConfigFile.h,v $
|
// $Log: ConfigFile.h,v $
|
||||||
// Revision 1.1 2005/01/27 03:35:23 cozman
|
// Revision 1.2 2005/01/31 15:44:13 cozman
|
||||||
// initial import (exceptions,types, and logging,oh my!)
|
// ConfigFile rewrite
|
||||||
//
|
//
|
||||||
//
|
// Revision 1.1 2005/01/27 03:35:23 cozman
|
||||||
|
// initial import (exceptions,types, and logging,oh my!)
|
||||||
#ifndef PHOTON_UTIL_CONFIGFILE_H
|
//
|
||||||
#define PHOTON_UTIL_CONFIGFILE_H
|
//
|
||||||
|
|
||||||
namespace photon {
|
#ifndef PHOTON_UTIL_CONFIGFILE_H
|
||||||
namespace util {
|
#define PHOTON_UTIL_CONFIGFILE_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <list>
|
||||||
}
|
#include <sstream>
|
||||||
}
|
#include <functional>
|
||||||
|
#include <iostream>
|
||||||
#endif //PHOTON_UTIL_CONFIGFILE_H
|
|
||||||
|
namespace photon
|
||||||
|
{
|
||||||
|
namespace util
|
||||||
|
{
|
||||||
|
|
||||||
|
// Class: ConfigFile
|
||||||
|
// ConfigFile class, for reading/writing INI-style config files.
|
||||||
|
//
|
||||||
|
// File format is fairly flexible, whitespace and comments beginning with # or
|
||||||
|
// ; are ignored & left intact.
|
||||||
|
//
|
||||||
|
// Use []'s to denote sections.
|
||||||
|
//
|
||||||
|
// Variables are defined in var=val format.
|
||||||
|
class ConfigFile
|
||||||
|
{
|
||||||
|
|
||||||
|
public: // types used in ConfigFile
|
||||||
|
|
||||||
|
//predicate for search
|
||||||
|
template<class pairT>
|
||||||
|
class StrPairEq
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef pairT first_argument_type;
|
||||||
|
typedef std::string second_argument_type;
|
||||||
|
typedef bool result_type;
|
||||||
|
bool operator()(const pairT& lhs, const std::string& rhs) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::pair<std::string,std::string> Variable;
|
||||||
|
typedef std::list< Variable > Section;
|
||||||
|
typedef std::pair< std::string, std::list< Variable > > NamedSection;
|
||||||
|
typedef std::list< NamedSection > Layout;
|
||||||
|
|
||||||
|
// Group: (Con/De)structors
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Function: ConfigFile
|
||||||
|
// Default constructor for ConfigFile.
|
||||||
|
ConfigFile();
|
||||||
|
|
||||||
|
// Function: ConfigFile
|
||||||
|
// Constructor for ConfigFile, calls <open>.
|
||||||
|
//
|
||||||
|
// Parameters:
|
||||||
|
// filename - Name of ConfigFile to open.
|
||||||
|
ConfigFile(const std::string& filename);
|
||||||
|
|
||||||
|
// Function: ~ConfigFile
|
||||||
|
// Calls close upon the ConfigFile.
|
||||||
|
virtual ~ConfigFile();
|
||||||
|
|
||||||
|
// Group: File Access
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Function: open
|
||||||
|
// open a file, processing it as an INI-like config file.
|
||||||
|
//
|
||||||
|
// Parameters:
|
||||||
|
// filename - Name of ConfigFile to open.
|
||||||
|
void open(const std::string& filename);
|
||||||
|
|
||||||
|
// Function: flush
|
||||||
|
// Flushes the data written to the config file to disk, generally needs
|
||||||
|
// not be called.
|
||||||
|
void flush();
|
||||||
|
|
||||||
|
// Function: close
|
||||||
|
// Flushes the data and closes, open must be called again before using same
|
||||||
|
// ConfigFile.
|
||||||
|
void close();
|
||||||
|
|
||||||
|
// Function: setVariable
|
||||||
|
// Template function for setting variables in the config file.
|
||||||
|
//
|
||||||
|
// WARNING: Do not try to use this with user-defined types, numeric types
|
||||||
|
// and strings work fine, and this is all that should be contained in
|
||||||
|
// an INI.
|
||||||
|
//
|
||||||
|
// Parameters:
|
||||||
|
// sec - section name within config file
|
||||||
|
// var - variable name within section
|
||||||
|
// value - value to set variable equal to
|
||||||
|
template<class varType>
|
||||||
|
void setVariable(const std::string& sec,
|
||||||
|
const std::string& var,
|
||||||
|
varType value);
|
||||||
|
|
||||||
|
// Function: getVariable
|
||||||
|
// Template function for getting values from the config file. Supports
|
||||||
|
// returning a default value if the desired variable was not found.
|
||||||
|
//
|
||||||
|
// WARNING: Do not try to use this with user-defined types, numeric types
|
||||||
|
// and strings work fine, and this is all that should be contained in
|
||||||
|
// an INI.
|
||||||
|
//
|
||||||
|
// Parameters:
|
||||||
|
// sec - section name within config file
|
||||||
|
// var - variable name within section
|
||||||
|
// defVal - value to return if variable does not exist
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// Value of variable within config file or defVal if value was not found.
|
||||||
|
template<class varType>
|
||||||
|
varType getVariable(const std::string& sec,
|
||||||
|
const std::string& var,
|
||||||
|
varType defVal) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static std::string cleanString(const std::string& str);
|
||||||
|
static std::string bracketString(const std::string& str);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Layout layout_;
|
||||||
|
std::string filename_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
//predicate for search
|
||||||
|
template<class pairT>
|
||||||
|
bool ConfigFile::StrPairEq<pairT>::operator()(const pairT& lhs,
|
||||||
|
const std::string& rhs) const
|
||||||
|
{
|
||||||
|
return ConfigFile::cleanString(lhs.first) == ConfigFile::cleanString(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Template implementation
|
||||||
|
template<class varType>
|
||||||
|
void
|
||||||
|
ConfigFile::setVariable(const std::string& sec,
|
||||||
|
const std::string& var,
|
||||||
|
varType value)
|
||||||
|
{
|
||||||
|
std::string secBrac(bracketString(sec));
|
||||||
|
Layout::iterator secIter;
|
||||||
|
Section::iterator varIter;
|
||||||
|
std::ostringstream ss;
|
||||||
|
|
||||||
|
ss << value; //write value to string
|
||||||
|
|
||||||
|
//search for section
|
||||||
|
secIter = std::find_if( layout_.begin(),
|
||||||
|
layout_.end(),
|
||||||
|
std::bind2nd(StrPairEq<NamedSection>(), secBrac) );
|
||||||
|
|
||||||
|
// add the section if it does not exist
|
||||||
|
if(secIter == layout_.end())
|
||||||
|
{
|
||||||
|
layout_.push_back( NamedSection( secBrac, Section() ) );
|
||||||
|
|
||||||
|
//search again, assert that it now exists
|
||||||
|
secIter = std::find_if( layout_.begin(),
|
||||||
|
layout_.end(),
|
||||||
|
std::bind2nd(StrPairEq<NamedSection>(), secBrac) );
|
||||||
|
assert(secIter != layout_.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
//search for variable
|
||||||
|
varIter = std::find_if( secIter->second.begin(),
|
||||||
|
secIter->second.end(),
|
||||||
|
std::bind2nd(StrPairEq<Variable>(), var) );
|
||||||
|
|
||||||
|
// add the variable if it does not exist
|
||||||
|
if(varIter == secIter->second.end())
|
||||||
|
{
|
||||||
|
secIter->second.push_back( Variable(var, ss.str()) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
varIter->second = ss.str();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//template specialization for setVariable<std::string>
|
||||||
|
/*template<>
|
||||||
|
void
|
||||||
|
ConfigFile::setVariable(std::string sec, std::string var, std::string value)
|
||||||
|
{
|
||||||
|
sec = "[" + sec + "]"; //add []s to section name
|
||||||
|
value = "\"" + value + "\""; //add ""s to value
|
||||||
|
|
||||||
|
layout_[sec][var] = value; //actually set it
|
||||||
|
}*/
|
||||||
|
|
||||||
|
template<class varType>
|
||||||
|
varType
|
||||||
|
ConfigFile::getVariable(const std::string& sec,
|
||||||
|
const std::string& var,
|
||||||
|
varType defVal) const
|
||||||
|
{
|
||||||
|
std::string secBrac(bracketString(sec));
|
||||||
|
std::stringstream ss;
|
||||||
|
varType ret(defVal);
|
||||||
|
Layout::const_iterator secIter;
|
||||||
|
Section::const_iterator varIter;
|
||||||
|
|
||||||
|
secIter = std::find_if( layout_.begin(),
|
||||||
|
layout_.end(),
|
||||||
|
std::bind2nd(StrPairEq<NamedSection>(), secBrac) );
|
||||||
|
if(secIter != layout_.end())
|
||||||
|
{
|
||||||
|
varIter = std::find_if( secIter->second.begin(),
|
||||||
|
secIter->second.end(),
|
||||||
|
std::bind2nd(StrPairEq<Variable>(), var) );
|
||||||
|
if(varIter != secIter->second.end())
|
||||||
|
{
|
||||||
|
ss.str(varIter->second);
|
||||||
|
ss >> ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //PHOTON_UTIL_CONFIGFILE_H
|
||||||
|
@ -5,22 +5,191 @@
|
|||||||
// James Turk (jpt2433@rit.edu)
|
// James Turk (jpt2433@rit.edu)
|
||||||
//
|
//
|
||||||
// Version:
|
// Version:
|
||||||
// $Id: ConfigFile.cpp,v 1.1 2005/01/27 03:35:24 cozman Exp $
|
// $Id: ConfigFile.cpp,v 1.2 2005/01/31 15:44:13 cozman Exp $
|
||||||
//
|
//
|
||||||
// Revisions:
|
// Revisions:
|
||||||
// $Log: ConfigFile.cpp,v $
|
// $Log: ConfigFile.cpp,v $
|
||||||
|
// Revision 1.2 2005/01/31 15:44:13 cozman
|
||||||
|
// ConfigFile rewrite
|
||||||
|
//
|
||||||
// Revision 1.1 2005/01/27 03:35:24 cozman
|
// Revision 1.1 2005/01/27 03:35:24 cozman
|
||||||
// initial import (exceptions,types, and logging,oh my!)
|
// initial import (exceptions,types, and logging,oh my!)
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "util/ConfigFile.h"
|
#include "util/ConfigFile.h"
|
||||||
|
#include "exceptions.h"
|
||||||
|
#include <cctype>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
namespace photon
|
||||||
|
{
|
||||||
|
namespace util
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
namespace photon {
|
|
||||||
namespace util {
|
|
||||||
|
|
||||||
|
//(Con/De)structors
|
||||||
|
|
||||||
|
ConfigFile::ConfigFile()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfigFile::ConfigFile(const std::string& filename)
|
||||||
|
{
|
||||||
|
open(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfigFile::~ConfigFile()
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
//File Access
|
||||||
|
|
||||||
|
void ConfigFile::open(const std::string& filename)
|
||||||
|
{
|
||||||
|
filename_ = filename;
|
||||||
|
if(filename_.empty())
|
||||||
|
{
|
||||||
|
throw PreconditionException("No filename in ConfigFile::open");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string section, var, val, str, clean;
|
||||||
|
std::ifstream file(filename_.c_str());
|
||||||
|
|
||||||
|
if(!file)
|
||||||
|
{
|
||||||
|
throw Error("Unable to open " + filename_ +
|
||||||
|
" for reading in ConfigFile::open");
|
||||||
|
}
|
||||||
|
|
||||||
|
layout_.clear(); //clear layout, just in case
|
||||||
|
|
||||||
|
while(file) //parses entire file
|
||||||
|
{
|
||||||
|
std::getline(file,str); //read in a line
|
||||||
|
clean = cleanString(str); //get a clean version
|
||||||
|
|
||||||
|
//if std::string is bracketed it is a section
|
||||||
|
if(clean[0] == '[' && clean[clean.length()-1] == ']')
|
||||||
|
{
|
||||||
|
section = str;
|
||||||
|
}
|
||||||
|
else if(std::isalpha(clean[0])) //variables must start with a letter
|
||||||
|
{
|
||||||
|
//split at the equals sign
|
||||||
|
var = str.substr(0,str.find('='));
|
||||||
|
val = str.substr(str.find('=')+1);
|
||||||
|
setVariable(section,var,val);
|
||||||
|
}
|
||||||
|
else if(clean[0] == '#' || clean[0] == ';') //comments
|
||||||
|
{
|
||||||
|
setVariable(section,"_comment",str);
|
||||||
|
}
|
||||||
|
else if(clean.length() == 0 && !file.eof()) //save blank lines
|
||||||
|
{
|
||||||
|
setVariable(section,"_newline",str);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigFile::flush()
|
||||||
|
{
|
||||||
|
Layout::iterator sec;
|
||||||
|
Section::iterator var;
|
||||||
|
std::string secName;
|
||||||
|
|
||||||
|
//in case the filename is already cleared
|
||||||
|
if(filename_.empty())
|
||||||
|
{
|
||||||
|
throw PreconditionException("No filename in ConfigFile::flush");
|
||||||
|
}
|
||||||
|
|
||||||
|
//open the file blanked out, to not duplicate entries
|
||||||
|
std::ofstream file(filename_.c_str(), std::ios::out|std::ios::trunc);
|
||||||
|
|
||||||
|
if(!file)
|
||||||
|
{
|
||||||
|
throw Error("Unable to open " + filename_ +
|
||||||
|
" for writing in ConfigFile::flush");
|
||||||
|
}
|
||||||
|
|
||||||
|
//iteration through sections
|
||||||
|
for(sec = layout_.begin(); sec != layout_.end(); ++sec)
|
||||||
|
{
|
||||||
|
//ensure that section is valid
|
||||||
|
secName = cleanString(sec->first);
|
||||||
|
if(secName[0] == '[' && secName[secName.length()-1] == ']')
|
||||||
|
{
|
||||||
|
file << sec->first << std::endl; //write out raw section title
|
||||||
|
|
||||||
|
//for each variable in section, write out variable=value
|
||||||
|
for(var = sec->second.begin(); var != sec->second.end(); ++var)
|
||||||
|
{
|
||||||
|
if(var->first[0] == '_') //special values start with _
|
||||||
|
{
|
||||||
|
if(var->first.substr(1) == "comment")
|
||||||
|
{
|
||||||
|
file << var->second << std::endl;
|
||||||
|
}
|
||||||
|
else if(var->first.substr(1) == "newline")
|
||||||
|
{
|
||||||
|
file << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(!cleanString(var->first).empty()) //a variable
|
||||||
|
{
|
||||||
|
file << var->first << '=' << var->second << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigFile::close()
|
||||||
|
{
|
||||||
|
//flush and clear out the data members
|
||||||
|
flush();
|
||||||
|
filename_ = std::string();
|
||||||
|
layout_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ConfigFile::cleanString(const std::string& str)
|
||||||
|
{
|
||||||
|
std::string ret(str);
|
||||||
|
|
||||||
|
//convert to lower case
|
||||||
|
std::transform( ret.begin(), ret.end(), ret.begin(),
|
||||||
|
static_cast<int(*)(int)>(std::tolower) );
|
||||||
|
|
||||||
|
//remove all spaces
|
||||||
|
for(std::string::iterator i=ret.begin(); i != ret.end(); ++i)
|
||||||
|
{
|
||||||
|
if(std::isspace(*i))
|
||||||
|
{
|
||||||
|
i = ret.erase(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ConfigFile::bracketString(const std::string& str)
|
||||||
|
{
|
||||||
|
std::string ret( cleanString(str) );
|
||||||
|
|
||||||
|
//add brackets if they do not exist, unless the string is empty
|
||||||
|
if(!ret.empty() && ret[0] != '[' || ret[ret.length()-1] != ']')
|
||||||
|
{
|
||||||
|
ret = "["+ret+"]";
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user