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

Revision 263, 9.8 KB checked in by xi, 6 years ago (diff)

Completed the first phase of API refactoring.

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