Mercurial > embed
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 |