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 134 emitter->anchors = 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 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 * 248yaml_emitter_generate_anchor(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 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 395