kparam.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  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/kptype.h>
  9. #include <klish/kparam.h>
  10. struct kparam_s {
  11. char *name;
  12. char *help;
  13. char *ptype_ref; // Text reference to PTYPE
  14. kptype_t *ptype; // Resolved PARAM's PTYPE
  15. faux_list_t *params; // Nested parameters
  16. };
  17. // Simple methods
  18. // Name
  19. KGET_STR(param, name);
  20. KSET_STR_ONCE(param, name);
  21. // Help
  22. KGET_STR(param, help);
  23. KSET_STR(param, help);
  24. // PTYPE reference (must be resolved later)
  25. KGET_STR(param, ptype_ref);
  26. KSET_STR(param, ptype_ref);
  27. // PTYPE (resolved)
  28. KGET(param, kptype_t *, ptype);
  29. KSET(param, kptype_t *, ptype);
  30. // PARAM list
  31. static KCMP_NESTED(param, param, name);
  32. static KCMP_NESTED_BY_KEY(param, param, name);
  33. KADD_NESTED(param, param);
  34. KFIND_NESTED(param, param);
  35. static kparam_t *kparam_new_empty(void)
  36. {
  37. kparam_t *param = NULL;
  38. param = faux_zmalloc(sizeof(*param));
  39. assert(param);
  40. if (!param)
  41. return NULL;
  42. // Initialize
  43. param->name = NULL;
  44. param->help = NULL;
  45. param->ptype_ref = NULL;
  46. param->ptype = NULL;
  47. param->params = faux_list_new(FAUX_LIST_UNSORTED, FAUX_LIST_UNIQUE,
  48. kparam_param_compare, kparam_param_kcompare,
  49. (void (*)(void *))kparam_free);
  50. assert(param->params);
  51. return param;
  52. }
  53. kparam_t *kparam_new(const iparam_t *info, kparam_error_e *error)
  54. {
  55. kparam_t *param = NULL;
  56. param = kparam_new_empty();
  57. assert(param);
  58. if (!param) {
  59. if (error)
  60. *error = KPARAM_ERROR_ALLOC;
  61. return NULL;
  62. }
  63. if (!info)
  64. return param;
  65. if (!kparam_parse(param, info, error)) {
  66. kparam_free(param);
  67. return NULL;
  68. }
  69. return param;
  70. }
  71. void kparam_free(kparam_t *param)
  72. {
  73. if (!param)
  74. return;
  75. faux_str_free(param->name);
  76. faux_str_free(param->help);
  77. faux_str_free(param->ptype_ref);
  78. faux_list_free(param->params);
  79. faux_free(param);
  80. }
  81. const char *kparam_strerror(kparam_error_e error)
  82. {
  83. const char *str = NULL;
  84. switch (error) {
  85. case KPARAM_ERROR_OK:
  86. str = "Ok";
  87. break;
  88. case KPARAM_ERROR_INTERNAL:
  89. str = "Internal error";
  90. break;
  91. case KPARAM_ERROR_ALLOC:
  92. str = "Memory allocation error";
  93. break;
  94. case KPARAM_ERROR_ATTR_NAME:
  95. str = "Illegal 'name' attribute";
  96. break;
  97. case KPARAM_ERROR_ATTR_HELP:
  98. str = "Illegal 'help' attribute";
  99. break;
  100. case KPARAM_ERROR_ATTR_PTYPE:
  101. str = "Illegal 'ptype' attribute";
  102. break;
  103. default:
  104. str = "Unknown error";
  105. break;
  106. }
  107. return str;
  108. }
  109. bool_t kparam_parse(kparam_t *param, const iparam_t *info, kparam_error_e *error)
  110. {
  111. // Name [mandatory]
  112. if (faux_str_is_empty(info->name)) {
  113. if (error)
  114. *error = KPARAM_ERROR_ATTR_NAME;
  115. return BOOL_FALSE;
  116. } else {
  117. if (!kparam_set_name(param, info->name)) {
  118. if (error)
  119. *error = KPARAM_ERROR_ATTR_NAME;
  120. return BOOL_FALSE;
  121. }
  122. }
  123. // Help
  124. if (!faux_str_is_empty(info->name)) {
  125. if (!kparam_set_help(param, info->help)) {
  126. if (error)
  127. *error = KPARAM_ERROR_ATTR_HELP;
  128. return BOOL_FALSE;
  129. }
  130. }
  131. // PTYPE reference
  132. if (!faux_str_is_empty(info->ptype)) {
  133. if (!kparam_set_ptype_ref(param, info->ptype)) {
  134. if (error)
  135. *error = KPARAM_ERROR_ATTR_PTYPE;
  136. return BOOL_FALSE;
  137. }
  138. }
  139. return BOOL_TRUE;
  140. }
  141. bool_t kparam_nested_from_iparam(kparam_t *kparam, iparam_t *iparam,
  142. faux_error_t *error_stack)
  143. {
  144. bool_t retval = BOOL_TRUE;
  145. if (!kparam || !iparam) {
  146. faux_error_add(error_stack,
  147. kparam_strerror(KPARAM_ERROR_INTERNAL));
  148. return BOOL_FALSE;
  149. }
  150. // Nested PARAM list
  151. if (iparam->params) {
  152. iparam_t **p_iparam = NULL;
  153. for (p_iparam = *iparam->params; *p_iparam; p_iparam++) {
  154. kparam_t *nkparam = NULL;
  155. iparam_t *niparam = *p_iparam;
  156. nkparam = kparam_from_iparam(niparam, error_stack);
  157. if (!nkparam) {
  158. retval = BOOL_FALSE;
  159. continue;
  160. }
  161. if (!kparam_add_param(kparam, nkparam)) {
  162. // Search for PARAM duplicates
  163. if (kparam_find_param(kparam,
  164. kparam_name(nkparam))) {
  165. faux_error_sprintf(error_stack,
  166. "PARAM: "
  167. "Can't add duplicate PARAM "
  168. "\"%s\"",
  169. kparam_name(nkparam));
  170. } else {
  171. faux_error_sprintf(error_stack,
  172. "PARAM: "
  173. "Can't add PARAM \"%s\"",
  174. kparam_name(nkparam));
  175. }
  176. kparam_free(nkparam);
  177. retval = BOOL_FALSE;
  178. continue;
  179. }
  180. }
  181. }
  182. if (!retval)
  183. faux_error_sprintf(error_stack,
  184. "PARAM \"%s\": Illegal nested elements",
  185. kparam_name(kparam));
  186. return retval;
  187. }
  188. kparam_t *kparam_from_iparam(iparam_t *iparam, faux_error_t *error_stack)
  189. {
  190. kparam_t *kparam = NULL;
  191. kparam_error_e kparam_error = KPARAM_ERROR_OK;
  192. kparam = kparam_new(iparam, &kparam_error);
  193. if (!kparam) {
  194. faux_error_sprintf(error_stack, "PARAM \"%s\": %s",
  195. iparam->name ? iparam->name : "(null)",
  196. kparam_strerror(kparam_error));
  197. return NULL;
  198. }
  199. // Parse nested elements
  200. if (!kparam_nested_from_iparam(kparam, iparam, error_stack)) {
  201. kparam_free(kparam);
  202. return NULL;
  203. }
  204. return kparam;
  205. }