Welcome, Guest. Please login or register. Did you miss your activation email?

Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Topics - matkod

Pages: [1]
1
SFML projects / Config Parser
« on: March 29, 2013, 01:44:50 am »
Hi,
I made .cfg parser based on this: https://github.com/SFML/SFML/wiki/Source%3A-Settings-Parser
the basic diference is that mine is divided by sectors  ;D

Its not great but i would like to share  ;)

sorry if its not the right place to post it.

EDIT: now has comment support

TODO: add vector<string> support

Convert.hpp
#ifndef _CONVERT_HPP
#define _CONVERT_HPP

#include <string>
#include <sstream>

namespace Convert
{
//public:
   // Convert T, which should be a primitive, to a std::string.
   template <typename T>
   static std::string T_to_string(T const &val)
   {
      std::ostringstream ostr;
      ostr << val;

      return ostr.str();
   }
   
   // Convert a std::string to T.
   template <typename T>
   static T string_to_T(std::string const &val)
   {
      std::istringstream istr(val);
      T returnVal;
      if (!(istr >> returnVal))
         exit(EXIT_FAILURE);

      return returnVal;
   }

   template <>
   static std::string string_to_T(std::string const &val)
   {
      return val;
   }

};

#endif

ConfigParser.hpp
#ifndef _CONFIGPARSER_HPP
#define _CONFIGPARSER_HPP

#include <string>
#include <map>
#include <vector>

#include "Convert.hpp"

typedef std::map< const std::string, std::pair< std::string, std::string > > DataFormat;
typedef std::map< const std::string, DataFormat > CfgFormat;


class ConfigParser
{
public:
        ConfigParser(char comsep='#');
        ~ConfigParser();

        bool Read(const std::string& filename);

        bool Write(const std::string& filename);

        bool SectionExists(const std::string& section) const;
       
        // Only for primitives
        template <typename TYPE>
        TYPE Get(const std::string& section, const std::string& key, const TYPE& defValue=TYPE()) const
        {
                if(SectionExists(section))
                        if(mProperties.at(section).count(key))
                                return Convert::string_to_T<TYPE>(mProperties.at(section).at(key).first);

                return defValue;
        };

        // Only for primitives
        template <typename TYPE>
        void Set(const std::string& section, const std::string& key, const TYPE value, const std::string& comment="")
        {
                mIsChanged = true;
               
                if(!SectionExists(section))
                {
                        DataFormat prop;
                        prop[key] = std::make_pair(Convert::T_to_string(value), comment);
                        mProperties[section] = prop;
                        mOrder.push_back(section);
                }
                else
                {
                        mProperties[section][key].first = Convert::T_to_string(value);
                        if(comment.size())
                        {
                                mProperties[section][key].second = comment;
                        }
                }
        };
       
private:
        CfgFormat mProperties;

        std::vector<const std::string> mOrder;

        bool mIsChanged;

        std::string mFileName;

        char mComSep;
};

#endif

ConfigParser.cpp
#include <fstream>
#include <iostream>

#include "ConfigParser.hpp"

ConfigParser::ConfigParser(char comsep):
        mProperties(),
        mOrder(),
        mIsChanged(false),
        mFileName("config.cfg"),
        mComSep(comsep)
{

}


ConfigParser::~ConfigParser()
{
        if(mIsChanged)
                Write(mFileName);
}

