Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/libyaml/src/dumper.c
39507 views
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_anchors_t*)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(SHIM(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
395
396