ientry.c 7.8 KB

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