]>
Commit | Line | Data |
---|---|---|
e27a3c88 KS |
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 |