Skip to content

Instantly share code, notes, and snippets.

@prodeveloper0
Created December 5, 2018 14:58
Show Gist options
  • Select an option

  • Save prodeveloper0/d09a35e3dea7a82faf340f637a34dd6e to your computer and use it in GitHub Desktop.

Select an option

Save prodeveloper0/d09a35e3dea7a82faf340f637a34dd6e to your computer and use it in GitHub Desktop.
Simple INI Parser for C++11
#pragma once
//////////////////////////////
// Simple INI Parser
// Written by Samuel Lee(pr0ximo, prodeveloper0)
//
//
// Usage:
// sample.ini
// [Pri]
// ; This is my information
// name = "Samuel Lee"
// age = 25
//
// [Sub]
// ; This is my status
// healthy = 20
// tired = 1000
// vision_left = 0.3
// vision_right = 0.4
//
//
// main.cpp
// Config cfg("sample.ini");
// // No errors!
// std::string name = cfg["Pri"]["name"];
// int heathy = cfg["Sub"]["healthy"];
// float vision_left = cfg["Sub"]["vision_left"];
//
// // Exceptions are throwed!
// int name_invalid_type = cfg["Pri"]["name"];
//
#include <string>
#include <map>
#include <sstream>
#include <fstream>
#include <algorithm>
template<typename T = void>
class Config_
{
protected:
static const char* ws;
static const char* ws_section;
static const char* ws_property;
inline std::string& rtrim(std::string& s, const char* t = ws)
{
s.erase(s.find_last_not_of(t) + 1);
return s;
}
inline std::string& ltrim(std::string& s, const char* t = ws)
{
s.erase(0, s.find_first_not_of(t));
return s;
}
inline std::string& trim(std::string& s, const char* t = ws)
{
return ltrim(rtrim(s, t), t);
}
public:
class Value
{
protected:
template<typename T>
static T lexical_cast(const std::string& s)
{
std::stringstream ss(s);
T result;
if((ss >> result).fail() || !(ss >> std::ws).eof())
throw std::bad_cast();
return result;
}
public:
template<typename T>
operator T ()
{
return lexical_cast<T>(value);
}
public:
std::string value;
public:
Value(const std::string& v = "")
: value(v)
{
}
public:
Value& operator=(const std::string& v)
{
value = v;
return *this;
}
Value& operator=(const Value& v)
{
value = v.value;
return *this;
}
};
class Property
{
public:
std::map<std::string, Value> properties;
public:
void Add(const std::string& k, const Value& v)
{
properties[k] = v;
}
public:
Value& operator [] (const std::string& k)
{
auto& v = properties.find(k);
if(v == properties.cend())
throw std::out_of_range("Cannot found property");
return v->second;
}
};
protected:
std::map<std::string, Property> _Config;
public:
Config_(const std::string& filename = "")
{
if(filename.size() == 0)
return;
Read(filename);
}
public:
bool Read(const std::string& filename)
{
std::ifstream ifs(filename);
bool result = false;
std::string section;
std::string line;
std::string key;
std::string value;
std::map<std::string, Property> config;
// Is a file is opened successfully?
if(!ifs.is_open())
goto result;
while(std::getline(ifs, line))
{
line = trim(line);
// Is the current line a comment or blank line?
if(line.size() == 0 || *line.cbegin() == ';')
continue;
// Is the current line a section contains brackets '[]'?
if(*line.cbegin() == '[' || *line.cend() == ']')
{
section = trim(line, ws_section);
if(section.size() == 0)
goto result;
continue;
}
// Is the current line a property?
if(section.size() == 0)
goto result;
size_t kv_offset = line.find('=');
if(kv_offset == std::string::npos)
goto result;
key = trim(line.substr(0, kv_offset), ws_property);
value = trim(line.substr(kv_offset + 1), ws_property);
if(key.size() == 0)
goto result;
config[section].Add(key, value);
}
result = true;
_Config = config;
result:
ifs.close();
return result;
}
public:
Property& operator [] (const std::string& s)
{
auto& p = _Config.find(s);
if(p == _Config.cend())
throw std::out_of_range("Cannot found section");
return p->second;
}
};
const char* Config_<>::ws = " \t\n\r\f\v";
const char* Config_<>::ws_section = " \t\n\r\f\v[]";
const char* Config_<>::ws_property = " \t\n\r\f\v\'\"";
class Config : public Config_<>
{
public:
Config(const std::string filename = "")
: Config_(filename)
{
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment