kscheme.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  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/kview.h>
  10. #include <klish/kscheme.h>
  11. struct kscheme_s {
  12. faux_list_t *ptypes;
  13. faux_list_t *views;
  14. };
  15. // Simple methods
  16. // PTYPE list
  17. KCMP_NESTED(scheme, ptype, name);
  18. KCMP_NESTED_BY_KEY(scheme, ptype, name);
  19. KADD_NESTED(scheme, ptype);
  20. KFIND_NESTED(scheme, ptype);
  21. // VIEW list
  22. KCMP_NESTED(scheme, view, name);
  23. KCMP_NESTED_BY_KEY(scheme, view, name);
  24. KADD_NESTED(scheme, view);
  25. KFIND_NESTED(scheme, view);
  26. kscheme_t *kscheme_new(kscheme_error_e *error)
  27. {
  28. kscheme_t *scheme = NULL;
  29. scheme = faux_zmalloc(sizeof(*scheme));
  30. assert(scheme);
  31. if (!scheme) {
  32. if (error)
  33. *error = KSCHEME_ERROR_ALLOC;
  34. return NULL;
  35. }
  36. // PTYPE list
  37. scheme->ptypes = faux_list_new(FAUX_LIST_SORTED, FAUX_LIST_UNIQUE,
  38. kscheme_ptype_compare, kscheme_ptype_kcompare,
  39. (void (*)(void *))kptype_free);
  40. assert(scheme->ptypes);
  41. // VIEW list
  42. scheme->views = faux_list_new(FAUX_LIST_SORTED, FAUX_LIST_UNIQUE,
  43. kscheme_view_compare, kscheme_view_kcompare,
  44. (void (*)(void *))kview_free);
  45. assert(scheme->views);
  46. return scheme;
  47. }
  48. void kscheme_free(kscheme_t *scheme)
  49. {
  50. if (!scheme)
  51. return;
  52. faux_list_free(scheme->ptypes);
  53. faux_list_free(scheme->views);
  54. faux_free(scheme);
  55. }
  56. const char *kscheme_strerror(kscheme_error_e error)
  57. {
  58. const char *str = NULL;
  59. switch (error) {
  60. case KSCHEME_ERROR_OK:
  61. str = "Ok";
  62. break;
  63. case KSCHEME_ERROR_INTERNAL:
  64. str = "Internal error";
  65. break;
  66. case KVIEW_ERROR_ALLOC:
  67. str = "Memory allocation error";
  68. break;
  69. default:
  70. str = "Unknown error";
  71. break;
  72. }
  73. return str;
  74. }
  75. bool_t kscheme_nested_from_ischeme(kscheme_t *kscheme, ischeme_t *ischeme,
  76. faux_error_t *error_stack)
  77. {
  78. bool_t retval = BOOL_TRUE;
  79. if (!kscheme || !ischeme) {
  80. faux_error_add(error_stack,
  81. kscheme_strerror(KSCHEME_ERROR_INTERNAL));
  82. return BOOL_FALSE;
  83. }
  84. // PTYPE list
  85. if (ischeme->ptypes) {
  86. iptype_t **p_iptype = NULL;
  87. for (p_iptype = *ischeme->ptypes; *p_iptype; p_iptype++) {
  88. kptype_t *kptype = NULL;
  89. iptype_t *iptype = *p_iptype;
  90. kptype = kptype_from_iptype(iptype, error_stack);
  91. if (!kptype) {
  92. retval = BOOL_FALSE; // Don't stop
  93. continue;
  94. }
  95. if (!kscheme_add_ptype(kscheme, kptype)) {
  96. // Search for PTYPE duplicates
  97. if (kscheme_find_ptype(kscheme,
  98. kptype_name(kptype))) {
  99. faux_error_sprintf(error_stack,
  100. "SCHEME: "
  101. "Can't add duplicate PTYPE "
  102. "\"%s\"",
  103. kptype_name(kptype));
  104. } else {
  105. faux_error_sprintf(error_stack,
  106. "SCHEME: "
  107. "Can't add PTYPE \"%s\"",
  108. kptype_name(kptype));
  109. }
  110. kptype_free(kptype);
  111. retval = BOOL_FALSE;
  112. }
  113. }
  114. }
  115. // VIEW list
  116. // VIEW entries can be duplicate. Duplicated entries will add nested
  117. // elements to existent VIEW. Also it can overwrite VIEW attributes.
  118. // So there is no special rule which attribute value will be "on top".
  119. // It's a random. Technically later VIEW entries will rewrite previous
  120. // values.
  121. if (ischeme->views) {
  122. iview_t **p_iview = NULL;
  123. for (p_iview = *ischeme->views; *p_iview; p_iview++) {
  124. kview_t *kview = NULL;
  125. iview_t *iview = *p_iview;
  126. const char *view_name = iview->name;
  127. if (view_name)
  128. kview = kscheme_find_view(kscheme, view_name);
  129. // VIEW already exists
  130. if (kview) {
  131. kview_error_e kview_error = KVIEW_ERROR_OK;
  132. if (!kview_parse(kview, iview, &kview_error)) {
  133. faux_error_sprintf(error_stack,
  134. "VIEW \"%s\": %s",
  135. iview->name ? iview->name : "(null)",
  136. kview_strerror(kview_error));
  137. retval = BOOL_FALSE;
  138. continue;
  139. }
  140. if (!kview_nested_from_iview(kview, iview,
  141. error_stack)) {
  142. retval = BOOL_FALSE;
  143. continue;
  144. }
  145. continue;
  146. }
  147. // New VIEW
  148. kview = kview_from_iview(iview, error_stack);
  149. if (!kview) {
  150. retval = BOOL_FALSE;
  151. continue;
  152. }
  153. if (!kscheme_add_view(kscheme, kview)) {
  154. faux_error_sprintf(error_stack,
  155. "SCHEME: "
  156. "Can't add VIEW \"%s\"",
  157. kview_name(kview));
  158. kview_free(kview);
  159. retval = BOOL_FALSE;
  160. continue;
  161. }
  162. }
  163. }
  164. if (!retval)
  165. faux_error_sprintf(error_stack, "SCHEME: Illegal nested elements");
  166. return retval;
  167. }
  168. kscheme_t *kscheme_from_ischeme(ischeme_t *ischeme, faux_error_t *error_stack)
  169. {
  170. kscheme_t *kscheme = NULL;
  171. kscheme_error_e kscheme_error = KSCHEME_ERROR_OK;
  172. kscheme = kscheme_new(&kscheme_error);
  173. if (!kscheme) {
  174. faux_error_sprintf(error_stack, "SCHEME: %s",
  175. kscheme_strerror(kscheme_error));
  176. return NULL;
  177. }
  178. // Parse nested elements
  179. if (!kscheme_nested_from_ischeme(kscheme, ischeme, error_stack)) {
  180. kscheme_free(kscheme);
  181. return NULL;
  182. }
  183. return kscheme;
  184. }