kscheme.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  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. char *msg = NULL;
  97. // Search for PTYPE duplicates
  98. if (kscheme_find_ptype(kscheme,
  99. kptype_name(kptype))) {
  100. msg = faux_str_sprintf("SCHEME: "
  101. "Can't add duplicate PTYPE "
  102. "\"%s\"",
  103. kptype_name(kptype));
  104. } else {
  105. msg = faux_str_sprintf("SCHEME: "
  106. "Can't add PTYPE \"%s\"",
  107. kptype_name(kptype));
  108. }
  109. faux_error_add(error_stack, msg);
  110. faux_str_free(msg);
  111. kptype_free(kptype);
  112. retval = BOOL_FALSE;
  113. }
  114. }
  115. }
  116. // VIEW list
  117. // VIEW entries can be duplicate. Duplicated entries will add nested
  118. // elements to existent VIEW. Also it can overwrite VIEW attributes.
  119. // So there is no special rule which attribute value will be "on top".
  120. // It's a random. Technically later VIEW entries will rewrite previous
  121. // values.
  122. if (ischeme->views) {
  123. iview_t **p_iview = NULL;
  124. for (p_iview = *ischeme->views; *p_iview; p_iview++) {
  125. kview_t *kview = NULL;
  126. iview_t *iview = *p_iview;
  127. const char *view_name = iview->name;
  128. if (view_name)
  129. kview = kscheme_find_view(kscheme, view_name);
  130. // VIEW already exists
  131. if (kview) {
  132. kview_error_e kview_error = KVIEW_ERROR_OK;
  133. if (!kview_parse(kview, iview, &kview_error)) {
  134. char *msg = faux_str_sprintf("VIEW \"%s\": %s",
  135. iview->name ? iview->name : "(null)",
  136. kview_strerror(kview_error));
  137. faux_error_add(error_stack, msg);
  138. faux_str_free(msg);
  139. retval = BOOL_FALSE;
  140. continue;
  141. }
  142. if (!kview_nested_from_iview(kview, iview,
  143. error_stack)) {
  144. retval = BOOL_FALSE;
  145. continue;
  146. }
  147. continue;
  148. }
  149. // New VIEW
  150. kview = kview_from_iview(iview, error_stack);
  151. if (!kview) {
  152. retval = BOOL_FALSE;
  153. continue;
  154. }
  155. if (!kscheme_add_view(kscheme, kview)) {
  156. char *msg = faux_str_sprintf("SCHEME: "
  157. "Can't add VIEW \"%s\"",
  158. kview_name(kview));
  159. faux_error_add(error_stack, msg);
  160. faux_str_free(msg);
  161. kview_free(kview);
  162. retval = BOOL_FALSE;
  163. continue;
  164. }
  165. }
  166. }
  167. if (!retval) {
  168. char *msg = NULL;
  169. msg = faux_str_sprintf("SCHEME: Illegal nested elements");
  170. faux_error_add(error_stack, msg);
  171. faux_str_free(msg);
  172. }
  173. return retval;
  174. }
  175. kscheme_t *kscheme_from_ischeme(ischeme_t *ischeme, faux_error_t *error_stack)
  176. {
  177. kscheme_t *kscheme = NULL;
  178. kscheme_error_e kscheme_error = KSCHEME_ERROR_OK;
  179. kscheme = kscheme_new(&kscheme_error);
  180. if (!kscheme) {
  181. char *msg = NULL;
  182. msg = faux_str_sprintf("SCHEME: %s",
  183. kscheme_strerror(kscheme_error));
  184. faux_error_add(error_stack, msg);
  185. faux_str_free(msg);
  186. return NULL;
  187. }
  188. // Parse nested elements
  189. if (!kscheme_nested_from_ischeme(kscheme, ischeme, error_stack)) {
  190. kscheme_free(kscheme);
  191. return NULL;
  192. }
  193. return kscheme;
  194. }