comparison yaml/src/dumper.c @ 1:4d89bd8a3f7f

yaml: import 0.1.5
author David Demelier <markand@malikania.fr>
date Wed, 24 Feb 2016 20:50:29 +0100
parents
children
comparison
equal deleted inserted replaced
0:0047655db1aa 1:4d89bd8a3f7f
1
2 #include "yaml_private.h"
3
4 /*
5 * API functions.
6 */
7
8 YAML_DECLARE(int)
9 yaml_emitter_open(yaml_emitter_t *emitter);
10
11 YAML_DECLARE(int)
12 yaml_emitter_close(yaml_emitter_t *emitter);
13
14 YAML_DECLARE(int)
15 yaml_emitter_dump(yaml_emitter_t *emitter, yaml_document_t *document);
16
17 /*
18 * Clean up functions.
19 */
20
21 static void
22 yaml_emitter_delete_document_and_anchors(yaml_emitter_t *emitter);
23
24 /*
25 * Anchor functions.
26 */
27
28 static void
29 yaml_emitter_anchor_node(yaml_emitter_t *emitter, int index);
30
31 static yaml_char_t *
32 yaml_emitter_generate_anchor(yaml_emitter_t *emitter, int anchor_id);
33
34
35 /*
36 * Serialize functions.
37 */
38
39 static int
40 yaml_emitter_dump_node(yaml_emitter_t *emitter, int index);
41
42 static int
43 yaml_emitter_dump_alias(yaml_emitter_t *emitter, yaml_char_t *anchor);
44
45 static int
46 yaml_emitter_dump_scalar(yaml_emitter_t *emitter, yaml_node_t *node,
47 yaml_char_t *anchor);
48
49 static int
50 yaml_emitter_dump_sequence(yaml_emitter_t *emitter, yaml_node_t *node,
51 yaml_char_t *anchor);
52
53 static int
54 yaml_emitter_dump_mapping(yaml_emitter_t *emitter, yaml_node_t *node,
55 yaml_char_t *anchor);
56
57 /*
58 * Issue a STREAM-START event.
59 */
60
61 YAML_DECLARE(int)
62 yaml_emitter_open(yaml_emitter_t *emitter)
63 {
64 yaml_event_t event;
65 yaml_mark_t mark = { 0, 0, 0 };
66
67 assert(emitter); /* Non-NULL emitter object is required. */
68 assert(!emitter->opened); /* Emitter should not be opened yet. */
69
70 STREAM_START_EVENT_INIT(event, YAML_ANY_ENCODING, mark, mark);
71
72 if (!yaml_emitter_emit(emitter, &event)) {
73 return 0;
74 }
75
76 emitter->opened = 1;
77
78 return 1;
79 }
80
81 /*
82 * Issue a STREAM-END event.
83 */
84
85 YAML_DECLARE(int)
86 yaml_emitter_close(yaml_emitter_t *emitter)
87 {
88 yaml_event_t event;
89 yaml_mark_t mark = { 0, 0, 0 };
90
91 assert(emitter); /* Non-NULL emitter object is required. */
92 assert(emitter->opened); /* Emitter should be opened. */
93
94 if (emitter->closed) return 1;
95
96 STREAM_END_EVENT_INIT(event, mark, mark);
97
98 if (!yaml_emitter_emit(emitter, &event)) {
99 return 0;
100 }
101
102 emitter->closed = 1;
103
104 return 1;
105 }
106
107 /*
108 * Dump a YAML document.
109 */
110
111 YAML_DECLARE(int)
112 yaml_emitter_dump(yaml_emitter_t *emitter, yaml_document_t *document)
113 {
114 yaml_event_t event;
115 yaml_mark_t mark = { 0, 0, 0 };
116
117 assert(emitter); /* Non-NULL emitter object is required. */
118 assert(document); /* Non-NULL emitter object is expected. */
119
120 emitter->document = document;
121
122 if (!emitter->opened) {
123 if (!yaml_emitter_open(emitter)) goto error;
124 }
125
126 if (STACK_EMPTY(emitter, document->nodes)) {
127 if (!yaml_emitter_close(emitter)) goto error;
128 yaml_emitter_delete_document_and_anchors(emitter);
129 return 1;
130 }
131
132 assert(emitter->opened); /* Emitter should be opened. */
133
134 emitter->anchors = yaml_malloc(sizeof(*(emitter->anchors))
135 * (document->nodes.top - document->nodes.start));
136 if (!emitter->anchors) goto error;
137 memset(emitter->anchors, 0, sizeof(*(emitter->anchors))
138 * (document->nodes.top - document->nodes.start));
139
140 DOCUMENT_START_EVENT_INIT(event, document->version_directive,
141 document->tag_directives.start, document->tag_directives.end,
142 document->start_implicit, mark, mark);
143 if (!yaml_emitter_emit(emitter, &event)) goto error;
144
145 yaml_emitter_anchor_node(emitter, 1);
146 if (!yaml_emitter_dump_node(emitter, 1)) goto error;
147
148 DOCUMENT_END_EVENT_INIT(event, document->end_implicit, mark, mark);
149 if (!yaml_emitter_emit(emitter, &event)) goto error;
150
151 yaml_emitter_delete_document_and_anchors(emitter);
152
153 return 1;
154
155 error:
156
157 yaml_emitter_delete_document_and_anchors(emitter);
158
159 return 0;
160 }
161
162 /*
163 * Clean up the emitter object after a document is dumped.
164 */
165
166 static void
167 yaml_emitter_delete_document_and_anchors(yaml_emitter_t *emitter)
168 {
169 int index;
170
171 if (!emitter->anchors) {
172 yaml_document_delete(emitter->document);
173 emitter->document = NULL;
174 return;
175 }
176
177 for (index = 0; emitter->document->nodes.start + index
178 < emitter->document->nodes.top; index ++) {
179 yaml_node_t node = emitter->document->nodes.start[index];
180 if (!emitter->anchors[index].serialized) {
181 yaml_free(node.tag);
182 if (node.type == YAML_SCALAR_NODE) {
183 yaml_free(node.data.scalar.value);
184 }
185 }
186 if (node.type == YAML_SEQUENCE_NODE) {
187 STACK_DEL(emitter, node.data.sequence.items);
188 }
189 if (node.type == YAML_MAPPING_NODE) {
190 STACK_DEL(emitter, node.data.mapping.pairs);
191 }
192 }
193
194 STACK_DEL(emitter, emitter->document->nodes);
195 yaml_free(emitter->anchors);
196
197 emitter->anchors = NULL;
198 emitter->last_anchor_id = 0;
199 emitter->document = NULL;
200 }
201
202 /*
203 * Check the references of a node and assign the anchor id if needed.
204 */
205
206 static void
207 yaml_emitter_anchor_node(yaml_emitter_t *emitter, int index)
208 {
209 yaml_node_t *node = emitter->document->nodes.start + index - 1;
210 yaml_node_item_t *item;
211 yaml_node_pair_t *pair;
212
213 emitter->anchors[index-1].references ++;
214
215 if (emitter->anchors[index-1].references == 1) {
216 switch (node->type) {
217 case YAML_SEQUENCE_NODE:
218 for (item = node->data.sequence.items.start;
219 item < node->data.sequence.items.top; item ++) {
220 yaml_emitter_anchor_node(emitter, *item);
221 }
222 break;
223 case YAML_MAPPING_NODE:
224 for (pair = node->data.mapping.pairs.start;
225 pair < node->data.mapping.pairs.top; pair ++) {
226 yaml_emitter_anchor_node(emitter, pair->key);
227 yaml_emitter_anchor_node(emitter, pair->value);
228 }
229 break;
230 default:
231 break;
232 }
233 }
234
235 else if (emitter->anchors[index-1].references == 2) {
236 emitter->anchors[index-1].anchor = (++ emitter->last_anchor_id);
237 }
238 }
239
240 /*
241 * Generate a textual representation for an anchor.
242 */
243
244 #define ANCHOR_TEMPLATE "id%03d"
245 #define ANCHOR_TEMPLATE_LENGTH 16
246
247 static yaml_char_t *
248 yaml_emitter_generate_anchor(yaml_emitter_t *emitter, int anchor_id)
249 {
250 yaml_char_t *anchor = yaml_malloc(ANCHOR_TEMPLATE_LENGTH);
251
252 if (!anchor) return NULL;
253
254 sprintf((char *)anchor, ANCHOR_TEMPLATE, anchor_id);
255
256 return anchor;
257 }
258
259 /*
260 * Serialize a node.
261 */
262
263 static int
264 yaml_emitter_dump_node(yaml_emitter_t *emitter, int index)
265 {
266 yaml_node_t *node = emitter->document->nodes.start + index - 1;
267 int anchor_id = emitter->anchors[index-1].anchor;
268 yaml_char_t *anchor = NULL;
269
270 if (anchor_id) {
271 anchor = yaml_emitter_generate_anchor(emitter, anchor_id);
272 if (!anchor) return 0;
273 }
274
275 if (emitter->anchors[index-1].serialized) {
276 return yaml_emitter_dump_alias(emitter, anchor);
277 }
278
279 emitter->anchors[index-1].serialized = 1;
280
281 switch (node->type) {
282 case YAML_SCALAR_NODE:
283 return yaml_emitter_dump_scalar(emitter, node, anchor);
284 case YAML_SEQUENCE_NODE:
285 return yaml_emitter_dump_sequence(emitter, node, anchor);
286 case YAML_MAPPING_NODE:
287 return yaml_emitter_dump_mapping(emitter, node, anchor);
288 default:
289 assert(0); /* Could not happen. */
290 break;
291 }
292
293 return 0; /* Could not happen. */
294 }
295
296 /*
297 * Serialize an alias.
298 */
299
300 static int
301 yaml_emitter_dump_alias(yaml_emitter_t *emitter, yaml_char_t *anchor)
302 {
303 yaml_event_t event;
304 yaml_mark_t mark = { 0, 0, 0 };
305
306 ALIAS_EVENT_INIT(event, anchor, mark, mark);
307
308 return yaml_emitter_emit(emitter, &event);
309 }
310
311 /*
312 * Serialize a scalar.
313 */
314
315 static int
316 yaml_emitter_dump_scalar(yaml_emitter_t *emitter, yaml_node_t *node,
317 yaml_char_t *anchor)
318 {
319 yaml_event_t event;
320 yaml_mark_t mark = { 0, 0, 0 };
321
322 int plain_implicit = (strcmp((char *)node->tag,
323 YAML_DEFAULT_SCALAR_TAG) == 0);
324 int quoted_implicit = (strcmp((char *)node->tag,
325 YAML_DEFAULT_SCALAR_TAG) == 0);
326
327 SCALAR_EVENT_INIT(event, anchor, node->tag, node->data.scalar.value,
328 node->data.scalar.length, plain_implicit, quoted_implicit,
329 node->data.scalar.style, mark, mark);
330
331 return yaml_emitter_emit(emitter, &event);
332 }
333
334 /*
335 * Serialize a sequence.
336 */
337
338 static int
339 yaml_emitter_dump_sequence(yaml_emitter_t *emitter, yaml_node_t *node,
340 yaml_char_t *anchor)
341 {
342 yaml_event_t event;
343 yaml_mark_t mark = { 0, 0, 0 };
344
345 int implicit = (strcmp((char *)node->tag, YAML_DEFAULT_SEQUENCE_TAG) == 0);
346
347 yaml_node_item_t *item;
348
349 SEQUENCE_START_EVENT_INIT(event, anchor, node->tag, implicit,
350 node->data.sequence.style, mark, mark);
351 if (!yaml_emitter_emit(emitter, &event)) return 0;
352
353 for (item = node->data.sequence.items.start;
354 item < node->data.sequence.items.top; item ++) {
355 if (!yaml_emitter_dump_node(emitter, *item)) return 0;
356 }
357
358 SEQUENCE_END_EVENT_INIT(event, mark, mark);
359 if (!yaml_emitter_emit(emitter, &event)) return 0;
360
361 return 1;
362 }
363
364 /*
365 * Serialize a mapping.
366 */
367
368 static int
369 yaml_emitter_dump_mapping(yaml_emitter_t *emitter, yaml_node_t *node,
370 yaml_char_t *anchor)
371 {
372 yaml_event_t event;
373 yaml_mark_t mark = { 0, 0, 0 };
374
375 int implicit = (strcmp((char *)node->tag, YAML_DEFAULT_MAPPING_TAG) == 0);
376
377 yaml_node_pair_t *pair;
378
379 MAPPING_START_EVENT_INIT(event, anchor, node->tag, implicit,
380 node->data.mapping.style, mark, mark);
381 if (!yaml_emitter_emit(emitter, &event)) return 0;
382
383 for (pair = node->data.mapping.pairs.start;
384 pair < node->data.mapping.pairs.top; pair ++) {
385 if (!yaml_emitter_dump_node(emitter, pair->key)) return 0;
386 if (!yaml_emitter_dump_node(emitter, pair->value)) return 0;
387 }
388
389 MAPPING_END_EVENT_INIT(event, mark, mark);
390 if (!yaml_emitter_emit(emitter, &event)) return 0;
391
392 return 1;
393 }
394