/* * Copyright (c) 2015 r-lyeh (https://github.com/r-lyeh) * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef UTIL_MINI_H #define UTIL_MINI_H #include #include #include #include #include #include #include #include #include "Util/util.h" using namespace std; namespace toolkit { template class mINI_basic: public map { // Public API : existing map<> interface plus following methods public: void parse(const string &text) { // reset, split lines and parse vector lines = tokenize(text, "\n"); string symbol, tag; for (auto &line : lines){ // trim blanks line = trim(line); // split line into tokens and parse tokens if(line.empty() || line.front() == ';' || line.front() == '#'){ continue; } if (line.size() >= 3 && line.front() == '[' && line.back() == ']') { tag = trim(line.substr(1, line.size() - 2)); } else { auto at = line.find('='); symbol = trim(tag + "." + line.substr(0, at)); (*this)[symbol] = (at == string::npos ? string() : trim(line.substr(at + 1))); } } } void parseFile(const string &fileName = exePath() + ".ini") { ifstream in(fileName, ios::in | ios::binary | ios::ate); if (!in.good()) { stringstream ss; ss << "invalid ini file:" << fileName; throw invalid_argument(ss.str()); } auto size = in.tellg(); in.seekg(0, ios::beg); string buf; buf.resize(size); in.read((char *) buf.data(), size); parse(buf); } string dump(const string &header = "; auto-generated by mINI class {", const string &footer = "; } ---") const { string output(header + (header.empty() ? "" : "\r\n")), tag; for (auto &pr : *this) { vector kv = tokenize(pr.first, "."); if (tag != kv[0]) { output += "\r\n[" + (tag = kv[0]) + "]\r\n"; } output += kv[1] + "=" + pr.second + "\r\n"; } return output + "\r\n" + footer + (footer.empty() ? "" : "\r\n"); } void dumpFile(const string &fileName = exePath() + ".ini") { ofstream out(fileName, ios::out | ios::binary | ios::trunc); auto dmp = dump(); out.write(dmp.data(),dmp.size()); } static mINI_basic &Instance(); private: vector tokenize(const string &self, const string &chars) const { vector tokens(1); string map(256, '\0'); for (char ch : chars) { map[(uint8_t) ch] = '\1'; } for (char ch : self) { if (!map.at((uint8_t) ch)) { tokens.back().push_back(ch); } else if (tokens.back().size()) { tokens.push_back(string()); } } while (tokens.size() && tokens.back().empty()) { tokens.pop_back(); } return tokens; } }; // handy variant class as key/values struct variant: public string { template variant(const T &t) : string(to_string(t)) { } template variant(const char (&s)[N]) : string(s, N) { } variant(const char *cstr) : string(cstr) { } variant(const string &other = string()) : string(other) { } template operator T() const { T t; stringstream ss; return ss << *this && ss >> t ? t : T(); } template bool operator ==(const T &t) const { return 0 == this->compare(variant(t)); } bool operator ==(const char *t) const { return this->compare(t) == 0; } template T as() const { return (T) (*this); } }; using mINI = mINI_basic; } // namespace toolkit #endif //UTIL_MINI_H