Ruby  2.0.0p247(2013-06-27revision41674)
ext/psych/yaml/dumper.c
Go to the documentation of this file.
00001 
00002 #include "yaml_private.h"
00003 
00004 /*
00005  * API functions.
00006  */
00007 
00008 YAML_DECLARE(int)
00009 yaml_emitter_open(yaml_emitter_t *emitter);
00010 
00011 YAML_DECLARE(int)
00012 yaml_emitter_close(yaml_emitter_t *emitter);
00013 
00014 YAML_DECLARE(int)
00015 yaml_emitter_dump(yaml_emitter_t *emitter, yaml_document_t *document);
00016 
00017 /*
00018  * Clean up functions.
00019  */
00020 
00021 static void
00022 yaml_emitter_delete_document_and_anchors(yaml_emitter_t *emitter);
00023 
00024 /*
00025  * Anchor functions.
00026  */
00027 
00028 static void
00029 yaml_emitter_anchor_node(yaml_emitter_t *emitter, int index);
00030 
00031 static yaml_char_t *
00032 yaml_emitter_generate_anchor(yaml_emitter_t *emitter, int anchor_id);
00033 
00034 
00035 /*
00036  * Serialize functions.
00037  */
00038 
00039 static int
00040 yaml_emitter_dump_node(yaml_emitter_t *emitter, int index);
00041 
00042 static int
00043 yaml_emitter_dump_alias(yaml_emitter_t *emitter, yaml_char_t *anchor);
00044 
00045 static int
00046 yaml_emitter_dump_scalar(yaml_emitter_t *emitter, yaml_node_t *node,
00047         yaml_char_t *anchor);
00048 
00049 static int
00050 yaml_emitter_dump_sequence(yaml_emitter_t *emitter, yaml_node_t *node,
00051         yaml_char_t *anchor);
00052 
00053 static int
00054 yaml_emitter_dump_mapping(yaml_emitter_t *emitter, yaml_node_t *node,
00055         yaml_char_t *anchor);
00056 
00057 /*
00058  * Issue a STREAM-START event.
00059  */
00060 
00061 YAML_DECLARE(int)
00062 yaml_emitter_open(yaml_emitter_t *emitter)
00063 {
00064     yaml_event_t event;
00065     yaml_mark_t mark = { 0, 0, 0 };
00066 
00067     assert(emitter);            /* Non-NULL emitter object is required. */
00068     assert(!emitter->opened);   /* Emitter should not be opened yet. */
00069 
00070     STREAM_START_EVENT_INIT(event, YAML_ANY_ENCODING, mark, mark);
00071 
00072     if (!yaml_emitter_emit(emitter, &event)) {
00073         return 0;
00074     }
00075 
00076     emitter->opened = 1;
00077 
00078     return 1;
00079 }
00080 
00081 /*
00082  * Issue a STREAM-END event.
00083  */
00084 
00085 YAML_DECLARE(int)
00086 yaml_emitter_close(yaml_emitter_t *emitter)
00087 {
00088     yaml_event_t event;
00089     yaml_mark_t mark = { 0, 0, 0 };
00090 
00091     assert(emitter);            /* Non-NULL emitter object is required. */
00092     assert(emitter->opened);    /* Emitter should be opened. */
00093 
00094     if (emitter->closed) return 1;
00095 
00096     STREAM_END_EVENT_INIT(event, mark, mark);
00097 
00098     if (!yaml_emitter_emit(emitter, &event)) {
00099         return 0;
00100     }
00101 
00102     emitter->closed = 1;
00103 
00104     return 1;
00105 }
00106 
00107 /*
00108  * Dump a YAML document.
00109  */
00110 
00111 YAML_DECLARE(int)
00112 yaml_emitter_dump(yaml_emitter_t *emitter, yaml_document_t *document)
00113 {
00114     yaml_event_t event;
00115     yaml_mark_t mark = { 0, 0, 0 };
00116 
00117     assert(emitter);            /* Non-NULL emitter object is required. */
00118     assert(document);           /* Non-NULL emitter object is expected. */
00119 
00120     emitter->document = document;
00121 
00122     if (!emitter->opened) {
00123         if (!yaml_emitter_open(emitter)) goto error;
00124     }
00125 
00126     if (STACK_EMPTY(emitter, document->nodes)) {
00127         if (!yaml_emitter_close(emitter)) goto error;
00128         yaml_emitter_delete_document_and_anchors(emitter);
00129         return 1;
00130     }
00131 
00132     assert(emitter->opened);    /* Emitter should be opened. */
00133 
00134     emitter->anchors = yaml_malloc(sizeof(*(emitter->anchors))
00135             * (document->nodes.top - document->nodes.start));
00136     if (!emitter->anchors) goto error;
00137     memset(emitter->anchors, 0, sizeof(*(emitter->anchors))
00138             * (document->nodes.top - document->nodes.start));
00139 
00140     DOCUMENT_START_EVENT_INIT(event, document->version_directive,
00141             document->tag_directives.start, document->tag_directives.end,
00142             document->start_implicit, mark, mark);
00143     if (!yaml_emitter_emit(emitter, &event)) goto error;
00144 
00145     yaml_emitter_anchor_node(emitter, 1);
00146     if (!yaml_emitter_dump_node(emitter, 1)) goto error;
00147 
00148     DOCUMENT_END_EVENT_INIT(event, document->end_implicit, mark, mark);
00149     if (!yaml_emitter_emit(emitter, &event)) goto error;
00150 
00151     yaml_emitter_delete_document_and_anchors(emitter);
00152 
00153     return 1;
00154 
00155 error:
00156 
00157     yaml_emitter_delete_document_and_anchors(emitter);
00158 
00159     return 0;
00160 }
00161 
00162 /*
00163  * Clean up the emitter object after a document is dumped.
00164  */
00165 
00166 static void
00167 yaml_emitter_delete_document_and_anchors(yaml_emitter_t *emitter)
00168 {
00169     int index;
00170 
00171     if (!emitter->anchors) {
00172         yaml_document_delete(emitter->document);
00173         emitter->document = NULL;
00174         return;
00175     }
00176 
00177     for (index = 0; emitter->document->nodes.start + index
00178             < emitter->document->nodes.top; index ++) {
00179         yaml_node_t node = emitter->document->nodes.start[index];
00180         if (!emitter->anchors[index].serialized) {
00181             yaml_free(node.tag);
00182             if (node.type == YAML_SCALAR_NODE) {
00183                 yaml_free(node.data.scalar.value);
00184             }
00185         }
00186         if (node.type == YAML_SEQUENCE_NODE) {
00187             STACK_DEL(emitter, node.data.sequence.items);
00188         }
00189         if (node.type == YAML_MAPPING_NODE) {
00190             STACK_DEL(emitter, node.data.mapping.pairs);
00191         }
00192     }
00193 
00194     STACK_DEL(emitter, emitter->document->nodes);
00195     yaml_free(emitter->anchors);
00196 
00197     emitter->anchors = NULL;
00198     emitter->last_anchor_id = 0;
00199     emitter->document = NULL;
00200 }
00201 
00202 /*
00203  * Check the references of a node and assign the anchor id if needed.
00204  */
00205 
00206 static void
00207 yaml_emitter_anchor_node(yaml_emitter_t *emitter, int index)
00208 {
00209     yaml_node_t *node = emitter->document->nodes.start + index - 1;
00210     yaml_node_item_t *item;
00211     yaml_node_pair_t *pair;
00212 
00213     emitter->anchors[index-1].references ++;
00214 
00215     if (emitter->anchors[index-1].references == 1) {
00216         switch (node->type) {
00217             case YAML_SEQUENCE_NODE:
00218                 for (item = node->data.sequence.items.start;
00219                         item < node->data.sequence.items.top; item ++) {
00220                     yaml_emitter_anchor_node(emitter, *item);
00221                 }
00222                 break;
00223             case YAML_MAPPING_NODE:
00224                 for (pair = node->data.mapping.pairs.start;
00225                         pair < node->data.mapping.pairs.top; pair ++) {
00226                     yaml_emitter_anchor_node(emitter, pair->key);
00227                     yaml_emitter_anchor_node(emitter, pair->value);
00228                 }
00229                 break;
00230             default:
00231                 break;
00232         }
00233     }
00234 
00235     else if (emitter->anchors[index-1].references == 2) {
00236         emitter->anchors[index-1].anchor = (++ emitter->last_anchor_id);
00237     }
00238 }
00239 
00240 /*
00241  * Generate a textual representation for an anchor.
00242  */
00243 
00244 #define ANCHOR_TEMPLATE         "id%03d"
00245 #define ANCHOR_TEMPLATE_LENGTH  16
00246 
00247 static yaml_char_t *
00248 yaml_emitter_generate_anchor(yaml_emitter_t *emitter, int anchor_id)
00249 {
00250     yaml_char_t *anchor = yaml_malloc(ANCHOR_TEMPLATE_LENGTH);
00251 
00252     if (!anchor) return NULL;
00253 
00254     sprintf((char *)anchor, ANCHOR_TEMPLATE, anchor_id);
00255 
00256     return anchor;
00257 }
00258 
00259 /*
00260  * Serialize a node.
00261  */
00262 
00263 static int
00264 yaml_emitter_dump_node(yaml_emitter_t *emitter, int index)
00265 {
00266     yaml_node_t *node = emitter->document->nodes.start + index - 1;
00267     int anchor_id = emitter->anchors[index-1].anchor;
00268     yaml_char_t *anchor = NULL;
00269 
00270     if (anchor_id) {
00271         anchor = yaml_emitter_generate_anchor(emitter, anchor_id);
00272         if (!anchor) return 0;
00273     }
00274 
00275     if (emitter->anchors[index-1].serialized) {
00276         return yaml_emitter_dump_alias(emitter, anchor);
00277     }
00278 
00279     emitter->anchors[index-1].serialized = 1;
00280 
00281     switch (node->type) {
00282         case YAML_SCALAR_NODE:
00283             return yaml_emitter_dump_scalar(emitter, node, anchor);
00284         case YAML_SEQUENCE_NODE:
00285             return yaml_emitter_dump_sequence(emitter, node, anchor);
00286         case YAML_MAPPING_NODE:
00287             return yaml_emitter_dump_mapping(emitter, node, anchor);
00288         default:
00289             assert(0);      /* Could not happen. */
00290             break;
00291     }
00292 
00293     return 0;       /* Could not happen. */
00294 }
00295 
00296 /*
00297  * Serialize an alias.
00298  */
00299 
00300 static int
00301 yaml_emitter_dump_alias(yaml_emitter_t *emitter, yaml_char_t *anchor)
00302 {
00303     yaml_event_t event;
00304     yaml_mark_t mark  = { 0, 0, 0 };
00305 
00306     ALIAS_EVENT_INIT(event, anchor, mark, mark);
00307 
00308     return yaml_emitter_emit(emitter, &event);
00309 }
00310 
00311 /*
00312  * Serialize a scalar.
00313  */
00314 
00315 static int
00316 yaml_emitter_dump_scalar(yaml_emitter_t *emitter, yaml_node_t *node,
00317         yaml_char_t *anchor)
00318 {
00319     yaml_event_t event;
00320     yaml_mark_t mark  = { 0, 0, 0 };
00321 
00322     int plain_implicit = (strcmp((char *)node->tag,
00323                 YAML_DEFAULT_SCALAR_TAG) == 0);
00324     int quoted_implicit = (strcmp((char *)node->tag,
00325                 YAML_DEFAULT_SCALAR_TAG) == 0);
00326 
00327     SCALAR_EVENT_INIT(event, anchor, node->tag, node->data.scalar.value,
00328             node->data.scalar.length, plain_implicit, quoted_implicit,
00329             node->data.scalar.style, mark, mark);
00330 
00331     return yaml_emitter_emit(emitter, &event);
00332 }
00333 
00334 /*
00335  * Serialize a sequence.
00336  */
00337 
00338 static int
00339 yaml_emitter_dump_sequence(yaml_emitter_t *emitter, yaml_node_t *node,
00340         yaml_char_t *anchor)
00341 {
00342     yaml_event_t event;
00343     yaml_mark_t mark  = { 0, 0, 0 };
00344 
00345     int implicit = (strcmp((char *)node->tag, YAML_DEFAULT_SEQUENCE_TAG) == 0);
00346 
00347     yaml_node_item_t *item;
00348 
00349     SEQUENCE_START_EVENT_INIT(event, anchor, node->tag, implicit,
00350             node->data.sequence.style, mark, mark);
00351     if (!yaml_emitter_emit(emitter, &event)) return 0;
00352 
00353     for (item = node->data.sequence.items.start;
00354             item < node->data.sequence.items.top; item ++) {
00355         if (!yaml_emitter_dump_node(emitter, *item)) return 0;
00356     }
00357 
00358     SEQUENCE_END_EVENT_INIT(event, mark, mark);
00359     if (!yaml_emitter_emit(emitter, &event)) return 0;
00360 
00361     return 1;
00362 }
00363 
00364 /*
00365  * Serialize a mapping.
00366  */
00367 
00368 static int
00369 yaml_emitter_dump_mapping(yaml_emitter_t *emitter, yaml_node_t *node,
00370         yaml_char_t *anchor)
00371 {
00372     yaml_event_t event;
00373     yaml_mark_t mark  = { 0, 0, 0 };
00374 
00375     int implicit = (strcmp((char *)node->tag, YAML_DEFAULT_MAPPING_TAG) == 0);
00376 
00377     yaml_node_pair_t *pair;
00378 
00379     MAPPING_START_EVENT_INIT(event, anchor, node->tag, implicit,
00380             node->data.mapping.style, mark, mark);
00381     if (!yaml_emitter_emit(emitter, &event)) return 0;
00382 
00383     for (pair = node->data.mapping.pairs.start;
00384             pair < node->data.mapping.pairs.top; pair ++) {
00385         if (!yaml_emitter_dump_node(emitter, pair->key)) return 0;
00386         if (!yaml_emitter_dump_node(emitter, pair->value)) return 0;
00387     }
00388 
00389     MAPPING_END_EVENT_INIT(event, mark, mark);
00390     if (!yaml_emitter_emit(emitter, &event)) return 0;
00391 
00392     return 1;
00393 }
00394 
00395