1247738Sbapt
2247738Sbapt#include "yaml_private.h"
3247738Sbapt
4247738Sbapt/*
5247738Sbapt * API functions.
6247738Sbapt */
7247738Sbapt
8247738SbaptYAML_DECLARE(int)
9247738Sbaptyaml_emitter_open(yaml_emitter_t *emitter);
10247738Sbapt
11247738SbaptYAML_DECLARE(int)
12247738Sbaptyaml_emitter_close(yaml_emitter_t *emitter);
13247738Sbapt
14247738SbaptYAML_DECLARE(int)
15247738Sbaptyaml_emitter_dump(yaml_emitter_t *emitter, yaml_document_t *document);
16247738Sbapt
17247738Sbapt/*
18247738Sbapt * Clean up functions.
19247738Sbapt */
20247738Sbapt
21247738Sbaptstatic void
22247738Sbaptyaml_emitter_delete_document_and_anchors(yaml_emitter_t *emitter);
23247738Sbapt
24247738Sbapt/*
25247738Sbapt * Anchor functions.
26247738Sbapt */
27247738Sbapt
28247738Sbaptstatic void
29247738Sbaptyaml_emitter_anchor_node(yaml_emitter_t *emitter, int index);
30247738Sbapt
31247738Sbaptstatic yaml_char_t *
32247738Sbaptyaml_emitter_generate_anchor(yaml_emitter_t *emitter, int anchor_id);
33247738Sbapt
34247738Sbapt
35247738Sbapt/*
36247738Sbapt * Serialize functions.
37247738Sbapt */
38247738Sbapt
39247738Sbaptstatic int
40247738Sbaptyaml_emitter_dump_node(yaml_emitter_t *emitter, int index);
41247738Sbapt
42247738Sbaptstatic int
43247738Sbaptyaml_emitter_dump_alias(yaml_emitter_t *emitter, yaml_char_t *anchor);
44247738Sbapt
45247738Sbaptstatic int
46247738Sbaptyaml_emitter_dump_scalar(yaml_emitter_t *emitter, yaml_node_t *node,
47247738Sbapt        yaml_char_t *anchor);
48247738Sbapt
49247738Sbaptstatic int
50247738Sbaptyaml_emitter_dump_sequence(yaml_emitter_t *emitter, yaml_node_t *node,
51247738Sbapt        yaml_char_t *anchor);
52247738Sbapt
53247738Sbaptstatic int
54247738Sbaptyaml_emitter_dump_mapping(yaml_emitter_t *emitter, yaml_node_t *node,
55247738Sbapt        yaml_char_t *anchor);
56247738Sbapt
57247738Sbapt/*
58247738Sbapt * Issue a STREAM-START event.
59247738Sbapt */
60247738Sbapt
61247738SbaptYAML_DECLARE(int)
62247738Sbaptyaml_emitter_open(yaml_emitter_t *emitter)
63247738Sbapt{
64247738Sbapt    yaml_event_t event;
65247738Sbapt    yaml_mark_t mark = { 0, 0, 0 };
66247738Sbapt
67247738Sbapt    assert(emitter);            /* Non-NULL emitter object is required. */
68247738Sbapt    assert(!emitter->opened);   /* Emitter should not be opened yet. */
69247738Sbapt
70247738Sbapt    STREAM_START_EVENT_INIT(event, YAML_ANY_ENCODING, mark, mark);
71247738Sbapt
72247738Sbapt    if (!yaml_emitter_emit(emitter, &event)) {
73247738Sbapt        return 0;
74247738Sbapt    }
75247738Sbapt
76247738Sbapt    emitter->opened = 1;
77247738Sbapt
78247738Sbapt    return 1;
79247738Sbapt}
80247738Sbapt
81247738Sbapt/*
82247738Sbapt * Issue a STREAM-END event.
83247738Sbapt */
84247738Sbapt
85247738SbaptYAML_DECLARE(int)
86247738Sbaptyaml_emitter_close(yaml_emitter_t *emitter)
87247738Sbapt{
88247738Sbapt    yaml_event_t event;
89247738Sbapt    yaml_mark_t mark = { 0, 0, 0 };
90247738Sbapt
91247738Sbapt    assert(emitter);            /* Non-NULL emitter object is required. */
92247738Sbapt    assert(emitter->opened);    /* Emitter should be opened. */
93247738Sbapt
94247738Sbapt    if (emitter->closed) return 1;
95247738Sbapt
96247738Sbapt    STREAM_END_EVENT_INIT(event, mark, mark);
97247738Sbapt
98247738Sbapt    if (!yaml_emitter_emit(emitter, &event)) {
99247738Sbapt        return 0;
100247738Sbapt    }
101247738Sbapt
102247738Sbapt    emitter->closed = 1;
103247738Sbapt
104247738Sbapt    return 1;
105247738Sbapt}
106247738Sbapt
107247738Sbapt/*
108247738Sbapt * Dump a YAML document.
109247738Sbapt */
110247738Sbapt
111247738SbaptYAML_DECLARE(int)
112247738Sbaptyaml_emitter_dump(yaml_emitter_t *emitter, yaml_document_t *document)
113247738Sbapt{
114247738Sbapt    yaml_event_t event;
115247738Sbapt    yaml_mark_t mark = { 0, 0, 0 };
116247738Sbapt
117247738Sbapt    assert(emitter);            /* Non-NULL emitter object is required. */
118247738Sbapt    assert(document);           /* Non-NULL emitter object is expected. */
119247738Sbapt
120247738Sbapt    emitter->document = document;
121247738Sbapt
122247738Sbapt    if (!emitter->opened) {
123247738Sbapt        if (!yaml_emitter_open(emitter)) goto error;
124247738Sbapt    }
125247738Sbapt
126247738Sbapt    if (STACK_EMPTY(emitter, document->nodes)) {
127247738Sbapt        if (!yaml_emitter_close(emitter)) goto error;
128247738Sbapt        yaml_emitter_delete_document_and_anchors(emitter);
129247738Sbapt        return 1;
130247738Sbapt    }
131247738Sbapt
132247738Sbapt    assert(emitter->opened);    /* Emitter should be opened. */
133247738Sbapt
134247738Sbapt    emitter->anchors = yaml_malloc(sizeof(*(emitter->anchors))
135247738Sbapt            * (document->nodes.top - document->nodes.start));
136247738Sbapt    if (!emitter->anchors) goto error;
137247738Sbapt    memset(emitter->anchors, 0, sizeof(*(emitter->anchors))
138247738Sbapt            * (document->nodes.top - document->nodes.start));
139247738Sbapt
140247738Sbapt    DOCUMENT_START_EVENT_INIT(event, document->version_directive,
141247738Sbapt            document->tag_directives.start, document->tag_directives.end,
142247738Sbapt            document->start_implicit, mark, mark);
143247738Sbapt    if (!yaml_emitter_emit(emitter, &event)) goto error;
144247738Sbapt
145247738Sbapt    yaml_emitter_anchor_node(emitter, 1);
146247738Sbapt    if (!yaml_emitter_dump_node(emitter, 1)) goto error;
147247738Sbapt
148247738Sbapt    DOCUMENT_END_EVENT_INIT(event, document->end_implicit, mark, mark);
149247738Sbapt    if (!yaml_emitter_emit(emitter, &event)) goto error;
150247738Sbapt
151247738Sbapt    yaml_emitter_delete_document_and_anchors(emitter);
152247738Sbapt
153247738Sbapt    return 1;
154247738Sbapt
155247738Sbapterror:
156247738Sbapt
157247738Sbapt    yaml_emitter_delete_document_and_anchors(emitter);
158247738Sbapt
159247738Sbapt    return 0;
160247738Sbapt}
161247738Sbapt
162247738Sbapt/*
163247738Sbapt * Clean up the emitter object after a document is dumped.
164247738Sbapt */
165247738Sbapt
166247738Sbaptstatic void
167247738Sbaptyaml_emitter_delete_document_and_anchors(yaml_emitter_t *emitter)
168247738Sbapt{
169247738Sbapt    int index;
170247738Sbapt
171247738Sbapt    if (!emitter->anchors) {
172247738Sbapt        yaml_document_delete(emitter->document);
173247738Sbapt        emitter->document = NULL;
174247738Sbapt        return;
175247738Sbapt    }
176247738Sbapt
177247738Sbapt    for (index = 0; emitter->document->nodes.start + index
178247738Sbapt            < emitter->document->nodes.top; index ++) {
179247738Sbapt        yaml_node_t node = emitter->document->nodes.start[index];
180247738Sbapt        if (!emitter->anchors[index].serialized) {
181247738Sbapt            yaml_free(node.tag);
182247738Sbapt            if (node.type == YAML_SCALAR_NODE) {
183247738Sbapt                yaml_free(node.data.scalar.value);
184247738Sbapt            }
185247738Sbapt        }
186247738Sbapt        if (node.type == YAML_SEQUENCE_NODE) {
187247738Sbapt            STACK_DEL(emitter, node.data.sequence.items);
188247738Sbapt        }
189247738Sbapt        if (node.type == YAML_MAPPING_NODE) {
190247738Sbapt            STACK_DEL(emitter, node.data.mapping.pairs);
191247738Sbapt        }
192247738Sbapt    }
193247738Sbapt
194247738Sbapt    STACK_DEL(emitter, emitter->document->nodes);
195247738Sbapt    yaml_free(emitter->anchors);
196247738Sbapt
197247738Sbapt    emitter->anchors = NULL;
198247738Sbapt    emitter->last_anchor_id = 0;
199247738Sbapt    emitter->document = NULL;
200247738Sbapt}
201247738Sbapt
202247738Sbapt/*
203247738Sbapt * Check the references of a node and assign the anchor id if needed.
204247738Sbapt */
205247738Sbapt
206247738Sbaptstatic void
207247738Sbaptyaml_emitter_anchor_node(yaml_emitter_t *emitter, int index)
208247738Sbapt{
209247738Sbapt    yaml_node_t *node = emitter->document->nodes.start + index - 1;
210247738Sbapt    yaml_node_item_t *item;
211247738Sbapt    yaml_node_pair_t *pair;
212247738Sbapt
213247738Sbapt    emitter->anchors[index-1].references ++;
214247738Sbapt
215247738Sbapt    if (emitter->anchors[index-1].references == 1) {
216247738Sbapt        switch (node->type) {
217247738Sbapt            case YAML_SEQUENCE_NODE:
218247738Sbapt                for (item = node->data.sequence.items.start;
219247738Sbapt                        item < node->data.sequence.items.top; item ++) {
220247738Sbapt                    yaml_emitter_anchor_node(emitter, *item);
221247738Sbapt                }
222247738Sbapt                break;
223247738Sbapt            case YAML_MAPPING_NODE:
224247738Sbapt                for (pair = node->data.mapping.pairs.start;
225247738Sbapt                        pair < node->data.mapping.pairs.top; pair ++) {
226247738Sbapt                    yaml_emitter_anchor_node(emitter, pair->key);
227247738Sbapt                    yaml_emitter_anchor_node(emitter, pair->value);
228247738Sbapt                }
229247738Sbapt                break;
230247738Sbapt            default:
231247738Sbapt                break;
232247738Sbapt        }
233247738Sbapt    }
234247738Sbapt
235247738Sbapt    else if (emitter->anchors[index-1].references == 2) {
236247738Sbapt        emitter->anchors[index-1].anchor = (++ emitter->last_anchor_id);
237247738Sbapt    }
238247738Sbapt}
239247738Sbapt
240247738Sbapt/*
241247738Sbapt * Generate a textual representation for an anchor.
242247738Sbapt */
243247738Sbapt
244247738Sbapt#define ANCHOR_TEMPLATE         "id%03d"
245247738Sbapt#define ANCHOR_TEMPLATE_LENGTH  16
246247738Sbapt
247247738Sbaptstatic yaml_char_t *
248247738Sbaptyaml_emitter_generate_anchor(yaml_emitter_t *emitter, int anchor_id)
249247738Sbapt{
250247738Sbapt    yaml_char_t *anchor = yaml_malloc(ANCHOR_TEMPLATE_LENGTH);
251247738Sbapt
252247738Sbapt    if (!anchor) return NULL;
253247738Sbapt
254247738Sbapt    sprintf((char *)anchor, ANCHOR_TEMPLATE, anchor_id);
255247738Sbapt
256247738Sbapt    return anchor;
257247738Sbapt}
258247738Sbapt
259247738Sbapt/*
260247738Sbapt * Serialize a node.
261247738Sbapt */
262247738Sbapt
263247738Sbaptstatic int
264247738Sbaptyaml_emitter_dump_node(yaml_emitter_t *emitter, int index)
265247738Sbapt{
266247738Sbapt    yaml_node_t *node = emitter->document->nodes.start + index - 1;
267247738Sbapt    int anchor_id = emitter->anchors[index-1].anchor;
268247738Sbapt    yaml_char_t *anchor = NULL;
269247738Sbapt
270247738Sbapt    if (anchor_id) {
271247738Sbapt        anchor = yaml_emitter_generate_anchor(emitter, anchor_id);
272247738Sbapt        if (!anchor) return 0;
273247738Sbapt    }
274247738Sbapt
275247738Sbapt    if (emitter->anchors[index-1].serialized) {
276247738Sbapt        return yaml_emitter_dump_alias(emitter, anchor);
277247738Sbapt    }
278247738Sbapt
279247738Sbapt    emitter->anchors[index-1].serialized = 1;
280247738Sbapt
281247738Sbapt    switch (node->type) {
282247738Sbapt        case YAML_SCALAR_NODE:
283247738Sbapt            return yaml_emitter_dump_scalar(emitter, node, anchor);
284247738Sbapt        case YAML_SEQUENCE_NODE:
285247738Sbapt            return yaml_emitter_dump_sequence(emitter, node, anchor);
286247738Sbapt        case YAML_MAPPING_NODE:
287247738Sbapt            return yaml_emitter_dump_mapping(emitter, node, anchor);
288247738Sbapt        default:
289247738Sbapt            assert(0);      /* Could not happen. */
290247738Sbapt            break;
291247738Sbapt    }
292247738Sbapt
293247738Sbapt    return 0;       /* Could not happen. */
294247738Sbapt}
295247738Sbapt
296247738Sbapt/*
297247738Sbapt * Serialize an alias.
298247738Sbapt */
299247738Sbapt
300247738Sbaptstatic int
301247738Sbaptyaml_emitter_dump_alias(yaml_emitter_t *emitter, yaml_char_t *anchor)
302247738Sbapt{
303247738Sbapt    yaml_event_t event;
304247738Sbapt    yaml_mark_t mark  = { 0, 0, 0 };
305247738Sbapt
306247738Sbapt    ALIAS_EVENT_INIT(event, anchor, mark, mark);
307247738Sbapt
308247738Sbapt    return yaml_emitter_emit(emitter, &event);
309247738Sbapt}
310247738Sbapt
311247738Sbapt/*
312247738Sbapt * Serialize a scalar.
313247738Sbapt */
314247738Sbapt
315247738Sbaptstatic int
316247738Sbaptyaml_emitter_dump_scalar(yaml_emitter_t *emitter, yaml_node_t *node,
317247738Sbapt        yaml_char_t *anchor)
318247738Sbapt{
319247738Sbapt    yaml_event_t event;
320247738Sbapt    yaml_mark_t mark  = { 0, 0, 0 };
321247738Sbapt
322247738Sbapt    int plain_implicit = (strcmp((char *)node->tag,
323247738Sbapt                YAML_DEFAULT_SCALAR_TAG) == 0);
324247738Sbapt    int quoted_implicit = (strcmp((char *)node->tag,
325247738Sbapt                YAML_DEFAULT_SCALAR_TAG) == 0);
326247738Sbapt
327247738Sbapt    SCALAR_EVENT_INIT(event, anchor, node->tag, node->data.scalar.value,
328247738Sbapt            node->data.scalar.length, plain_implicit, quoted_implicit,
329247738Sbapt            node->data.scalar.style, mark, mark);
330247738Sbapt
331247738Sbapt    return yaml_emitter_emit(emitter, &event);
332247738Sbapt}
333247738Sbapt
334247738Sbapt/*
335247738Sbapt * Serialize a sequence.
336247738Sbapt */
337247738Sbapt
338247738Sbaptstatic int
339247738Sbaptyaml_emitter_dump_sequence(yaml_emitter_t *emitter, yaml_node_t *node,
340247738Sbapt        yaml_char_t *anchor)
341247738Sbapt{
342247738Sbapt    yaml_event_t event;
343247738Sbapt    yaml_mark_t mark  = { 0, 0, 0 };
344247738Sbapt
345247738Sbapt    int implicit = (strcmp((char *)node->tag, YAML_DEFAULT_SEQUENCE_TAG) == 0);
346247738Sbapt
347247738Sbapt    yaml_node_item_t *item;
348247738Sbapt
349247738Sbapt    SEQUENCE_START_EVENT_INIT(event, anchor, node->tag, implicit,
350247738Sbapt            node->data.sequence.style, mark, mark);
351247738Sbapt    if (!yaml_emitter_emit(emitter, &event)) return 0;
352247738Sbapt
353247738Sbapt    for (item = node->data.sequence.items.start;
354247738Sbapt            item < node->data.sequence.items.top; item ++) {
355247738Sbapt        if (!yaml_emitter_dump_node(emitter, *item)) return 0;
356247738Sbapt    }
357247738Sbapt
358247738Sbapt    SEQUENCE_END_EVENT_INIT(event, mark, mark);
359247738Sbapt    if (!yaml_emitter_emit(emitter, &event)) return 0;
360247738Sbapt
361247738Sbapt    return 1;
362247738Sbapt}
363247738Sbapt
364247738Sbapt/*
365247738Sbapt * Serialize a mapping.
366247738Sbapt */
367247738Sbapt
368247738Sbaptstatic int
369247738Sbaptyaml_emitter_dump_mapping(yaml_emitter_t *emitter, yaml_node_t *node,
370247738Sbapt        yaml_char_t *anchor)
371247738Sbapt{
372247738Sbapt    yaml_event_t event;
373247738Sbapt    yaml_mark_t mark  = { 0, 0, 0 };
374247738Sbapt
375247738Sbapt    int implicit = (strcmp((char *)node->tag, YAML_DEFAULT_MAPPING_TAG) == 0);
376247738Sbapt
377247738Sbapt    yaml_node_pair_t *pair;
378247738Sbapt
379247738Sbapt    MAPPING_START_EVENT_INIT(event, anchor, node->tag, implicit,
380247738Sbapt            node->data.mapping.style, mark, mark);
381247738Sbapt    if (!yaml_emitter_emit(emitter, &event)) return 0;
382247738Sbapt
383247738Sbapt    for (pair = node->data.mapping.pairs.start;
384247738Sbapt            pair < node->data.mapping.pairs.top; pair ++) {
385247738Sbapt        if (!yaml_emitter_dump_node(emitter, pair->key)) return 0;
386247738Sbapt        if (!yaml_emitter_dump_node(emitter, pair->value)) return 0;
387247738Sbapt    }
388247738Sbapt
389247738Sbapt    MAPPING_END_EVENT_INIT(event, mark, mark);
390247738Sbapt    if (!yaml_emitter_emit(emitter, &event)) return 0;
391247738Sbapt
392247738Sbapt    return 1;
393247738Sbapt}
394247738Sbapt
395