kptype.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  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/kptype.h>
  10. #include <klish/kaction.h>
  11. struct kptype_s {
  12. char *name;
  13. char *help;
  14. faux_list_t *actions;
  15. };
  16. // Simple methods
  17. // Name
  18. KGET_STR(ptype, name);
  19. KSET_STR_ONCE(ptype, name);
  20. // Help
  21. KGET_STR(ptype, help);
  22. KSET_STR(ptype, help);
  23. // ACTION list
  24. KADD_NESTED(ptype, action);
  25. static kptype_t *kptype_new_empty(void)
  26. {
  27. kptype_t *ptype = NULL;
  28. ptype = faux_zmalloc(sizeof(*ptype));
  29. assert(ptype);
  30. if (!ptype)
  31. return NULL;
  32. // Initialize
  33. ptype->name = NULL;
  34. ptype->help = NULL;
  35. // ACTION list
  36. ptype->actions = faux_list_new(FAUX_LIST_UNSORTED, FAUX_LIST_NONUNIQUE,
  37. NULL, NULL, (void (*)(void *))kaction_free);
  38. assert(ptype->actions);
  39. return ptype;
  40. }
  41. kptype_t *kptype_new(const iptype_t *info, kptype_error_e *error)
  42. {
  43. kptype_t *ptype = NULL;
  44. ptype = kptype_new_empty();
  45. assert(ptype);
  46. if (!ptype) {
  47. if (error)
  48. *error = KPTYPE_ERROR_ALLOC;
  49. return NULL;
  50. }
  51. if (!info)
  52. return ptype;
  53. if (!kptype_parse(ptype, info, error)) {
  54. kptype_free(ptype);
  55. return NULL;
  56. }
  57. return ptype;
  58. }
  59. void kptype_free(kptype_t *ptype)
  60. {
  61. if (!ptype)
  62. return;
  63. faux_str_free(ptype->name);
  64. faux_str_free(ptype->help);
  65. faux_list_free(ptype->actions);
  66. faux_free(ptype);
  67. }
  68. const char *kptype_strerror(kptype_error_e error)
  69. {
  70. const char *str = NULL;
  71. switch (error) {
  72. case KPTYPE_ERROR_OK:
  73. str = "Ok";
  74. break;
  75. case KPTYPE_ERROR_INTERNAL:
  76. str = "Internal error";
  77. break;
  78. case KPTYPE_ERROR_ALLOC:
  79. str = "Memory allocation error";
  80. break;
  81. case KPTYPE_ERROR_ATTR_NAME:
  82. str = "Illegal 'name' attribute";
  83. break;
  84. case KPTYPE_ERROR_ATTR_HELP:
  85. str = "Illegal 'help' attribute";
  86. break;
  87. default:
  88. str = "Unknown error";
  89. break;
  90. }
  91. return str;
  92. }
  93. bool_t kptype_parse(kptype_t *ptype, const iptype_t *info, kptype_error_e *error)
  94. {
  95. // Name [mandatory]
  96. if (faux_str_is_empty(info->name)) {
  97. if (error)
  98. *error = KPTYPE_ERROR_ATTR_NAME;
  99. return BOOL_FALSE;
  100. } else {
  101. if (!kptype_set_name(ptype, info->name)) {
  102. if (error)
  103. *error = KPTYPE_ERROR_ATTR_NAME;
  104. return BOOL_FALSE;
  105. }
  106. }
  107. // Help
  108. if (!faux_str_is_empty(info->name)) {
  109. if (!kptype_set_help(ptype, info->help)) {
  110. if (error)
  111. *error = KPTYPE_ERROR_ATTR_HELP;
  112. return BOOL_FALSE;
  113. }
  114. }
  115. return BOOL_TRUE;
  116. }
  117. bool_t kptype_nested_from_iptype(kptype_t *kptype, iptype_t *iptype,
  118. faux_error_t *error_stack)
  119. {
  120. bool_t retval = BOOL_TRUE;
  121. if (!kptype || !iptype) {
  122. faux_error_add(error_stack,
  123. kptype_strerror(KPTYPE_ERROR_INTERNAL));
  124. return BOOL_FALSE;
  125. }
  126. // ACTION list
  127. if (iptype->actions) {
  128. iaction_t **p_iaction = NULL;
  129. for (p_iaction = *iptype->actions; *p_iaction; p_iaction++) {
  130. kaction_t *kaction = NULL;
  131. iaction_t *iaction = *p_iaction;
  132. kaction = kaction_from_iaction(iaction, error_stack);
  133. if (!kaction) {
  134. retval = BOOL_FALSE;
  135. continue;
  136. }
  137. if (!kptype_add_action(kptype, kaction)) {
  138. faux_error_sprintf(error_stack, "PTYPE: "
  139. "Can't add ACTION #%d",
  140. faux_list_len(kptype->actions) + 1);
  141. kaction_free(kaction);
  142. retval = BOOL_FALSE;
  143. continue;
  144. }
  145. }
  146. }
  147. if (!retval)
  148. faux_error_sprintf(error_stack,
  149. "PTYPE \"%s\": Illegal nested elements",
  150. kptype_name(kptype));
  151. return retval;
  152. }
  153. kptype_t *kptype_from_iptype(iptype_t *iptype, faux_error_t *error_stack)
  154. {
  155. kptype_t *kptype = NULL;
  156. kptype_error_e kptype_error = KPTYPE_ERROR_OK;
  157. kptype = kptype_new(iptype, &kptype_error);
  158. if (!kptype) {
  159. faux_error_sprintf(error_stack, "PTYPE \"%s\": %s",
  160. iptype->name ? iptype->name : "(null)",
  161. kptype_strerror(kptype_error));
  162. return NULL;
  163. }
  164. // Parse nested elements
  165. if (!kptype_nested_from_iptype(kptype, iptype, error_stack)) {
  166. kptype_free(kptype);
  167. return NULL;
  168. }
  169. return kptype;
  170. }