/src/libyaml/dumper.c

https://code.google.com/ · C · 394 lines · 251 code · 98 blank · 45 comment · 46 complexity · fc3b40e7be71bf6c15fc119275f1c13d MD5 · raw file

  1. #include "yaml_private.h"
  2. /*
  3. * API functions.
  4. */
  5. YAML_DECLARE(int)
  6. yaml_emitter_open(yaml_emitter_t *emitter);
  7. YAML_DECLARE(int)
  8. yaml_emitter_close(yaml_emitter_t *emitter);
  9. YAML_DECLARE(int)
  10. yaml_emitter_dump(yaml_emitter_t *emitter, yaml_document_t *document);
  11. /*
  12. * Clean up functions.
  13. */
  14. static void
  15. yaml_emitter_delete_document_and_anchors(yaml_emitter_t *emitter);
  16. /*
  17. * Anchor functions.
  18. */
  19. static void
  20. yaml_emitter_anchor_node(yaml_emitter_t *emitter, int index);
  21. static yaml_char_t *
  22. yaml_emitter_generate_anchor(yaml_emitter_t *emitter, int anchor_id);
  23. /*
  24. * Serialize functions.
  25. */
  26. static int
  27. yaml_emitter_dump_node(yaml_emitter_t *emitter, int index);
  28. static int
  29. yaml_emitter_dump_alias(yaml_emitter_t *emitter, yaml_char_t *anchor);
  30. static int
  31. yaml_emitter_dump_scalar(yaml_emitter_t *emitter, yaml_node_t *node,
  32. yaml_char_t *anchor);
  33. static int
  34. yaml_emitter_dump_sequence(yaml_emitter_t *emitter, yaml_node_t *node,
  35. yaml_char_t *anchor);
  36. static int
  37. yaml_emitter_dump_mapping(yaml_emitter_t *emitter, yaml_node_t *node,
  38. yaml_char_t *anchor);
  39. /*
  40. * Issue a STREAM-START event.
  41. */
  42. YAML_DECLARE(int)
  43. yaml_emitter_open(yaml_emitter_t *emitter)
  44. {
  45. yaml_event_t event;
  46. yaml_mark_t mark = { 0, 0, 0 };
  47. assert(emitter); /* Non-NULL emitter object is required. */
  48. assert(!emitter->opened); /* Emitter should not be opened yet. */
  49. STREAM_START_EVENT_INIT(event, YAML_ANY_ENCODING, mark, mark);
  50. if (!yaml_emitter_emit(emitter, &event)) {
  51. return 0;
  52. }
  53. emitter->opened = 1;
  54. return 1;
  55. }
  56. /*
  57. * Issue a STREAM-END event.
  58. */
  59. YAML_DECLARE(int)
  60. yaml_emitter_close(yaml_emitter_t *emitter)
  61. {
  62. yaml_event_t event;
  63. yaml_mark_t mark = { 0, 0, 0 };
  64. assert(emitter); /* Non-NULL emitter object is required. */
  65. assert(emitter->opened); /* Emitter should be opened. */
  66. if (emitter->closed) return 1;
  67. STREAM_END_EVENT_INIT(event, mark, mark);
  68. if (!yaml_emitter_emit(emitter, &event)) {
  69. return 0;
  70. }
  71. emitter->closed = 1;
  72. return 1;
  73. }
  74. /*
  75. * Dump a YAML document.
  76. */
  77. YAML_DECLARE(int)
  78. yaml_emitter_dump(yaml_emitter_t *emitter, yaml_document_t *document)
  79. {
  80. yaml_event_t event;
  81. yaml_mark_t mark = { 0, 0, 0 };
  82. assert(emitter); /* Non-NULL emitter object is required. */
  83. assert(document); /* Non-NULL emitter object is expected. */
  84. emitter->document = document;
  85. if (!emitter->opened) {
  86. if (!yaml_emitter_open(emitter)) goto error;
  87. }
  88. if (STACK_EMPTY(emitter, document->nodes)) {
  89. if (!yaml_emitter_close(emitter)) goto error;
  90. yaml_emitter_delete_document_and_anchors(emitter);
  91. return 1;
  92. }
  93. assert(emitter->opened); /* Emitter should be opened. */
  94. emitter->anchors = yaml_malloc(sizeof(*(emitter->anchors))
  95. * (document->nodes.top - document->nodes.start));
  96. if (!emitter->anchors) goto error;
  97. memset(emitter->anchors, 0, sizeof(*(emitter->anchors))
  98. * (document->nodes.top - document->nodes.start));
  99. DOCUMENT_START_EVENT_INIT(event, document->version_directive,
  100. document->tag_directives.start, document->tag_directives.end,
  101. document->start_implicit, mark, mark);
  102. if (!yaml_emitter_emit(emitter, &event)) goto error;
  103. yaml_emitter_anchor_node(emitter, 1);
  104. if (!yaml_emitter_dump_node(emitter, 1)) goto error;
  105. DOCUMENT_END_EVENT_INIT(event, document->end_implicit, mark, mark);
  106. if (!yaml_emitter_emit(emitter, &event)) goto error;
  107. yaml_emitter_delete_document_and_anchors(emitter);
  108. return 1;
  109. error:
  110. yaml_emitter_delete_document_and_anchors(emitter);
  111. return 0;
  112. }
  113. /*
  114. * Clean up the emitter object after a document is dumped.
  115. */
  116. static void
  117. yaml_emitter_delete_document_and_anchors(yaml_emitter_t *emitter)
  118. {
  119. int index;
  120. if (!emitter->anchors) {
  121. yaml_document_delete(emitter->document);
  122. emitter->document = NULL;
  123. return;
  124. }
  125. for (index = 0; emitter->document->nodes.start + index
  126. < emitter->document->nodes.top; index ++) {
  127. yaml_node_t node = emitter->document->nodes.start[index];
  128. if (!emitter->anchors[index].serialized) {
  129. yaml_free(node.tag);
  130. if (node.type == YAML_SCALAR_NODE) {
  131. yaml_free(node.data.scalar.value);
  132. }
  133. }
  134. if (node.type == YAML_SEQUENCE_NODE) {
  135. STACK_DEL(emitter, node.data.sequence.items);
  136. }
  137. if (node.type == YAML_MAPPING_NODE) {
  138. STACK_DEL(emitter, node.data.mapping.pairs);
  139. }
  140. }
  141. STACK_DEL(emitter, emitter->document->nodes);
  142. yaml_free(emitter->anchors);
  143. emitter->anchors = NULL;
  144. emitter->last_anchor_id = 0;
  145. emitter->document = NULL;
  146. }
  147. /*
  148. * Check the references of a node and assign the anchor id if needed.
  149. */
  150. static void
  151. yaml_emitter_anchor_node(yaml_emitter_t *emitter, int index)
  152. {
  153. yaml_node_t *node = emitter->document->nodes.start + index - 1;
  154. yaml_node_item_t *item;
  155. yaml_node_pair_t *pair;
  156. emitter->anchors[index-1].references ++;
  157. if (emitter->anchors[index-1].references == 1) {
  158. switch (node->type) {
  159. case YAML_SEQUENCE_NODE:
  160. for (item = node->data.sequence.items.start;
  161. item < node->data.sequence.items.top; item ++) {
  162. yaml_emitter_anchor_node(emitter, *item);
  163. }
  164. break;
  165. case YAML_MAPPING_NODE:
  166. for (pair = node->data.mapping.pairs.start;
  167. pair < node->data.mapping.pairs.top; pair ++) {
  168. yaml_emitter_anchor_node(emitter, pair->key);
  169. yaml_emitter_anchor_node(emitter, pair->value);
  170. }
  171. break;
  172. default:
  173. break;
  174. }
  175. }
  176. else if (emitter->anchors[index-1].references == 2) {
  177. emitter->anchors[index-1].anchor = (++ emitter->last_anchor_id);
  178. }
  179. }
  180. /*
  181. * Generate a textual representation for an anchor.
  182. */
  183. #define ANCHOR_TEMPLATE "id%03d"
  184. #define ANCHOR_TEMPLATE_LENGTH 16
  185. static yaml_char_t *
  186. yaml_emitter_generate_anchor(yaml_emitter_t *emitter, int anchor_id)
  187. {
  188. yaml_char_t *anchor = yaml_malloc(ANCHOR_TEMPLATE_LENGTH);
  189. if (!anchor) return NULL;
  190. sprintf((char *)anchor, ANCHOR_TEMPLATE, anchor_id);
  191. return anchor;
  192. }
  193. /*
  194. * Serialize a node.
  195. */
  196. static int
  197. yaml_emitter_dump_node(yaml_emitter_t *emitter, int index)
  198. {
  199. yaml_node_t *node = emitter->document->nodes.start + index - 1;
  200. int anchor_id = emitter->anchors[index-1].anchor;
  201. yaml_char_t *anchor = NULL;
  202. if (anchor_id) {
  203. anchor = yaml_emitter_generate_anchor(emitter, anchor_id);
  204. if (!anchor) return 0;
  205. }
  206. if (emitter->anchors[index-1].serialized) {
  207. return yaml_emitter_dump_alias(emitter, anchor);
  208. }
  209. emitter->anchors[index-1].serialized = 1;
  210. switch (node->type) {
  211. case YAML_SCALAR_NODE:
  212. return yaml_emitter_dump_scalar(emitter, node, anchor);
  213. case YAML_SEQUENCE_NODE:
  214. return yaml_emitter_dump_sequence(emitter, node, anchor);
  215. case YAML_MAPPING_NODE:
  216. return yaml_emitter_dump_mapping(emitter, node, anchor);
  217. default:
  218. assert(0); /* Could not happen. */
  219. break;
  220. }
  221. return 0; /* Could not happen. */
  222. }
  223. /*
  224. * Serialize an alias.
  225. */
  226. static int
  227. yaml_emitter_dump_alias(yaml_emitter_t *emitter, yaml_char_t *anchor)
  228. {
  229. yaml_event_t event;
  230. yaml_mark_t mark = { 0, 0, 0 };
  231. ALIAS_EVENT_INIT(event, anchor, mark, mark);
  232. return yaml_emitter_emit(emitter, &event);
  233. }
  234. /*
  235. * Serialize a scalar.
  236. */
  237. static int
  238. yaml_emitter_dump_scalar(yaml_emitter_t *emitter, yaml_node_t *node,
  239. yaml_char_t *anchor)
  240. {
  241. yaml_event_t event;
  242. yaml_mark_t mark = { 0, 0, 0 };
  243. int plain_implicit = (strcmp((char *)node->tag,
  244. YAML_DEFAULT_SCALAR_TAG) == 0);
  245. int quoted_implicit = (strcmp((char *)node->tag,
  246. YAML_DEFAULT_SCALAR_TAG) == 0);
  247. SCALAR_EVENT_INIT(event, anchor, node->tag, node->data.scalar.value,
  248. node->data.scalar.length, plain_implicit, quoted_implicit,
  249. node->data.scalar.style, mark, mark);
  250. return yaml_emitter_emit(emitter, &event);
  251. }
  252. /*
  253. * Serialize a sequence.
  254. */
  255. static int
  256. yaml_emitter_dump_sequence(yaml_emitter_t *emitter, yaml_node_t *node,
  257. yaml_char_t *anchor)
  258. {
  259. yaml_event_t event;
  260. yaml_mark_t mark = { 0, 0, 0 };
  261. int implicit = (strcmp((char *)node->tag, YAML_DEFAULT_SEQUENCE_TAG) == 0);
  262. yaml_node_item_t *item;
  263. SEQUENCE_START_EVENT_INIT(event, anchor, node->tag, implicit,
  264. node->data.sequence.style, mark, mark);
  265. if (!yaml_emitter_emit(emitter, &event)) return 0;
  266. for (item = node->data.sequence.items.start;
  267. item < node->data.sequence.items.top; item ++) {
  268. if (!yaml_emitter_dump_node(emitter, *item)) return 0;
  269. }
  270. SEQUENCE_END_EVENT_INIT(event, mark, mark);
  271. if (!yaml_emitter_emit(emitter, &event)) return 0;
  272. return 1;
  273. }
  274. /*
  275. * Serialize a mapping.
  276. */
  277. static int
  278. yaml_emitter_dump_mapping(yaml_emitter_t *emitter, yaml_node_t *node,
  279. yaml_char_t *anchor)
  280. {
  281. yaml_event_t event;
  282. yaml_mark_t mark = { 0, 0, 0 };
  283. int implicit = (strcmp((char *)node->tag, YAML_DEFAULT_MAPPING_TAG) == 0);
  284. yaml_node_pair_t *pair;
  285. MAPPING_START_EVENT_INIT(event, anchor, node->tag, implicit,
  286. node->data.mapping.style, mark, mark);
  287. if (!yaml_emitter_emit(emitter, &event)) return 0;
  288. for (pair = node->data.mapping.pairs.start;
  289. pair < node->data.mapping.pairs.top; pair ++) {
  290. if (!yaml_emitter_dump_node(emitter, pair->key)) return 0;
  291. if (!yaml_emitter_dump_node(emitter, pair->value)) return 0;
  292. }
  293. MAPPING_END_EVENT_INIT(event, mark, mark);
  294. if (!yaml_emitter_emit(emitter, &event)) return 0;
  295. return 1;
  296. }