load.c 22 KB

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