iniparser.cpp 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. #include "iniparser.h"
  2. #include <sstream>
  3. #include "hdef.h"
  4. #include "herr.h"
  5. #include "hstring.h"
  6. #include "hfile.h"
  7. #include "hbase.h"
  8. using namespace hv;
  9. /**********************************
  10. # div
  11. [section]
  12. key = value # span
  13. # div
  14. ***********************************/
  15. class IniNode {
  16. public:
  17. enum Type {
  18. INI_NODE_TYPE_UNKNOWN,
  19. INI_NODE_TYPE_ROOT,
  20. INI_NODE_TYPE_SECTION,
  21. INI_NODE_TYPE_KEY_VALUE,
  22. INI_NODE_TYPE_DIV,
  23. INI_NODE_TYPE_SPAN,
  24. } type;
  25. std::string label; // section|key|comment
  26. std::string value;
  27. std::list<IniNode*> children;
  28. virtual ~IniNode() {
  29. for (auto pNode : children) {
  30. if (pNode) {
  31. delete pNode;
  32. }
  33. }
  34. children.clear();
  35. }
  36. void Add(IniNode* pNode) {
  37. children.push_back(pNode);
  38. }
  39. void Del(IniNode* pNode) {
  40. for (auto iter = children.begin(); iter != children.end(); ++iter) {
  41. if ((*iter) == pNode) {
  42. delete (*iter);
  43. children.erase(iter);
  44. return;
  45. }
  46. }
  47. }
  48. IniNode* Get(const std::string& label, Type type = INI_NODE_TYPE_KEY_VALUE) {
  49. for (auto pNode : children) {
  50. if (pNode->type == type && pNode->label == label) {
  51. return pNode;
  52. }
  53. }
  54. return NULL;
  55. }
  56. };
  57. class IniSection : public IniNode {
  58. public:
  59. IniSection() : IniNode(), section(label) {
  60. type = INI_NODE_TYPE_SECTION;
  61. }
  62. std::string &section;
  63. };
  64. class IniKeyValue : public IniNode {
  65. public:
  66. IniKeyValue() : IniNode(), key(label) {
  67. type = INI_NODE_TYPE_KEY_VALUE;
  68. }
  69. std::string &key;
  70. };
  71. class IniComment : public IniNode {
  72. public:
  73. IniComment() : IniNode(), comment(label) {
  74. }
  75. std::string &comment;
  76. };
  77. IniParser::IniParser() {
  78. _comment = DEFAULT_INI_COMMENT;
  79. _delim = DEFAULT_INI_DELIM;
  80. root_ = NULL;
  81. }
  82. IniParser::~IniParser() {
  83. Unload();
  84. }
  85. int IniParser::Unload() {
  86. SAFE_DELETE(root_);
  87. return 0;
  88. }
  89. int IniParser::Reload() {
  90. return LoadFromFile(_filepath.c_str());
  91. }
  92. int IniParser::LoadFromFile(const char* filepath) {
  93. _filepath = filepath;
  94. HFile file;
  95. if (file.open(filepath, "r") != 0) {
  96. return ERR_OPEN_FILE;
  97. }
  98. std::string str;
  99. file.readall(str);
  100. const char* c_str = str.c_str();
  101. unsigned char utf8_bom[3] = { 0xEF, 0xBB, 0xBF };
  102. if (str.size() >= 3 && memcmp(c_str, utf8_bom, 3) == 0) {
  103. c_str += 3;
  104. }
  105. return LoadFromMem(c_str);
  106. }
  107. int IniParser::LoadFromMem(const char* data) {
  108. Unload();
  109. root_ = new IniNode;
  110. root_->type = IniNode::INI_NODE_TYPE_ROOT;
  111. std::stringstream ss;
  112. ss << data;
  113. std::string strLine;
  114. int line = 0;
  115. std::string::size_type pos;
  116. std::string content, comment, strDiv;
  117. IniNode* pScopeNode = root_;
  118. IniNode* pNewNode = NULL;
  119. while (std::getline(ss, strLine)) {
  120. ++line;
  121. content = ltrim(strLine);
  122. if (content.length() == 0) {
  123. // blank line
  124. strDiv += '\n';
  125. continue;
  126. }
  127. // trim_comment
  128. comment = "";
  129. pos = content.find_first_of(_comment);
  130. if (pos != std::string::npos) {
  131. comment = content.substr(pos);
  132. content = content.substr(0, pos);
  133. }
  134. content = rtrim(content);
  135. if (content.length() == 0) {
  136. strDiv += strLine;
  137. strDiv += '\n';
  138. continue;
  139. } else if (strDiv.length() != 0) {
  140. IniNode* pNode = new IniNode;
  141. pNode->type = IniNode::INI_NODE_TYPE_DIV;
  142. pNode->label = strDiv;
  143. pScopeNode->Add(pNode);
  144. strDiv = "";
  145. }
  146. if (content[0] == '[') {
  147. if (content[content.length()-1] == ']') {
  148. // section
  149. content = trim(content.substr(1, content.length()-2));
  150. pNewNode = new IniNode;
  151. pNewNode->type = IniNode::INI_NODE_TYPE_SECTION;
  152. pNewNode->label = content;
  153. root_->Add(pNewNode);
  154. pScopeNode = pNewNode;
  155. } else {
  156. // hlogw("format error, line:%d", line);
  157. continue; // ignore
  158. }
  159. } else {
  160. pos = content.find_first_of(_delim);
  161. if (pos != std::string::npos) {
  162. // key-value
  163. pNewNode = new IniNode;
  164. pNewNode->type = IniNode::INI_NODE_TYPE_KEY_VALUE;
  165. pNewNode->label = trim(content.substr(0, pos));
  166. pNewNode->value = trim(content.substr(pos+_delim.length()));
  167. pScopeNode->Add(pNewNode);
  168. } else {
  169. // hlogw("format error, line:%d", line);
  170. continue; // ignore
  171. }
  172. }
  173. if (comment.length() != 0) {
  174. // tail_comment
  175. IniNode* pNode = new IniNode;
  176. pNode->type = IniNode::INI_NODE_TYPE_SPAN;
  177. pNode->label = comment;
  178. pNewNode->Add(pNode);
  179. comment = "";
  180. }
  181. }
  182. // file end comment
  183. if (strDiv.length() != 0) {
  184. IniNode* pNode = new IniNode;
  185. pNode->type = IniNode::INI_NODE_TYPE_DIV;
  186. pNode->label = strDiv;
  187. root_->Add(pNode);
  188. }
  189. return 0;
  190. }
  191. void IniParser::DumpString(IniNode* pNode, std::string& str) {
  192. if (pNode == NULL) return;
  193. if (pNode->type != IniNode::INI_NODE_TYPE_SPAN) {
  194. if (str.length() > 0 && str[str.length()-1] != '\n') {
  195. str += '\n';
  196. }
  197. }
  198. switch (pNode->type) {
  199. case IniNode::INI_NODE_TYPE_SECTION: {
  200. str += '[';
  201. str += pNode->label;
  202. str += ']';
  203. }
  204. break;
  205. case IniNode::INI_NODE_TYPE_KEY_VALUE: {
  206. str += asprintf("%s %s %s", pNode->label.c_str(), _delim.c_str(), pNode->value.c_str());
  207. }
  208. break;
  209. case IniNode::INI_NODE_TYPE_DIV: {
  210. str += pNode->label;
  211. }
  212. break;
  213. case IniNode::INI_NODE_TYPE_SPAN: {
  214. str += '\t';
  215. str += pNode->label;
  216. }
  217. break;
  218. default:
  219. break;
  220. }
  221. for (auto p : pNode->children) {
  222. DumpString(p, str);
  223. }
  224. }
  225. std::string IniParser::DumpString() {
  226. std::string str;
  227. DumpString(root_, str);
  228. return str;
  229. }
  230. int IniParser::Save() {
  231. return SaveAs(_filepath.c_str());
  232. }
  233. int IniParser::SaveAs(const char* filepath) {
  234. std::string str = DumpString();
  235. if (str.length() == 0) {
  236. return 0;
  237. }
  238. HFile file;
  239. if (file.open(filepath, "w") != 0) {
  240. return ERR_SAVE_FILE;
  241. }
  242. file.write(str.c_str(), str.length());
  243. return 0;
  244. }
  245. std::list<std::string> IniParser::GetSections() {
  246. std::list<std::string> ret;
  247. if (root_ == NULL) return std::move(ret);
  248. for (auto pNode : root_->children) {
  249. if (pNode->type == IniNode::INI_NODE_TYPE_SECTION) {
  250. ret.push_back(pNode->label);
  251. }
  252. }
  253. return std::move(ret);
  254. }
  255. std::list<std::string> IniParser::GetKeys(const std::string& section) {
  256. std::list<std::string> ret;
  257. if (root_ == NULL) return std::move(ret);
  258. IniNode* pSection = root_;
  259. if (section.length() != 0) {
  260. pSection = root_->Get(section, IniNode::INI_NODE_TYPE_SECTION);
  261. if (pSection == NULL) return std::move(ret);
  262. }
  263. for (auto pNode : pSection->children) {
  264. if (pNode->type == IniNode::INI_NODE_TYPE_KEY_VALUE) {
  265. ret.push_back(pNode->label);
  266. }
  267. }
  268. return std::move(ret);
  269. }
  270. std::string IniParser::GetValue(const std::string& key, const std::string& section) {
  271. if (root_ == NULL) return "";
  272. IniNode* pSection = root_;
  273. if (section.length() != 0) {
  274. pSection = root_->Get(section, IniNode::INI_NODE_TYPE_SECTION);
  275. if (pSection == NULL) return "";
  276. }
  277. IniNode* pKV = pSection->Get(key, IniNode::INI_NODE_TYPE_KEY_VALUE);
  278. if (pKV == NULL) return "";
  279. return pKV->value;
  280. }
  281. void IniParser::SetValue(const std::string& key, const std::string& value, const std::string& section) {
  282. if (root_ == NULL) {
  283. root_ = new IniNode;
  284. }
  285. IniNode* pSection = root_;
  286. if (section.length() != 0) {
  287. pSection = root_->Get(section, IniNode::INI_NODE_TYPE_SECTION);
  288. if (pSection == NULL) {
  289. pSection = new IniNode;
  290. pSection->type = IniNode::INI_NODE_TYPE_SECTION;
  291. pSection->label = section;
  292. root_->Add(pSection);
  293. }
  294. }
  295. IniNode* pKV = pSection->Get(key, IniNode::INI_NODE_TYPE_KEY_VALUE);
  296. if (pKV == NULL) {
  297. pKV = new IniNode;
  298. pKV->type = IniNode::INI_NODE_TYPE_KEY_VALUE;
  299. pKV->label = key;
  300. pSection->Add(pKV);
  301. }
  302. pKV->value = value;
  303. }
  304. template<>
  305. HV_EXPORT bool IniParser::Get(const std::string& key, const std::string& section, bool defvalue) {
  306. std::string str = GetValue(key, section);
  307. return str.empty() ? defvalue : hv_getboolean(str.c_str());
  308. }
  309. template<>
  310. HV_EXPORT int IniParser::Get(const std::string& key, const std::string& section, int defvalue) {
  311. std::string str = GetValue(key, section);
  312. return str.empty() ? defvalue : atoi(str.c_str());
  313. }
  314. template<>
  315. HV_EXPORT float IniParser::Get(const std::string& key, const std::string& section, float defvalue) {
  316. std::string str = GetValue(key, section);
  317. return str.empty() ? defvalue : atof(str.c_str());
  318. }
  319. template<>
  320. HV_EXPORT void IniParser::Set(const std::string& key, const bool& value, const std::string& section) {
  321. SetValue(key, value ? "true" : "false", section);
  322. }
  323. template<>
  324. HV_EXPORT void IniParser::Set(const std::string& key, const int& value, const std::string& section) {
  325. SetValue(key, asprintf("%d", value), section);
  326. }
  327. template<>
  328. HV_EXPORT void IniParser::Set(const std::string& key, const float& value, const std::string& section) {
  329. SetValue(key, asprintf("%f", value), section);
  330. }