/* * 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 "util.h" namespace toolkit { template class mINI_basic : public std::map { // Public API : existing map<> interface plus following methods public: void parse(const std::string &text) { // reset, split lines and parse std::vector lines = tokenize(text, "\n"); std::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 == std::string::npos ? std::string() : trim(line.substr(at + 1))); } } } void parseFile(const std::string &fileName = exePath() + ".ini") { std::ifstream in(fileName, std::ios::in | std::ios::binary | std::ios::ate); if (!in.good()) { throw std::invalid_argument("Invalid ini file: " + fileName); } auto size = in.tellg(); in.seekg(0, std::ios::beg); std::string buf; buf.resize(size); in.read((char *) buf.data(), size); parse(buf); } std::string dump(const std::string &header = "; auto-generated by mINI class {", const std::string &footer = "; } ---") const { std::string front(header + (header.empty() ? "" : "\r\n")), output, tag; std::vector kv; for (auto &pr : *this) { auto pos = pr.first.find('.'); if (pos == std::string::npos) { kv = {"", pr.first}; } else { kv = {pr.first.substr(0, pos), pr.first.substr(pos + 1)}; } if (kv[0].empty()) { front += kv[1] + "=" + pr.second + "\r\n"; continue; } if (tag != kv[0]) { output += "\r\n[" + (tag = kv[0]) + "]\r\n"; } output += kv[1] + "=" + pr.second + "\r\n"; } return front + output + "\r\n" + footer + (footer.empty() ? "" : "\r\n"); } void dumpFile(const std::string &fileName = exePath() + ".ini") { std::ofstream out(fileName, std::ios::out | std::ios::binary | std::ios::trunc); auto dmp = dump(); out.write(dmp.data(), dmp.size()); } static mINI_basic &Instance(); private: std::vector tokenize(const std::string &self, const std::string &chars) const { std::vector tokens(1); std::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(std::string()); } } while (tokens.size() && tokens.back().empty()) { tokens.pop_back(); } return tokens; } }; // handy variant class as key/values struct variant : public std::string { template variant(const T &t) : std::string(std::to_string(t)) { } template variant(const char (&s)[N]) : std::string(s, N) { } variant(const char *cstr) : std::string(cstr) { } variant(const std::string &other = std::string()) : std::string(other) { } template operator T() const { return as(); } 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 typename std::enable_if::value, T>::type as() const { return as_default(); } template typename std::enable_if::value, T>::type as() const { return T((const std::string &)*this); } private: template T as_default() const { T t; std::stringstream ss; return ss << *this && ss >> t ? t : T(); } }; template <> bool variant::as() const; template <> uint8_t variant::as() const; using mINI = mINI_basic; } // namespace toolkit #endif //UTIL_MINI_H