/services/fconf/fconf_xml.c

http://ftk.googlecode.com/ · C · 829 lines · 669 code · 131 blank · 29 comment · 211 complexity · 835abd0a21ce44098a8cf7ea2a2078a6 MD5 · raw file

  1. /*
  2. * File: fconf_xml.c
  3. * Author: Li XianJing <xianjimli@hotmail.com>
  4. * Brief: xml implementation for interface FConf.
  5. *
  6. * Copyright (c) 2009 - 2010 Li XianJing <xianjimli@hotmail.com>
  7. *
  8. * Licensed under the Academic Free License version 2.1
  9. *
  10. * This program is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation; either version 2 of the License, or
  13. * (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program; if not, write to the Free Software
  22. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  23. */
  24. /*
  25. * History:
  26. * ================================================================
  27. * 2010-08-01 Li XianJing <xianjimli@hotmail.com> created
  28. *
  29. */
  30. #include "ftk_path.h"
  31. #include "fconf_xml.h"
  32. #include "ftk_mmap.h"
  33. #include "ftk_util.h"
  34. #include "ftk_xml_parser.h"
  35. #include "ftk_allocator.h"
  36. typedef enum _XmlNodeAttr
  37. {
  38. NODE_ATTR_READONLY = 1,
  39. NODE_ATTR_MODIFIED = 2
  40. }XmlNodeAttr;
  41. typedef struct _XmlNode
  42. {
  43. char* name;
  44. char* value;
  45. unsigned int attr;
  46. struct _XmlNode* next;
  47. struct _XmlNode* prev;
  48. struct _XmlNode* parent;
  49. struct _XmlNode* children;
  50. }XmlNode;
  51. static XmlNode* xml_node_create(const char* name, const char* value)
  52. {
  53. XmlNode* node = NULL;
  54. return_val_if_fail(name != NULL, NULL);
  55. if((node = FTK_ZALLOC(sizeof(XmlNode))) != NULL)
  56. {
  57. node->name = ftk_strdup(name);
  58. if(node->name != NULL)
  59. {
  60. if(value != NULL)
  61. {
  62. node->value = ftk_strdup(value);
  63. }
  64. }
  65. else
  66. {
  67. FTK_FREE(node);
  68. }
  69. }
  70. return node;
  71. }
  72. static Ret xml_node_set_value(XmlNode* node, const char* value)
  73. {
  74. return_val_if_fail(node != NULL, RET_FAIL);
  75. return_val_if_fail((node->attr & NODE_ATTR_READONLY) == 0, RET_FAIL);
  76. FTK_FREE(node->value);
  77. if(value != NULL)
  78. {
  79. node->value = ftk_strdup(value);
  80. }
  81. return RET_OK;
  82. }
  83. static Ret xml_node_set_readonly(XmlNode* node, int readonly)
  84. {
  85. return_val_if_fail(node != NULL, RET_FAIL);
  86. if(readonly)
  87. {
  88. node->attr |= NODE_ATTR_READONLY;
  89. }
  90. else
  91. {
  92. node->attr &= ~NODE_ATTR_READONLY;
  93. }
  94. return RET_OK;
  95. }
  96. static Ret xml_node_set_modified(XmlNode* node, int modified)
  97. {
  98. return_val_if_fail(node != NULL, RET_FAIL);
  99. if(modified)
  100. {
  101. node->attr |= NODE_ATTR_MODIFIED;
  102. }
  103. else
  104. {
  105. node->attr &= ~NODE_ATTR_MODIFIED;
  106. }
  107. return RET_OK;
  108. }
  109. static int xml_node_get_child_count(XmlNode* node)
  110. {
  111. int nr = 0;
  112. XmlNode* iter = NULL;
  113. return_val_if_fail(node != NULL, 0);
  114. for(iter = node->children; iter != NULL; iter = iter->next)
  115. {
  116. nr++;
  117. }
  118. return nr;
  119. }
  120. static XmlNode* xml_node_get_child(XmlNode* node, size_t index)
  121. {
  122. XmlNode* iter = NULL;
  123. return_val_if_fail(node != NULL, 0);
  124. for(iter = node->children; iter != NULL; iter = iter->next)
  125. {
  126. if(index == 0)
  127. {
  128. return iter;
  129. }
  130. else
  131. {
  132. index--;
  133. }
  134. }
  135. return NULL;
  136. }
  137. static XmlNode* xml_node_find(XmlNode* node, FtkPath* path)
  138. {
  139. return_val_if_fail(node != NULL && node->name != NULL && path != NULL, NULL);
  140. for(; node != NULL; node = node->next)
  141. {
  142. if(strcmp(node->name, ftk_path_current(path)) == 0)
  143. {
  144. if(ftk_path_is_leaf(path))
  145. {
  146. return node;
  147. }
  148. else if(node->children != NULL)
  149. {
  150. ftk_path_down(path);
  151. return xml_node_find(node->children, path);
  152. }
  153. else
  154. {
  155. return NULL;
  156. }
  157. }
  158. }
  159. return NULL;
  160. }
  161. static XmlNode* xml_node_append_sibling(XmlNode* node, const char* name, const char* value)
  162. {
  163. XmlNode* iter = NULL;
  164. XmlNode* sibling = NULL;
  165. return_val_if_fail(name != NULL, NULL);
  166. if((sibling = xml_node_create(name, value)) != NULL)
  167. {
  168. if(node != NULL)
  169. {
  170. for(iter = node; iter->next != NULL; iter = iter->next)
  171. {
  172. }
  173. iter->next = sibling;
  174. sibling->prev = iter;
  175. sibling->parent = node->parent;
  176. }
  177. }
  178. return sibling;
  179. }
  180. static Ret xml_node_add(XmlNode* node, FtkPath* path, const char* value)
  181. {
  182. XmlNode* iter = node;
  183. return_val_if_fail(node != NULL && node->name != NULL && path != NULL, RET_FAIL);
  184. for(; iter != NULL; iter = iter->next)
  185. {
  186. if(strcmp(iter->name, ftk_path_current(path)) == 0)
  187. {
  188. if(ftk_path_is_leaf(path))
  189. {
  190. xml_node_set_value(iter, value);
  191. }
  192. else
  193. {
  194. ftk_path_down(path);
  195. if(iter->children == NULL)
  196. {
  197. iter->children = xml_node_create(ftk_path_current(path), NULL);
  198. iter->children->parent = iter;
  199. }
  200. xml_node_add(iter->children, path, value);
  201. }
  202. return RET_OK;
  203. }
  204. }
  205. iter = xml_node_append_sibling(node, ftk_path_current(path), value);
  206. if(!ftk_path_is_leaf(path))
  207. {
  208. return xml_node_add(iter, path, value);
  209. }
  210. return RET_OK;
  211. }
  212. static void xml_node_destroy(XmlNode* node)
  213. {
  214. XmlNode* iter = NULL;
  215. XmlNode* temp = NULL;
  216. if(node != NULL)
  217. {
  218. iter = node->children;
  219. while(iter != NULL)
  220. {
  221. temp = iter->next;
  222. xml_node_destroy(iter);
  223. iter = temp;
  224. }
  225. if(node->parent != NULL)
  226. {
  227. if(node->parent->children == node)
  228. {
  229. node->parent->children = node->next;
  230. }
  231. }
  232. if(node->prev != NULL)
  233. {
  234. node->prev->next = node->next;
  235. }
  236. if(node->next != NULL)
  237. {
  238. node->next->prev = node->prev;
  239. }
  240. FTK_ZFREE(node, sizeof(XmlNode));
  241. }
  242. return;
  243. }
  244. static Ret xml_node_save(XmlNode* node, FILE* fp)
  245. {
  246. return_val_if_fail(node != NULL && fp != NULL, RET_FAIL);
  247. if(node->children == NULL)
  248. {
  249. fprintf(fp, "<%s value=\"%s\" readonly=\"%d\"/>\n",
  250. node->name, node->value, node->attr & NODE_ATTR_READONLY ? 1 : 0);
  251. }
  252. else
  253. {
  254. XmlNode* iter = NULL;
  255. fprintf(fp, "<%s>\n", node->name);
  256. for(iter = node->children; iter != NULL; iter = iter->next)
  257. {
  258. xml_node_save(iter, fp);
  259. }
  260. fprintf(fp, "</%s>\n", node->name);
  261. }
  262. return RET_OK;
  263. }
  264. typedef struct _PrivInfo
  265. {
  266. int modified;
  267. XmlNode* root;
  268. char* root_path;
  269. FtkPath* path;
  270. FConfOnChanged on_changed;
  271. void* on_changed_ctx;
  272. }PrivInfo;
  273. Ret fconf_xml_save(FConf* thiz)
  274. {
  275. FILE* fp = NULL;
  276. XmlNode* iter = NULL;
  277. DECL_PRIV(thiz, priv);
  278. char filename[FTK_MAX_PATH+1] = {0};
  279. return_val_if_fail(thiz != NULL && priv->root != NULL, RET_FAIL);
  280. for(iter = priv->root; iter != NULL; iter = iter->next)
  281. {
  282. if(iter->attr & NODE_ATTR_MODIFIED)
  283. {
  284. ftk_snprintf(filename, FTK_MAX_PATH, "%s%c%s.cnf", priv->root_path, FTK_PATH_DELIM, iter->name);
  285. if((fp = fopen(filename, "w+")) != NULL)
  286. {
  287. xml_node_save(iter, fp);
  288. xml_node_set_modified(iter, 0);
  289. fclose(fp);
  290. }
  291. }
  292. }
  293. priv->modified = 0;
  294. ftk_logd("%s: done\n", __func__);
  295. return RET_OK;
  296. }
  297. typedef struct _BuilderInfo
  298. {
  299. XmlNode* root;
  300. XmlNode* current;
  301. }BuilderInfo;
  302. static void fconf_xml_builder_on_start(FtkXmlBuilder* thiz, const char* tag, const char** attrs)
  303. {
  304. int i = 0;
  305. int readonly = 0;
  306. XmlNode* node = NULL;
  307. const char* data = NULL;
  308. BuilderInfo* info = (BuilderInfo*)thiz->priv;
  309. return_if_fail(thiz != NULL && tag != NULL && attrs != NULL);
  310. for(i = 0; attrs[i] != NULL; i+=2)
  311. {
  312. const char* name = attrs[i];
  313. const char* value = attrs[i+1];
  314. if(strcmp(name, "value") == 0)
  315. {
  316. data = value;
  317. }
  318. else if(strcmp(name, "readonly") == 0)
  319. {
  320. readonly = ftk_str2bool(value);
  321. }
  322. }
  323. node = xml_node_append_sibling(info->current->children, tag, data);
  324. return_if_fail(node != NULL);
  325. if(readonly)
  326. {
  327. xml_node_set_readonly(node, readonly);
  328. }
  329. if(info->current->children == NULL)
  330. {
  331. info->current->children = node;
  332. node->parent = info->current;
  333. }
  334. info->current = node;
  335. return;
  336. }
  337. static void fconf_xml_builder_on_end(FtkXmlBuilder* thiz, const char* tag)
  338. {
  339. BuilderInfo* info = (BuilderInfo*)thiz->priv;
  340. return_if_fail(info->current != NULL);
  341. if(info->current->parent != NULL)
  342. {
  343. info->current = info->current->parent;
  344. }
  345. return;
  346. }
  347. static void fconf_xml_builder_on_text(FtkXmlBuilder* thiz, const char* text, size_t length)
  348. {
  349. return;
  350. }
  351. static void fconf_xml_builder_destroy(FtkXmlBuilder* thiz)
  352. {
  353. if(thiz != NULL)
  354. {
  355. FTK_ZFREE(thiz, sizeof(FtkXmlBuilder) + sizeof(BuilderInfo));
  356. }
  357. return;
  358. }
  359. static FtkXmlBuilder* fconf_xml_builder_create(void)
  360. {
  361. FtkXmlBuilder* thiz = FTK_ZALLOC(sizeof(FtkXmlBuilder) + sizeof(BuilderInfo));
  362. if(thiz != NULL)
  363. {
  364. thiz->on_start_element = fconf_xml_builder_on_start;
  365. thiz->on_end_element = fconf_xml_builder_on_end;
  366. thiz->on_text = fconf_xml_builder_on_text;
  367. thiz->destroy = fconf_xml_builder_destroy;
  368. }
  369. return thiz;
  370. }
  371. static XmlNode* fconf_xml_parse(const char* name, const char* xml, size_t length)
  372. {
  373. XmlNode* node = NULL;
  374. FtkXmlParser* parser = NULL;
  375. FtkXmlBuilder* builder = NULL;
  376. return_val_if_fail(xml != NULL, NULL);
  377. node = xml_node_create(name, NULL);
  378. return_val_if_fail(node != NULL, NULL);
  379. if((parser = ftk_xml_parser_create()) == NULL)
  380. {
  381. xml_node_destroy(node);
  382. return_val_if_fail(parser != NULL, NULL);
  383. }
  384. builder = fconf_xml_builder_create();
  385. if(builder != NULL)
  386. {
  387. BuilderInfo* priv = (BuilderInfo* )builder->priv;
  388. priv->root = priv->current = node;
  389. ftk_xml_parser_set_builder(parser, builder);
  390. ftk_xml_parser_parse(parser, xml, length);
  391. }
  392. ftk_xml_builder_destroy(builder);
  393. ftk_xml_parser_destroy(parser);
  394. return node;
  395. }
  396. Ret fconf_xml_load_buffer(FConf* thiz, const char* name, const char* xml, size_t length)
  397. {
  398. DECL_PRIV(thiz, priv);
  399. XmlNode* node = NULL;
  400. XmlNode* iter = NULL;
  401. node = fconf_xml_parse(name, xml, length);
  402. return_val_if_fail(node != NULL, RET_FAIL);
  403. if(priv->root == NULL)
  404. {
  405. priv->root = node;
  406. }
  407. else
  408. {
  409. for(iter = priv->root; iter->next != NULL; iter = iter->next);
  410. iter->next = node;
  411. node->prev = iter;
  412. }
  413. return RET_OK;
  414. }
  415. Ret fconf_xml_load_file(FConf* thiz, const char* filename)
  416. {
  417. FtkMmap* m = NULL;
  418. char* p = NULL;
  419. char root_node_name[FTK_MAX_PATH + 1] = {0};
  420. return_val_if_fail(thiz != NULL && filename != NULL, RET_FAIL);
  421. p = strrchr(filename, FTK_PATH_DELIM);
  422. if(p != NULL)
  423. {
  424. strncpy(root_node_name, p, FTK_MAX_PATH);
  425. }
  426. else
  427. {
  428. strncpy(root_node_name, filename, FTK_MAX_PATH);
  429. }
  430. if((p = strrchr(root_node_name, '.')) != NULL)
  431. {
  432. *p = '\0';
  433. }
  434. m = ftk_mmap_create(filename, 0, -1);
  435. return_val_if_fail(m != NULL, RET_FAIL);
  436. fconf_xml_load_buffer(thiz, root_node_name, ftk_mmap_data(m), ftk_mmap_length(m));
  437. ftk_mmap_destroy(m);
  438. return RET_OK;
  439. }
  440. Ret fconf_xml_load_dir(FConf* thiz, const char* path)
  441. {
  442. DIR* dir = NULL;
  443. struct dirent* iter = NULL;
  444. char filename[FTK_MAX_PATH+1] = {0};
  445. return_val_if_fail(thiz != NULL && path != NULL, RET_FAIL);
  446. dir = opendir(path);
  447. return_val_if_fail(dir != NULL, RET_FAIL);
  448. while((iter = readdir(dir)) != NULL)
  449. {
  450. if(iter->d_name[0] == '.') continue;
  451. if(strstr(iter->d_name, ".cnf") == NULL) continue;
  452. ftk_snprintf(filename, sizeof(filename)-1, "%s%c%s", path, FTK_PATH_DELIM, iter->d_name);
  453. fconf_xml_load_file(thiz, filename);
  454. }
  455. closedir(dir);
  456. return RET_OK;
  457. }
  458. Ret fconf_xml_load(FConf* thiz, const char* dir)
  459. {
  460. return fconf_xml_load_dir(thiz, dir);
  461. }
  462. static Ret fconf_xml_reg_changed_notify(FConf* thiz, FConfOnChanged on_changed, void* ctx)
  463. {
  464. DECL_PRIV(thiz, priv);
  465. priv->on_changed = on_changed;
  466. priv->on_changed_ctx = ctx;
  467. return RET_OK;
  468. }
  469. static Ret fconf_xml_on_changed(FConf* thiz, FConfChangeType change_type, const char* value)
  470. {
  471. XmlNode* iter = NULL;
  472. DECL_PRIV(thiz, priv);
  473. ftk_path_root(priv->path);
  474. for(iter = priv->root; iter != NULL; iter = iter->next)
  475. {
  476. if(strcmp(iter->name, ftk_path_current(priv->path)) == 0)
  477. {
  478. xml_node_set_modified(iter, 1);
  479. break;
  480. }
  481. }
  482. if(priv->on_changed != NULL)
  483. {
  484. priv->on_changed(priv->on_changed_ctx, 1, change_type, ftk_path_full(priv->path), value);
  485. }
  486. priv->modified = 1;
  487. return RET_OK;
  488. }
  489. Ret fconf_xml_remove(FConf* thiz, const char* path)
  490. {
  491. Ret ret = RET_FAIL;
  492. XmlNode* node = NULL;
  493. DECL_PRIV(thiz, priv);
  494. return_val_if_fail(thiz != NULL && priv->root != NULL && path != NULL, RET_FAIL);
  495. ftk_path_set_path(priv->path, path);
  496. if((node = xml_node_find(priv->root, priv->path)) != NULL)
  497. {
  498. if(priv->root == node)
  499. {
  500. priv->root = node->next;
  501. }
  502. ret = RET_OK;
  503. xml_node_destroy(node);
  504. fconf_xml_on_changed(thiz, FCONF_CHANGED_BY_REMOVE, NULL);
  505. }
  506. return ret;
  507. }
  508. Ret fconf_xml_get(FConf* thiz, const char* path, char** value)
  509. {
  510. XmlNode* node = NULL;
  511. DECL_PRIV(thiz, priv);
  512. return_val_if_fail(thiz != NULL && priv->root != NULL && path != NULL && value != NULL, RET_FAIL);
  513. ftk_path_set_path(priv->path, path);
  514. if((node = xml_node_find(priv->root, priv->path)) != NULL)
  515. {
  516. *value = node->value;
  517. }
  518. else
  519. {
  520. *value = NULL;
  521. }
  522. return *value != NULL ? RET_OK : RET_FAIL;
  523. }
  524. Ret fconf_xml_set(FConf* thiz, const char* path, const char* value)
  525. {
  526. Ret ret = RET_FAIL;
  527. XmlNode* node = NULL;
  528. DECL_PRIV(thiz, priv);
  529. FConfChangeType type = FCONF_CHANGED_BY_SET;
  530. return_val_if_fail(thiz != NULL && path != NULL && value != NULL, RET_FAIL);
  531. ftk_path_set_path(priv->path, path);
  532. if(priv->root == NULL)
  533. {
  534. type = FCONF_CHANGED_BY_ADD;
  535. if(ftk_path_is_leaf(priv->path))
  536. {
  537. priv->root = xml_node_create(ftk_path_current(priv->path), value);
  538. }
  539. else
  540. {
  541. priv->root = xml_node_create(ftk_path_current(priv->path), NULL);
  542. ret = xml_node_add(priv->root, priv->path, value);
  543. }
  544. }
  545. else
  546. {
  547. if((node = xml_node_find(priv->root, priv->path)) != NULL)
  548. {
  549. ret = xml_node_set_value(node, value);
  550. }
  551. else
  552. {
  553. ftk_path_root(priv->path);
  554. type = FCONF_CHANGED_BY_ADD;
  555. ret = xml_node_add(priv->root, priv->path, value);
  556. }
  557. }
  558. if(ret == RET_OK)
  559. {
  560. fconf_xml_on_changed(thiz, type, value);
  561. }
  562. return ret;
  563. }
  564. Ret fconf_xml_get_child_count(FConf* thiz, const char* path, int* nr)
  565. {
  566. Ret ret = RET_FAIL;
  567. XmlNode* node = NULL;
  568. DECL_PRIV(thiz, priv);
  569. return_val_if_fail(thiz != NULL && priv->root != NULL && path != NULL && nr != NULL, RET_FAIL);
  570. *nr = 0;
  571. ftk_path_set_path(priv->path, path);
  572. if((node = xml_node_find(priv->root, priv->path)) != NULL)
  573. {
  574. ret = RET_OK;
  575. *nr = xml_node_get_child_count(node);
  576. }
  577. return ret;
  578. }
  579. Ret fconf_xml_get_child(FConf* thiz, const char* path, int index, char** child)
  580. {
  581. Ret ret = RET_FAIL;
  582. XmlNode* node = NULL;
  583. DECL_PRIV(thiz, priv);
  584. return_val_if_fail(thiz != NULL && priv->root != NULL && path != NULL && child != NULL, RET_FAIL);
  585. *child = NULL;
  586. ftk_path_set_path(priv->path, path);
  587. if((node = xml_node_find(priv->root, priv->path)) != NULL)
  588. {
  589. if((node = xml_node_get_child(node, index)) != NULL)
  590. {
  591. ret = RET_OK;
  592. *child = node->name;
  593. }
  594. }
  595. return ret;
  596. }
  597. static Ret fconf_xml_lock(FConf* thiz)
  598. {
  599. return RET_FAIL;
  600. }
  601. static Ret fconf_xml_unlock(FConf* thiz)
  602. {
  603. return RET_FAIL;
  604. }
  605. void fconf_xml_destroy(FConf* thiz)
  606. {
  607. if(thiz != NULL)
  608. {
  609. DECL_PRIV(thiz, priv);
  610. XmlNode* temp = NULL;
  611. XmlNode* iter = priv->root;
  612. fconf_xml_save(thiz);
  613. while(iter != NULL)
  614. {
  615. temp = iter->next;
  616. xml_node_destroy(iter);
  617. iter = temp;
  618. }
  619. ftk_path_destroy(priv->path);
  620. FTK_FREE(priv->root_path);
  621. FTK_FREE(thiz);
  622. }
  623. return;
  624. }
  625. int fconf_xml_is_dirty(FConf* thiz)
  626. {
  627. DECL_PRIV(thiz, priv);
  628. return_val_if_fail(thiz != NULL, 0);
  629. return priv->modified;
  630. }
  631. FConf* fconf_xml_create(const char* dir)
  632. {
  633. FConf* thiz = NULL;
  634. return_val_if_fail(dir != NULL, NULL);
  635. thiz = FTK_ZALLOC(sizeof(FConf) + sizeof(PrivInfo));
  636. if(thiz != NULL)
  637. {
  638. DECL_PRIV(thiz, priv);
  639. thiz->lock = fconf_xml_lock;
  640. thiz->unlock = fconf_xml_unlock;
  641. thiz->remove = fconf_xml_remove;
  642. thiz->set = fconf_xml_set;
  643. thiz->get = fconf_xml_get;
  644. thiz->get_child_count = fconf_xml_get_child_count;
  645. thiz->get_child = fconf_xml_get_child;
  646. thiz->reg_changed_notify = fconf_xml_reg_changed_notify;
  647. thiz->destroy = fconf_xml_destroy;
  648. priv->path = ftk_path_create(NULL);
  649. if(dir != NULL)
  650. {
  651. priv->root_path = ftk_strdup(dir);
  652. fconf_xml_load(thiz, dir);
  653. }
  654. }
  655. return thiz;
  656. }
  657. #ifdef FCONF_XML_TEST
  658. #include <assert.h>
  659. #include "fconf.c"
  660. #include "ftk_allocator_default.h"
  661. void test_default(void)
  662. {
  663. FConf* thiz = NULL;
  664. thiz = fconf_xml_create("./config");
  665. fconf_test(thiz);
  666. fconf_xml_save(thiz);
  667. fconf_destroy(thiz);
  668. return;
  669. }
  670. const char* testcase = "<a1><b1><c1 value=\"data1\"/> <c2 value=\"data2\"/></b1>\
  671. <b2><c1 value=\"data3\"/> <c2 value=\"data4\"/></b2></a1>";
  672. void test_load(void)
  673. {
  674. FConf* thiz = NULL;
  675. char* data = NULL;
  676. thiz = fconf_xml_create("./config");
  677. fconf_xml_load_buffer(thiz, "test", testcase, strlen(testcase));
  678. assert(fconf_get(thiz, "/test/a1/b1/c1", &data) == RET_OK);
  679. assert(strcmp(data, "data1") == 0);
  680. assert(fconf_get(thiz, "/test/a1/b1/c2", &data) == RET_OK);
  681. assert(strcmp(data, "data2") == 0);
  682. assert(fconf_get(thiz, "/test/a1/b2/c1", &data) == RET_OK);
  683. assert(strcmp(data, "data3") == 0);
  684. assert(fconf_get(thiz, "/test/a1/b2/c2", &data) == RET_OK);
  685. assert(strcmp(data, "data4") == 0);
  686. fconf_destroy(thiz);
  687. return;
  688. }
  689. int main(int argc, char* argv[])
  690. {
  691. #ifndef USE_STD_MALLOC
  692. ftk_set_allocator((ftk_allocator_default_create()));
  693. #endif
  694. test_default();
  695. test_load();
  696. return 0;
  697. }
  698. #endif