bool ConfigParser::Read(const std::string& filename)
{
        mFileName = filename;

        std::ifstream in(filename.c_str());

        if(!in.is_open())
        {
                std::cerr << "error at reading" << std::endl;
                return false;
        }

        std::string line, section, value, param, comment;

        while(!in.eof())
        {
                char temp[256];
                in.getline(temp, 256);
                line.assign(temp);

                size_t lstart = line.find_first_not_of(' '); // remove whitespace before text

                if(line.size() > 0 && lstart != line.npos)
                {
                        if(line[lstart]=='[') // check for new section
                        {
                                size_t start = line.find_first_not_of(' ', lstart+1); // remove whitespace before text. +1 to ignore '['

                                size_t end = line.find_first_of(" ]", start); // get the text until a ']' or whitespace

                                end -= start; // from start to end

                                section = line.substr(start, end);

                                param = "";
                                value = "";
                                comment = "";
                        }
                        else if(line[lstart]==mComSep) //check for comment
                        {
                                mOrder.push_back(line.substr(lstart));
                        }
                        else // check for param and value
                        {
                                //get param
                                size_t end = line.find_first_of(" =", lstart);
                               
                                end -= lstart;

                                param = line.substr(lstart, end);

                                // get value
                                size_t start = line.find_first_of("=", lstart);
                                start++;
                                start = line.find_first_not_of(' ', start);
                               
                                end = line.find_first_of(mComSep, start);

                                end -= start;

                                value = line.substr(start, end);

                                start = line.find_first_of(mComSep, lstart);

                                if(start!=line.npos)
                                        comment = line.substr(start);
                                else
                                        comment = "";
                        }
                       
                }

                if(section.size())
                {
                        if(SectionExists(section))
                        {
                                if(param.size() && value.size())
                                        mProperties.at(section).insert(std::make_pair(param, std::make_pair(value, comment)));
                        }
                        else // the first time it will come here
                        {
                                DataFormat prop;
                                mProperties.insert(std::make_pair(section, prop));
                                mOrder.push_back(section);
                        }
                }

        }

        in.close();

        return true;
}

bool ConfigParser::Write(const std::string& filename)
{
        std::ofstream out(filename);

        if(!out.is_open())
        {
                std::cerr << "error at writing" << std::endl;
                return false;
        }

        std::string section = "";

        std::vector<const std::string>::const_iterator iter;
        for(iter=mOrder.begin(); iter!=mOrder.end(); ++iter)
        {
                if((*iter)[0] == mComSep)
                        out << (*iter) << std::endl;
                else
                {
                        if(section!=(*iter))
                        {
                                section = (*iter);

                                out << "[" << section << "]" << std::endl;
                        }

                        DataFormat::const_iterator iter2;
                        for(iter2=mProperties.at(*iter).begin(); iter2!=mProperties.at(*iter).end(); ++iter2)
                        {
                                if(iter2->second.second.size())
                                        out << iter2->first << " = " << iter2->second.first << " " << iter2->second.second << std::endl;
                                else
                                        out << iter2->first << " = " << iter2->second.first << std::endl;
                        }

                        out << std::endl;
                }
        }

        out.close();

        mIsChanged = false;

        return true;
}

bool ConfigParser::SectionExists(const std::string& section) const
{
        return mProperties.count(section) == 1;
}

 

main.cpp
#include <iostream>

#include "ConfigParser.hpp"


int main(void)
{
        ConfigParser cp;

        cp.Read("teste.cfg");

        cp.Set<int>("window1", "width1", 800);
       
        cp.Set<bool>("newSector", "newBool", true);
        cp.Set<bool>("newSector", "newBool2", false);
        cp.Set<int>("newSector", "newInt", 49);
        cp.Set<int>("newSector", "newInt2", 1000);

        cp.Set<float>("newSector2", "newFloat", 1.73);
        cp.Set<float>("newSector2", "newFloat", 2.499);
        cp.Set<double>("newSector2", "newDouble", 0.012);
        cp.Set<std::string>("newSector2", "newString", "I'm a big string of text!!!", "#change the comment");

        std::cout << cp.Get<bool>("teste", "bool") << std::endl;
        std::cout << cp.Get<int>("window", "width") << std::endl;
        std::cout << cp.Get<float>("newSector2", "newFloat") << std::endl;
        std::cout << cp.Get<int>("Invalid", "Invalid", 27) << std::endl; // invalid does not exist so it will return 27
        std::cout << cp.Get<std::string>("newSector2", "newString", "string does not exist") << std::endl;
       
        cp.Write("teste.cfg");

       
        system("pause");
        return 0;
}
 

teste.cfg
#Welcome!!!
#this is a comment
#
#

[window]
bpp = 32         #blablabla
height = 200          # comment 1
vsync = 0             ##other comment
width = 100              ###### yet another comment

#this is my second window config
[window1]
width1 = 800#nospace

# sound stuff
[sound]
fx = 1.0        #  max volume is 1.0
music = 0.5

[teste]
bool = 1

[teste2]
#teste2 is empty

Pages: [1]