ientry.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <assert.h>
  5. #include <faux/str.h>
  6. #include <faux/list.h>
  7. #include <faux/conv.h>
  8. #include <klish/khelper.h>
  9. #include <klish/ientry.h>
  10. #include <klish/kptype.h>
  11. #include <klish/kentry.h>
  12. #define TAG "ENTRY"
  13. bool_t ientry_parse(const ientry_t *info, kentry_t *entry, faux_error_t *error)
  14. {
  15. bool_t retcode = BOOL_TRUE;
  16. if (!info)
  17. return BOOL_FALSE;
  18. if (!entry)
  19. return BOOL_FALSE;
  20. // Help
  21. if (!faux_str_is_empty(info->help)) {
  22. if (!kentry_set_help(entry, info->help)) {
  23. faux_error_add(error, TAG": Illegal 'help' attribute");
  24. retcode = BOOL_FALSE;
  25. }
  26. }
  27. // Container
  28. if (!faux_str_is_empty(info->container)) {
  29. bool_t b = BOOL_FALSE;
  30. if (!faux_conv_str2bool(info->container, &b) ||
  31. !kentry_set_container(entry, b)) {
  32. faux_error_add(error, TAG": Illegal 'container' attribute");
  33. retcode = BOOL_FALSE;
  34. }
  35. }
  36. // Mode
  37. if (!faux_str_is_empty(info->mode)) {
  38. kentry_mode_e mode = KENTRY_MODE_NONE;
  39. if (!faux_str_casecmp(info->mode, "sequence"))
  40. mode = KENTRY_MODE_SEQUENCE;
  41. else if (!faux_str_casecmp(info->mode, "switch"))
  42. mode = KENTRY_MODE_SWITCH;
  43. else if (!faux_str_casecmp(info->mode, "empty"))
  44. mode = KENTRY_MODE_EMPTY;
  45. if ((KENTRY_MODE_NONE == mode) || !kentry_set_mode(entry, mode)) {
  46. faux_error_add(error, TAG": Illegal 'mode' attribute");
  47. retcode = BOOL_FALSE;
  48. }
  49. }
  50. // Min occurs
  51. if (!faux_str_is_empty(info->min)) {
  52. unsigned int i = 0;
  53. if (!faux_conv_atoui(info->min, &i, 0) ||
  54. !kentry_set_min(entry, (size_t)i)) {
  55. faux_error_add(error, TAG": Illegal 'min' attribute");
  56. retcode = BOOL_FALSE;
  57. }
  58. }
  59. // Max occurs
  60. if (!faux_str_is_empty(info->max)) {
  61. unsigned int i = 0;
  62. if (!faux_conv_atoui(info->max, &i, 0) ||
  63. !kentry_set_max(entry, (size_t)i)) {
  64. faux_error_add(error, TAG": Illegal 'max' attribute");
  65. retcode = BOOL_FALSE;
  66. }
  67. }
  68. // Ptype string
  69. if (!faux_str_is_empty(info->ptype)) {
  70. if (!kentry_set_ptype_str(entry, info->ptype)) {
  71. faux_error_add(error, TAG": Illegal 'ptype' attribute");
  72. retcode = BOOL_FALSE;
  73. }
  74. }
  75. // Ref string
  76. if (!faux_str_is_empty(info->ref)) {
  77. if (!kentry_set_ref_str(entry, info->ref)) {
  78. faux_error_add(error, TAG": Illegal 'ref' attribute");
  79. retcode = BOOL_FALSE;
  80. }
  81. }
  82. // Value
  83. if (!faux_str_is_empty(info->value)) {
  84. if (!kentry_set_value(entry, info->value)) {
  85. faux_error_add(error, TAG": Illegal 'value' attribute");
  86. retcode = BOOL_FALSE;
  87. }
  88. }
  89. // Restore
  90. if (!faux_str_is_empty(info->restore)) {
  91. bool_t b = BOOL_FALSE;
  92. if (!faux_conv_str2bool(info->restore, &b) ||
  93. !kentry_set_restore(entry, b)) {
  94. faux_error_add(error, TAG": Illegal 'restore' attribute");
  95. retcode = BOOL_FALSE;
  96. }
  97. }
  98. // Order
  99. if (!faux_str_is_empty(info->order)) {
  100. bool_t b = BOOL_FALSE;
  101. if (!faux_conv_str2bool(info->order, &b) ||
  102. !kentry_set_order(entry, b)) {
  103. faux_error_add(error, TAG": Illegal 'order' attribute");
  104. retcode = BOOL_FALSE;
  105. }
  106. }
  107. return retcode;
  108. }
  109. bool_t ientry_parse_nested(const ientry_t *ientry, kentry_t *kentry,
  110. faux_error_t *error)
  111. {
  112. bool_t retval = BOOL_TRUE;
  113. if (!kentry || !ientry) {
  114. faux_error_add(error, TAG": Internal error");
  115. return BOOL_FALSE;
  116. }
  117. // ENTRY list
  118. // ENTRYs can be duplicate. Duplicated ENTRY will add nested
  119. // elements to existent ENTRY. Also it can overwrite ENTRY attributes.
  120. // So there is no special rule which attribute value will be "on top".
  121. // It's a random. Technically later ENTRYs will rewrite previous
  122. // values.
  123. if (ientry->entrys) {
  124. ientry_t **p_ientry = NULL;
  125. for (p_ientry = *ientry->entrys; *p_ientry; p_ientry++) {
  126. kentry_t *nkentry = NULL;
  127. ientry_t *nientry = *p_ientry;
  128. const char *entry_name = nientry->name;
  129. if (entry_name)
  130. nkentry = kentry_find_entry(kentry, entry_name);
  131. // ENTRY already exists
  132. if (nkentry) {
  133. if (!ientry_parse(nientry, nkentry, error)) {
  134. retval = BOOL_FALSE;
  135. continue;
  136. }
  137. if (!ientry_parse_nested(nientry, nkentry,
  138. error)) {
  139. retval = BOOL_FALSE;
  140. continue;
  141. }
  142. continue;
  143. }
  144. // New ENTRY
  145. nkentry = ientry_load(nientry, error);
  146. if (!nkentry) {
  147. retval = BOOL_FALSE;
  148. continue;
  149. }
  150. kentry_set_parent(nkentry, kentry); // Set parent entry
  151. if (!kentry_add_entrys(kentry, nkentry)) {
  152. faux_error_sprintf(error,
  153. TAG": Can't add ENTRY \"%s\"",
  154. kentry_name(nkentry));
  155. kentry_free(nkentry);
  156. retval = BOOL_FALSE;
  157. continue;
  158. }
  159. }
  160. }
  161. // ACTION list
  162. if (ientry->actions) {
  163. iaction_t **p_iaction = NULL;
  164. for (p_iaction = *ientry->actions; *p_iaction; p_iaction++) {
  165. kaction_t *kaction = NULL;
  166. iaction_t *iaction = *p_iaction;
  167. kaction = iaction_load(iaction, error);
  168. if (!kaction) {
  169. retval = BOOL_FALSE;
  170. continue;
  171. }
  172. if (!kentry_add_actions(kentry, kaction)) {
  173. faux_error_sprintf(error,
  174. TAG": Can't add ACTION #%d",
  175. kentry_actions_len(kentry) + 1);
  176. kaction_free(kaction);
  177. retval = BOOL_FALSE;
  178. continue;
  179. }
  180. }
  181. }
  182. if (!retval)
  183. faux_error_sprintf(error, TAG" \"%s\": Illegal nested elements",
  184. kentry_name(kentry));
  185. return retval;
  186. }
  187. kentry_t *ientry_load(const ientry_t *ientry, faux_error_t *error)
  188. {
  189. kentry_t *kentry = NULL;
  190. if (!ientry)
  191. return NULL;
  192. // Name [mandatory]
  193. if (faux_str_is_empty(ientry->name)) {
  194. faux_error_add(error, TAG": Empty 'name' attribute");
  195. return NULL;
  196. }
  197. kentry = kentry_new(ientry->name);
  198. if (!kentry) {
  199. faux_error_sprintf(error, TAG" \"%s\": Can't create object",
  200. ientry->name);
  201. return NULL;
  202. }
  203. if (!ientry_parse(ientry, kentry, error)) {
  204. kentry_free(kentry);
  205. return NULL;
  206. }
  207. // Parse nested elements
  208. if (!ientry_parse_nested(ientry, kentry, error)) {
  209. kentry_free(kentry);
  210. return NULL;
  211. }
  212. return kentry;
  213. }
  214. char *ientry_deploy(const kentry_t *kentry, int level)
  215. {
  216. char *str = NULL;
  217. char *tmp = NULL;
  218. char *mode = NULL;
  219. kentry_entrys_node_t *entrys_iter = NULL;
  220. kentry_actions_node_t *actions_iter = NULL;
  221. char *num = NULL;
  222. tmp = faux_str_sprintf("%*cENTRY {\n", level, ' ');
  223. faux_str_cat(&str, tmp);
  224. faux_str_free(tmp);
  225. attr2ctext(&str, "name", kentry_name(kentry), level + 1);
  226. attr2ctext(&str, "help", kentry_help(kentry), level + 1);
  227. attr2ctext(&str, "ref", kentry_ref_str(kentry), level + 1);
  228. // Links (ENTRY with 'ref' attribute) doesn't need the following filds
  229. // that will be replaced by content of referenced ENTRY
  230. if (faux_str_is_empty(kentry_ref_str(kentry))) {
  231. attr2ctext(&str, "container", faux_conv_bool2str(kentry_container(kentry)), level + 1);
  232. // Mode
  233. switch (kentry_mode(kentry)) {
  234. case KENTRY_MODE_SEQUENCE:
  235. mode = "sequence";
  236. break;
  237. case KENTRY_MODE_SWITCH:
  238. mode = "switch";
  239. break;
  240. case KENTRY_MODE_EMPTY:
  241. mode = "empty";
  242. break;
  243. default:
  244. mode = NULL;
  245. }
  246. attr2ctext(&str, "mode", mode, level + 1);
  247. // Min occurs
  248. num = faux_str_sprintf("%u", kentry_min(kentry));
  249. attr2ctext(&str, "min", num, level + 1);
  250. faux_str_free(num);
  251. num = NULL;
  252. // Max occurs
  253. num = faux_str_sprintf("%u", kentry_max(kentry));
  254. attr2ctext(&str, "max", num, level + 1);
  255. faux_str_free(num);
  256. num = NULL;
  257. attr2ctext(&str, "ptype", kentry_ptype_str(kentry), level + 1);
  258. attr2ctext(&str, "value", kentry_value(kentry), level + 1);
  259. attr2ctext(&str, "restore", faux_conv_bool2str(kentry_restore(kentry)), level + 1);
  260. attr2ctext(&str, "order", faux_conv_bool2str(kentry_order(kentry)), level + 1);
  261. // ENTRY list
  262. entrys_iter = kentry_entrys_iter(kentry);
  263. if (entrys_iter) {
  264. kentry_t *nentry = NULL;
  265. tmp = faux_str_sprintf("\n%*cENTRY_LIST\n\n", level + 1, ' ');
  266. faux_str_cat(&str, tmp);
  267. faux_str_free(tmp);
  268. while ((nentry = kentry_entrys_each(&entrys_iter))) {
  269. tmp = ientry_deploy(nentry, level + 2);
  270. faux_str_cat(&str, tmp);
  271. faux_str_free(tmp);
  272. }
  273. tmp = faux_str_sprintf("%*cEND_ENTRY_LIST,\n", level + 1, ' ');
  274. faux_str_cat(&str, tmp);
  275. faux_str_free(tmp);
  276. }
  277. // ACTION list
  278. actions_iter = kentry_actions_iter(kentry);
  279. if (actions_iter) {
  280. kaction_t *action = NULL;
  281. tmp = faux_str_sprintf("\n%*cACTION_LIST\n\n", level + 1, ' ');
  282. faux_str_cat(&str, tmp);
  283. faux_str_free(tmp);
  284. while ((action = kentry_actions_each(&actions_iter))) {
  285. tmp = iaction_deploy(action, level + 2);
  286. faux_str_cat(&str, tmp);
  287. faux_str_free(tmp);
  288. }
  289. tmp = faux_str_sprintf("%*cEND_ACTION_LIST,\n", level + 1, ' ');
  290. faux_str_cat(&str, tmp);
  291. faux_str_free(tmp);
  292. }
  293. } // ref_str
  294. tmp = faux_str_sprintf("%*c},\n\n", level, ' ');
  295. faux_str_cat(&str, tmp);
  296. faux_str_free(tmp);
  297. return str;
  298. }