kcommand.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  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/error.h>
  8. #include <klish/khelper.h>
  9. #include <klish/kparam.h>
  10. #include <klish/kaction.h>
  11. #include <klish/kcommand.h>
  12. struct kcommand_s {
  13. char *name;
  14. char *help;
  15. faux_list_t *params;
  16. faux_list_t *actions;
  17. };
  18. // Simple attributes
  19. // Name
  20. KGET_STR(command, name);
  21. KSET_STR_ONCE(command, name);
  22. // Help
  23. KGET_STR(command, help);
  24. KSET_STR(command, help);
  25. // PARAM list
  26. static KCMP_NESTED(command, param, name);
  27. static KCMP_NESTED_BY_KEY(command, param, name);
  28. KADD_NESTED(command, param);
  29. KFIND_NESTED(command, param);
  30. // ACTION list
  31. KADD_NESTED(command, action);
  32. static kcommand_t *kcommand_new_empty(void)
  33. {
  34. kcommand_t *command = NULL;
  35. command = faux_zmalloc(sizeof(*command));
  36. assert(command);
  37. if (!command)
  38. return NULL;
  39. // Initialize
  40. command->name = NULL;
  41. command->help = NULL;
  42. // PARAM list
  43. command->params = faux_list_new(FAUX_LIST_UNSORTED, FAUX_LIST_UNIQUE,
  44. kcommand_param_compare, kcommand_param_kcompare,
  45. (void (*)(void *))kparam_free);
  46. assert(command->params);
  47. // ACTION list
  48. command->actions = faux_list_new(FAUX_LIST_UNSORTED, FAUX_LIST_NONUNIQUE,
  49. NULL, NULL, (void (*)(void *))kaction_free);
  50. assert(command->actions);
  51. return command;
  52. }
  53. kcommand_t *kcommand_new(const icommand_t *info, kcommand_error_e *error)
  54. {
  55. kcommand_t *command = NULL;
  56. command = kcommand_new_empty();
  57. assert(command);
  58. if (!command) {
  59. if (error)
  60. *error = KCOMMAND_ERROR_ALLOC;
  61. return NULL;
  62. }
  63. if (!info)
  64. return command;
  65. if (!kcommand_parse(command, info, error)) {
  66. kcommand_free(command);
  67. return NULL;
  68. }
  69. return command;
  70. }
  71. void kcommand_free(kcommand_t *command)
  72. {
  73. if (!command)
  74. return;
  75. faux_str_free(command->name);
  76. faux_str_free(command->help);
  77. faux_list_free(command->params);
  78. faux_list_free(command->actions);
  79. faux_free(command);
  80. }
  81. const char *kcommand_strerror(kcommand_error_e error)
  82. {
  83. const char *str = NULL;
  84. switch (error) {
  85. case KCOMMAND_ERROR_OK:
  86. str = "Ok";
  87. break;
  88. case KCOMMAND_ERROR_INTERNAL:
  89. str = "Internal error";
  90. break;
  91. case KCOMMAND_ERROR_ALLOC:
  92. str = "Memory allocation error";
  93. break;
  94. case KCOMMAND_ERROR_ATTR_NAME:
  95. str = "Illegal 'name' attribute";
  96. break;
  97. case KCOMMAND_ERROR_ATTR_HELP:
  98. str = "Illegal 'help' attribute";
  99. break;
  100. default:
  101. str = "Unknown error";
  102. break;
  103. }
  104. return str;
  105. }
  106. bool_t kcommand_parse(kcommand_t *command, const icommand_t *info, kcommand_error_e *error)
  107. {
  108. // Name [mandatory]
  109. if (faux_str_is_empty(info->name)) {
  110. if (error)
  111. *error = KCOMMAND_ERROR_ATTR_NAME;
  112. return BOOL_FALSE;
  113. } else {
  114. if (!kcommand_set_name(command, info->name)) {
  115. if (error)
  116. *error = KCOMMAND_ERROR_ATTR_NAME;
  117. return BOOL_FALSE;
  118. }
  119. }
  120. // Help
  121. if (!faux_str_is_empty(info->name)) {
  122. if (!kcommand_set_help(command, info->help)) {
  123. if (error)
  124. *error = KCOMMAND_ERROR_ATTR_HELP;
  125. return BOOL_FALSE;
  126. }
  127. }
  128. return BOOL_TRUE;
  129. }
  130. bool_t kcommand_nested_from_icommand(kcommand_t *kcommand, icommand_t *icommand,
  131. faux_error_t *error_stack)
  132. {
  133. bool_t retval = BOOL_TRUE;
  134. if (!kcommand || !icommand) {
  135. faux_error_add(error_stack,
  136. kcommand_strerror(KCOMMAND_ERROR_INTERNAL));
  137. return BOOL_FALSE;
  138. }
  139. // PARAM list
  140. if (icommand->params) {
  141. iparam_t **p_iparam = NULL;
  142. for (p_iparam = *icommand->params; *p_iparam; p_iparam++) {
  143. kparam_t *kparam = NULL;
  144. iparam_t *iparam = *p_iparam;
  145. kparam = kparam_from_iparam(iparam, error_stack);
  146. if (!kparam) {
  147. retval = BOOL_FALSE;
  148. continue;
  149. }
  150. if (!kcommand_add_param(kcommand, kparam)) {
  151. // Search for PARAM duplicates
  152. if (kcommand_find_param(kcommand,
  153. kparam_name(kparam))) {
  154. faux_error_sprintf(error_stack,
  155. "COMMAND: "
  156. "Can't add duplicate PARAM "
  157. "\"%s\"",
  158. kparam_name(kparam));
  159. } else {
  160. faux_error_sprintf(error_stack,
  161. "COMMAND: "
  162. "Can't add PARAM \"%s\"",
  163. kparam_name(kparam));
  164. }
  165. kparam_free(kparam);
  166. retval = BOOL_FALSE;
  167. continue;
  168. }
  169. }
  170. }
  171. // ACTION list
  172. if (icommand->actions) {
  173. iaction_t **p_iaction = NULL;
  174. for (p_iaction = *icommand->actions; *p_iaction; p_iaction++) {
  175. kaction_t *kaction = NULL;
  176. iaction_t *iaction = *p_iaction;
  177. kaction = kaction_from_iaction(iaction, error_stack);
  178. if (!kaction) {
  179. retval = BOOL_FALSE;
  180. continue;
  181. }
  182. if (!kcommand_add_action(kcommand, kaction)) {
  183. faux_error_sprintf(error_stack, "COMMAND: "
  184. "Can't add ACTION #%d",
  185. faux_list_len(kcommand->actions) + 1);
  186. kaction_free(kaction);
  187. retval = BOOL_FALSE;
  188. continue;
  189. }
  190. }
  191. }
  192. if (!retval)
  193. faux_error_sprintf(error_stack,
  194. "COMMAND \"%s\": Illegal nested elements",
  195. kcommand_name(kcommand));
  196. return retval;
  197. }
  198. kcommand_t *kcommand_from_icommand(icommand_t *icommand, faux_error_t *error_stack)
  199. {
  200. kcommand_t *kcommand = NULL;
  201. kcommand_error_e kcommand_error = KCOMMAND_ERROR_OK;
  202. kcommand = kcommand_new(icommand, &kcommand_error);
  203. if (!kcommand) {
  204. faux_error_sprintf(error_stack, "COMMAND \"%s\": %s",
  205. icommand->name ? icommand->name : "(null)",
  206. kcommand_strerror(kcommand_error));
  207. return NULL;
  208. }
  209. // Parse nested elements
  210. if (!kcommand_nested_from_icommand(kcommand, icommand, error_stack)) {
  211. kcommand_free(kcommand);
  212. return NULL;
  213. }
  214. return kcommand;
  215. }