source: libyaml/trunk/src/dumper.c @ 272

Revision 272, 10.0 KB checked in by xi, 6 years ago (diff)

Tagged the 0.1.1 release (better later than never).

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