]> andersk Git - libyaml.git/blame - src/dumper.c
fix C++-compat error
[libyaml.git] / src / dumper.c
CommitLineData
e27a3c88
KS
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->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
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->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
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->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
75eddf78 134 emitter->anchors = (yaml_anchors_t*)yaml_malloc(sizeof(*(emitter->anchors))
e27a3c88
KS
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
155error:
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
166static void
167yaml_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
206static void
207yaml_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
247static yaml_char_t *
fc2dd942 248yaml_emitter_generate_anchor(SHIM(yaml_emitter_t *emitter), int anchor_id)
e27a3c88 249{
fc2dd942 250 yaml_char_t *anchor = YAML_MALLOC(ANCHOR_TEMPLATE_LENGTH);
e27a3c88
KS
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
263static int
264yaml_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
300static int
301yaml_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
315static int
316yaml_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
338static int
339yaml_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
368static int
369yaml_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
This page took 0.334868 seconds and 5 git commands to generate.