/* Copyright 2017, Michele Santullo * This file is part of "tawashi". * * "tawashi" is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * "tawashi" is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with "tawashi". If not, see . */ #include "ini_file.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace tawashi { namespace { typedef boost::string_ref string_type; template struct IniGrammar : boost::spirit::qi::grammar { explicit IniGrammar (const std::string* parString); boost::spirit::qi::rule start; boost::spirit::qi::rule section_head; boost::spirit::qi::rule key; boost::spirit::qi::rule key_value; boost::spirit::qi::rule key_values; const std::string* m_master_string; Iterator m_begin; }; template IniGrammar::IniGrammar (const std::string* parString) : IniGrammar::base_type(start), m_master_string(parString), m_begin(m_master_string->cbegin()) { assert(m_master_string); namespace px = boost::phoenix; using boost::spirit::ascii::space; using boost::spirit::qi::_val; using boost::spirit::_1; using boost::spirit::qi::char_; using boost::spirit::qi::eol; using boost::spirit::qi::raw; using boost::string_ref; typedef IniFile::KeyValueMapType::value_type refpair; section_head = '[' >> raw[+(char_ - ']')][_val = px::bind( &string_ref::substr, px::construct(px::ref(*m_master_string)), px::begin(_1) - px::ref(m_begin), px::size(_1) )] >> ']' >> eol; key = raw[+(char_ - '=')][_val = px::bind( &string_ref::substr, px::construct(px::ref(*m_master_string)), px::begin(_1) - px::ref(m_begin), px::size(_1) )]; key_value = key[px::bind(&refpair::first, _val) = _1] >> '=' >> raw[*(char_ - eol)][px::bind(&refpair::second, _val) = px::bind( &string_ref::substr, px::construct(px::ref(*m_master_string)), px::begin(_1) - px::ref(m_begin), px::size(_1) )] >> eol; key_values = *key_value; start = *(section_head >> key_values); } IniFile::IniMapType parse_ini (const std::string* parIni) { using boost::spirit::qi::blank; using boost::spirit::qi::blank_type; IniGrammar gramm(parIni); IniFile::IniMapType result; std::string::const_iterator start_it = parIni->cbegin(); /*const bool parse_ok =*/ boost::spirit::qi::phrase_parse( start_it, parIni->cend(), gramm, blank, result ); //assert(parse_ok and (parIni->cend() == start_it)); return result; } } //unnamed namespace IniFile::IniFile (std::istream_iterator parInputFrom, std::istream_iterator parInputEnd) : IniFile(std::string(parInputFrom, parInputEnd)) { } IniFile::IniFile (std::string&& parIniData) : m_raw_ini(std::move(parIniData)), m_map(parse_ini(&m_raw_ini)) { } IniFile::IniFile (IniFile&& parOther) { auto* const old_data_ptr = parOther.m_raw_ini.data(); m_raw_ini = std::move(parOther.m_raw_ini); if (m_raw_ini.data() == old_data_ptr) m_map = std::move(parOther.m_map); else m_map = parse_ini(&m_raw_ini); } IniFile::~IniFile() noexcept { } } //namespace tawashi