Last active
January 20, 2017 21:02
-
-
Save sehe/1425972 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
*.swp | |
*.o | |
inireader.so | |
test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "inireader.h" | |
#include <fstream> | |
#include <iostream> | |
int main(int argc, const char *argv[]) | |
{ | |
IniFile<std::string> ini("example.ini"); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Does this code happen to be public domain/BSD? (Would be nice to have it for http://www.libelektra.org, see ElektraInitiative/libelektra#736)