123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186 |
- /*
- * 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 <cctype>
- #include <map>
- #include <string>
- #include <vector>
- #include <fstream>
- #include "util.h"
- namespace toolkit {
- template<typename key, typename variant>
- class mINI_basic : public std::map<key, variant> {
- // Public API : existing map<> interface plus following methods
- public:
- void parse(const std::string &text) {
- // reset, split lines and parse
- std::vector<std::string> 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<std::string> 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<std::string> tokenize(const std::string &self, const std::string &chars) const {
- std::vector<std::string> 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<typename T>
- variant(const T &t) :
- std::string(std::to_string(t)) {
- }
- template<size_t N>
- 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 <typename T>
- operator T() const {
- return as<T>();
- }
- template<typename T>
- 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 T>
- typename std::enable_if<!std::is_class<T>::value, T>::type as() const {
- return as_default<T>();
- }
- template <typename T>
- typename std::enable_if<std::is_class<T>::value, T>::type as() const {
- return T((const std::string &)*this);
- }
- private:
- template <typename T>
- T as_default() const {
- T t;
- std::stringstream ss;
- return ss << *this && ss >> t ? t : T();
- }
- };
- template <>
- bool variant::as<bool>() const;
- template <>
- uint8_t variant::as<uint8_t>() const;
- using mINI = mINI_basic<std::string, variant>;
- } // namespace toolkit
- #endif //UTIL_MINI_H
|