shell_xml.c 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009
  1. /*
  2. * ------------------------------------------------------
  3. * shell_xml.c
  4. *
  5. * This file implements the means to read an XML encoded file and populate the
  6. * CLI tree based on the contents.
  7. * ------------------------------------------------------
  8. */
  9. #include "private.h"
  10. #include "xmlapi.h"
  11. #include "lub/string.h"
  12. #include "lub/ctype.h"
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include <assert.h>
  16. #include <errno.h>
  17. typedef void (PROCESS_FN) (clish_shell_t * instance,
  18. clish_xmlnode_t * element, void *parent);
  19. /* Define a control block for handling the decode of an XML file */
  20. typedef struct clish_xml_cb_s clish_xml_cb_t;
  21. struct clish_xml_cb_s {
  22. const char *element;
  23. PROCESS_FN *handler;
  24. };
  25. /* forward declare the handler functions */
  26. static PROCESS_FN
  27. process_clish_module,
  28. process_startup,
  29. process_view,
  30. process_command,
  31. process_param,
  32. process_action,
  33. process_ptype,
  34. process_overview,
  35. process_detail,
  36. process_namespace,
  37. process_config,
  38. process_var,
  39. process_wdog;
  40. static clish_xml_cb_t xml_elements[] = {
  41. {"CLISH_MODULE", process_clish_module},
  42. {"STARTUP", process_startup},
  43. {"VIEW", process_view},
  44. {"COMMAND", process_command},
  45. {"PARAM", process_param},
  46. {"ACTION", process_action},
  47. {"PTYPE", process_ptype},
  48. {"OVERVIEW", process_overview},
  49. {"DETAIL", process_detail},
  50. {"NAMESPACE", process_namespace},
  51. {"CONFIG", process_config},
  52. {"VAR", process_var},
  53. {"WATCHDOG", process_wdog},
  54. {NULL, NULL}
  55. };
  56. /*
  57. * ------------------------------------------------------
  58. * This function reads an element from the XML stream and processes it.
  59. * ------------------------------------------------------
  60. */
  61. static void process_node(clish_shell_t * shell, clish_xmlnode_t * node, void *parent)
  62. {
  63. switch (clish_xmlnode_get_type(node)) {
  64. case CLISH_XMLNODE_ELM: {
  65. clish_xml_cb_t * cb;
  66. char name[128];
  67. unsigned int namelen = sizeof(name);
  68. if (clish_xmlnode_get_name(node, name, &namelen) == 0) {
  69. for (cb = &xml_elements[0]; cb->element; cb++) {
  70. if (0 == strcmp(name, cb->element)) {
  71. #ifdef DEBUG
  72. fprintf(stderr, "NODE:");
  73. clish_xmlnode_print(node, stderr);
  74. fprintf(stderr, "\n");
  75. #endif
  76. /* process the elements at this level */
  77. cb->handler(shell, node, parent);
  78. break;
  79. }
  80. }
  81. }
  82. break;
  83. }
  84. case CLISH_XMLNODE_DOC:
  85. case CLISH_XMLNODE_TEXT:
  86. case CLISH_XMLNODE_ATTR:
  87. case CLISH_XMLNODE_PI:
  88. case CLISH_XMLNODE_COMMENT:
  89. case CLISH_XMLNODE_DECL:
  90. case CLISH_XMLNODE_UNKNOWN:
  91. default:
  92. break;
  93. }
  94. }
  95. /* ------------------------------------------------------ */
  96. static void process_children(clish_shell_t * shell,
  97. clish_xmlnode_t * element, void *parent)
  98. {
  99. clish_xmlnode_t *node = NULL;
  100. while ((node = clish_xmlnode_next_child(element, node)) != NULL) {
  101. /* Now deal with all the contained elements */
  102. process_node(shell, node, parent);
  103. }
  104. }
  105. /* ------------------------------------------------------ */
  106. static void
  107. process_clish_module(clish_shell_t * shell, clish_xmlnode_t * element, void *parent)
  108. {
  109. // create the global view
  110. if (!shell->global)
  111. shell->global = clish_shell_find_create_view(shell,
  112. "global", "");
  113. process_children(shell, element, shell->global);
  114. }
  115. /* ------------------------------------------------------ */
  116. static void process_view(clish_shell_t * shell, clish_xmlnode_t * element, void *parent)
  117. {
  118. clish_view_t *view;
  119. char name[128] = "";
  120. char prompt[128] = "";
  121. char depth[128] = "";
  122. char restore[128] = "";
  123. clish_xmlattr_t *a_name;
  124. clish_xmlattr_t *a_prompt;
  125. clish_xmlattr_t *a_depth;
  126. clish_xmlattr_t *a_restore;
  127. clish_xmlattr_t *a_access;
  128. int allowed = 1;
  129. a_name = clish_xmlnode_fetch_attr(element, "name");
  130. a_prompt = clish_xmlnode_fetch_attr(element, "prompt");
  131. a_depth = clish_xmlnode_fetch_attr(element, "depth");
  132. a_restore = clish_xmlnode_fetch_attr(element, "restore");
  133. a_access = clish_xmlnode_fetch_attr(element, "access");
  134. /* Check permissions */
  135. if (a_access) {
  136. char access[128] = "";
  137. allowed = 0;
  138. clish_xmlattr_get_value_noerr(a_access, access, sizeof(access));
  139. if (shell->client_hooks->access_fn)
  140. allowed = shell->client_hooks->access_fn(shell, access);
  141. }
  142. if (!allowed)
  143. return;
  144. clish_xmlattr_get_value_noerr(a_name, name, sizeof(name));
  145. clish_xmlattr_get_value_noerr(a_prompt, prompt, sizeof(prompt));
  146. /* re-use a view if it already exists */
  147. view = clish_shell_find_create_view(shell, name, prompt);
  148. clish_xmlattr_get_value_noerr(a_depth, depth, sizeof(depth));
  149. if (*depth && (lub_ctype_isdigit(*depth))) {
  150. unsigned res = atoi(depth);
  151. clish_view__set_depth(view, res);
  152. }
  153. clish_xmlattr_get_value_noerr(a_restore, restore, sizeof(restore));
  154. if (*restore) {
  155. if (!lub_string_nocasecmp(restore, "depth"))
  156. clish_view__set_restore(view, CLISH_RESTORE_DEPTH);
  157. else if (!lub_string_nocasecmp(restore, "view"))
  158. clish_view__set_restore(view, CLISH_RESTORE_VIEW);
  159. else
  160. clish_view__set_restore(view, CLISH_RESTORE_NONE);
  161. }
  162. process_children(shell, element, view);
  163. }
  164. /* ------------------------------------------------------ */
  165. static void process_ptype(clish_shell_t * shell, clish_xmlnode_t * element, void *parent)
  166. {
  167. clish_ptype_method_e method;
  168. clish_ptype_preprocess_e preprocess;
  169. clish_ptype_t *ptype;
  170. clish_xmlattr_t *a_name = clish_xmlnode_fetch_attr(element, "name");
  171. clish_xmlattr_t *a_help = clish_xmlnode_fetch_attr(element, "help");
  172. clish_xmlattr_t *a_pattern = clish_xmlnode_fetch_attr(element, "pattern");
  173. clish_xmlattr_t *a_method_name = clish_xmlnode_fetch_attr(element, "method");
  174. clish_xmlattr_t *a_preprocess_name =
  175. clish_xmlnode_fetch_attr(element, "preprocess");
  176. char name[128] = "";
  177. char help[128] = "";
  178. char pattern[128] = "";
  179. char method_name[128] = "";
  180. char preprocess_name[128] = "";
  181. clish_xmlattr_get_value_noerr(a_name, name, sizeof(name));
  182. clish_xmlattr_get_value_noerr(a_pattern, pattern, sizeof(pattern));
  183. assert(*name);
  184. assert(*pattern);
  185. clish_xmlattr_get_value_noerr(a_method_name, method_name,
  186. sizeof(method_name));
  187. method = clish_ptype_method_resolve(method_name);
  188. clish_xmlattr_get_value_noerr(a_preprocess_name, preprocess_name,
  189. sizeof(preprocess_name));
  190. clish_xmlattr_get_value_noerr(a_help, help, sizeof(help));
  191. preprocess = clish_ptype_preprocess_resolve(preprocess_name);
  192. ptype = clish_shell_find_create_ptype(shell,
  193. name, help, pattern, method, preprocess);
  194. assert(ptype);
  195. }
  196. /* ------------------------------------------------------ */
  197. static void
  198. process_overview(clish_shell_t * shell, clish_xmlnode_t * element, void *parent)
  199. {
  200. char *content = NULL;
  201. unsigned int content_len = 2048;
  202. int result;
  203. /*
  204. * the code below faithfully assume that we'll be able fully store
  205. * the content of the node. If it's really, really big, we may have
  206. * an issue (but then, if it's that big, how the hell does it
  207. * already fits in allocated memory?)
  208. * Ergo, it -should- be safe.
  209. */
  210. do {
  211. content = (char*)realloc(content, content_len);
  212. result = clish_xmlnode_get_content(element, content,
  213. &content_len);
  214. } while (result == -E2BIG);
  215. if (result == 0 && content) {
  216. /* set the overview text for this view */
  217. assert(NULL == shell->overview);
  218. /* store the overview */
  219. shell->overview = lub_string_dup(content);
  220. }
  221. if (content)
  222. free(content);
  223. }
  224. /* ------------------------------------------------------ */
  225. static void
  226. process_command(clish_shell_t * shell, clish_xmlnode_t * element, void *parent)
  227. {
  228. clish_view_t *v = (clish_view_t *) parent;
  229. clish_command_t *cmd = NULL;
  230. clish_command_t *old;
  231. char *alias_name = NULL;
  232. clish_view_t *alias_view = NULL;
  233. int allowed = 1;
  234. clish_xmlattr_t *a_access = clish_xmlnode_fetch_attr(element, "access");
  235. clish_xmlattr_t *a_name = clish_xmlnode_fetch_attr(element, "name");
  236. clish_xmlattr_t *a_help = clish_xmlnode_fetch_attr(element, "help");
  237. clish_xmlattr_t *a_view = clish_xmlnode_fetch_attr(element, "view");
  238. clish_xmlattr_t *a_viewid = clish_xmlnode_fetch_attr(element, "viewid");
  239. clish_xmlattr_t *a_escape_chars = clish_xmlnode_fetch_attr(element, "escape_chars");
  240. clish_xmlattr_t *a_args_name = clish_xmlnode_fetch_attr(element, "args");
  241. clish_xmlattr_t *a_args_help = clish_xmlnode_fetch_attr(element, "args_help");
  242. clish_xmlattr_t *a_lock = clish_xmlnode_fetch_attr(element, "lock");
  243. clish_xmlattr_t *a_interrupt = clish_xmlnode_fetch_attr(element, "interrupt");
  244. clish_xmlattr_t *a_ref = clish_xmlnode_fetch_attr(element, "ref");
  245. char name[128];
  246. char help[128];
  247. char ref[128];
  248. char view[128];
  249. char viewid[128];
  250. char lock[128];
  251. char interrupt[128];
  252. char escape_chars[128];
  253. char args_name[128];
  254. /* Check permissions */
  255. if (a_access) {
  256. char access[128];
  257. allowed = 0;
  258. clish_xmlattr_get_value_noerr(a_access, access, sizeof(access));
  259. if (shell->client_hooks->access_fn)
  260. allowed = shell->client_hooks->access_fn(shell, access);
  261. }
  262. if (!allowed)
  263. return;
  264. clish_xmlattr_get_value_noerr(a_name, name, sizeof(name));
  265. /* check this command doesn't already exist */
  266. old = clish_view_find_command(v, name, BOOL_FALSE);
  267. if (old) {
  268. /* flag the duplication then ignore further definition */
  269. printf("DUPLICATE COMMAND: %s\n",
  270. clish_command__get_name(old));
  271. return;
  272. }
  273. clish_xmlattr_get_value_noerr(a_help, help, sizeof(help));
  274. assert(*name);
  275. assert(*help);
  276. clish_xmlattr_get_value_noerr(a_ref, ref, sizeof(ref));
  277. /* Reference 'ref' field */
  278. if (*ref) {
  279. char *saveptr;
  280. const char *delim = "@";
  281. char *view_name = NULL;
  282. char *cmdn = NULL;
  283. char *str = lub_string_dup(ref);
  284. cmdn = strtok_r(str, delim, &saveptr);
  285. if (!cmdn) {
  286. printf("EMPTY REFERENCE COMMAND: %s\n", name);
  287. lub_string_free(str);
  288. return;
  289. }
  290. alias_name = lub_string_dup(cmdn);
  291. view_name = strtok_r(NULL, delim, &saveptr);
  292. if (!view_name)
  293. alias_view = v;
  294. else
  295. alias_view = clish_shell_find_create_view(shell,
  296. view_name, NULL);
  297. lub_string_free(str);
  298. }
  299. clish_xmlattr_get_value_noerr(a_escape_chars, escape_chars,
  300. sizeof(escape_chars));
  301. clish_xmlattr_get_value_noerr(a_args_name, args_name,
  302. sizeof(args_name));
  303. /* create a command */
  304. cmd = clish_view_new_command(v, name, help);
  305. assert(cmd);
  306. clish_command__set_pview(cmd, v);
  307. /* define some specialist escape characters */
  308. if (*escape_chars)
  309. clish_command__set_escape_chars(cmd, escape_chars);
  310. if (*args_name) {
  311. /* define a "rest of line" argument */
  312. char args_help[128];
  313. clish_param_t *param;
  314. clish_ptype_t *tmp = NULL;
  315. clish_xmlattr_get_value_noerr(a_args_help, args_help,
  316. sizeof(args_help));
  317. assert(*args_help);
  318. tmp = clish_shell_find_ptype(shell, "internal_ARGS");
  319. assert(tmp);
  320. param = clish_param_new(args_name, args_help, tmp);
  321. clish_command__set_args(cmd, param);
  322. }
  323. clish_xmlattr_get_value_noerr(a_view, view, sizeof(view));
  324. /* define the view which this command changes to */
  325. if (*view) {
  326. clish_view_t *next = clish_shell_find_create_view(shell, view,
  327. NULL);
  328. /* reference the next view */
  329. clish_command__set_view(cmd, next);
  330. }
  331. clish_xmlattr_get_value_noerr(a_viewid, viewid, sizeof(viewid));
  332. /* define the view id which this command changes to */
  333. if (*viewid)
  334. clish_command__set_viewid(cmd, viewid);
  335. /* lock field */
  336. clish_xmlattr_get_value_noerr(a_lock, lock, sizeof(lock));
  337. if (lub_string_nocasecmp(lock, "false") == 0)
  338. clish_command__set_lock(cmd, BOOL_FALSE);
  339. else
  340. clish_command__set_lock(cmd, BOOL_TRUE);
  341. /* interrupt field */
  342. clish_xmlattr_get_value_noerr(a_interrupt, interrupt, sizeof(interrupt));
  343. if (lub_string_nocasecmp(interrupt, "true") == 0)
  344. clish_command__set_interrupt(cmd, BOOL_TRUE);
  345. else
  346. clish_command__set_interrupt(cmd, BOOL_FALSE);
  347. /* Set alias */
  348. if (alias_name) {
  349. assert(!((alias_view == v) && (!strcmp(alias_name, name))));
  350. clish_command__set_alias(cmd, alias_name);
  351. assert(alias_view);
  352. clish_command__set_alias_view(cmd, alias_view);
  353. lub_string_free(alias_name);
  354. }
  355. process_children(shell, element, cmd);
  356. }
  357. /* ------------------------------------------------------ */
  358. static void
  359. process_startup(clish_shell_t * shell, clish_xmlnode_t * element, void *parent)
  360. {
  361. clish_view_t *v = (clish_view_t *) parent;
  362. clish_command_t *cmd = NULL;
  363. clish_xmlattr_t *a_view = clish_xmlnode_fetch_attr(element, "view");
  364. clish_xmlattr_t *a_viewid = clish_xmlnode_fetch_attr(element, "viewid");
  365. clish_xmlattr_t *a_default_shebang =
  366. clish_xmlnode_fetch_attr(element, "default_shebang");
  367. clish_xmlattr_t *a_timeout = clish_xmlnode_fetch_attr(element, "timeout");
  368. clish_xmlattr_t *a_lock = clish_xmlnode_fetch_attr(element, "lock");
  369. clish_xmlattr_t *a_interrupt = clish_xmlnode_fetch_attr(element, "interrupt");
  370. char view[128];
  371. char viewid[128];
  372. char timeout[128];
  373. char lock[128];
  374. char interrupt[128];
  375. char default_shebang[128];
  376. assert(!shell->startup);
  377. clish_xmlattr_get_value_noerr(a_view, view, sizeof(view));
  378. assert(*view);
  379. /* create a command with NULL help */
  380. cmd = clish_view_new_command(v, "startup", NULL);
  381. clish_command__set_lock(cmd, BOOL_FALSE);
  382. /* define the view which this command changes to */
  383. clish_view_t *next = clish_shell_find_create_view(shell, view, NULL);
  384. /* reference the next view */
  385. clish_command__set_view(cmd, next);
  386. /* define the view id which this command changes to */
  387. clish_xmlattr_get_value_noerr(a_viewid, viewid, sizeof(viewid));
  388. if (*viewid)
  389. clish_command__set_viewid(cmd, viewid);
  390. clish_xmlattr_get_value_noerr(a_default_shebang, default_shebang,
  391. sizeof(default_shebang));
  392. if (*default_shebang)
  393. clish_shell__set_default_shebang(shell, default_shebang);
  394. clish_xmlattr_get_value_noerr(a_timeout, timeout, sizeof(timeout));
  395. if (*timeout)
  396. clish_shell__set_timeout(shell, atoi(timeout));
  397. /* lock field */
  398. clish_xmlattr_get_value_noerr(a_lock, lock, sizeof(lock));
  399. if (lub_string_nocasecmp(lock, "false") == 0)
  400. clish_command__set_lock(cmd, BOOL_FALSE);
  401. else
  402. clish_command__set_lock(cmd, BOOL_TRUE);
  403. /* interrupt field */
  404. clish_xmlattr_get_value_noerr(a_interrupt, interrupt, sizeof(interrupt));
  405. if (lub_string_nocasecmp(interrupt, "true") == 0)
  406. clish_command__set_interrupt(cmd, BOOL_TRUE);
  407. else
  408. clish_command__set_interrupt(cmd, BOOL_FALSE);
  409. /* remember this command */
  410. shell->startup = cmd;
  411. process_children(shell, element, cmd);
  412. }
  413. /* ------------------------------------------------------ */
  414. static void
  415. process_param(clish_shell_t * shell, clish_xmlnode_t * element, void *parent)
  416. {
  417. clish_command_t *cmd = NULL;
  418. clish_param_t *p_param = NULL;
  419. clish_xmlnode_t *pelement;
  420. char *pname;
  421. pelement = clish_xmlnode_parent(element);
  422. pname = clish_xmlnode_get_all_name(pelement);
  423. if (pname && lub_string_nocasecmp(pname, "PARAM") == 0)
  424. p_param = (clish_param_t *)parent;
  425. else
  426. cmd = (clish_command_t *)parent;
  427. if (pname)
  428. free(pname);
  429. if (cmd || p_param) {
  430. clish_xmlattr_t *a_name = clish_xmlnode_fetch_attr(element, "name");
  431. clish_xmlattr_t *a_help = clish_xmlnode_fetch_attr(element, "help");
  432. clish_xmlattr_t *a_ptype = clish_xmlnode_fetch_attr(element, "ptype");
  433. clish_xmlattr_t *a_prefix = clish_xmlnode_fetch_attr(element, "prefix");
  434. clish_xmlattr_t *a_defval = clish_xmlnode_fetch_attr(element, "default");
  435. clish_xmlattr_t *a_mode = clish_xmlnode_fetch_attr(element, "mode");
  436. clish_xmlattr_t *a_optional = clish_xmlnode_fetch_attr(element, "optional");
  437. clish_xmlattr_t *a_order = clish_xmlnode_fetch_attr(element, "order");
  438. clish_xmlattr_t *a_value = clish_xmlnode_fetch_attr(element, "value");
  439. clish_xmlattr_t *a_hidden = clish_xmlnode_fetch_attr(element, "hidden");
  440. clish_xmlattr_t *a_test = clish_xmlnode_fetch_attr(element, "test");
  441. clish_xmlattr_t *a_completion = clish_xmlnode_fetch_attr(element, "completion");
  442. clish_param_t *param;
  443. clish_ptype_t *tmp = NULL;
  444. char name[128];
  445. char help[128];
  446. char ptype[128];
  447. char prefix[128];
  448. char defval[128];
  449. char mode[128];
  450. char optional[128];
  451. char order[128];
  452. char value[128];
  453. char hidden[128];
  454. char test[128];
  455. char completion[128];
  456. assert((!cmd) || (cmd != shell->startup));
  457. clish_xmlattr_get_value_noerr(a_name, name, sizeof(name));
  458. clish_xmlattr_get_value_noerr(a_help, help, sizeof(help));
  459. clish_xmlattr_get_value_noerr(a_ptype, ptype, sizeof(ptype));
  460. /* create a command */
  461. assert(*name);
  462. assert(*help);
  463. assert(*ptype);
  464. if (*ptype) {
  465. tmp = clish_shell_find_create_ptype(shell, ptype,
  466. NULL, NULL,
  467. CLISH_PTYPE_REGEXP,
  468. CLISH_PTYPE_NONE);
  469. assert(tmp);
  470. }
  471. param = clish_param_new(name, help, tmp);
  472. /* If prefix is set clish will emulate old optional
  473. * command syntax over newer optional command mechanism.
  474. * It will create nested PARAM.
  475. */
  476. clish_xmlattr_get_value_noerr(a_prefix, prefix, sizeof(prefix));
  477. clish_xmlattr_get_value_noerr(a_test, test, sizeof(test));
  478. if (*prefix) {
  479. const char *ptype_name = "__SUBCOMMAND";
  480. clish_param_t *opt_param = NULL;
  481. /* Create a ptype for prefix-named subcommand that
  482. * will contain the nested optional parameter. The
  483. * name of ptype is hardcoded. It's not good but
  484. * it's only the service ptype.
  485. */
  486. tmp = (clish_ptype_t *)lub_bintree_find(
  487. &shell->ptype_tree, ptype_name);
  488. if (!tmp)
  489. tmp = clish_shell_find_create_ptype(shell,
  490. ptype_name, "Option", "[^\\\\]+",
  491. CLISH_PTYPE_REGEXP, CLISH_PTYPE_NONE);
  492. assert(tmp);
  493. opt_param = clish_param_new(prefix, help, tmp);
  494. clish_param__set_mode(opt_param,
  495. CLISH_PARAM_SUBCOMMAND);
  496. clish_param__set_optional(opt_param, BOOL_TRUE);
  497. if (*test)
  498. clish_param__set_test(opt_param, test);
  499. /* add the parameter to the command */
  500. if (cmd)
  501. clish_command_insert_param(cmd, opt_param);
  502. /* add the parameter to the param */
  503. if (p_param)
  504. clish_param_insert_param(p_param, opt_param);
  505. /* Unset cmd and set parent param to opt_param */
  506. cmd = NULL;
  507. p_param = opt_param;
  508. }
  509. clish_xmlattr_get_value_noerr(a_defval, defval, sizeof(defval));
  510. if (*defval)
  511. clish_param__set_default(param, defval);
  512. clish_xmlattr_get_value_noerr(a_hidden, hidden, sizeof(hidden));
  513. if (lub_string_nocasecmp(hidden, "true") == 0)
  514. clish_param__set_hidden(param, BOOL_TRUE);
  515. else
  516. clish_param__set_hidden(param, BOOL_FALSE);
  517. clish_xmlattr_get_value_noerr(a_mode, mode, sizeof(mode));
  518. if (*mode) {
  519. if (lub_string_nocasecmp(mode, "switch") == 0) {
  520. clish_param__set_mode(param,
  521. CLISH_PARAM_SWITCH);
  522. /* Force hidden attribute */
  523. clish_param__set_hidden(param, BOOL_TRUE);
  524. } else if (lub_string_nocasecmp(mode, "subcommand") == 0)
  525. clish_param__set_mode(param,
  526. CLISH_PARAM_SUBCOMMAND);
  527. else
  528. clish_param__set_mode(param,
  529. CLISH_PARAM_COMMON);
  530. }
  531. clish_xmlattr_get_value_noerr(a_optional, optional,
  532. sizeof(optional));
  533. if (lub_string_nocasecmp(optional, "true") == 0)
  534. clish_param__set_optional(param, BOOL_TRUE);
  535. else
  536. clish_param__set_optional(param, BOOL_FALSE);
  537. clish_xmlattr_get_value_noerr(a_order, order, sizeof(order));
  538. if (lub_string_nocasecmp(order, "true") == 0)
  539. clish_param__set_order(param, BOOL_TRUE);
  540. else
  541. clish_param__set_order(param, BOOL_FALSE);
  542. clish_xmlattr_get_value_noerr(a_value, value, sizeof(value));
  543. if (*value) {
  544. clish_param__set_value(param, value);
  545. /* Force mode to subcommand */
  546. clish_param__set_mode(param,
  547. CLISH_PARAM_SUBCOMMAND);
  548. }
  549. if (*test && !*prefix)
  550. clish_param__set_test(param, test);
  551. clish_xmlattr_get_value_noerr(a_completion, completion,
  552. sizeof(completion));
  553. if (*completion)
  554. clish_param__set_completion(param, completion);
  555. /* add the parameter to the command */
  556. if (cmd)
  557. clish_command_insert_param(cmd, param);
  558. /* add the parameter to the param */
  559. if (p_param)
  560. clish_param_insert_param(p_param, param);
  561. process_children(shell, element, param);
  562. }
  563. }
  564. /* ------------------------------------------------------ */
  565. static void
  566. process_action(clish_shell_t * shell, clish_xmlnode_t * element, void *parent)
  567. {
  568. clish_action_t *action = NULL;
  569. clish_xmlattr_t *a_builtin = clish_xmlnode_fetch_attr(element, "builtin");
  570. clish_xmlattr_t *a_shebang = clish_xmlnode_fetch_attr(element, "shebang");
  571. clish_xmlnode_t *pelement = clish_xmlnode_parent(element);
  572. char *pname = clish_xmlnode_get_all_name(pelement);
  573. char *text;
  574. char builtin[128];
  575. char shebang[128];
  576. if (pname && lub_string_nocasecmp(pname, "VAR") == 0)
  577. action = clish_var__get_action((clish_var_t *)parent);
  578. else
  579. action = clish_command__get_action((clish_command_t *)parent);
  580. assert(action);
  581. if (pname)
  582. free(pname);
  583. text = clish_xmlnode_get_all_content(element);
  584. if (text && *text) {
  585. /* store the action */
  586. clish_action__set_script(action, text);
  587. }
  588. if (text)
  589. free(text);
  590. clish_xmlattr_get_value_noerr(a_builtin, builtin, sizeof(builtin));
  591. clish_xmlattr_get_value_noerr(a_shebang, shebang, sizeof(shebang));
  592. if (*builtin)
  593. clish_action__set_builtin(action, builtin);
  594. if (*shebang)
  595. clish_action__set_shebang(action, shebang);
  596. }
  597. /* ------------------------------------------------------ */
  598. static void
  599. process_detail(clish_shell_t * shell, clish_xmlnode_t * element, void *parent)
  600. {
  601. clish_command_t *cmd = (clish_command_t *) parent;
  602. /* read the following text element */
  603. char *text = clish_xmlnode_get_all_content(element);
  604. if (text && *text) {
  605. /* store the action */
  606. clish_command__set_detail(cmd, text);
  607. }
  608. if (text)
  609. free(text);
  610. }
  611. /* ------------------------------------------------------ */
  612. static void
  613. process_namespace(clish_shell_t * shell, clish_xmlnode_t * element, void *parent)
  614. {
  615. clish_view_t *v = (clish_view_t *) parent;
  616. clish_nspace_t *nspace = NULL;
  617. clish_xmlattr_t *a_view = clish_xmlnode_fetch_attr(element, "ref");
  618. clish_xmlattr_t *a_prefix = clish_xmlnode_fetch_attr(element, "prefix");
  619. clish_xmlattr_t *a_prefix_help = clish_xmlnode_fetch_attr(element, "prefix_help");
  620. clish_xmlattr_t *a_help = clish_xmlnode_fetch_attr(element, "help");
  621. clish_xmlattr_t *a_completion = clish_xmlnode_fetch_attr(element, "completion");
  622. clish_xmlattr_t *a_context_help = clish_xmlnode_fetch_attr(element, "context_help");
  623. clish_xmlattr_t *a_inherit = clish_xmlnode_fetch_attr(element, "inherit");
  624. clish_xmlattr_t *a_access = clish_xmlnode_fetch_attr(element, "access");
  625. char view[128];
  626. char prefix[128];
  627. char help[128];
  628. char completion[128];
  629. char context_help[128];
  630. char inherit[128];
  631. int allowed = 1;
  632. if (a_access) {
  633. char access[128];
  634. allowed = 0;
  635. clish_xmlattr_get_value_noerr(a_access, access, sizeof(access));
  636. if (shell->client_hooks->access_fn)
  637. allowed = shell->client_hooks->access_fn(shell, access);
  638. }
  639. if (!allowed)
  640. return;
  641. clish_xmlattr_get_value_noerr(a_view, view, sizeof(view));
  642. clish_xmlattr_get_value_noerr(a_prefix, prefix, sizeof(prefix));
  643. assert(*view);
  644. clish_view_t *ref_view = clish_shell_find_create_view(shell,
  645. view, NULL);
  646. assert(ref_view);
  647. /* Don't include itself without prefix */
  648. if ((ref_view == v) && !*prefix)
  649. return;
  650. nspace = clish_nspace_new(ref_view);
  651. assert(nspace);
  652. clish_view_insert_nspace(v, nspace);
  653. if (*prefix) {
  654. char prefix_help[128];
  655. clish_nspace__set_prefix(nspace, prefix);
  656. clish_xmlattr_get_value_noerr(a_prefix_help, prefix_help,
  657. sizeof(prefix_help));
  658. if (*prefix_help)
  659. clish_nspace_create_prefix_cmd(nspace,
  660. "prefix",
  661. prefix_help);
  662. else
  663. clish_nspace_create_prefix_cmd(nspace,
  664. "prefix",
  665. "Prefix for the imported commands.");
  666. }
  667. clish_xmlattr_get_value_noerr(a_help, help, sizeof(help));
  668. if (lub_string_nocasecmp(help, "true") == 0)
  669. clish_nspace__set_help(nspace, BOOL_TRUE);
  670. else
  671. clish_nspace__set_help(nspace, BOOL_FALSE);
  672. clish_xmlattr_get_value_noerr(a_completion, completion,
  673. sizeof(completion));
  674. if (lub_string_nocasecmp(completion, "false") == 0)
  675. clish_nspace__set_completion(nspace, BOOL_FALSE);
  676. else
  677. clish_nspace__set_completion(nspace, BOOL_TRUE);
  678. clish_xmlattr_get_value_noerr(a_context_help, context_help,
  679. sizeof(context_help));
  680. if (lub_string_nocasecmp(context_help, "true") == 0)
  681. clish_nspace__set_context_help(nspace, BOOL_TRUE);
  682. else
  683. clish_nspace__set_context_help(nspace, BOOL_FALSE);
  684. clish_xmlattr_get_value_noerr(a_inherit, inherit, sizeof(inherit));
  685. if (lub_string_nocasecmp(inherit, "false") == 0)
  686. clish_nspace__set_inherit(nspace, BOOL_FALSE);
  687. else
  688. clish_nspace__set_inherit(nspace, BOOL_TRUE);
  689. }
  690. /* ------------------------------------------------------ */
  691. static void
  692. process_config(clish_shell_t * shell, clish_xmlnode_t * element, void *parent)
  693. {
  694. clish_command_t *cmd = (clish_command_t *)parent;
  695. clish_config_t *config;
  696. if (!cmd)
  697. return;
  698. config = clish_command__get_config(cmd);
  699. /* read the following text element */
  700. clish_xmlattr_t *a_operation = clish_xmlnode_fetch_attr(element, "operation");
  701. clish_xmlattr_t *a_priority = clish_xmlnode_fetch_attr(element, "priority");
  702. clish_xmlattr_t *a_pattern = clish_xmlnode_fetch_attr(element, "pattern");
  703. clish_xmlattr_t *a_file = clish_xmlnode_fetch_attr(element, "file");
  704. clish_xmlattr_t *a_splitter = clish_xmlnode_fetch_attr(element, "splitter");
  705. clish_xmlattr_t *a_seq = clish_xmlnode_fetch_attr(element, "sequence");
  706. clish_xmlattr_t *a_unique = clish_xmlnode_fetch_attr(element, "unique");
  707. clish_xmlattr_t *a_depth = clish_xmlnode_fetch_attr(element, "depth");
  708. char operation[128];
  709. char priority[128];
  710. char pattern[128];
  711. char file[128];
  712. char splitter[128];
  713. char seq[128];
  714. char unique[128];
  715. char depth[128];
  716. clish_xmlattr_get_value_noerr(a_operation, operation, sizeof(operation));
  717. if (!lub_string_nocasecmp(operation, "unset"))
  718. clish_config__set_op(config, CLISH_CONFIG_UNSET);
  719. else if (!lub_string_nocasecmp(operation, "none"))
  720. clish_config__set_op(config, CLISH_CONFIG_NONE);
  721. else if (!lub_string_nocasecmp(operation, "dump"))
  722. clish_config__set_op(config, CLISH_CONFIG_DUMP);
  723. else {
  724. clish_config__set_op(config, CLISH_CONFIG_SET);
  725. /* The priority if no clearly specified */
  726. clish_config__set_priority(config, 0x7f00);
  727. }
  728. clish_xmlattr_get_value_noerr(a_priority, priority, sizeof(priority));
  729. if (*priority) {
  730. long val = 0;
  731. char *endptr;
  732. unsigned short pri;
  733. val = strtol(priority, &endptr, 0);
  734. if (endptr == priority)
  735. pri = 0;
  736. else if (val > 0xffff)
  737. pri = 0xffff;
  738. else if (val < 0)
  739. pri = 0;
  740. else
  741. pri = (unsigned short)val;
  742. clish_config__set_priority(config, pri);
  743. }
  744. clish_xmlattr_get_value_noerr(a_pattern, pattern, sizeof(pattern));
  745. if (*pattern)
  746. clish_config__set_pattern(config, pattern);
  747. else
  748. clish_config__set_pattern(config, "^${__cmd}");
  749. clish_xmlattr_get_value_noerr(a_file, file, sizeof(file));
  750. if (*file)
  751. clish_config__set_file(config, file);
  752. clish_xmlattr_get_value_noerr(a_splitter, splitter, sizeof(splitter));
  753. if (lub_string_nocasecmp(splitter, "false") == 0)
  754. clish_config__set_splitter(config, BOOL_FALSE);
  755. else
  756. clish_config__set_splitter(config, BOOL_TRUE);
  757. clish_xmlattr_get_value_noerr(a_unique, unique, sizeof(unique));
  758. if (lub_string_nocasecmp(unique, "false") == 0)
  759. clish_config__set_unique(config, BOOL_FALSE);
  760. else
  761. clish_config__set_unique(config, BOOL_TRUE);
  762. clish_xmlattr_get_value_noerr(a_seq, seq, sizeof(seq));
  763. if (*seq)
  764. clish_config__set_seq(config, seq);
  765. else
  766. /* The entries without sequence cannot be non-unique */
  767. clish_config__set_unique(config, BOOL_TRUE);
  768. clish_xmlattr_get_value_noerr(a_depth, depth, sizeof(depth));
  769. if (*depth)
  770. clish_config__set_depth(config, depth);
  771. }
  772. /* ------------------------------------------------------ */
  773. static void process_var(clish_shell_t * shell, clish_xmlnode_t * element, void *parent)
  774. {
  775. clish_var_t *var = NULL;
  776. clish_xmlattr_t *a_name = clish_xmlnode_fetch_attr(element, "name");
  777. clish_xmlattr_t *a_dynamic = clish_xmlnode_fetch_attr(element, "dynamic");
  778. clish_xmlattr_t *a_value = clish_xmlnode_fetch_attr(element, "value");
  779. char name[128];
  780. char value[128];
  781. char dynamic[128];
  782. clish_xmlattr_get_value_noerr(a_name, name, sizeof(name));
  783. assert(*name);
  784. /* Check if this var doesn't already exist */
  785. var = (clish_var_t *)lub_bintree_find(&shell->var_tree, name);
  786. if (var) {
  787. printf("DUPLICATE VAR: %s\n", name);
  788. assert(!var);
  789. }
  790. /* Create var instance */
  791. var = clish_var_new(name);
  792. lub_bintree_insert(&shell->var_tree, var);
  793. clish_xmlattr_get_value_noerr(a_dynamic, dynamic, sizeof(dynamic));
  794. if (lub_string_nocasecmp(dynamic, "true") == 0)
  795. clish_var__set_dynamic(var, BOOL_TRUE);
  796. clish_xmlattr_get_value_noerr(a_value, value, sizeof(value));
  797. if (*value)
  798. clish_var__set_value(var, value);
  799. process_children(shell, element, var);
  800. }
  801. /* ------------------------------------------------------ */
  802. static void process_wdog(clish_shell_t *shell,
  803. clish_xmlnode_t *element, void *parent)
  804. {
  805. clish_view_t *v = (clish_view_t *)parent;
  806. clish_command_t *cmd = NULL;
  807. assert(!shell->wdog);
  808. /* create a command with NULL help */
  809. cmd = clish_view_new_command(v, "watchdog", NULL);
  810. clish_command__set_lock(cmd, BOOL_FALSE);
  811. /* Remember this command */
  812. shell->wdog = cmd;
  813. process_children(shell, element, cmd);
  814. }
  815. /* ------------------------------------------------------ */
  816. int clish_shell_xml_read(clish_shell_t * shell, const char *filename)
  817. {
  818. int ret = -1;
  819. clish_xmldoc_t *doc;
  820. doc = clish_xmldoc_read(filename);
  821. if (clish_xmldoc_is_valid(doc)) {
  822. clish_xmlnode_t *root = clish_xmldoc_get_root(doc);
  823. process_node(shell, root, NULL);
  824. ret = 0;
  825. } else {
  826. int errcaps = clish_xmldoc_error_caps(doc);
  827. printf("Unable to open file '%s'", filename);
  828. if ((errcaps & CLISH_XMLERR_LINE) == CLISH_XMLERR_LINE)
  829. printf(", at line %d", clish_xmldoc_get_err_line(doc));
  830. if ((errcaps & CLISH_XMLERR_COL) == CLISH_XMLERR_COL)
  831. printf(", at column %d", clish_xmldoc_get_err_col(doc));
  832. if ((errcaps & CLISH_XMLERR_DESC) == CLISH_XMLERR_DESC)
  833. printf(", message is %s", clish_xmldoc_get_err_msg(doc));
  834. printf("\n");
  835. }
  836. clish_xmldoc_release(doc);
  837. return ret;
  838. }
  839. /* ------------------------------------------------------ */