Skip to content

Instantly share code, notes, and snippets.

@sehe
Last active January 20, 2017 21:02
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sehe/1425972 to your computer and use it in GitHub Desktop.
Save sehe/1425972 to your computer and use it in GitHub Desktop.
*.swp
*.o
inireader.so
test
[Cat1]
name1=100 #skipped
name2=200 \#not \\skipped
name3= dhfj dhjgfd/* skipped
*/
[Cat_2]
UsagePage=9
Usage=19
Offset=0x1204
/*
[Cat_2_bak]
UsagePage=9
Usage=19
Offset=0x1204
*/
[Cat_3]
UsagePage=12
Usage=39
#Usage4=39
Offset=0x12304
#pragma once
#define POSITIONINFO 0
#include <map>
#include <string>
#include <iterator>
#include <boost/tuple/tuple_comparison.hpp>
template <typename S=std::string, typename Cmp=std::less<S> >
class IniFile
{
public:
IniFile(Cmp cmp=Cmp()) : _cmp(cmp)
{}
IniFile(const std::string& filename, Cmp cmp=Cmp()) : _cmp(cmp)
{ open(filename); }
void open(const std::string& filename);
typedef S string_t;
#if POSITIONINFO
struct textnode_t
{
int sline, eline,
scol, ecol;
string_t text;
operator const string_t&() const { return text; }
friend std::ostream& operator<<(std::ostream& os, const textnode_t& t)
{
os << "[L:" << t.sline << ",C" << t.scol << " .. L" << t.eline << ",C" << t.ecol << ":";
for (typename string_t::const_iterator it=t.text.begin(); it!=t.text.end(); ++it)
switch (*it)
{
case '\r' : os << "\\r"; break;
case '\n' : os << "\\n"; break;
case '\t' : os << "\\t"; break;
case '\0' : os << "\\0"; break;
default: os << *it ; break;
}
return os << "]";
}
bool operator<(const textnode_t& o) const
{ return boost::tie(text/*, sline, eline, scol, ecol*/) <
boost::tie(o.text/*, o.sline, o.eline, o.scol, o.ecol*/); }
textnode_t() : sline(0), eline(0), scol(0), ecol(0) { }
};
#else
typedef string_t textnode_t;
#endif
typedef std::pair<textnode_t, textnode_t> keyvalue_t;
typedef std::map<textnode_t, textnode_t> section_t;
typedef std::map<textnode_t, section_t> sections_t;
private:
Cmp _cmp;
};
///////////////////////////////////////
// template implementation
//#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/support_istream_iterator.hpp>
#include <boost/spirit/include/support_line_pos_iterator.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/fusion/adapted/std_pair.hpp>
#include <fstream>
namespace qi = boost::spirit::qi;
namespace phx= boost::phoenix;
namespace inireader
{
struct printer
{
printer(std::ostream& os) : _os(os) {}
std::ostream& _os;
typedef boost::spirit::utf8_string string;
void element(string const& tag, string const& value, int depth) const
{
for (int i = 0; i < (depth*4); ++i) // indent to depth
_os << ' ';
_os << "tag: " << tag;
if (value != "")
_os << ", value: " << value;
_os << std::endl;
}
};
void print_info(std::ostream& os, boost::spirit::info const& what)
{
using boost::spirit::basic_info_walker;
printer pr(os);
basic_info_walker<printer> walker(pr, what.tag, 0);
boost::apply_visitor(walker, what.value);
}
template <typename It, typename Skipper, typename Ini>
struct Grammar : qi::grammar<It, typename Ini::sections_t(), Skipper>
{
typedef typename Ini::string_t string_t;
typedef typename Ini::textnode_t textnode_t;
struct textbuilder
{
template <typename> struct result { typedef textnode_t type; };
textbuilder(It begin) : _begin(begin) { }
textnode_t operator()(const boost::iterator_range<It>& iters) const
{
#if !POSITIONINFO
return textnode_t(std::begin(iters), std::end(iters));
#else
using boost::spirit::get_line;
using boost::spirit::get_line_start;
using boost::spirit::get_column;
textnode_t element;
element.text = string_t (std::begin(iters) , std::end(iters));
element.sline = get_line (std::begin(iters));
element.eline = get_line (std::end(iters));
It sol = get_line_start (_begin , std::begin(iters));
element.scol = get_column (sol , std::begin(iters));
element.ecol = get_column (sol , std::end(iters));
return element;
#endif
}
private:
const It _begin;
} makenode;
Grammar(It begin) : Grammar::base_type(inifile), makenode(begin)
{
using namespace qi;
txt_ch = (lit('\\') > char_) | (char_ - (eol | '#' | "/*"));
key = raw [ lexeme [ +(txt_ch - char_("=")) ] ] [ _val = phx::bind(makenode, _1) ];
value = raw [ lexeme [ +txt_ch ] ] [ _val = phx::bind(makenode, _1) ];
pair %= key > '=' > value;
heading = ('[' > raw [ +~char_(']') ] > ']') [ _val = phx::bind(makenode, _1) ];
section %= heading >> +eol >> -((pair-heading) % +eol);
inifile %= -(section % +eol) >> *eol > eoi;
comment =
('#' >> *(char_ - eol))
| ("/*" > *(char_ - "*/") > "*/");
//BOOST_SPIRIT_DEBUG_NODE(comment);
//BOOST_SPIRIT_DEBUG_NODE(txt_ch);
BOOST_SPIRIT_DEBUG_NODE(heading);
BOOST_SPIRIT_DEBUG_NODE(section);
BOOST_SPIRIT_DEBUG_NODE(key);
BOOST_SPIRIT_DEBUG_NODE(value);
BOOST_SPIRIT_DEBUG_NODE(pair);
BOOST_SPIRIT_DEBUG_NODE(inifile);
}
typedef typename Ini::keyvalue_t keyvalue_t;
typedef typename Ini::section_t section_t;
typedef typename Ini::sections_t sections_t;
typedef typename string_t::value_type Char;
qi::rule<It> comment;
qi::rule<It, Char()> txt_ch;
qi::rule<It, textnode_t(), Skipper> key, value, heading;
qi::rule<It, keyvalue_t(), Skipper> pair;
qi::rule<It, std::pair<textnode_t, section_t>(), Skipper> section;
qi::rule<It, sections_t(), Skipper> inifile;
};
template <typename It, typename Builder>
typename Builder::template result<void>::type
fragment(const It& first, const It& last, const Builder& builder)
{
size_t len = std::distance(first, last);
It frag_end = first;
std::advance(frag_end, std::min(10ul, len));
return builder(boost::iterator_range<It>(first, frag_end));
}
}
template <typename S, typename Cmp>
void IniFile<S, Cmp>::open(const std::string& filename)
{
using namespace qi;
std::ifstream ifs(filename.c_str());
ifs.unsetf(std::ios::skipws);
#if POSITIONINFO
typedef std::string::const_iterator RawIt;
typedef boost::spirit::line_pos_iterator<RawIt> It;
typedef rule<It> Skipper;
std::string buffer(std::istreambuf_iterator<char>(ifs), (std::istreambuf_iterator<char>()));
It f(buffer.begin()), l(buffer.end());
#else
typedef boost::spirit::istream_iterator It;
typedef rule<It> Skipper;
It f(ifs), l;
#endif
inireader::Grammar<It, Skipper, IniFile<S, Cmp> > grammar(f);
Skipper skip = char_(" \t") | grammar.comment;
try
{
sections_t data;
bool ok = phrase_parse(f, l, grammar, skip, data);
if (ok)
{
std::cout << "Parse success!" << std::endl;
for (auto& section : data)
{
std::cout << "[" << section.first << "]" << std::endl;
for (auto& pair : section.second)
std::cout << pair.first << " = " << pair.second << std::endl;
}
} else
{
std::cerr << "Parse failed" << std::endl;
}
} catch (const qi::expectation_failure<It>& e)
{
std::cerr << "Exception: " << e.what() <<
" " << inireader::fragment(e.first, e.last, grammar.makenode) << "... ";
inireader::print_info(std::cerr, e.what_);
}
if (f!=l)
{
std::cerr << "Stopped at: '" << inireader::fragment(f, l, grammar.makenode) << "'" << std::endl;
}
}
all: test | .depends
# BOOSTDIR=~/custom/boost_1_47_0
# CPPFLAGS+=-I $(BOOSTDIR)
CPPFLAGS+=-g -O2
CPPFLAGS+=-std=c++0x
CPPFLAGS+=-Wall
%.o: %.cpp
g++ $(CPPFLAGS) -o $@ -c $<
%: %.o
g++ $(CPPFLAGS) -o $@ $<
.depends: *.cpp
g++ $(CPPFLAGS) -M $^ -o $@
clean:
rm -rf test .depends
.PHONY: all clean
-include .depends
#include "inireader.h"
#include <fstream>
#include <iostream>
int main(int argc, const char *argv[])
{
IniFile<std::string> ini("example.ini");
return 0;
}
@markus2330
Copy link

Does this code happen to be public domain/BSD? (Would be nice to have it for http://www.libelektra.org, see ElektraInitiative/libelektra#736)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment