1
0

iniparser.cpp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. #include "iniparser.h"
  2. #include <list>
  3. #include <sstream>
  4. #include "hdef.h"
  5. #include "herr.h"
  6. #include "hstring.h"
  7. #include "hfile.h"
  8. #include "hbase.h"
  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. string label; // section|key|comment
  26. 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 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. string &section;
  63. };
  64. class IniKeyValue : public IniNode {
  65. public:
  66. IniKeyValue() : IniNode(), key(label) {
  67. type = INI_NODE_TYPE_KEY_VALUE;
  68. }
  69. string &key;
  70. };
  71. class IniComment : public IniNode {
  72. public:
  73. IniComment() : IniNode(), comment(label) {
  74. }
  75. 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. return LoadFromMem(str.c_str());
  101. }
  102. int IniParser::LoadFromMem(const char* data) {
  103. Unload();
  104. root_ = new IniNode;
  105. root_->type = IniNode::INI_NODE_TYPE_ROOT;
  106. std::stringstream ss;
  107. ss << data;
  108. std::string strLine;
  109. int line = 0;
  110. string::size_type pos;
  111. string content;
  112. string comment;
  113. string strDiv;
  114. IniNode* pScopeNode = root_;
  115. IniNode* pNewNode = NULL;
  116. while (std::getline(ss, strLine)) {
  117. ++line;
  118. content = trimL(strLine);
  119. if (content.length() == 0) {
  120. // blank line
  121. strDiv += '\n';
  122. continue;
  123. }
  124. // trim_comment
  125. comment = "";
  126. pos = content.find_first_of(_comment);
  127. if (pos != string::npos) {
  128. comment = content.substr(pos);
  129. content = content.substr(0, pos);
  130. }
  131. content = trimR(content);
  132. if (content.length() == 0) {
  133. strDiv += strLine;
  134. strDiv += '\n';
  135. continue;
  136. } else if (strDiv.length() != 0) {
  137. IniNode* pNode = new IniNode;
  138. pNode->type = IniNode::INI_NODE_TYPE_DIV;
  139. pNode->label = strDiv;
  140. pScopeNode->Add(pNode);
  141. strDiv = "";
  142. }
  143. if (content[0] == '[') {
  144. if (content[content.length()-1] == ']') {
  145. // section
  146. content = trim(content.substr(1, content.length()-2));
  147. pNewNode = new IniNode;
  148. pNewNode->type = IniNode::INI_NODE_TYPE_SECTION;
  149. pNewNode->label = content;
  150. root_->Add(pNewNode);
  151. pScopeNode = pNewNode;
  152. } else {
  153. // hlogw("format error, line:%d", line);
  154. continue; // ignore
  155. }
  156. } else {
  157. pos = content.find_first_of(_delim);
  158. if (pos != string::npos) {
  159. // key-value
  160. pNewNode = new IniNode;
  161. pNewNode->type = IniNode::INI_NODE_TYPE_KEY_VALUE;
  162. pNewNode->label = trim(content.substr(0, pos));
  163. pNewNode->value = trim(content.substr(pos+_delim.length()));
  164. pScopeNode->Add(pNewNode);
  165. } else {
  166. // hlogw("format error, line:%d", line);
  167. continue; // ignore
  168. }
  169. }
  170. if (comment.length() != 0) {
  171. // tail_comment
  172. IniNode* pNode = new IniNode;
  173. pNode->type = IniNode::INI_NODE_TYPE_SPAN;
  174. pNode->label = comment;
  175. pNewNode->Add(pNode);
  176. comment = "";
  177. }
  178. }
  179. // file end comment
  180. if (strDiv.length() != 0) {
  181. IniNode* pNode = new IniNode;
  182. pNode->type = IniNode::INI_NODE_TYPE_DIV;
  183. pNode->label = strDiv;
  184. root_->Add(pNode);
  185. }
  186. return 0;
  187. }
  188. void IniParser::DumpString(IniNode* pNode, string& str) {
  189. if (pNode == NULL) return;
  190. if (pNode->type != IniNode::INI_NODE_TYPE_SPAN) {
  191. if (str.length() > 0 && str[str.length()-1] != '\n') {
  192. str += '\n';
  193. }
  194. }
  195. switch (pNode->type) {
  196. case IniNode::INI_NODE_TYPE_SECTION: {
  197. str += '[';
  198. str += pNode->label;
  199. str += ']';
  200. }
  201. break;
  202. case IniNode::INI_NODE_TYPE_KEY_VALUE: {
  203. str += asprintf("%s %s %s", pNode->label.c_str(), _delim.c_str(), pNode->value.c_str());
  204. }
  205. break;
  206. case IniNode::INI_NODE_TYPE_DIV: {
  207. str += pNode->label;
  208. }
  209. break;
  210. case IniNode::INI_NODE_TYPE_SPAN: {
  211. str += '\t';
  212. str += pNode->label;
  213. }
  214. break;
  215. default:
  216. break;
  217. }
  218. for (auto p : pNode->children) {
  219. DumpString(p, str);
  220. }
  221. }
  222. string IniParser::DumpString() {
  223. string str;
  224. DumpString(root_, str);
  225. return str;
  226. }
  227. int IniParser::Save() {
  228. return SaveAs(_filepath.c_str());
  229. }
  230. int IniParser::SaveAs(const char* filepath) {
  231. string str = DumpString();
  232. if (str.length() == 0) {
  233. return 0;
  234. }
  235. HFile file;
  236. if (file.open(filepath, "w") != 0) {
  237. return ERR_SAVE_FILE;
  238. }
  239. file.write(str.c_str(), str.length());
  240. return 0;
  241. }
  242. string IniParser::GetValue(const string& key, const string& section) {
  243. if (root_ == NULL) return "";
  244. IniNode* pSection = root_;
  245. if (section.length() != 0) {
  246. pSection = root_->Get(section, IniNode::INI_NODE_TYPE_SECTION);
  247. if (pSection == NULL) return "";
  248. }
  249. IniNode* pKV = pSection->Get(key, IniNode::INI_NODE_TYPE_KEY_VALUE);
  250. if (pKV == NULL) return "";
  251. return pKV->value;
  252. }
  253. void IniParser::SetValue(const string& key, const string& value, const string& section) {
  254. if (root_ == NULL) {
  255. root_ = new IniNode;
  256. }
  257. IniNode* pSection = root_;
  258. if (section.length() != 0) {
  259. pSection = root_->Get(section, IniNode::INI_NODE_TYPE_SECTION);
  260. if (pSection == NULL) {
  261. pSection = new IniNode;
  262. pSection->type = IniNode::INI_NODE_TYPE_SECTION;
  263. pSection->label = section;
  264. root_->Add(pSection);
  265. }
  266. }
  267. IniNode* pKV = pSection->Get(key, IniNode::INI_NODE_TYPE_KEY_VALUE);
  268. if (pKV == NULL) {
  269. pKV = new IniNode;
  270. pKV->type = IniNode::INI_NODE_TYPE_KEY_VALUE;
  271. pKV->label = key;
  272. pSection->Add(pKV);
  273. }
  274. pKV->value = value;
  275. }
  276. template<>
  277. HV_EXPORT bool IniParser::Get(const string& key, const string& section, bool defvalue) {
  278. string str = GetValue(key, section);
  279. return str.empty() ? defvalue : getboolean(str.c_str());
  280. }
  281. template<>
  282. HV_EXPORT int IniParser::Get(const string& key, const string& section, int defvalue) {
  283. string str = GetValue(key, section);
  284. return str.empty() ? defvalue : atoi(str.c_str());
  285. }
  286. template<>
  287. HV_EXPORT float IniParser::Get(const string& key, const string& section, float defvalue) {
  288. string str = GetValue(key, section);
  289. return str.empty() ? defvalue : atof(str.c_str());
  290. }
  291. template<>
  292. HV_EXPORT void IniParser::Set(const string& key, const bool& value, const string& section) {
  293. SetValue(key, value ? "true" : "false", section);
  294. }
  295. template<>
  296. HV_EXPORT void IniParser::Set(const string& key, const int& value, const string& section) {
  297. SetValue(key, asprintf("%d", value), section);
  298. }
  299. template<>
  300. HV_EXPORT void IniParser::Set(const string& key, const float& value, const string& section) {
  301. SetValue(key, asprintf("%f", value), section);
  302. }