mini.h 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. /*
  2. * Copyright (c) 2015 r-lyeh (https://github.com/r-lyeh)
  3. * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com>
  4. *
  5. * This software is provided 'as-is', without any express or implied
  6. * warranty. In no event will the authors be held liable for any damages
  7. * arising from the use of this software.
  8. *
  9. * Permission is granted to anyone to use this software for any purpose,
  10. * including commercial applications, and to alter it and redistribute it
  11. * freely, subject to the following restrictions:
  12. *
  13. * 1. The origin of this software must not be misrepresented; you must not
  14. * claim that you wrote the original software. If you use this software
  15. * in a product, an acknowledgment in the product documentation would be
  16. * appreciated but is not required.
  17. * 2. Altered source versions must be plainly marked as such, and must not be
  18. * misrepresented as being the original software.
  19. * 3. This notice may not be removed or altered from any source distribution.
  20. */
  21. #ifndef UTIL_MINI_H
  22. #define UTIL_MINI_H
  23. #include <map>
  24. #include <string>
  25. #include <vector>
  26. #include <fstream>
  27. #include <cstring>
  28. #include <cassert>
  29. #include <iostream>
  30. #include <exception>
  31. #include "Util/util.h"
  32. using namespace std;
  33. namespace toolkit {
  34. template<typename key, typename variant>
  35. class mINI_basic: public map<key, variant> {
  36. // Public API : existing map<> interface plus following methods
  37. public:
  38. void parse(const string &text) {
  39. // reset, split lines and parse
  40. vector<string> lines = tokenize(text, "\n");
  41. string symbol, tag;
  42. for (auto &line : lines){
  43. // trim blanks
  44. line = trim(line);
  45. // split line into tokens and parse tokens
  46. if(line.empty() || line.front() == ';' || line.front() == '#'){
  47. continue;
  48. }
  49. if (line.size() >= 3 && line.front() == '[' && line.back() == ']') {
  50. tag = trim(line.substr(1, line.size() - 2));
  51. } else {
  52. auto at = line.find('=');
  53. symbol = trim(tag + "." + line.substr(0, at));
  54. (*this)[symbol] = (at == string::npos ? string() : trim(line.substr(at + 1)));
  55. }
  56. }
  57. }
  58. void parseFile(const string &fileName = exePath() + ".ini") {
  59. ifstream in(fileName, ios::in | ios::binary | ios::ate);
  60. if (!in.good()) {
  61. stringstream ss;
  62. ss << "invalid ini file:" << fileName;
  63. throw invalid_argument(ss.str());
  64. }
  65. auto size = in.tellg();
  66. in.seekg(0, ios::beg);
  67. string buf;
  68. buf.resize(size);
  69. in.read((char *) buf.data(), size);
  70. parse(buf);
  71. }
  72. string dump(const string &header = "; auto-generated by mINI class {",
  73. const string &footer = "; } ---") const {
  74. string output(header + (header.empty() ? "" : "\r\n")), tag;
  75. for (auto &pr : *this) {
  76. vector<string> kv = tokenize(pr.first, ".");
  77. if (tag != kv[0]) {
  78. output += "\r\n[" + (tag = kv[0]) + "]\r\n";
  79. }
  80. output += kv[1] + "=" + pr.second + "\r\n";
  81. }
  82. return output + "\r\n" + footer + (footer.empty() ? "" : "\r\n");
  83. }
  84. void dumpFile(const string &fileName = exePath() + ".ini") {
  85. ofstream out(fileName, ios::out | ios::binary | ios::trunc);
  86. auto dmp = dump();
  87. out.write(dmp.data(),dmp.size());
  88. }
  89. static mINI_basic &Instance();
  90. private:
  91. vector<string> tokenize(const string &self, const string &chars) const {
  92. vector<string> tokens(1);
  93. string map(256, '\0');
  94. for (char ch : chars) {
  95. map[(uint8_t) ch] = '\1';
  96. }
  97. for (char ch : self) {
  98. if (!map.at((uint8_t) ch)) {
  99. tokens.back().push_back(ch);
  100. } else if (tokens.back().size()) {
  101. tokens.push_back(string());
  102. }
  103. }
  104. while (tokens.size() && tokens.back().empty()) {
  105. tokens.pop_back();
  106. }
  107. return tokens;
  108. }
  109. };
  110. // handy variant class as key/values
  111. struct variant: public string {
  112. template<typename T>
  113. variant(const T &t) :
  114. string(to_string(t)) {
  115. }
  116. template<size_t N>
  117. variant(const char (&s)[N]) :
  118. string(s, N) {
  119. }
  120. variant(const char *cstr) :
  121. string(cstr) {
  122. }
  123. variant(const string &other = string()) :
  124. string(other) {
  125. }
  126. template<typename T>
  127. operator T() const {
  128. T t;
  129. stringstream ss;
  130. return ss << *this && ss >> t ? t : T();
  131. }
  132. template<typename T> bool operator ==(const T &t) const {
  133. return 0 == this->compare(variant(t));
  134. }
  135. bool operator ==(const char *t) const {
  136. return this->compare(t) == 0;
  137. }
  138. template<typename T>
  139. T as() const {
  140. return (T) (*this);
  141. }
  142. };
  143. using mINI = mINI_basic<string, variant>;
  144. } // namespace toolkit
  145. #endif //UTIL_MINI_H