markup.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. /* vim: tabstop=4 shiftwidth=4 noexpandtab
  2. * This file is part of ToaruOS and is released under the terms
  3. * of the NCSA / University of Illinois License - see LICENSE.md
  4. * Copyright (C) 2018 K. Lange
  5. *
  6. * Markup parser.
  7. */
  8. #include <stdio.h>
  9. #include <toaru/markup.h>
  10. struct markup_state {
  11. int state;
  12. void * user;
  13. markup_callback_tag_open callback_tag_open;
  14. markup_callback_tag_close callback_tag_close;
  15. markup_callback_data callback_data;
  16. /* Private stuff */
  17. struct markup_tag tag;
  18. size_t len;
  19. char data[64];
  20. char * attr;
  21. };
  22. struct markup_state * markup_init(void * user, markup_callback_tag_open open, markup_callback_tag_close close, markup_callback_data data) {
  23. struct markup_state * out = malloc(sizeof(out));
  24. out->state = 0;
  25. out->user = user;
  26. out->len = 0;
  27. out->callback_tag_open = open;
  28. out->callback_tag_close = close;
  29. out->callback_data = data;
  30. return out;
  31. }
  32. static void _dump_buffer(struct markup_state * state) {
  33. if (state->len) {
  34. state->data[state->len] = '\0';
  35. state->callback_data(state, state->user, state->data);
  36. state->data[0] = '\0';
  37. state->len = 0;
  38. }
  39. }
  40. static void _finish_name(struct markup_state * state) {
  41. state->data[state->len] = '\0';
  42. state->tag.name = strdup(state->data);
  43. state->tag.options = hashmap_create(5);
  44. state->data[0] = '\0';
  45. state->len = 0;
  46. state->state = 2;
  47. }
  48. static void _finish_close(struct markup_state * state) {
  49. state->data[state->len] = '\0';
  50. state->callback_tag_close(state, state->user, state->data);
  51. state->data[0] = '\0';
  52. state->len = 0;
  53. state->state = 0;
  54. }
  55. static void _finish_tag(struct markup_state * state) {
  56. state->callback_tag_open(state, state->user, &state->tag);
  57. state->state = 0;
  58. }
  59. static void _finish_bare_attr(struct markup_state * state) {
  60. state->data[state->len] = '\0';
  61. hashmap_set(state->tag.options, state->data, strdup(state->data));
  62. state->data[0] = '\0';
  63. state->len = 0;
  64. }
  65. static void _finish_attr(struct markup_state * state) {
  66. state->data[state->len] = '\0';
  67. state->attr = strdup(state->data);
  68. state->data[0] = '\0';
  69. state->len = 0;
  70. state->state = 4;
  71. }
  72. static void _finish_attr_value(struct markup_state * state) {
  73. state->data[state->len] = '\0';
  74. hashmap_set(state->tag.options, state->attr, strdup(state->data));
  75. free(state->attr);
  76. state->data[0] = '\0';
  77. state->len = 0;
  78. state->state = 2;
  79. }
  80. int markup_free_tag(struct markup_tag * tag) {
  81. free(tag->name);
  82. list_t * keys = hashmap_keys(tag->options);
  83. if (keys->length) {
  84. foreach(node, keys) {
  85. free(hashmap_get(tag->options, node->value));
  86. }
  87. }
  88. list_free(keys);
  89. free(keys);
  90. hashmap_free(tag->options);
  91. return 0;
  92. }
  93. int markup_parse(struct markup_state * state, char c) {
  94. switch (state->state) {
  95. case 0: /* STATE_NORMAL */
  96. if (state->len == 63) {
  97. _dump_buffer(state);
  98. }
  99. switch (c) {
  100. case '<':
  101. _dump_buffer(state);
  102. state->state = 1;
  103. return 0;
  104. default:
  105. state->data[state->len] = c;
  106. state->len++;
  107. return 0;
  108. }
  109. break;
  110. case 1: /* STATE_TAG_OPEN */
  111. switch (c) {
  112. case '/':
  113. if (state->len) {
  114. fprintf(stderr, "syntax error\n");
  115. return 1;
  116. }
  117. state->state = 3; /* STATE_TAG_CLOSE */
  118. return 0;
  119. case '>':
  120. _finish_name(state);
  121. _finish_tag(state);
  122. return 0;
  123. case ' ':
  124. _finish_name(state);
  125. return 0;
  126. default:
  127. state->data[state->len] = c;
  128. state->len++;
  129. return 0;
  130. }
  131. break;
  132. case 2: /* STATE_TAG_ATTRIB */
  133. switch (c) {
  134. case ' ': /* attribute has no value, end it and append it with = self */
  135. _finish_bare_attr(state);
  136. return 0;
  137. case '>':
  138. _finish_bare_attr(state);
  139. _finish_tag(state);
  140. return 0;
  141. case '=': /* attribute has a value, go to next mode */
  142. _finish_attr(state);
  143. return 0;
  144. default:
  145. state->data[state->len] = c;
  146. state->len++;
  147. return 0;
  148. }
  149. return 0;
  150. case 3: /* STATE_TAG_CLOSE */
  151. switch (c) {
  152. case '>':
  153. _finish_close(state);
  154. return 0;
  155. default:
  156. state->data[state->len] = c;
  157. state->len++;
  158. return 0;
  159. }
  160. break;
  161. case 4: /* STATE_ATTR_VALUE */
  162. switch (c) {
  163. case ' ':
  164. _finish_attr_value(state);
  165. return 0;
  166. case '>':
  167. _finish_attr_value(state);
  168. _finish_tag(state);
  169. return 0;
  170. default:
  171. state->data[state->len] = c;
  172. state->len++;
  173. return 0;
  174. }
  175. break;
  176. default:
  177. fprintf(stderr, "parser in unknown state\n");
  178. return 1;
  179. }
  180. return 0;
  181. }
  182. int markup_finish(struct markup_state * state) {
  183. if (state->state != 0) {
  184. fprintf(stderr, "unexpected end of data\n");
  185. return 1;
  186. } else {
  187. _dump_buffer(state);
  188. free(state);
  189. return 0;
  190. }
  191. }