load.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869
  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. ientry_t ientry = {};
  262. kentry_t *entry = 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. // Mandatory VIEW name
  267. ientry.name = kxml_node_attr(element, "name");
  268. if (!ientry.name) {
  269. faux_error_sprintf(error, TAG": VIEW without name");
  270. return BOOL_FALSE;
  271. }
  272. ientry.help = kxml_node_attr(element, "help");
  273. ientry.container = "true";
  274. ientry.mode = "switch";
  275. ientry.min = "1";
  276. ientry.max = "1";
  277. ientry.ptype = NULL;
  278. ientry.ref = NULL;
  279. ientry.value = NULL;
  280. ientry.restore = "false";
  281. ientry.order = "true";
  282. // Parent must be a KLISH tag
  283. if (parent_tag != KTAG_KLISH) {
  284. faux_error_sprintf(error,
  285. TAG": Tag \"%s\" can't contain VIEW tag",
  286. kxml_tag_name(parent_tag));
  287. goto err;
  288. }
  289. if (!scheme) {
  290. faux_error_sprintf(error,
  291. TAG": Broken parent object for VIEW \"%s\"",
  292. ientry.name);
  293. goto err;
  294. }
  295. // Does VIEW already exist
  296. entry = kscheme_find_entry(scheme, ientry.name);
  297. if (entry) {
  298. if (!ientry_parse(&ientry, entry, error))
  299. goto err;
  300. } else { // New VIEW object
  301. entry = ientry_load(&ientry, error);
  302. if (!entry)
  303. goto err;
  304. if (!kscheme_add_entrys(scheme, entry)) {
  305. faux_error_sprintf(error, TAG": Can't add VIEW \"%s\". "
  306. "Probably duplication",
  307. kentry_name(entry));
  308. kentry_free(entry);
  309. goto err;
  310. }
  311. }
  312. if (!process_children(element, entry, error))
  313. goto err;
  314. res = BOOL_TRUE;
  315. err:
  316. kxml_node_attr_free(ientry.name);
  317. kxml_node_attr_free(ientry.help);
  318. return res;
  319. }
  320. static bool_t process_ptype(const kxml_node_t *element, void *parent,
  321. faux_error_t *error)
  322. {
  323. ientry_t ientry = {};
  324. kentry_t *entry = NULL;
  325. bool_t res = BOOL_FALSE;
  326. ktags_e parent_tag = kxml_node_tag(kxml_node_parent(element));
  327. kscheme_t *scheme = (kscheme_t *)parent;
  328. // Mandatory PTYPE name
  329. ientry.name = kxml_node_attr(element, "name");
  330. if (!ientry.name) {
  331. faux_error_sprintf(error, TAG": PTYPE without name");
  332. return BOOL_FALSE;
  333. }
  334. ientry.help = kxml_node_attr(element, "help");
  335. ientry.container = "true";
  336. ientry.mode = "sequence";
  337. ientry.min = "1";
  338. ientry.max = "1";
  339. ientry.ptype = NULL;
  340. ientry.ref = NULL;
  341. ientry.value = kxml_node_attr(element, "value");
  342. ientry.restore = "false";
  343. ientry.order = "true";
  344. // Parent must be a KLISH tag
  345. if (parent_tag != KTAG_KLISH) {
  346. faux_error_sprintf(error,
  347. TAG": Tag \"%s\" can't contain PTYPE tag",
  348. kxml_tag_name(parent_tag));
  349. goto err;
  350. }
  351. if (!scheme) {
  352. faux_error_sprintf(error,
  353. TAG": Broken parent object for PTYPE \"%s\"",
  354. ientry.name);
  355. goto err;
  356. }
  357. // Create and add object
  358. entry = ientry_load(&ientry, error);
  359. if (!entry)
  360. goto err;
  361. if (!kscheme_add_entrys(scheme, entry)) {
  362. faux_error_sprintf(error, TAG": Can't add PTYPE \"%s\". "
  363. "Probably duplication",
  364. kentry_name(entry));
  365. kentry_free(entry);
  366. goto err;
  367. }
  368. if (!process_children(element, entry, error))
  369. goto err;
  370. res = BOOL_TRUE;
  371. err:
  372. kxml_node_attr_free(ientry.name);
  373. kxml_node_attr_free(ientry.help);
  374. kxml_node_attr_free(ientry.value);
  375. return res;
  376. }
  377. static bool_t process_plugin(const kxml_node_t *element, void *parent,
  378. faux_error_t *error)
  379. {
  380. iplugin_t iplugin = {};
  381. kplugin_t *plugin = NULL;
  382. bool_t res = BOOL_FALSE;
  383. ktags_e parent_tag = kxml_node_tag(kxml_node_parent(element));
  384. if (parent_tag != KTAG_KLISH) {
  385. faux_error_sprintf(error,
  386. TAG": Tag \"%s\" can't contain PLUGIN tag",
  387. kxml_tag_name(parent_tag));
  388. return BOOL_FALSE;
  389. }
  390. iplugin.name = kxml_node_attr(element, "name");
  391. iplugin.id = kxml_node_attr(element, "id");
  392. iplugin.file = kxml_node_attr(element, "file");
  393. iplugin.conf = kxml_node_content(element);
  394. plugin = iplugin_load(&iplugin, error);
  395. if (!plugin)
  396. goto err;
  397. if (!kscheme_add_plugins((kscheme_t *)parent, plugin)) {
  398. faux_error_sprintf(error, TAG": Can't add PLUGIN \"%s\". "
  399. "Probably duplication",
  400. kplugin_name(plugin));
  401. kplugin_free(plugin);
  402. goto err;
  403. }
  404. if (!process_children(element, plugin, error))
  405. goto err;
  406. res = BOOL_TRUE;
  407. err:
  408. kxml_node_attr_free(iplugin.name);
  409. kxml_node_attr_free(iplugin.id);
  410. kxml_node_attr_free(iplugin.file);
  411. kxml_node_content_free(iplugin.conf);
  412. return res;
  413. }
  414. static bool_t process_param(const kxml_node_t *element, void *parent,
  415. faux_error_t *error)
  416. {
  417. ientry_t ientry = {};
  418. kentry_t *entry = NULL;
  419. bool_t res = BOOL_FALSE;
  420. ktags_e parent_tag = kxml_node_tag(kxml_node_parent(element));
  421. kentry_t *parent_entry = (kentry_t *)parent;
  422. kentry_t *entry_add_to = parent_entry;
  423. // Mandatory PARAM name
  424. ientry.name = kxml_node_attr(element, "name");
  425. if (!ientry.name) {
  426. faux_error_sprintf(error, TAG": PARAM without name");
  427. return BOOL_FALSE;
  428. }
  429. ientry.help = kxml_node_attr(element, "help");
  430. ientry.container = kxml_node_attr(element, "container");
  431. ientry.mode = kxml_node_attr(element, "mode");
  432. ientry.min = kxml_node_attr(element, "min");
  433. ientry.max = kxml_node_attr(element, "max");
  434. ientry.ptype = kxml_node_attr(element, "ptype");
  435. ientry.ref = kxml_node_attr(element, "ref");
  436. ientry.value = kxml_node_attr(element, "value");
  437. ientry.restore = "false";
  438. ientry.order = kxml_node_attr(element, "order");
  439. entry = ientry_load(&ientry, error);
  440. if (!entry)
  441. goto err;
  442. if ((KTAG_COMMAND != parent_tag) &&
  443. (KTAG_PARAM != parent_tag) &&
  444. (KTAG_ENTRY != parent_tag)) {
  445. faux_error_sprintf(error,
  446. TAG": Tag \"%s\" can't contain PARAM tag",
  447. kxml_tag_name(parent_tag));
  448. kentry_free(entry);
  449. goto err;
  450. }
  451. // Add newly created entry to special container in 'sequence' mode if
  452. // parent entry can has 'switch' mode.
  453. if (kentry_mode(parent_entry) == KENTRY_MODE_SWITCH) {
  454. const char *seq_entry_name = "__sequence";
  455. kentry_t *seq_entry = kentry_find_entry(parent_entry, seq_entry_name);
  456. if (!seq_entry) {
  457. seq_entry = kentry_new(seq_entry_name);
  458. assert(seq_entry);
  459. kentry_set_container(seq_entry, BOOL_TRUE);
  460. kentry_set_mode(seq_entry, KENTRY_MODE_SEQUENCE);
  461. kentry_add_entrys(parent_entry, seq_entry);
  462. }
  463. entry_add_to = seq_entry;
  464. }
  465. if (!kentry_add_entrys(entry_add_to, entry)) {
  466. faux_error_sprintf(error,
  467. TAG": Can't add PARAM \"%s\" to ENTRY \"%s\". "
  468. "Probably duplication",
  469. kentry_name(entry_add_to), kentry_name(entry_add_to));
  470. kentry_free(entry);
  471. goto err;
  472. }
  473. if (!process_children(element, entry, error))
  474. goto err;
  475. res = BOOL_TRUE;
  476. err:
  477. kxml_node_attr_free(ientry.name);
  478. kxml_node_attr_free(ientry.help);
  479. kxml_node_attr_free(ientry.container);
  480. kxml_node_attr_free(ientry.mode);
  481. kxml_node_attr_free(ientry.min);
  482. kxml_node_attr_free(ientry.max);
  483. kxml_node_attr_free(ientry.ptype);
  484. kxml_node_attr_free(ientry.ref);
  485. kxml_node_attr_free(ientry.value);
  486. kxml_node_attr_free(ientry.order);
  487. return res;
  488. }
  489. static bool_t process_command(const kxml_node_t *element, void *parent,
  490. faux_error_t *error)
  491. {
  492. ientry_t ientry = {};
  493. kentry_t *entry = NULL;
  494. bool_t res = BOOL_FALSE;
  495. ktags_e parent_tag = kxml_node_tag(kxml_node_parent(element));
  496. kentry_t *parent_entry = (kentry_t *)parent;
  497. // Mandatory COMMAND name
  498. ientry.name = kxml_node_attr(element, "name");
  499. if (!ientry.name) {
  500. faux_error_sprintf(error, TAG": COMMAND without name");
  501. return BOOL_FALSE;
  502. }
  503. ientry.help = kxml_node_attr(element, "help");
  504. ientry.container = "false";
  505. ientry.mode = "switch";
  506. ientry.min = "1";
  507. ientry.max = "1";
  508. ientry.ptype = kxml_node_attr(element, "ptype");
  509. ientry.ref = kxml_node_attr(element, "ref");
  510. ientry.value = kxml_node_attr(element, "value");
  511. ientry.restore = kxml_node_attr(element, "restore");
  512. ientry.order = kxml_node_attr(element, "order");
  513. entry = ientry_load(&ientry, error);
  514. if (!entry)
  515. goto err;
  516. if ((KTAG_COMMAND != parent_tag) &&
  517. (KTAG_VIEW != parent_tag) &&
  518. (KTAG_ENTRY != parent_tag)) {
  519. faux_error_sprintf(error,
  520. TAG": Tag \"%s\" can't contain COMMAND tag",
  521. kxml_tag_name(parent_tag));
  522. kentry_free(entry);
  523. goto err;
  524. }
  525. if (!kentry_add_entrys(parent_entry, entry)) {
  526. faux_error_sprintf(error,
  527. TAG": Can't add PARAM \"%s\" to ENTRY \"%s\". "
  528. "Probably duplication",
  529. kentry_name(entry), kentry_name(parent_entry));
  530. kentry_free(entry);
  531. goto err;
  532. }
  533. if (!process_children(element, entry, error))
  534. goto err;
  535. res = BOOL_TRUE;
  536. err:
  537. kxml_node_attr_free(ientry.name);
  538. kxml_node_attr_free(ientry.help);
  539. kxml_node_attr_free(ientry.ptype);
  540. kxml_node_attr_free(ientry.ref);
  541. kxml_node_attr_free(ientry.value);
  542. kxml_node_attr_free(ientry.restore);
  543. kxml_node_attr_free(ientry.order);
  544. return res;
  545. }
  546. static bool_t process_action(const kxml_node_t *element, void *parent,
  547. faux_error_t *error)
  548. {
  549. iaction_t iaction = {};
  550. kaction_t *action = NULL;
  551. bool_t res = BOOL_FALSE;
  552. ktags_e parent_tag = kxml_node_tag(kxml_node_parent(element));
  553. kentry_t *parent_entry = (kentry_t *)parent;
  554. iaction.sym = kxml_node_attr(element, "sym");
  555. iaction.lock = kxml_node_attr(element, "lock");
  556. iaction.interrupt = kxml_node_attr(element, "interrupt");
  557. iaction.interactive = kxml_node_attr(element, "interactive");
  558. iaction.exec_on = kxml_node_attr(element, "exec_on");
  559. iaction.update_retcode = kxml_node_attr(element, "update_retcode");
  560. iaction.script = kxml_node_content(element);
  561. action = iaction_load(&iaction, error);
  562. if (!action)
  563. goto err;
  564. if ((parent_tag != KTAG_ENTRY) &&
  565. (parent_tag != KTAG_COMMAND) &&
  566. (parent_tag != KTAG_PTYPE)) {
  567. faux_error_sprintf(error,
  568. TAG": Tag \"%s\" can't contain ACTION tag",
  569. kxml_tag_name(parent_tag));
  570. kaction_free(action);
  571. goto err;
  572. }
  573. if (!kentry_add_actions(parent_entry, action)) {
  574. faux_error_sprintf(error,
  575. TAG": Can't add ACTION #%d to ENTRY \"%s\". "
  576. "Probably duplication",
  577. kentry_actions_len(parent_entry) + 1,
  578. kentry_name(parent_entry));
  579. kaction_free(action);
  580. goto err;
  581. }
  582. if (!process_children(element, action, error))
  583. goto err;
  584. res = BOOL_TRUE;
  585. err:
  586. kxml_node_attr_free(iaction.sym);
  587. kxml_node_attr_free(iaction.lock);
  588. kxml_node_attr_free(iaction.interrupt);
  589. kxml_node_attr_free(iaction.interactive);
  590. kxml_node_attr_free(iaction.exec_on);
  591. kxml_node_attr_free(iaction.update_retcode);
  592. kxml_node_content_free(iaction.script);
  593. return res;
  594. }
  595. static bool_t process_nspace(const kxml_node_t *element, void *parent,
  596. faux_error_t *error)
  597. {
  598. ientry_t ientry = {};
  599. kentry_t *entry = NULL;
  600. bool_t res = BOOL_FALSE;
  601. ktags_e parent_tag = kxml_node_tag(kxml_node_parent(element));
  602. kentry_t *parent_entry = (kentry_t *)parent;
  603. // Mandatory NSPACE name
  604. ientry.name = kxml_node_attr(element, "name");
  605. if (!ientry.name) {
  606. faux_error_sprintf(error, TAG": NSPACE without name");
  607. return BOOL_FALSE;
  608. }
  609. ientry.help = kxml_node_attr(element, "help");
  610. ientry.container = kxml_node_attr(element, "container");
  611. ientry.mode = kxml_node_attr(element, "mode");;
  612. ientry.min = kxml_node_attr(element, "min");
  613. ientry.max = kxml_node_attr(element, "max");
  614. ientry.ptype = kxml_node_attr(element, "ptype");
  615. ientry.ref = kxml_node_attr(element, "ref");
  616. ientry.value = kxml_node_attr(element, "value");
  617. ientry.restore = kxml_node_attr(element, "restore");
  618. ientry.order = kxml_node_attr(element, "order");
  619. entry = ientry_load(&ientry, error);
  620. if (!entry)
  621. goto err;
  622. if ((KTAG_COMMAND != parent_tag) &&
  623. (KTAG_VIEW != parent_tag) &&
  624. (KTAG_PARAM != parent_tag) &&
  625. (KTAG_ENTRY != parent_tag)) {
  626. faux_error_sprintf(error,
  627. TAG": Tag \"%s\" can't contain NSPACE tag",
  628. kxml_tag_name(parent_tag));
  629. kentry_free(entry);
  630. goto err;
  631. }
  632. if (!kentry_add_entrys(parent_entry, entry)) {
  633. faux_error_sprintf(error,
  634. TAG": Can't add NSPACE \"%s\" to ENTRY \"%s\". "
  635. "Probably duplication",
  636. kentry_name(entry), kentry_name(parent_entry));
  637. kentry_free(entry);
  638. goto err;
  639. }
  640. if (!process_children(element, entry, error))
  641. goto err;
  642. res = BOOL_TRUE;
  643. err:
  644. kxml_node_attr_free(ientry.name);
  645. kxml_node_attr_free(ientry.help);
  646. kxml_node_attr_free(ientry.container);
  647. kxml_node_attr_free(ientry.mode);
  648. kxml_node_attr_free(ientry.min);
  649. kxml_node_attr_free(ientry.max);
  650. kxml_node_attr_free(ientry.ptype);
  651. kxml_node_attr_free(ientry.ref);
  652. kxml_node_attr_free(ientry.value);
  653. kxml_node_attr_free(ientry.restore);
  654. kxml_node_attr_free(ientry.order);
  655. return res;
  656. }
  657. static bool_t process_entry(const kxml_node_t *element, void *parent,
  658. faux_error_t *error)
  659. {
  660. ientry_t ientry = {};
  661. kentry_t *entry = NULL;
  662. bool_t res = BOOL_FALSE;
  663. ktags_e parent_tag = kxml_node_tag(kxml_node_parent(element));
  664. kentry_t *parent_entry = (kentry_t *)parent;
  665. // Mandatory entry name
  666. ientry.name = kxml_node_attr(element, "name");
  667. if (!ientry.name) {
  668. faux_error_sprintf(error, TAG": entry without name");
  669. return BOOL_FALSE;
  670. }
  671. ientry.help = kxml_node_attr(element, "help");
  672. ientry.container = kxml_node_attr(element, "container");
  673. ientry.mode = kxml_node_attr(element, "mode");
  674. ientry.min = kxml_node_attr(element, "min");
  675. ientry.max = kxml_node_attr(element, "max");
  676. ientry.ptype = kxml_node_attr(element, "ptype");
  677. ientry.ref = kxml_node_attr(element, "ref");
  678. ientry.value = kxml_node_attr(element, "value");
  679. ientry.restore = kxml_node_attr(element, "restore");
  680. ientry.order = kxml_node_attr(element, "order");
  681. // Parent must be a KLISH or ENTRY tag
  682. if ((parent_tag != KTAG_KLISH) && (parent_tag != KTAG_ENTRY)) {
  683. faux_error_sprintf(error,
  684. TAG": Tag \"%s\" can't contain ENTRY tag",
  685. kxml_tag_name(parent_tag));
  686. goto err;
  687. }
  688. if (!parent_entry) {
  689. faux_error_sprintf(error,
  690. TAG": Broken parent object for ENTRY \"%s\"",
  691. ientry.name);
  692. goto err;
  693. }
  694. if (KTAG_KLISH == parent_tag) { // High level ENTRY
  695. // Does such ENTRY already exist
  696. entry = kscheme_find_entry((kscheme_t *)parent, ientry.name);
  697. if (entry) {
  698. if (!ientry_parse(&ientry, entry, error))
  699. goto err;
  700. } else { // New entry object
  701. entry = ientry_load(&ientry, error);
  702. if (!entry)
  703. goto err;
  704. if (!kscheme_add_entrys((kscheme_t *)parent, entry)) {
  705. faux_error_sprintf(error, TAG": Can't add entry \"%s\". "
  706. "Probably duplication",
  707. kentry_name(entry));
  708. kentry_free(entry);
  709. goto err;
  710. }
  711. }
  712. } else { // ENTRY within ENTRY
  713. // Does such ENTRY already exist
  714. entry = kentry_find_entry(parent_entry, ientry.name);
  715. if (entry) {
  716. if (!ientry_parse(&ientry, entry, error))
  717. goto err;
  718. } else { // New entry object
  719. entry = ientry_load(&ientry, error);
  720. if (!entry)
  721. goto err;
  722. kentry_set_parent(entry, parent_entry);
  723. if (!kentry_add_entrys(parent_entry, entry)) {
  724. faux_error_sprintf(error, TAG": Can't add entry \"%s\". "
  725. "Probably duplication",
  726. kentry_name(entry));
  727. kentry_free(entry);
  728. goto err;
  729. }
  730. }
  731. }
  732. if (!process_children(element, entry, error))
  733. goto err;
  734. res = BOOL_TRUE;
  735. err:
  736. kxml_node_attr_free(ientry.name);
  737. kxml_node_attr_free(ientry.help);
  738. kxml_node_attr_free(ientry.container);
  739. kxml_node_attr_free(ientry.mode);
  740. kxml_node_attr_free(ientry.min);
  741. kxml_node_attr_free(ientry.max);
  742. kxml_node_attr_free(ientry.ptype);
  743. kxml_node_attr_free(ientry.ref);
  744. kxml_node_attr_free(ientry.value);
  745. kxml_node_attr_free(ientry.restore);
  746. kxml_node_attr_free(ientry.order);
  747. return res;
  748. }