load.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804
  1. /** @file load.c
  2. * @brief Common part for XML parsing.
  3. *
  4. * Different XML parsing engines can provide a functions in a form of
  5. * standardized API. This code uses this API and parses XML to kscheme.
  6. */
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <assert.h>
  10. #include <errno.h>
  11. #include <sys/types.h>
  12. #include <dirent.h>
  13. #include <faux/faux.h>
  14. #include <faux/str.h>
  15. #include <faux/error.h>
  16. #include <klish/kscheme.h>
  17. #include <klish/ischeme.h>
  18. #include <klish/kxml.h>
  19. #define TAG "XML"
  20. #ifdef DEBUG
  21. #define KXML_DEBUG DEBUG
  22. #endif
  23. typedef bool_t (kxml_process_fn)(const kxml_node_t *element,
  24. void *parent, faux_error_t *error);
  25. static kxml_process_fn
  26. process_action,
  27. process_param,
  28. process_command,
  29. process_view,
  30. process_ptype,
  31. process_plugin,
  32. process_nspace,
  33. process_klish,
  34. process_entry;
  35. // Different TAGs types
  36. typedef enum {
  37. KTAG_NONE,
  38. KTAG_ACTION,
  39. KTAG_PARAM,
  40. KTAG_SWITCH, // PARAM alias
  41. KTAG_SUBCOMMAND, // PARAM alias
  42. KTAG_MULTI, // PARAM alias
  43. KTAG_COMMAND,
  44. KTAG_VIEW,
  45. KTAG_PTYPE,
  46. KTAG_PLUGIN,
  47. KTAG_NSPACE,
  48. KTAG_KLISH,
  49. KTAG_ENTRY,
  50. KTAG_MAX,
  51. } ktags_e;
  52. static const char * const kxml_tags[] = {
  53. NULL,
  54. "ACTION",
  55. "PARAM",
  56. "SWITCH",
  57. "SUBCOMMAND",
  58. "MULTI",
  59. "COMMAND",
  60. "VIEW",
  61. "PTYPE",
  62. "PLUGIN",
  63. "NSPACE",
  64. "KLISH",
  65. "ENTRY",
  66. };
  67. static kxml_process_fn *kxml_handlers[] = {
  68. NULL,
  69. process_action,
  70. process_param,
  71. process_param,
  72. process_param,
  73. process_param,
  74. process_command,
  75. process_view,
  76. process_ptype,
  77. process_plugin,
  78. process_nspace,
  79. process_klish,
  80. process_entry,
  81. };
  82. static const char *kxml_tag_name(ktags_e tag)
  83. {
  84. if ((KTAG_NONE == tag) || (tag >= KTAG_MAX))
  85. return "NONE";
  86. return kxml_tags[tag];
  87. }
  88. static ktags_e kxml_node_tag(const kxml_node_t *node)
  89. {
  90. ktags_e tag = KTAG_NONE;
  91. char *name = NULL;
  92. if (!node)
  93. return KTAG_NONE;
  94. if (kxml_node_type(node) != KXML_NODE_ELM)
  95. return KTAG_NONE;
  96. name = kxml_node_name(node);
  97. if (!name)
  98. return KTAG_NONE; // Strange case
  99. for (tag = (KTAG_NONE + 1); tag < KTAG_MAX; tag++) {
  100. if (faux_str_casecmp(name, kxml_tags[tag]) == 0)
  101. break;
  102. }
  103. kxml_node_name_free(name);
  104. if (tag >= KTAG_MAX)
  105. return KTAG_NONE;
  106. return tag;
  107. }
  108. static kxml_process_fn *kxml_node_handler(const kxml_node_t *node)
  109. {
  110. return kxml_handlers[kxml_node_tag(node)];
  111. }
  112. /** @brief Reads an element from the XML stream and processes it.
  113. */
  114. static bool_t process_node(const kxml_node_t *node, void *parent, faux_error_t *error)
  115. {
  116. kxml_process_fn *handler = NULL;
  117. // Process only KXML_NODE_ELM. Don't process other types like:
  118. // KXML_NODE_DOC,
  119. // KXML_NODE_TEXT,
  120. // KXML_NODE_ATTR,
  121. // KXML_NODE_COMMENT,
  122. // KXML_NODE_PI,
  123. // KXML_NODE_DECL,
  124. // KXML_NODE_UNKNOWN,
  125. if (kxml_node_type(node) != KXML_NODE_ELM)
  126. return BOOL_TRUE;
  127. handler = kxml_node_handler(node);
  128. if (!handler) { // Unknown element
  129. faux_error_sprintf(error,
  130. TAG": Unknown tag \"%s\"", kxml_node_name(node));
  131. return BOOL_FALSE;
  132. }
  133. #ifdef KXML_DEBUG
  134. printf("kxml: Tag \"%s\"\n", kxml_node_name(node));
  135. #endif
  136. return handler(node, parent, error);
  137. }
  138. static bool_t kxml_load_file(kscheme_t *scheme, const char *filename,
  139. faux_error_t *error)
  140. {
  141. kxml_doc_t *doc = NULL;
  142. kxml_node_t *root = NULL;
  143. bool_t r = BOOL_FALSE;
  144. if (!scheme)
  145. return BOOL_FALSE;
  146. if (!filename)
  147. return BOOL_FALSE;
  148. #ifdef KXML_DEBUG
  149. printf("kxml: Processing XML file \"%s\"\n", filename);
  150. #endif
  151. doc = kxml_doc_read(filename);
  152. if (!kxml_doc_is_valid(doc)) {
  153. /* int errcaps = kxml_doc_error_caps(doc);
  154. printf("Unable to open file '%s'", filename);
  155. if ((errcaps & kxml_ERR_LINE) == kxml_ERR_LINE)
  156. printf(", at line %d", kxml_doc_err_line(doc));
  157. if ((errcaps & kxml_ERR_COL) == kxml_ERR_COL)
  158. printf(", at column %d", kxml_doc_err_col(doc));
  159. if ((errcaps & kxml_ERR_DESC) == kxml_ERR_DESC)
  160. printf(", message is %s", kxml_doc_err_msg(doc));
  161. printf("\n");
  162. */ kxml_doc_release(doc);
  163. return BOOL_FALSE;
  164. }
  165. root = kxml_doc_root(doc);
  166. r = process_node(root, scheme, error);
  167. kxml_doc_release(doc);
  168. if (!r) {
  169. faux_error_sprintf(error, TAG": Illegal file %s", filename);
  170. return BOOL_FALSE;
  171. }
  172. return BOOL_TRUE;
  173. }
  174. /** @brief Default path to get XML files from.
  175. */
  176. static const char *default_path = "/etc/klish;~/.klish";
  177. static const char *path_separators = ":;";
  178. bool_t kxml_load_scheme(kscheme_t *scheme, const char *xml_path,
  179. faux_error_t *error)
  180. {
  181. char *path = NULL;
  182. char *fn = NULL;
  183. char *saveptr = NULL;
  184. bool_t ret = BOOL_TRUE;
  185. assert(scheme);
  186. if (!scheme)
  187. return BOOL_FALSE;
  188. // Use the default path if xml path is not specified.
  189. // Dup is needed because sring will be tokenized but
  190. // the xml_path is must be const.
  191. if (!xml_path)
  192. path = faux_str_dup(default_path);
  193. else
  194. path = faux_str_dup(xml_path);
  195. #ifdef KXML_DEBUG
  196. printf("kxml: Loading scheme \"%s\"\n", path);
  197. #endif
  198. // Loop through each directory
  199. for (fn = strtok_r(path, path_separators, &saveptr);
  200. fn; fn = strtok_r(NULL, path_separators, &saveptr)) {
  201. DIR *dir = NULL;
  202. struct dirent *entry = NULL;
  203. char *realpath = NULL;
  204. // Expand tilde. Tilde must be the first symbol.
  205. realpath = faux_expand_tilde(fn);
  206. // Regular file
  207. if (faux_isfile(realpath)) {
  208. if (!kxml_load_file(scheme, realpath, error))
  209. ret = BOOL_FALSE;
  210. faux_str_free(realpath);
  211. continue;
  212. }
  213. // Search this directory for any XML files
  214. #ifdef KXML_DEBUG
  215. printf("kxml: Processing XML dir \"%s\"\n", realpath);
  216. #endif
  217. dir = opendir(realpath);
  218. if (!dir) {
  219. faux_str_free(realpath);
  220. continue;
  221. }
  222. for (entry = readdir(dir); entry; entry = readdir(dir)) {
  223. const char *extension = strrchr(entry->d_name, '.');
  224. char *filename = NULL;
  225. // Check the filename
  226. if (!extension || strcmp(".xml", extension))
  227. continue;
  228. filename = faux_str_sprintf("%s/%s", realpath, entry->d_name);
  229. if (!kxml_load_file(scheme, filename, error))
  230. ret = BOOL_FALSE;
  231. faux_str_free(filename);
  232. }
  233. closedir(dir);
  234. faux_str_free(realpath);
  235. }
  236. faux_str_free(path);
  237. return ret;
  238. }
  239. /** @brief Iterate through element's children.
  240. */
  241. static bool_t process_children(const kxml_node_t *element, void *parent,
  242. faux_error_t *error)
  243. {
  244. const kxml_node_t *node = NULL;
  245. while ((node = kxml_node_next_child(element, node)) != NULL) {
  246. bool_t res = BOOL_FALSE;
  247. res = process_node(node, parent, error);
  248. if (!res)
  249. return res;
  250. }
  251. return BOOL_TRUE;
  252. }
  253. static bool_t process_klish(const kxml_node_t *element, void *parent,
  254. faux_error_t *error)
  255. {
  256. return process_children(element, parent, error);
  257. }
  258. static bool_t process_view(const kxml_node_t *element, void *parent,
  259. faux_error_t *error)
  260. {
  261. iview_t iview = {};
  262. kview_t *view = NULL;
  263. bool_t res = BOOL_FALSE;
  264. ktags_e parent_tag = kxml_node_tag(kxml_node_parent(element));
  265. kscheme_t *scheme = (kscheme_t *)parent;
  266. // Parent must be a KLISH tag
  267. if (parent_tag != KTAG_KLISH) {
  268. faux_error_sprintf(error,
  269. TAG": Tag \"%s\" can't contain VIEW tag",
  270. kxml_tag_name(parent_tag));
  271. return BOOL_FALSE;
  272. }
  273. if (!scheme) {
  274. faux_error_sprintf(error,
  275. TAG": Broken parent object for VIEW \"%s\"",
  276. iview.name);
  277. return BOOL_FALSE;
  278. }
  279. // Mandatory VIEW name
  280. iview.name = kxml_node_attr(element, "name");
  281. if (!iview.name) {
  282. faux_error_sprintf(error, TAG": VIEW without name");
  283. return BOOL_FALSE;
  284. }
  285. // Does VIEW already exist
  286. view = kscheme_find_view(scheme, iview.name);
  287. if (view) {
  288. if (!iview_parse(&iview, view, error))
  289. goto err;
  290. } else { // New VIEW object
  291. view = iview_load(&iview, error);
  292. if (!view)
  293. goto err;
  294. if (!kscheme_add_views(scheme, view)) {
  295. faux_error_sprintf(error, TAG": Can't add VIEW \"%s\". "
  296. "Probably duplication",
  297. kview_name(view));
  298. kview_free(view);
  299. goto err;
  300. }
  301. }
  302. if (!process_children(element, view, error))
  303. goto err;
  304. res = BOOL_TRUE;
  305. err:
  306. kxml_node_attr_free(iview.name);
  307. return res;
  308. }
  309. static bool_t process_ptype(const kxml_node_t *element, void *parent,
  310. faux_error_t *error)
  311. {
  312. iptype_t iptype = {};
  313. kptype_t *ptype = NULL;
  314. bool_t res = BOOL_FALSE;
  315. ktags_e parent_tag = kxml_node_tag(kxml_node_parent(element));
  316. if (parent_tag != KTAG_KLISH) {
  317. faux_error_sprintf(error,
  318. TAG": Tag \"%s\" can't contain PTYPE tag",
  319. kxml_tag_name(parent_tag));
  320. return BOOL_FALSE;
  321. }
  322. iptype.name = kxml_node_attr(element, "name");
  323. iptype.help = kxml_node_attr(element, "help");
  324. ptype = iptype_load(&iptype, error);
  325. if (!ptype)
  326. goto err;
  327. if (!kscheme_add_ptypes((kscheme_t *)parent, ptype)) {
  328. faux_error_sprintf(error, TAG": Can't add PTYPE \"%s\". "
  329. "Probably duplication",
  330. kptype_name(ptype));
  331. kptype_free(ptype);
  332. goto err;
  333. }
  334. if (!process_children(element, ptype, error))
  335. goto err;
  336. res = BOOL_TRUE;
  337. err:
  338. kxml_node_attr_free(iptype.name);
  339. kxml_node_attr_free(iptype.help);
  340. return res;
  341. }
  342. static bool_t process_plugin(const kxml_node_t *element, void *parent,
  343. faux_error_t *error)
  344. {
  345. iplugin_t iplugin = {};
  346. kplugin_t *plugin = NULL;
  347. bool_t res = BOOL_FALSE;
  348. ktags_e parent_tag = kxml_node_tag(kxml_node_parent(element));
  349. if (parent_tag != KTAG_KLISH) {
  350. faux_error_sprintf(error,
  351. TAG": Tag \"%s\" can't contain PLUGIN tag",
  352. kxml_tag_name(parent_tag));
  353. return BOOL_FALSE;
  354. }
  355. iplugin.name = kxml_node_attr(element, "name");
  356. iplugin.id = kxml_node_attr(element, "id");
  357. iplugin.file = kxml_node_attr(element, "file");
  358. iplugin.conf = kxml_node_content(element);
  359. plugin = iplugin_load(&iplugin, error);
  360. if (!plugin)
  361. goto err;
  362. if (!kscheme_add_plugins((kscheme_t *)parent, plugin)) {
  363. faux_error_sprintf(error, TAG": Can't add PLUGIN \"%s\". "
  364. "Probably duplication",
  365. kplugin_name(plugin));
  366. kplugin_free(plugin);
  367. goto err;
  368. }
  369. if (!process_children(element, plugin, error))
  370. goto err;
  371. res = BOOL_TRUE;
  372. err:
  373. kxml_node_attr_free(iplugin.name);
  374. kxml_node_attr_free(iplugin.id);
  375. kxml_node_attr_free(iplugin.file);
  376. kxml_node_content_free(iplugin.conf);
  377. return res;
  378. }
  379. static bool_t process_param(const kxml_node_t *element, void *parent,
  380. faux_error_t *error)
  381. {
  382. iparam_t iparam = {};
  383. kparam_t *param = NULL;
  384. bool_t res = BOOL_FALSE;
  385. ktags_e parent_tag = kxml_node_tag(kxml_node_parent(element));
  386. ktags_e tag = kxml_node_tag(element);
  387. char *mode = NULL;
  388. iparam.name = kxml_node_attr(element, "name");
  389. iparam.help = kxml_node_attr(element, "help");
  390. iparam.ptype = kxml_node_attr(element, "ptype");
  391. // Special case for mode
  392. mode = kxml_node_attr(element, "mode");
  393. if (!faux_str_is_empty(mode)) {
  394. iparam.mode = mode;
  395. } else {
  396. switch (tag) {
  397. case KTAG_SWITCH:
  398. iparam.mode = "switch";
  399. break;
  400. case KTAG_SUBCOMMAND:
  401. iparam.mode = "subcommand";
  402. break;
  403. case KTAG_MULTI:
  404. iparam.mode = "multi";
  405. break;
  406. default:
  407. break;
  408. }
  409. }
  410. param = iparam_load(&iparam, error);
  411. if (!param)
  412. goto err;
  413. if (KTAG_COMMAND == parent_tag) {
  414. kcommand_t *command = (kcommand_t *)parent;
  415. if (!kcommand_add_params(command, param)) {
  416. faux_error_sprintf(error,
  417. TAG": Can't add PARAM \"%s\" to COMMAND \"%s\". "
  418. "Probably duplication",
  419. kparam_name(param), kcommand_name(command));
  420. kparam_free(param);
  421. goto err;
  422. }
  423. } else if (
  424. (KTAG_PARAM == parent_tag) ||
  425. (KTAG_SWITCH == parent_tag) ||
  426. (KTAG_SUBCOMMAND == parent_tag) ||
  427. (KTAG_MULTI == parent_tag)
  428. ) {
  429. kparam_t *parent_param = (kparam_t *)parent;
  430. if (!kparam_add_params(parent_param, param)) {
  431. faux_error_sprintf(error,
  432. TAG": Can't add PARAM \"%s\" to PARAM \"%s\". "
  433. "Probably duplication",
  434. kparam_name(param), kparam_name(parent_param));
  435. kparam_free(param);
  436. goto err;
  437. }
  438. } else {
  439. faux_error_sprintf(error,
  440. TAG": Tag \"%s\" can't contain PARAM tag",
  441. kxml_tag_name(parent_tag));
  442. kparam_free(param);
  443. goto err;
  444. }
  445. if (!process_children(element, param, error))
  446. goto err;
  447. res = BOOL_TRUE;
  448. err:
  449. kxml_node_attr_free(iparam.name);
  450. kxml_node_attr_free(iparam.help);
  451. kxml_node_attr_free(iparam.ptype);
  452. kxml_node_attr_free(mode);
  453. return res;
  454. }
  455. static bool_t process_command(const kxml_node_t *element, void *parent,
  456. faux_error_t *error)
  457. {
  458. icommand_t icommand = {};
  459. kcommand_t *command = NULL;
  460. bool_t res = BOOL_FALSE;
  461. ktags_e parent_tag = kxml_node_tag(kxml_node_parent(element));
  462. if (parent_tag != KTAG_VIEW) {
  463. faux_error_sprintf(error,
  464. TAG": Tag \"%s\" can't contain COMMAND tag",
  465. kxml_tag_name(parent_tag));
  466. return BOOL_FALSE;
  467. }
  468. icommand.name = kxml_node_attr(element, "name");
  469. icommand.help = kxml_node_attr(element, "help");
  470. command = icommand_load(&icommand, error);
  471. if (!command)
  472. goto err;
  473. if (!kview_add_commands((kview_t *)parent, command)) {
  474. faux_error_sprintf(error, TAG": Can't add COMMAND \"%s\". "
  475. "Probably duplication",
  476. kcommand_name(command));
  477. kcommand_free(command);
  478. goto err;
  479. }
  480. if (!process_children(element, command, error))
  481. goto err;
  482. res = BOOL_TRUE;
  483. err:
  484. kxml_node_attr_free(icommand.name);
  485. kxml_node_attr_free(icommand.help);
  486. return res;
  487. }
  488. static bool_t process_action(const kxml_node_t *element, void *parent,
  489. faux_error_t *error)
  490. {
  491. iaction_t iaction = {};
  492. kaction_t *action = NULL;
  493. bool_t res = BOOL_FALSE;
  494. ktags_e parent_tag = kxml_node_tag(kxml_node_parent(element));
  495. iaction.sym = kxml_node_attr(element, "sym");
  496. iaction.lock = kxml_node_attr(element, "lock");
  497. iaction.interrupt = kxml_node_attr(element, "interrupt");
  498. iaction.interactive = kxml_node_attr(element, "interactive");
  499. iaction.exec_on = kxml_node_attr(element, "exec_on");
  500. iaction.update_retcode = kxml_node_attr(element, "update_retcode");
  501. iaction.script = kxml_node_content(element);
  502. action = iaction_load(&iaction, error);
  503. if (!action)
  504. goto err;
  505. if (KTAG_COMMAND == parent_tag) {
  506. kcommand_t *command = (kcommand_t *)parent;
  507. if (!kcommand_add_actions(command, action)) {
  508. faux_error_sprintf(error,
  509. TAG": Can't add ACTION #%d to COMMAND \"%s\". "
  510. "Probably duplication",
  511. kcommand_actions_len(command) + 1,
  512. kcommand_name(command));
  513. kaction_free(action);
  514. goto err;
  515. }
  516. } else if (KTAG_PTYPE == parent_tag) {
  517. kptype_t *ptype = (kptype_t *)parent;
  518. if (!kptype_add_actions(ptype, action)) {
  519. faux_error_sprintf(error,
  520. TAG": Can't add ACTION #%d to PTYPE \"%s\". "
  521. "Probably duplication",
  522. kptype_actions_len(ptype) + 1,
  523. kptype_name(ptype));
  524. kaction_free(action);
  525. goto err;
  526. }
  527. } else if (KTAG_ENTRY == parent_tag) {
  528. kentry_t *entry = (kentry_t *)parent;
  529. if (!kentry_add_actions(entry, action)) {
  530. faux_error_sprintf(error,
  531. TAG": Can't add ACTION #%d to ENTRY \"%s\". "
  532. "Probably duplication",
  533. kentry_actions_len(entry) + 1,
  534. kentry_name(entry));
  535. kaction_free(action);
  536. goto err;
  537. }
  538. } else {
  539. faux_error_sprintf(error,
  540. TAG": Tag \"%s\" can't contain ACTION tag",
  541. kxml_tag_name(parent_tag));
  542. kaction_free(action);
  543. goto err;
  544. }
  545. if (!process_children(element, action, error))
  546. goto err;
  547. res = BOOL_TRUE;
  548. err:
  549. kxml_node_attr_free(iaction.sym);
  550. kxml_node_attr_free(iaction.lock);
  551. kxml_node_attr_free(iaction.interrupt);
  552. kxml_node_attr_free(iaction.interactive);
  553. kxml_node_attr_free(iaction.exec_on);
  554. kxml_node_attr_free(iaction.update_retcode);
  555. kxml_node_content_free(iaction.script);
  556. return res;
  557. }
  558. static bool_t process_nspace(const kxml_node_t *element, void *parent,
  559. faux_error_t *error)
  560. {
  561. inspace_t inspace = {};
  562. knspace_t *nspace = NULL;
  563. bool_t res = BOOL_FALSE;
  564. ktags_e parent_tag = kxml_node_tag(kxml_node_parent(element));
  565. if (parent_tag != KTAG_VIEW) {
  566. faux_error_sprintf(error,
  567. TAG": Tag \"%s\" can't contain NSPACE tag",
  568. kxml_tag_name(parent_tag));
  569. return BOOL_FALSE;
  570. }
  571. inspace.ref = kxml_node_attr(element, "ref");
  572. inspace.prefix = kxml_node_attr(element, "prefix");
  573. nspace = inspace_load(&inspace, error);
  574. if (!nspace)
  575. goto err;
  576. if (!kview_add_nspaces((kview_t *)parent, nspace)) {
  577. faux_error_sprintf(error, TAG": Can't add NSPACE \"%s\". ",
  578. knspace_view_ref(nspace));
  579. knspace_free(nspace);
  580. goto err;
  581. }
  582. if (!process_children(element, nspace, error))
  583. goto err;
  584. res = BOOL_TRUE;
  585. err:
  586. kxml_node_attr_free(inspace.ref);
  587. kxml_node_attr_free(inspace.prefix);
  588. return res;
  589. }
  590. static bool_t process_entry(const kxml_node_t *element, void *parent,
  591. faux_error_t *error)
  592. {
  593. ientry_t ientry = {};
  594. kentry_t *entry = NULL;
  595. bool_t res = BOOL_FALSE;
  596. ktags_e parent_tag = kxml_node_tag(kxml_node_parent(element));
  597. kentry_t *parent_entry = (kentry_t *)parent;
  598. // Mandatory entry name
  599. ientry.name = kxml_node_attr(element, "name");
  600. if (!ientry.name) {
  601. faux_error_sprintf(error, TAG": entry without name");
  602. return BOOL_FALSE;
  603. }
  604. ientry.help = kxml_node_attr(element, "help");
  605. ientry.container = kxml_node_attr(element, "container");
  606. ientry.mode = kxml_node_attr(element, "mode");
  607. ientry.min = kxml_node_attr(element, "min");
  608. ientry.max = kxml_node_attr(element, "max");
  609. ientry.ptype = kxml_node_attr(element, "ptype");
  610. ientry.ref = kxml_node_attr(element, "ref");
  611. ientry.value = kxml_node_attr(element, "value");
  612. ientry.restore = kxml_node_attr(element, "restore");
  613. ientry.order = kxml_node_attr(element, "order");
  614. // Parent must be a KLISH or ENTRY tag
  615. if ((parent_tag != KTAG_KLISH) && (parent_tag != KTAG_ENTRY)) {
  616. faux_error_sprintf(error,
  617. TAG": Tag \"%s\" can't contain ENTRY tag",
  618. kxml_tag_name(parent_tag));
  619. goto err;
  620. }
  621. if (!parent_entry) {
  622. faux_error_sprintf(error,
  623. TAG": Broken parent object for ENTRY \"%s\"",
  624. ientry.name);
  625. goto err;
  626. }
  627. if (KTAG_KLISH == parent_tag) { // High level ENTRY
  628. // Does such ENTRY already exist
  629. entry = kscheme_find_entry((kscheme_t *)parent, ientry.name);
  630. if (entry) {
  631. if (!ientry_parse(&ientry, entry, error))
  632. goto err;
  633. } else { // New entry object
  634. entry = ientry_load(&ientry, error);
  635. if (!entry)
  636. goto err;
  637. if (!kscheme_add_entrys((kscheme_t *)parent, entry)) {
  638. faux_error_sprintf(error, TAG": Can't add entry \"%s\". "
  639. "Probably duplication",
  640. kentry_name(entry));
  641. kentry_free(entry);
  642. goto err;
  643. }
  644. }
  645. } else { // ENTRY within ENTRY
  646. // Does such ENTRY already exist
  647. entry = kentry_find_entry(parent_entry, ientry.name);
  648. if (entry) {
  649. if (!ientry_parse(&ientry, entry, error))
  650. goto err;
  651. } else { // New entry object
  652. entry = ientry_load(&ientry, error);
  653. if (!entry)
  654. goto err;
  655. kentry_set_parent(entry, parent_entry);
  656. if (!kentry_add_entrys(parent_entry, entry)) {
  657. faux_error_sprintf(error, TAG": Can't add entry \"%s\". "
  658. "Probably duplication",
  659. kentry_name(entry));
  660. kentry_free(entry);
  661. goto err;
  662. }
  663. }
  664. }
  665. if (!process_children(element, entry, error))
  666. goto err;
  667. res = BOOL_TRUE;
  668. err:
  669. kxml_node_attr_free(ientry.name);
  670. kxml_node_attr_free(ientry.help);
  671. kxml_node_attr_free(ientry.container);
  672. kxml_node_attr_free(ientry.mode);
  673. kxml_node_attr_free(ientry.min);
  674. kxml_node_attr_free(ientry.max);
  675. kxml_node_attr_free(ientry.ptype);
  676. kxml_node_attr_free(ientry.ref);
  677. kxml_node_attr_free(ientry.value);
  678. kxml_node_attr_free(ientry.restore);
  679. kxml_node_attr_free(ientry.order);
  680. return res;
  681. }