]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/libyaml/src/dumper.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / libyaml / src / dumper.c
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