|
Configuration Parser
Submitted by |
This is a configparser utility I've written. The config code uses some other small utilities I've made but they are rather boring. The config stuff however is somewhat cool. Maybe the code itself isn't the most beautiful piece of code ever created but I am pretty pleased with the interface that's presented to the user. It's very simple and you can give it whatever types you want, strings, ints, doubles, etc (check out main.cpp for an example). The only things the types need are a default constructor, an input operator and an output operator. It's also quite stable, it will not crash or anything if it encounters something that's wrong in the config file being parsed. Last but not least the config file will not be reformatted when you save the new values (try it out on config.txt that's included in the zip file).
ArchMiffo
Send me a mail: archmiffo@darkbits.org
For more code and other cool stuff visit: http://darkbits.org
|
Currently browsing [configstuff.zip] (7,461 bytes) - [config code/archio.hpp] - (4,747 bytes)
/* -----------------------------------------
archio.hpp
All the code in this file is open source
so feel free to use it any way you would
like.
designed and implemented by
ArchMiffo, member of Darkbits
----------------------------------------- */
#ifndef AUL_ARCHIO_HPP
#define AUL_ARCHIO_HPP
/* -------------------
Include directives
------------------- */
#include <istream>
#include <limits>
#include <cctype>
#include <algorithm>
// aul stands for ArchMiffo Utility Library
namespace aul
{
/* ---------------------------------------------------
The archio is a work in progress. What you see
here is just some stuff that I did to help me
when I wrote the console code for another project.
Most of the functions are nothing more tham a
wrapper around basic istream funtions. The idea
whith theese wrappers are that you will get a
more flexible function that will work in more
cases whithout having to think about the syntax.
Hopefully I will add some more usefull functions
to this library in the future since it ain't very
interesting right now.
--------------------------------------------------- */
/* ----------------------------------
IgnoreLine
Ignores everything in the input
stream until a linebreak is found
---------------------------------- */
template<class charT, class traits>
inline std::basic_istream<charT, traits>&
IgnoreLine(std::basic_istream<charT, traits>& in)
{
in.ignore(std::numeric_limits<int>::max(), in.widen('\n'));
return in;
} // end IgnoreLine
/* ---------------------------------------
IgnoreTo
A more generell form of IgnoreLine.
This function could be used everywhere
you use IgnoreLine but will also work
if you want to ignore everything to
some other character that you specify.
--------------------------------------- */
template<class charT, class traits>
inline std::basic_istream<charT, traits>&
IgnoreTo(std::basic_istream<charT, traits>& in, char delim)
{
in.ignore(std::numeric_limits<int>::max(), in.widen(delim));
return in;
} // end IgnoreLine
/* ----------------------------------------------
GetNextChar
What this funtion does is return the next
char that will be read from the input stream.
Unlike peek this function skips all the
leading whitespaces and returns an actual
character (this is not all true becouse it
could return a '\n' or something similar).
---------------------------------------------- */
template<class charT, class traits>
char GetNextChar(std::basic_istream<charT, traits>& in)
{
in>>std::ws;
return in.peek();
} // end GetNextChar
/* --------------------------------------------------
GetLine
This is a rather pathetic wrapper that lets you
get the a whole line up to a delimiter by writing
about 7 charactersless than whithout the wrapper.
The extra characters that you don't have to write
gives you a function that will work in almost any
case.
-------------------------------------------------- */
template<class charT, class traits>
inline std::basic_istream<charT, traits>&
GetLine(std::basic_istream<charT, traits>& in, std::string& str, char delim)
{
std::getline(in, str, in.widen(delim));
return in;
} // end GetLine
/* -------------------------------------------
RemoveSpace
This function removes all space characters
from a string
------------------------------------------- */
inline void RemoveSpace(std::string& str)
{
str.erase(std::remove_if(str.begin(), str.end(), std::isspace), str.end());
} // end RemoveSpace
/* ---------------------------------------------------
GetCommadVal
This function was designed to be used as a part
of a some config stuff I wrote. What it does is,
given an input stream, extracts a command and it's
value to the two strings that the user supplies.
Example:
This is in the stream: invertmouse = 1
GetCommandVal(is, str1, str2, '=')
=> str1 = invertmouse, str2 = 1.
--------------------------------------------------- */
template<class charT, class traits>
std::basic_istream<charT, traits>&
GetCommandVal(std::basic_istream<charT, traits>& in,
std::string& command, std::string& val, char sep)
{
std::string str;
in>>std::ws;
GetLine(in, str, '\n');
RemoveSpace(str);
std::string::size_type index = str.find(sep);
if(index == std::string::npos)
throw "wrong seperator";
command = std::string(str.begin(), str.begin() + index);
val = std::string(str.begin() + index + 1, str.end());
return in;
} // end GetCommandVal
} // end aul
#endif // end AUL_ARCHIO_HPP |
|
Currently browsing [configstuff.zip] (7,461 bytes) - [config code/configparser.cpp] - (6,020 bytes)
/* -----------------------------------------
configparser.cpp
All the code in this file is open source
so feel free to use it any way you would
like.
design and implementation by
ArchMiffo, member of Darkbits
----------------------------------------- */
/* -------------------
Include directives
------------------- */
#include "configparser.hpp"
#include "archio.hpp"
#include <sstream>
#include <queue>
#include <fstream>
// aul stands for ArchMiffo Utility Library
namespace aul
{
/* --------------------------------------
ParseFile
This is the main function that parses
every line in the file
-------------------------------------- */
int ConfigParser::ParseFile(const std::string& filename)
{
m_Errors.clear();
bool parseError = false;
CFGError err;
int line = 0;
m_Filename = filename;
std::ifstream file;
file.open(m_Filename.c_str(), std::ios::in);
if(file.fail()) // Couldn't open the file
return CFG_ERROR::FILE_ERROR;
std::string str;
while(!file.eof())
{
aul::GetLine(file, str, '\n');
++line;
if(str.empty())
continue;
if(str[0] == '#')
continue;
std::string::size_type index = str.find('=');
if(index == std::string::npos)
{
err.line = line;
err.code = CFG_ERROR::MISSING_SIGN_ERROR;
m_Errors.push_back(err);
parseError = true;
continue;
} // end if
index = str.find('#');
if(index != std::string::npos)
{
err.line = line;
err.code = CFG_ERROR::COMMENT_ERROR;
m_Errors.push_back(err);
parseError = true;
continue;
} // end if
std::string command, val;
std::istringstream is(str);
aul::GetCommandVal(is, command, val, '=');
if(Initialize(command, val) != CFG_ERROR::SUCCESS)
{
err.line = line;
err.code = CFG_ERROR::UNKNOWN_COMMAND_ERROR;
m_Errors.push_back(err);
parseError = true;
continue;
} // end if
} // end while
if(parseError)
return CFG_ERROR::PARSE_ERROR;
return CFG_ERROR::SUCCESS;
} // end ConfigParser::ParseFile
/* --------------------------------------------
Initialize
Checks if the command that were found exist
and if it does it gives the right variable
its new value
-------------------------------------------- */
int ConfigParser::Initialize(const std::string& command, const std::string& val)
{
ConfigMap::iterator it = m_ConfigItems.find(command);
if(it == m_ConfigItems.end())
return CFG_ERROR::UNKNOWN_COMMAND_ERROR;
std::stringstream in(val);
(it->second)->Read(in);
return CFG_ERROR::SUCCESS;
} // end ConfigParser::Initialize
/* --------------------------------------------
SaveFile
Save the current settings. Doing this will
not change the format of the config file.
In other words the comments and everything
will look exactly as before (except the new
values of course)
-------------------------------------------- */
int ConfigParser::SaveFile()
{
std::queue<std::string> tempque;
std::string str;
ConfigMap::iterator it;
{
std::fstream file;
file.open(m_Filename.c_str(), std::ios::out | std::ios::in);
if(file.fail()) // Couldn't open the file
return CFG_ERROR::FILE_ERROR;
while(!file.eof())
{
aul::GetLine(file, str, '\n');
tempque.push(str);
} // end while
} // end block
std::fstream file;
file.open(m_Filename.c_str(), std::ios::out | std::ios::trunc);
if(file.fail()) // Couldn't open the file
return CFG_ERROR::FILE_ERROR;
while(!tempque.empty())
{
str = tempque.front();
tempque.pop();
std::string::size_type index = str.find('=');
if(index == std::string::npos || str[0] == '#')
{
if(tempque.empty())
file<<str;
else
file<<str<<'\n';
continue;
} // end if
std::string::iterator strit = std::find_if(str.begin() + index, str.end(), std::isalnum);
std::string command, val;
std::istringstream is(str);
aul::GetCommandVal(is, command, val, '=');
it = m_ConfigItems.find(command);
if(it == m_ConfigItems.end())
{
file<<str<<'\n';
continue;
} // end if
std::string temp;
std::ostringstream os(temp);
(it->second)->Write(os);
m_ConfigItems.erase(it);
temp = os.str();
str.erase(strit, str.end());
str += temp;
file<<str<<'\n';
} // end while
it = m_ConfigItems.begin();
for(it; it != m_ConfigItems.end(); ++it)
{
file<<it->first<<'=';
(it->second)->Write(file);
file<<'\n';
} // end for
return CFG_ERROR::SUCCESS;
} // end ConfigParser::SaveFile
/* -----------------------------------------
PrintErrors
Print all the errors that occured during
parsing of the config file
----------------------------------------- */
void ConfigParser::PrintErrors(std::ostream& out)
{
if(m_Errors.empty())
{
out<<"No errors found in file "<<m_Filename<<std::endl;
return;
} // end if
out<<"The following errors were found in "<<m_Filename<<":"<<std::endl;
for(int i=0; i != m_Errors.size(); ++i)
{
out<<"error: "<<m_Errors[i].code<<" line: "<<m_Errors[i].line<<'\t';
switch(m_Errors[i].code)
{
case CFG_ERROR::COMMENT_ERROR :
out<<"\'#\' sign not at start of line"<<std::endl;
break;
case CFG_ERROR::UNKNOWN_COMMAND_ERROR :
out<<"Command could not be found"<<std::endl;
break;
case CFG_ERROR::MISSING_SIGN_ERROR :
out<<"Missing \'=\' sign between the command and value"<<std::endl;
break;
default : break;
} // end switch
} // end for
} // end ConfigParser::PrintErrors
} // end aul |
|
Currently browsing [configstuff.zip] (7,461 bytes) - [config code/configparser.hpp] - (3,515 bytes)
/* -----------------------------------------
configparser.hpp
All the code in this file is open source
so feel free to use it any way you would
like.
design and implementation by
ArchMiffo, member of Darkbits
----------------------------------------- */
#ifndef AUL_CONFIGPARSER_HPP
#define AUL_CONFIGPARSER_HPP
/* -------------------
Include directives
------------------- */
#include <string>
#include <map>
#include <vector>
#include <iostream>
#include "countedptr.hpp"
// aul stands for ArchMiffo Utility Library
namespace aul
{
/* ------------------------
The CFG_ERROR namespace
------------------------ */
namespace CFG_ERROR
{
// An enum for error codes
enum
{
SUCCESS = 100,
FILE_ERROR = 101,
PARSE_ERROR = 102,
COMMENT_ERROR = 103,
UNKNOWN_COMMAND_ERROR = 104,
MISSING_SIGN_ERROR = 105
}; // end enum
} // end CFG_ERROR
/* --------------------------------
The CFGError struct
Used to store error information
-------------------------------- */
struct CFGError
{
int line;
int code;
}; // end CFGError
/* --------------------------------------------------
The BasicConfigItem class
This is a base class that allows us to store any
type of the template class ConfigItem in a vector
or some other kind of container class
-------------------------------------------------- */
class BasicConfigItem
{
public :
virtual ~BasicConfigItem() {}
virtual std::istream& Read(std::istream& in) = 0;
virtual std::ostream& Write(std::ostream& out) = 0;
}; // end BasicConfigItem
/* ------------------------------------------------
The ConfigItem class
This class is a placeholder for different types
of variables. In the ConfigParser class we want
to store any type to be read from the config
file. To do this we make use of polymorphism
------------------------------------------------ */
template<typename T>
class ConfigItem : public BasicConfigItem
{
public :
ConfigItem(T* item, T value = T())
: m_Item(item) { *m_Item = value; }
std::istream& Read(std::istream& in) { return in>>*m_Item; }
std::ostream& Write(std::ostream& out) { return out<<*m_Item; }
private :
T* m_Item;
}; // end ConfigItem
/* ---------------------------------------------
The ConfigParser class
Whith this class you can save time by not
having to write the same code over and over
every time you want to have a config file.
Another thing you don't have to do is change
any config code if you want to add a new
command in the config file. You simply use
AddItem and the parse the file
--------------------------------------------- */
class ConfigParser
{
public :
int ParseFile(const std::string& filename);
int SaveFile();
template<typename T>
void AddItem(const std::string& command, T* item, T val=T())
{ m_ConfigItems[command] =
aul::counted_ptr<BasicConfigItem>(new ConfigItem<T>(item, val)); }
const std::vector<CFGError>& GetErrors() { return m_Errors; }
void PrintErrors(std::ostream& out);
private :
int Initialize(const std::string& command, const std::string& val);
typedef std::map<std::string, aul::counted_ptr<BasicConfigItem> > ConfigMap;
ConfigMap m_ConfigItems;
std::vector<CFGError> m_Errors;
std::string m_Filename;
}; // end ConfigParser
} // end aul
#endif // end AUL_CONFIGPARSER_HPP |
|
Currently browsing [configstuff.zip] (7,461 bytes) - [config code/countedptr.hpp] - (3,203 bytes)
/* -----------------------------------------
countedptr.hpp
All the code in this file is open source
so feel free to use it any way you would
like.
designed and implemented by
ArchMiffo, member of Darkbits
----------------------------------------- */
#ifndef AUL_COUNTED_PTR_HPP
#define AUL_COUNTED_PTR_HPP
// aul stands for ArchMiffo Utility Library
namespace aul
{
/* ------------------------------------------------------
The counted_ptr class
Acts like a real pointer but it keeps track of itīs
pointee and deletes it when the last object that uses
it goes out of scope. This is a very simple type of
smart pointer but it does what it's supposed to do.
Unlike the standard auto_ptr class you can use this
pointer class in the standard containers (vector,
list, etc) and you don't have to remember to free
the memory when you are done with the pointer.
------------------------------------------------------ */
template<typename T>
class counted_ptr
{
public:
// Some typedefs for accessing the
// type of the pointer
typedef T value_type;
typedef T* pointer;
typedef T& reference;
explicit counted_ptr(T* ptr=0)
: pointee_(ptr), refCount_(new int(1))
{}
~counted_ptr() { decrease(); }
counted_ptr(const counted_ptr<T>& cp)
: pointee_(cp.pointee_), refCount_(cp.refCount_)
{ ++*refCount_; }
// This constructor is used for implicit conversion
// between diffrent types of counted_ptr
template<typename U>
counted_ptr(const counted_ptr<U>& cp)
: pointee_(cp.pointee_), refCount_(cp.refCount_)
{ ++*refCount_; }
counted_ptr<T>& operator=(const counted_ptr<T>& cp);
// Conversion to regular pointer
T* toPointer() { return pointee_; }
T& operator*() { return *pointee_; }
T* operator->() { return pointee_; }
// To check for null pointer
bool operator!() { return !pointee_; }
int getCount() { return *refCount_; }
T* extractPointer();
private:
// Decrease refcount and clean
// up if this is the last object
void decrease()
{
if(--*refCount_ == 0)
{
delete pointee_;
delete refCount_;
} // end if
} // end decrease
template<typename U>
friend class counted_ptr;
T* pointee_;
int* refCount_;
}; // end counted_ptr
/* ----------------
Copy assignment
---------------- */
template<typename T>
counted_ptr<T>& counted_ptr<T>::operator=(const counted_ptr<T>& cp)
{
if(pointee_ == cp.pointee_)
return *this;
decrease();
pointee_ = cp.pointee_;
refCount_ = cp.refCount_;
++*refCount_;
return *this;
} // end counted_ptr<T>::operator=
/* --------------------------------------------------
extractPointer
Set the pointer to 0.
After this the client is responsible for deleting
the returned pointer
-------------------------------------------------- */
template<typename T>
T* counted_ptr<T>::extractPointer()
{
T* ptr = pointee_;
pointee_ = 0;
return ptr;
} // end counted_ptr<T>::extractPointer
} // en namespace aul
#endif // end AUL_COUNTED_PTR_HPP |
|
Currently browsing [configstuff.zip] (7,461 bytes) - [config code/main.cpp] - (1,715 bytes)
#include <iostream>
#include <string>
#include "configparser.hpp"
int main(int argc, char* argv[])
{
aul::ConfigParser cfgParser;
bool invertMouse;
bool showFPS;
int width;
int height;
double number;
std::string name;
// This is all you need to do to use my config stuff
// Add the things you want read...
cfgParser.AddItem("invertmouse", &invertMouse, true);
cfgParser.AddItem("showfps", &showFPS, true);
cfgParser.AddItem("width", &width, 1024);
cfgParser.AddItem("height", &height, 768);
cfgParser.AddItem("number", &number, 42.0);
cfgParser.AddItem("name", &name);
// ...and parse the file. You don't have to bother
// with the errors since the whole file will be parsed
// anyway. The only reason you can check for errors
// is in case you misspelled something or made some
// other misstake in the config file
int error = cfgParser.ParseFile("config.txt");
// Handle the errors if you want to know what
// went wrong
if(error == aul::CFG_ERROR::PARSE_ERROR)
cfgParser.PrintErrors(std::cout);
else if(error == aul::CFG_ERROR::FILE_ERROR)
std::cout<<"Unable to load cfg file";
else if(error == aul::CFG_ERROR::SUCCESS)
std::cout<<"Yeah";
std::cout<<std::endl;
std::cout<<std::endl;
std::cout<<std::endl;
std::cout<<"invertmouse: \t"<<invertMouse<<std::endl;
std::cout<<"showfps: \t"<<showFPS<<std::endl;
std::cout<<"width: \t\t"<<width<<std::endl;
std::cout<<"height: \t"<<height<<std::endl;
std::cout<<"number: \t"<<number<<std::endl;
std::cout<<"name: \t\t"<<name<<std::endl;
cfgParser.SaveFile();
std::cin.get();
return 0;
}
|
|
The zip file viewer built into the Developer Toolbox made use
of the zlib library, as well as the zlibdll source additions.
|