summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxi <xi@18f92427-320e-0410-9341-c67f048884a3>2007-01-07 20:11:16 +0000
committerxi <xi@18f92427-320e-0410-9341-c67f048884a3>2007-01-07 20:11:16 +0000
commitdd329a85cdb65dde7ac4a5bc3d47ca25cbc2036a (patch)
treea99269e56362f968985551445cab0267c16d2aa9
parent07ebb0347fc9ff410b0b93c92f6ece52568d6991 (diff)
downloadlibyaml-dd329a85cdb65dde7ac4a5bc3d47ca25cbc2036a.tar.gz
Add functions for constructing, parsing and emitting YAML documents.
git-svn-id: http://svn.pyyaml.org/libyaml/trunk@238 18f92427-320e-0410-9341-c67f048884a3
-rw-r--r--configure.ac2
-rw-r--r--include/yaml.h557
-rw-r--r--src/Makefile.am2
-rw-r--r--src/api.c309
-rw-r--r--src/dumper.c394
-rw-r--r--src/emitter.c26
-rw-r--r--src/loader.c429
-rw-r--r--src/yaml_private.h30
-rw-r--r--tests/Makefile.am4
-rw-r--r--tests/example-deconstructor-alt.c800
-rw-r--r--tests/example-deconstructor.c116
-rw-r--r--tests/example-reformatter-alt.c217
-rw-r--r--tests/run-dumper.c305
-rw-r--r--tests/run-emitter.c2
-rw-r--r--tests/run-loader.c59
15 files changed, 2892 insertions, 360 deletions
diff --git a/configure.ac b/configure.ac
index 95ec383..2aba399 100644
--- a/configure.ac
+++ b/configure.ac
@@ -18,7 +18,7 @@ m4_define([YAML_BUGS], [http://pyyaml.org/newticket?component=libyaml])
# else:
# YAML_AGE = 0
m4_define([YAML_RELEASE], 0)
-m4_define([YAML_CURRENT], 0)
+m4_define([YAML_CURRENT], 1)
m4_define([YAML_REVISION], 0)
m4_define([YAML_AGE], 0)
diff --git a/include/yaml.h b/include/yaml.h
index afb62f0..515bf7c 100644
--- a/include/yaml.h
+++ b/include/yaml.h
@@ -59,9 +59,9 @@ yaml_get_version_string(void);
/**
* Get the library version numbers.
*
- * @param[out] major Major version number.
- * @param[out] minor Minor version number.
- * @param[out] patch Patch version number.
+ * @param[out] major Major version number.
+ * @param[out] minor Minor version number.
+ * @param[out] patch Patch version number.
*/
YAML_DECLARE(void)
@@ -78,7 +78,7 @@ yaml_get_version(int *major, int *minor, int *patch);
typedef unsigned char yaml_char_t;
/** The version directive data. */
-typedef struct {
+typedef struct yaml_version_directive_s {
/** The major version number. */
int major;
/** The minor version number. */
@@ -86,7 +86,7 @@ typedef struct {
} yaml_version_directive_t;
/** The tag directive data. */
-typedef struct {
+typedef struct yaml_tag_directive_s {
/** The tag handle. */
yaml_char_t *handle;
/** The tag prefix. */
@@ -94,7 +94,7 @@ typedef struct {
} yaml_tag_directive_t;
/** The stream encoding. */
-typedef enum {
+typedef enum yaml_encoding_e {
YAML_ANY_ENCODING,
YAML_UTF8_ENCODING,
YAML_UTF16LE_ENCODING,
@@ -103,7 +103,7 @@ typedef enum {
/** Line break types. */
-typedef enum {
+typedef enum yaml_break_e {
YAML_ANY_BREAK,
YAML_CR_BREAK,
YAML_LN_BREAK,
@@ -111,7 +111,7 @@ typedef enum {
} yaml_break_t;
/** Many bad things could happen with the parser and emitter. */
-typedef enum {
+typedef enum yaml_error_type_e {
YAML_NO_ERROR,
YAML_MEMORY_ERROR,
@@ -119,13 +119,14 @@ typedef enum {
YAML_READER_ERROR,
YAML_SCANNER_ERROR,
YAML_PARSER_ERROR,
+ YAML_COMPOSER_ERROR,
YAML_WRITER_ERROR,
YAML_EMITTER_ERROR
} yaml_error_type_t;
/** The pointer position. */
-typedef struct {
+typedef struct yaml_mark_s {
/** The position index. */
size_t index;
@@ -144,7 +145,7 @@ typedef struct {
*/
/** Scalar styles. */
-typedef enum {
+typedef enum yaml_scalar_style_e {
YAML_ANY_SCALAR_STYLE,
YAML_PLAIN_SCALAR_STYLE,
@@ -157,7 +158,7 @@ typedef enum {
} yaml_scalar_style_t;
/** Sequence styles. */
-typedef enum {
+typedef enum yaml_sequence_style_e {
YAML_ANY_SEQUENCE_STYLE,
YAML_BLOCK_SEQUENCE_STYLE,
@@ -165,7 +166,7 @@ typedef enum {
} yaml_sequence_style_t;
/** Mapping styles. */
-typedef enum {
+typedef enum yaml_mapping_style_e {
YAML_ANY_MAPPING_STYLE,
YAML_BLOCK_MAPPING_STYLE,
@@ -181,7 +182,7 @@ typedef enum {
*/
/** Token types. */
-typedef enum {
+typedef enum yaml_token_type_e {
YAML_NO_TOKEN,
YAML_STREAM_START_TOKEN,
@@ -213,7 +214,7 @@ typedef enum {
} yaml_token_type_t;
/** The token structure. */
-typedef struct {
+typedef struct yaml_token_s {
/** The token type. */
yaml_token_type_t type;
@@ -299,7 +300,7 @@ yaml_token_delete(yaml_token_t *token);
*/
/** Event types. */
-typedef enum {
+typedef enum yaml_event_type_e {
YAML_NO_EVENT,
YAML_STREAM_START_EVENT,
@@ -319,7 +320,7 @@ typedef enum {
} yaml_event_type_t;
/** The event structure. */
-typedef struct {
+typedef struct yaml_event_s {
/** The event type. */
yaml_event_type_t type;
@@ -416,8 +417,8 @@ typedef struct {
/**
* Create the STREAM-START event.
*
- * @param[out] event An empty event object.
- * @param[in] encoding The stream encoding.
+ * @param[out] event An empty event object.
+ * @param[in] encoding The stream encoding.
*
* @returns @c 1 if the function succeeded, @c 0 on error.
*/
@@ -429,7 +430,7 @@ yaml_stream_start_event_initialize(yaml_event_t *event,
/**
* Create the STREAM-END event.
*
- * @param[out] event An empty event object.
+ * @param[out] event An empty event object.
*
* @returns @c 1 if the function succeeded, @c 0 on error.
*/
@@ -443,11 +444,15 @@ yaml_stream_end_event_initialize(yaml_event_t *event);
* The @a implicit argument is considered as a stylistic parameter and may be
* ignored by the emitter.
*
- * @param[out] event An empty event object.
- * @param[in] version_directive The %YAML directive value or @c NULL.
- * @param[in] tag_directives_start The beginning of the %TAG directives list.
- * @param[in] tag_directives_end The end of the %TAG directives list.
- * @param[in] implicit If the document start indicator is implicit.
+ * @param[out] event An empty event object.
+ * @param[in] version_directive The %YAML directive value or
+ * @c NULL.
+ * @param[in] tag_directives_start The beginning of the %TAG
+ * directives list.
+ * @param[in] tag_directives_end The end of the %TAG directives
+ * list.
+ * @param[in] implicit If the document start indicator is
+ * implicit.
*
* @returns @c 1 if the function succeeded, @c 0 on error.
*/
@@ -465,8 +470,8 @@ yaml_document_start_event_initialize(yaml_event_t *event,
* The @a implicit argument is considered as a stylistic parameter and may be
* ignored by the emitter.
*
- * @param[out] event An empty event object.
- * @param[in] implicit If the document end indicator is implicit.
+ * @param[out] event An empty event object.
+ * @param[in] implicit If the document end indicator is implicit.
*
* @returns @c 1 if the function succeeded, @c 0 on error.
*/
@@ -477,8 +482,8 @@ yaml_document_end_event_initialize(yaml_event_t *event, int implicit);
/**
* Create an ALIAS event.
*
- * @param[out] event An empty event object.
- * @param[in] anchor The anchor value.
+ * @param[out] event An empty event object.
+ * @param[in] anchor The anchor value.
*
* @returns @c 1 if the function succeeded, @c 0 on error.
*/
@@ -494,14 +499,16 @@ yaml_alias_event_initialize(yaml_event_t *event, yaml_char_t *anchor);
* Either the @a tag attribute or one of the @a plain_implicit and
* @a quoted_implicit flags must be set.
*
- * @param[out] event An empty event object.
- * @param[in] anchor The scalar anchor or @c NULL.
- * @param[in] tag The scalar tag or @c NULL.
- * @param[in] value The scalar value.
- * @param[in] length The length of the scalar value.
- * @param[in] plain_implicit If the tag may be omitted for the plain style.
- * @param[in] quoted_implicit If the tag may be omitted for any non-plain style.
- * @param[in] style The scalar style.
+ * @param[out] event An empty event object.
+ * @param[in] anchor The scalar anchor or @c NULL.
+ * @param[in] tag The scalar tag or @c NULL.
+ * @param[in] value The scalar value.
+ * @param[in] length The length of the scalar value.
+ * @param[in] plain_implicit If the tag may be omitted for the plain
+ * style.
+ * @param[in] quoted_implicit If the tag may be omitted for any
+ * non-plain style.
+ * @param[in] style The scalar style.
*
* @returns @c 1 if the function succeeded, @c 0 on error.
*/
@@ -520,11 +527,11 @@ yaml_scalar_event_initialize(yaml_event_t *event,
*
* Either the @a tag attribute or the @a implicit flag must be set.
*
- * @param[out] event An empty event object.
- * @param[in] anchor The sequence anchor or @c NULL.
- * @param[in] tag The sequence tag or @c NULL.
- * @param[in] implicit If the tag may be omitted.
- * @param[in] style The sequence style.
+ * @param[out] event An empty event object.
+ * @param[in] anchor The sequence anchor or @c NULL.
+ * @param[in] tag The sequence tag or @c NULL.
+ * @param[in] implicit If the tag may be omitted.
+ * @param[in] style The sequence style.
*
* @returns @c 1 if the function succeeded, @c 0 on error.
*/
@@ -537,7 +544,7 @@ yaml_sequence_start_event_initialize(yaml_event_t *event,
/**
* Create a SEQUENCE-END event.
*
- * @param[out] event An empty event object.
+ * @param[out] event An empty event object.
*
* @returns @c 1 if the function succeeded, @c 0 on error.
*/
@@ -552,11 +559,11 @@ yaml_sequence_end_event_initialize(yaml_event_t *event);
*
* Either the @a tag attribute or the @a implicit flag must be set.
*
- * @param[out] event An empty event object.
- * @param[in] anchor The mapping anchor or @c NULL.
- * @param[in] tag The mapping tag or @c NULL.
- * @param[in] implicit If the tag may be omitted.
- * @param[in] style The mapping style.
+ * @param[out] event An empty event object.
+ * @param[in] anchor The mapping anchor or @c NULL.
+ * @param[in] tag The mapping tag or @c NULL.
+ * @param[in] implicit If the tag may be omitted.
+ * @param[in] style The mapping style.
*
* @returns @c 1 if the function succeeded, @c 0 on error.
*/
@@ -569,7 +576,7 @@ yaml_mapping_start_event_initialize(yaml_event_t *event,
/**
* Create a MAPPING-END event.
*
- * @param[out] event An empty event object.
+ * @param[out] event An empty event object.
*
* @returns @c 1 if the function succeeded, @c 0 on error.
*/
@@ -580,7 +587,7 @@ yaml_mapping_end_event_initialize(yaml_event_t *event);
/**
* Free any memory allocated for an event object.
*
- * @param[out] event An event object.
+ * @param[in,out] event An event object.
*/
YAML_DECLARE(void)
@@ -603,10 +610,10 @@ yaml_event_delete(yaml_event_t *event);
#define YAML_DEFAULT_SCALAR_TAG YAML_STR_TAG
#define YAML_DEFAULT_SEQUENCE_TAG YAML_SEQ_TAG
-#define YAML_DEFAULT_MAPPING_STYLE YAML_MAP_TAG
+#define YAML_DEFAULT_MAPPING_TAG YAML_MAP_TAG
/** Node types. */
-typedef enum {
+typedef enum yaml_node_type_e {
YAML_NO_NODE,
YAML_SCALAR_NODE,
@@ -614,31 +621,34 @@ typedef enum {
YAML_MAPPING_NODE
} yaml_node_type_t;
-#if 0
+/** The forward definition of a document node structure. */
+typedef struct yaml_node_s yaml_node_t;
-typedef struct _yaml_node_t yaml_node_item_t;
+/** An element of a sequence node. */
+typedef int yaml_node_item_t;
-typedef struct {
- yaml_node_item_t key;
- yaml_node_item_t value;
+/** An element of a mapping node. */
+typedef struct yaml_node_pair_s {
+ /** The key of the element. */
+ int key;
+ /** The value of the element. */
+ int value;
} yaml_node_pair_t;
/** The node structure. */
-typedef struct _yaml_node_t {
+struct yaml_node_s {
/** The node type. */
yaml_node_type_t type;
- /* The reference counter. */
- int references;
+ /** The node tag. */
+ yaml_char_t *tag;
/** The node data. */
union {
/** The scalar parameters (for @c YAML_SCALAR_NODE). */
struct {
- /** The tag. */
- yaml_char_t *tag;
/** The scalar value. */
yaml_char_t *value;
/** The length of the scalar value. */
@@ -649,16 +659,14 @@ typedef struct _yaml_node_t {
/** The sequence parameters (for @c YAML_SEQUENCE_NODE). */
struct {
- /** The tag. */
- yaml_char_t *tag;
/** The stack of sequence items. */
struct {
/** The beginning of the stack. */
- struct yaml_node_item_t *start;
+ yaml_node_item_t *start;
/** The end of the stack. */
- struct yaml_node_item_t *end;
+ yaml_node_item_t *end;
/** The top of the stack. */
- struct yaml_node_item_t *top;
+ yaml_node_item_t *top;
} items;
/** The sequence style. */
yaml_sequence_style_t style;
@@ -666,16 +674,14 @@ typedef struct _yaml_node_t {
/** The mapping parameters (for @c YAML_MAPPING_NODE). */
struct {
- /** The tag. */
- yaml_char_t *tag;
- /** The stack of mapping pairs. */
+ /** The stack of mapping pairs (key, value). */
struct {
/** The beginning of the stack. */
- struct yaml_node_pair_t *start;
+ yaml_node_pair_t *start;
/** The end of the stack. */
- struct yaml_node_pair_t *end;
+ yaml_node_pair_t *end;
/** The top of the stack. */
- struct yaml_node_pair_t *top;
+ yaml_node_pair_t *top;
} pairs;
/** The mapping style. */
yaml_mapping_style_t style;
@@ -688,201 +694,191 @@ typedef struct _yaml_node_t {
/** The end of the node. */
yaml_mark_t end_mark;
-} yaml_node_t;
+};
-/**
- * Create a SCALAR node.
- *
- * The @a style argument may be ignored by the emitter.
- *
- * @param[out] node An empty node object.
- * @param[in] tag The scalar tag.
- * @param[in] value The scalar value.
- * @param[in] length The length of the scalar value.
- * @param[in] style The scalar style.
- *
- * @returns @c 1 if the function succeeded, @c 0 on error.
- */
+/** The document structure. */
+typedef struct yaml_document_s {
-YAML_DECLARE(int)
-yaml_scalar_node_initialize(yaml_node_t *node,
- yaml_char_t *tag, yaml_char_t *value, int length,
- yaml_scalar_style_t style);
+ /** The document nodes. */
+ struct {
+ /** The beginning of the stack. */
+ yaml_node_t *start;
+ /** The end of the stack. */
+ yaml_node_t *end;
+ /** The top of the stack. */
+ yaml_node_t *top;
+ } nodes;
+
+ /** The version directive. */
+ yaml_version_directive_t *version_directive;
+
+ /** The list of tag directives. */
+ struct {
+ /** The beginning of the tag directives list. */
+ yaml_tag_directive_t *start;
+ /** The end of the tag directives list. */
+ yaml_tag_directive_t *end;
+ } tag_directives;
+
+ /** Is the document start indicator implicit? */
+ int start_implicit;
+ /** Is the document end indicator implicit? */
+ int end_implicit;
+
+ /** The beginning of the document. */
+ yaml_mark_t start_mark;
+ /** The end of the document. */
+ yaml_mark_t end_mark;
+
+} yaml_document_t;
/**
- * Create a SEQUENCE node.
- *
- * The @a style argument may be ignored by the emitter.
+ * Create a YAML document.
*
- * @param[out] node An empty node object.
- * @param[in] tag The sequence tag.
- * @param[in] style The sequence style.
+ * @param[out] document An empty document object.
+ * @param[in] version_directive The %YAML directive value or
+ * @c NULL.
+ * @param[in] tag_directives_start The beginning of the %TAG
+ * directives list.
+ * @param[in] tag_directives_end The end of the %TAG directives
+ * list.
+ * @param[in] start_implicit If the document start indicator is
+ * implicit.
+ * @param[in] end_implicit If the document end indicator is
+ * implicit.
*
* @returns @c 1 if the function succeeded, @c 0 on error.
*/
YAML_DECLARE(int)
-yaml_sequence_node_initialize(yaml_node_t *node,
- yaml_char_t *tag, yaml_sequence_style_t style);
+yaml_document_initialize(yaml_document_t *document,
+ yaml_version_directive_t *version_directive,
+ yaml_tag_directive_t *tag_directives_start,
+ yaml_tag_directive_t *tag_directives_end,
+ int start_implicit, int end_implicit);
/**
- * Add an item to a SEQUENCE node
+ * Delete a YAML document and all its nodes.
*
- * @param[out] node A sequence node.
- * @param[in] item An item node.
-*
- * @returns @c 1 if the function succeeded, @c 0 on error.
+ * @param[in,out] document A document object.
*/
-YAML_DECLARE(int)
-yaml_sequence_node_add_item(yaml_node_t *node, yaml_node_t *item)
+YAML_DECLARE(void)
+yaml_document_delete(yaml_document_t *document);
/**
- * Create a SCALAR node and add it to a SEQUENCE node.
+ * Get a node of a YAML document.
*
- * @param[out] node A sequence node.
- * @param[in] tag The scalar tag.
- * @param[in] value The scalar value.
- * @param[in] length The length of the scalar value.
- * @param[in] style The scalar style.
+ * The pointer returned by this function is valid until any of the functions
+ * modifying the documents are called.
*
- * @returns @c 1 if the function succeeded, @c 0 on error.
+ * @param[in] document A document object.
+ * @param[in] node The node id.
+ *
+ * @returns the node objct or @c NULL if @c node_id is out of range.
*/
-YAML_DECLARE(int)
-yaml_sequence_node_add_scalar_item(yaml_node_t *node,
- yaml_char_t *tag, yaml_char_t *value, int length,
- yaml_scalar_style_t style);
+YAML_DECLARE(yaml_node_t *)
+yaml_document_get_node(yaml_document_t *document, int node_id);
/**
- * Get the number of subnodes of a SEQUENCE node.
+ * Get the root of a YAML document node.
*
- * @param[in] node A sequence node.
+ * The root object is the first object added to the document.
*
- * @returns the number of subnodes.
- */
-
-YAML_DECLARE(size_t)
-yaml_sequence_node_get_length(yaml_node_t *node);
-
-/**
- * Get a subnode of a SEQUENCE node.
+ * The pointer returned by this function is valid until any of the functions
+ * modifying the documents are called.
+ *
+ * An empty document produced by the parser signifies the end of a YAML
+ * stream.
+ *
+ * @param[in] document A document object.
*
- * @param[in] node A sequence node.
- * @param[in] index The index of a subnode.
- * @param[out] item A subnode.
+ * @returns the node object or @c NULL if the document is empty.
*/
-YAML_DECLARE(void)
-yaml_sequence_node_get_item(yaml_node_t *node, size_t index,
- yaml_node_t *item);
+YAML_DECLARE(yaml_node_t *)
+yaml_document_get_root_node(yaml_document_t *document);
/**
- * Create a MAPPING node.
+ * Create a SCALAR node and attach it to the document.
*
* The @a style argument may be ignored by the emitter.
*
- * @param[out] node An empty node object.
- * @param[in] tag The mapping tag.
- * @param[in] style The mapping style.
+ * @param[in,out] document A document object.
+ * @param[in] tag The scalar tag.
+ * @param[in] value The scalar value.
+ * @param[in] length The length of the scalar value.
+ * @param[in] style The scalar style.
*
- * @returns @c 1 if the function succeeded, @c 0 on error.
+ * @returns the node id or @c 0 on error.
*/
YAML_DECLARE(int)
-yaml_mapping_node_initialize(yaml_node_t *node,
- yaml_char_t *tag, yaml_mapping_style_t style);
+yaml_document_add_scalar(yaml_document_t *document,
+ yaml_char_t *tag, yaml_char_t *value, int length,
+ yaml_scalar_style_t style);
/**
- * Add a key/value pair of nodes to a MAPPING node.
+ * Create a SEQUENCE node and attach it to the document.
*
- * @param[out] node A mapping node.
- * @param[in] key A key node.
- * @param[in] value A value node.
+ * The @a style argument may be ignored by the emitter.
*
- * @returns @c 1 if the function succeeded, @c 0 on error.
+ * @param[in,out] document A document object.
+ * @param[in] tag The sequence tag.
+ * @param[in] style The sequence style.
+ *
+ * @returns the node id or @c 0 on error.
*/
YAML_DECLARE(int)
-yaml_mapping_node_add_pair(yaml_node_t *node,
- yaml_node_t *key, yaml_node_t *value)
+yaml_document_add_sequence(yaml_document_t *document,
+ yaml_char_t *tag, yaml_sequence_style_t style);
/**
- * Create a scalar key and add the key/value pair to a MAPPING node.
+ * Create a MAPPING node and attach it to the document.
*
- * @param[out] node A mapping node.
- * @param[in] key_tag The key node tag.
- * @param[in] key_value The key node value.
- * @param[in] key_length The length of the key node value.
- * @param[in] key_style The key node style.
- * @param[in] value A value node.
+ * The @a style argument may be ignored by the emitter.
*
- * @returns @c 1 if the function succeeded, @c 0 on error.
+ * @param[in,out] document A document object.
+ * @param[in] tag The sequence tag.
+ * @param[in] style The sequence style.
+ *
+ * @returns the node id or @c 0 on error.
*/
YAML_DECLARE(int)
-yaml_sequence_node_add_scalar_key_pair(yaml_node_t *node,
- yaml_char_t *key_tag, yaml_char_t *key_value, int key_length,
- yaml_scalar_style_t key_style,
- yaml_node_t *value);
+yaml_document_add_mapping(yaml_document_t *document,
+ yaml_char_t *tag, yaml_mapping_style_t style);
/**
- * Create a scalar key/value nodes and add the pair to a MAPPING node.
- *
- * @param[out] node A mapping node.
- * @param[in] key_tag The key node tag.
- * @param[in] key_value The key node value.
- * @param[in] key_length The length of the key node value.
- * @param[in] key_style The key node style.
- * @param[in] value_tag The value node tag.
- * @param[in] value_value The value node value.
- * @param[in] value_length The length of the value node value.
- * @param[in] value_style The value node style.
+ * Add an item to a SEQUENCE node.
*
+ * @param[in,out] document A document object.
+ * @param[in] sequence The sequence node id.
+ * @param[in] item The item node id.
+*
* @returns @c 1 if the function succeeded, @c 0 on error.
*/
YAML_DECLARE(int)
-yaml_sequence_node_add_scalar_pair(yaml_node_t *node,
- yaml_char_t *key_tag, yaml_char_t *key_value, int key_length,
- yaml_scalar_style_t key_style,
- yaml_char_t *value_tag, yaml_char_t *value_value, int value_length,
- yaml_scalar_style_t value_style);
-
-/**
- * Get the number of subnode pairs of a MAPPING node.
- *
- * @param[in] node A mapping node.
- *
- * @returns the number of pairs.
- */
-
-YAML_DECLARE(size_t)
-yaml_mapping_node_get_length(yaml_node_t *node);
+yaml_document_append_sequence_item(yaml_document_t *document,
+ int sequence, int item);
/**
- * Get a subnode of a SEQUENCE node.
+ * Add a pair of a key and a value to a MAPPING node.
*
- * @param[in] node A sequence node.
- * @param[in] index The index of a subnode.
- * @param[out] key The key subnode.
- * @param[out] value The value subnode.
- */
-
-YAML_DECLARE(void)
-yaml_mapping_node_get_pair(yaml_node_t *node, size_t index,
- yaml_node_t *key, yaml_node_t *value);
-
-/**
- * Delete a node and its subnodes.
- *
- * @param[out] node A node object.
+ * @param[in,out] document A document object.
+ * @param[in] mapping The mapping node id.
+ * @param[in] key The key node id.
+ * @param[in] value The value node id.
+*
+ * @returns @c 1 if the function succeeded, @c 0 on error.
*/
-YAML_DECLARE(void)
-yaml_node_delete(yaml_node_t *node);
-
-#endif
+YAML_DECLARE(int)
+yaml_document_append_mapping_pair(yaml_document_t *document,
+ int mapping, int key, int value);
/** @} */
@@ -916,7 +912,7 @@ typedef int yaml_read_handler_t(void *data, unsigned char *buffer, size_t size,
* This structure holds information about a potential simple key.
*/
-typedef struct {
+typedef struct yaml_simple_key_s {
/** Is a simple key possible? */
int possible;
@@ -933,7 +929,7 @@ typedef struct {
/**
* The states of the parser.
*/
-typedef enum {
+typedef enum yaml_parser_state_e {
YAML_PARSE_STREAM_START_STATE,
YAML_PARSE_IMPLICIT_DOCUMENT_START_STATE,
YAML_PARSE_DOCUMENT_START_STATE,
@@ -961,13 +957,26 @@ typedef enum {
} yaml_parser_state_t;
/**
+ * This structure holds aliases data.
+ */
+
+typedef struct yaml_alias_data_s {
+ /** The anchor. */
+ yaml_char_t *anchor;
+ /** The node id. */
+ int index;
+ /** The anchor mark. */
+ yaml_mark_t mark;
+} yaml_alias_data_t;
+
+/**
* The parser structure.
*
* All members are internal. Manage the structure using the @c yaml_parser_
* family of functions.
*/
-typedef struct {
+typedef struct yaml_parser_s {
/**
* @name Error handling
@@ -1167,6 +1176,28 @@ typedef struct {
* @}
*/
+ /**
+ * @name Dumper stuff
+ * @{
+ */
+
+ /** The alias data. */
+ struct {
+ /** The beginning of the list. */
+ yaml_alias_data_t *start;
+ /** The end of the list. */
+ yaml_alias_data_t *end;
+ /** The top of the list. */
+ yaml_alias_data_t *top;
+ } aliases;
+
+ /** The currently parsed document. */
+ yaml_document_t *document;
+
+ /**
+ * @}
+ */
+
} yaml_parser_t;
/**
@@ -1175,7 +1206,7 @@ typedef struct {
* This function creates a new parser object. An application is responsible
* for destroying the object using the yaml_parser_delete() function.
*
- * @param[out] parser An empty parser object.
+ * @param[out] parser An empty parser object.
*
* @returns @c 1 if the function succeeded, @c 0 on error.
*/
@@ -1256,7 +1287,8 @@ yaml_parser_set_encoding(yaml_parser_t *parser, yaml_encoding_t encoding);
* produced token object using the @c yaml_token_delete function.
*
* An application must not alternate the calls of yaml_parser_scan() with the
- * calls of yaml_parser_parse(). Doing this will break the parser.
+ * calls of yaml_parser_parse() or yaml_parser_load(). Doing this will break
+ * the parser.
*
* @param[in,out] parser A parser object.
* @param[out] token An empty token object.
@@ -1278,8 +1310,9 @@ yaml_parser_scan(yaml_parser_t *parser, yaml_token_t *token);
* An application is responsible for freeing any buffers associated with the
* produced event object using the yaml_event_delete() function.
*
- * An application must not alternate the calls of yaml_parser_scan() with the
- * calls of yaml_parser_parse(). Doing this will break the parser.
+ * An application must not alternate the calls of yaml_parser_parse() with the
+ * calls of yaml_parser_scan() or yaml_parser_load(). Doing this will break the
+ * parser.
*
* @param[in,out] parser A parser object.
* @param[out] event An empty event object.
@@ -1290,6 +1323,31 @@ yaml_parser_scan(yaml_parser_t *parser, yaml_token_t *token);
YAML_DECLARE(int)
yaml_parser_parse(yaml_parser_t *parser, yaml_event_t *event);
+/**
+ * Parse the input stream and produce the next YAML document.
+ *
+ * Call this function subsequently to produce a sequence of documents
+ * constituting the input stream.
+ *
+ * If the produced document has no root node, it means that the document
+ * end has been reached.
+ *
+ * An application is responsible for freeing any data associated with the
+ * produced document object using the yaml_document_delete() function.
+ *
+ * An application must not alternate the calls of yaml_parser_load() with the
+ * calls of yaml_parser_scan() or yaml_parser_parse(). Doing this will break
+ * the parser.
+ *
+ * @param[in,out] parser A parser object.
+ * @param[out] document An empty document object.
+ *
+ * @return @c 1 if the function succeeded, @c 0 on error.
+ */
+
+YAML_DECLARE(int)
+yaml_parser_load(yaml_parser_t *parser, yaml_document_t *document);
+
/** @} */
/**
@@ -1316,7 +1374,7 @@ yaml_parser_parse(yaml_parser_t *parser, yaml_event_t *event);
typedef int yaml_write_handler_t(void *data, unsigned char *buffer, size_t size);
/** The emitter states. */
-typedef enum {
+typedef enum yaml_emitter_state_e {
YAML_EMIT_STREAM_START_STATE,
YAML_EMIT_FIRST_DOCUMENT_START_STATE,
YAML_EMIT_DOCUMENT_START_STATE,
@@ -1344,7 +1402,7 @@ typedef enum {
* family of functions.
*/
-typedef struct {
+typedef struct yaml_emitter_s {
/**
* @name Error handling
@@ -1549,6 +1607,36 @@ typedef struct {
* @}
*/
+ /**
+ * @name Dumper stuff
+ * @{
+ */
+
+ /** If the stream was already opened? */
+ int opened;
+ /** If the stream was already closed? */
+ int closed;
+
+ /** The information associated with the document nodes. */
+ struct {
+ /** The number of references. */
+ int references;
+ /** The anchor id. */
+ int anchor;
+ /** If the node has been emitted? */
+ int serialized;
+ } *anchors;
+
+ /** The last assigned anchor id. */
+ int last_anchor_id;
+
+ /** The currently emitted document. */
+ yaml_document_t *document;
+
+ /**
+ * @}
+ */
+
} yaml_emitter_t;
/**
@@ -1697,6 +1785,49 @@ yaml_emitter_set_break(yaml_emitter_t *emitter, yaml_break_t line_break);
YAML_DECLARE(int)
yaml_emitter_emit(yaml_emitter_t *emitter, yaml_event_t *event);
+/*
+ * Start a YAML stream.
+ *
+ * This function should be used before yaml_emitter_dump() is called.
+ *
+ * @param[in,out] emitter An emitter object.
+ *
+ * @returns @c 1 if the function succeeded, @c 0 on error.
+ */
+
+YAML_DECLARE(int)
+yaml_emitter_open(yaml_emitter_t *emitter);
+
+/*
+ * Finish a YAML stream.
+ *
+ * This function should be used after yaml_emitter_dump() is called.
+ *
+ * @param[in,out] emitter An emitter object.
+ *
+ * @returns @c 1 if the function succeeded, @c 0 on error.
+ */
+
+YAML_DECLARE(int)
+yaml_emitter_close(yaml_emitter_t *emitter);
+
+/*
+ * Emit a YAML document.
+ *
+ * The documen object may be generated using the yaml_parser_load() function
+ * or the yaml_document_initialize() function. The emitter takes the
+ * responsibility for the document object and destoys its content after
+ * it is emitted. The document object is destroyedeven if the function fails.
+ *
+ * @param[in,out] emitter An emitter object.
+ * @param[in,out] document A document object.
+ *
+ * @returns @c 1 if the function succeeded, @c 0 on error.
+ */
+
+YAML_DECLARE(int)
+yaml_emitter_dump(yaml_emitter_t *emitter, yaml_document_t *document);
+
/**
* Flush the accumulated characters to the output.
*
diff --git a/src/Makefile.am b/src/Makefile.am
index f9cb7a2..724a1b2 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,4 +1,4 @@
AM_CPPFLAGS = -I$(top_srcdir)/include
lib_LTLIBRARIES = libyaml.la
-libyaml_la_SOURCES = yaml_private.h api.c reader.c scanner.c parser.c writer.c emitter.c
+libyaml_la_SOURCES = yaml_private.h api.c reader.c scanner.c parser.c loader.c writer.c emitter.c dumper.c
libyaml_la_LDFLAGS = -release $(YAML_LT_RELEASE) -version-info $(YAML_LT_CURRENT):$(YAML_LT_REVISION):$(YAML_LT_AGE)
diff --git a/src/api.c b/src/api.c
index a2d5543..a1fdf6b 100644
--- a/src/api.c
+++ b/src/api.c
@@ -399,6 +399,7 @@ yaml_emitter_delete(yaml_emitter_t *emitter)
yaml_free(tag_directive.prefix);
}
STACK_DEL(emitter, emitter->tag_directives);
+ yaml_free(emitter->anchors);
memset(emitter, 0, sizeof(yaml_emitter_t));
}
@@ -1019,23 +1020,187 @@ yaml_event_delete(yaml_event_t *event)
memset(event, 0, sizeof(yaml_event_t));
}
-#if 0
+/*
+ * Create a document object.
+ */
+
+YAML_DECLARE(int)
+yaml_document_initialize(yaml_document_t *document,
+ yaml_version_directive_t *version_directive,
+ yaml_tag_directive_t *tag_directives_start,
+ yaml_tag_directive_t *tag_directives_end,
+ int start_implicit, int end_implicit)
+{
+ struct {
+ yaml_error_type_t error;
+ } context;
+ struct {
+ yaml_node_t *start;
+ yaml_node_t *end;
+ yaml_node_t *top;
+ } nodes = { NULL, NULL, NULL };
+ yaml_version_directive_t *version_directive_copy = NULL;
+ struct {
+ yaml_tag_directive_t *start;
+ yaml_tag_directive_t *end;
+ yaml_tag_directive_t *top;
+ } tag_directives_copy = { NULL, NULL, NULL };
+ yaml_tag_directive_t value = { NULL, NULL };
+ yaml_mark_t mark = { 0, 0, 0 };
+
+ assert(document); /* Non-NULL document object is expected. */
+ assert((tag_directives_start && tag_directives_end) ||
+ (tag_directives_start == tag_directives_end));
+ /* Valid tag directives are expected. */
+
+ if (!STACK_INIT(&context, nodes, INITIAL_STACK_SIZE)) goto error;
+
+ if (version_directive) {
+ version_directive_copy = yaml_malloc(sizeof(yaml_version_directive_t));
+ if (!version_directive_copy) goto error;
+ version_directive_copy->major = version_directive->major;
+ version_directive_copy->minor = version_directive->minor;
+ }
+
+ if (tag_directives_start != tag_directives_end) {
+ yaml_tag_directive_t *tag_directive;
+ if (!STACK_INIT(&context, tag_directives_copy, INITIAL_STACK_SIZE))
+ goto error;
+ for (tag_directive = tag_directives_start;
+ tag_directive != tag_directives_end; tag_directive ++) {
+ assert(tag_directive->handle);
+ assert(tag_directive->prefix);
+ if (!yaml_check_utf8(tag_directive->handle,
+ strlen((char *)tag_directive->handle)))
+ goto error;
+ if (!yaml_check_utf8(tag_directive->prefix,
+ strlen((char *)tag_directive->prefix)))
+ goto error;
+ value.handle = yaml_strdup(tag_directive->handle);
+ value.prefix = yaml_strdup(tag_directive->prefix);
+ if (!value.handle || !value.prefix) goto error;
+ if (!PUSH(&context, tag_directives_copy, value))
+ goto error;
+ value.handle = NULL;
+ value.prefix = NULL;
+ }
+ }
+
+ DOCUMENT_INIT(*document, nodes.start, nodes.end, version_directive_copy,
+ tag_directives_copy.start, tag_directives_copy.top,
+ start_implicit, end_implicit, mark, mark);
+
+ return 1;
+
+error:
+ STACK_DEL(&context, nodes);
+ yaml_free(version_directive_copy);
+ while (!STACK_EMPTY(&context, tag_directives_copy)) {
+ yaml_tag_directive_t value = POP(&context, tag_directives_copy);
+ yaml_free(value.handle);
+ yaml_free(value.prefix);
+ }
+ STACK_DEL(&context, tag_directives_copy);
+ yaml_free(value.handle);
+ yaml_free(value.prefix);
+
+ return 0;
+}
+
+/*
+ * Destroy a document object.
+ */
+
+YAML_DECLARE(void)
+yaml_document_delete(yaml_document_t *document)
+{
+ struct {
+ yaml_error_type_t error;
+ } context;
+ yaml_tag_directive_t *tag_directive;
+
+ assert(document); /* Non-NULL document object is expected. */
+
+ while (!STACK_EMPTY(&context, document->nodes)) {
+ yaml_node_t node = POP(&context, document->nodes);
+ yaml_free(node.tag);
+ switch (node.type) {
+ case YAML_SCALAR_NODE:
+ yaml_free(node.data.scalar.value);
+ break;
+ case YAML_SEQUENCE_NODE:
+ STACK_DEL(&context, node.data.sequence.items);
+ break;
+ case YAML_MAPPING_NODE:
+ STACK_DEL(&context, node.data.mapping.pairs);
+ break;
+ default:
+ assert(0); /* Should not happen. */
+ }
+ }
+ STACK_DEL(&context, document->nodes);
+
+ yaml_free(document->version_directive);
+ for (tag_directive = document->tag_directives.start;
+ tag_directive != document->tag_directives.end;
+ tag_directive++) {
+ yaml_free(tag_directive->handle);
+ yaml_free(tag_directive->prefix);
+ }
+ yaml_free(document->tag_directives.start);
+
+ memset(document, 0, sizeof(yaml_document_t));
+}
+
+/**
+ * Get a document node.
+ */
+
+YAML_DECLARE(yaml_node_t *)
+yaml_document_get_node(yaml_document_t *document, int node)
+{
+ assert(document); /* Non-NULL document object is expected. */
+
+ if (node > 0 && document->nodes.start + node <= document->nodes.top) {
+ return document->nodes.start + node - 1;
+ }
+ return NULL;
+}
+
+/**
+ * Get the root object.
+ */
+
+YAML_DECLARE(yaml_node_t *)
+yaml_document_get_root_node(yaml_document_t *document)
+{
+ assert(document); /* Non-NULL document object is expected. */
+
+ if (document->nodes.top != document->nodes.start) {
+ return document->nodes.start;
+ }
+ return NULL;
+}
/*
- * Create a SCALAR node.
+ * Add a scalar node to a document.
*/
YAML_DECLARE(int)
-yaml_scalar_node_initialize(yaml_node_t *node,
+yaml_document_add_scalar(yaml_document_t *document,
yaml_char_t *tag, yaml_char_t *value, int length,
yaml_scalar_style_t style)
{
+ struct {
+ yaml_error_type_t error;
+ } context;
yaml_mark_t mark = { 0, 0, 0 };
yaml_char_t *tag_copy = NULL;
yaml_char_t *value_copy = NULL;
+ yaml_node_t node;
- assert(node); /* Non-NULL node object is expected. */
- assert(value); /* Non-NULL anchor is expected. */
+ assert(document); /* Non-NULL document object is expected. */
+ assert(value); /* Non-NULL value is expected. */
if (!tag) {
tag = YAML_DEFAULT_SCALAR_TAG;
@@ -1055,9 +1220,10 @@ yaml_scalar_node_initialize(yaml_node_t *node,
memcpy(value_copy, value, length);
value_copy[length] = '\0';
- SCALAR_NODE_INIT(*node, tag_copy, value_copy, length, style, mark, mark);
+ SCALAR_NODE_INIT(node, tag_copy, value_copy, length, style, mark, mark);
+ if (!PUSH(&context, document->nodes, node)) goto error;
- return 1;
+ return document->nodes.top - document->nodes.start;
error:
yaml_free(tag_copy);
@@ -1067,11 +1233,11 @@ error:
}
/*
- * Create a SEQUENCE node.
+ * Add a sequence node to a document.
*/
YAML_DECLARE(int)
-yaml_sequence_node_initialize(yaml_node_t *node,
+yaml_document_add_sequence(yaml_document_t *document,
yaml_char_t *tag, yaml_sequence_style_t style)
{
struct {
@@ -1084,39 +1250,39 @@ yaml_sequence_node_initialize(yaml_node_t *node,
yaml_node_item_t *end;
yaml_node_item_t *top;
} items = { NULL, NULL, NULL };
+ yaml_node_t node;
- assert(node); /* Non-NULL node object is expected. */
+ assert(document); /* Non-NULL document object is expected. */
if (!tag) {
tag = YAML_DEFAULT_SEQUENCE_TAG;
}
- if (tag) {
- if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error;
- tag_copy = yaml_strdup(tag);
- if (!tag_copy) goto error;
- }
+ if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error;
+ tag_copy = yaml_strdup(tag);
+ if (!tag_copy) goto error;
- if (!STACK_INIT(context, items, INITIAL_STACK_SIZE)) goto error;
+ if (!STACK_INIT(&context, items, INITIAL_STACK_SIZE)) goto error;
- SEQUENCE_NODE_INIT(*node, tag_copy, items.start, item.end, style,
- mark, mark);
+ SEQUENCE_NODE_INIT(node, tag_copy, items.start, items.end,
+ style, mark, mark);
+ if (!PUSH(&context, document->nodes, node)) goto error;
- return 1;
+ return document->nodes.top - document->nodes.start;
error:
+ STACK_DEL(&context, items);
yaml_free(tag_copy);
- STACK_DEL(context, items);
return 0;
}
/*
- * Create a MAPPING node.
+ * Add a mapping node to a document.
*/
YAML_DECLARE(int)
-yaml_mapping_node_initialize(yaml_node_t *node,
+yaml_document_add_mapping(yaml_document_t *document,
yaml_char_t *tag, yaml_mapping_style_t style)
{
struct {
@@ -1129,74 +1295,89 @@ yaml_mapping_node_initialize(yaml_node_t *node,
yaml_node_pair_t *end;
yaml_node_pair_t *top;
} pairs = { NULL, NULL, NULL };
+ yaml_node_t node;
- assert(node); /* Non-NULL node object is expected. */
+ assert(document); /* Non-NULL document object is expected. */
if (!tag) {
tag = YAML_DEFAULT_MAPPING_TAG;
}
- if (tag) {
- if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error;
- tag_copy = yaml_strdup(tag);
- if (!tag_copy) goto error;
- }
+ if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error;
+ tag_copy = yaml_strdup(tag);
+ if (!tag_copy) goto error;
- if (!STACK_INIT(context, pairs, INITIAL_STACK_SIZE)) goto error;
+ if (!STACK_INIT(&context, pairs, INITIAL_STACK_SIZE)) goto error;
- MAPPING_NODE_INIT(*node, tag_copy, pairs.start, pairs.end, style,
- mark, mark);
+ MAPPING_NODE_INIT(node, tag_copy, pairs.start, pairs.end,
+ style, mark, mark);
+ if (!PUSH(&context, document->nodes, node)) goto error;
- return 1;
+ return document->nodes.top - document->nodes.start;
error:
+ STACK_DEL(&context, pairs);
yaml_free(tag_copy);
- STACK_DEL(context, pairs);
return 0;
}
/*
- * Delete a node and its subnodes.
+ * Append an item to a sequence node.
*/
-YAML_DECLARE(void)
-yaml_node_delete(yaml_node_t *node)
+YAML_DECLARE(int)
+yaml_document_append_sequence_item(yaml_document_t *document,
+ int sequence, int item)
{
struct {
yaml_error_type_t error;
} context;
- struct {
- yaml_node_item_t *start;
- yaml_node_item_t *end;
- yaml_node_item_t *head;
- yaml_node_item_t *tail;
- } queue = { NULL, NULL, NULL, NULL };
- assert(node); /* Non-NULL node object is expected. */
+ assert(document); /* Non-NULL document is required. */
+ assert(sequence > 0
+ && document->nodes.start + sequence <= document->nodes.top);
+ /* Valid sequence id is required. */
+ assert(document->nodes.start[sequence-1].type == YAML_SEQUENCE_NODE);
+ /* A sequence node is required. */
+ assert(item > 0 && document->nodes.start + item <= document->nodes.top);
+ /* Valid item id is required. */
+
+ if (!PUSH(&context,
+ document->nodes.start[sequence-1].data.sequence.items, item))
+ return 0;
- if (node->type == YAML_SCALAR_NODE) {
- yaml_free(node->data.scalar.tag);
- yaml_free(node->data.scalar.value);
- memset(node, 0, sizeof(yaml_node_t));
- return;
- }
+ return 1;
+}
- if (!QUEUE_INIT(context, queue, INITIAL_QUEUE_SIZE)) goto error;
- if (!ENQUEUE(context, queue, node)) goto error;
+/*
+ * Append a pair of a key and a value to a mapping node.
+ */
- while (!QUEUE_EMPTY(context, queue)) {
- yaml_node_t node = DEQUEUE(context, queue);
- if (node.type == YAML_SCALAR_NODE) {
- if (!node->reference)
- }
- if (node->type == YAML_SEQUENCE_NODE) {
- while (!STACK_EMPTY(context, node->data.sequence.items)) {
- yaml_node_t *item =
- }
- }
- }
-}
+YAML_DECLARE(int)
+yaml_document_append_mapping_pair(yaml_document_t *document,
+ int mapping, int key, int value)
+{
+ struct {
+ yaml_error_type_t error;
+ } context;
+ yaml_node_pair_t pair = { key, value };
+
+ assert(document); /* Non-NULL document is required. */
+ assert(mapping > 0
+ && document->nodes.start + mapping <= document->nodes.top);
+ /* Valid mapping id is required. */
+ assert(document->nodes.start[mapping-1].type == YAML_MAPPING_NODE);
+ /* A mapping node is required. */
+ assert(key > 0 && document->nodes.start + key <= document->nodes.top);
+ /* Valid key id is required. */
+ assert(value > 0 && document->nodes.start + value <= document->nodes.top);
+ /* Valid value id is required. */
+
+ if (!PUSH(&context,
+ document->nodes.start[mapping-1].data.mapping.pairs, pair))
+ return 0;
-#endif
+ return 1;
+}
diff --git a/src/dumper.c b/src/dumper.c
new file mode 100644
index 0000000..203c6a7
--- /dev/null
+++ b/src/dumper.c
@@ -0,0 +1,394 @@
+
+#include "yaml_private.h"
+
+/*
+ * API functions.
+ */
+
+YAML_DECLARE(int)
+yaml_emitter_open(yaml_emitter_t *emitter);
+
+YAML_DECLARE(int)
+yaml_emitter_close(yaml_emitter_t *emitter);
+
+YAML_DECLARE(int)
+yaml_emitter_dump(yaml_emitter_t *emitter, yaml_document_t *document);
+
+/*
+ * Clean up functions.
+ */
+
+static void
+yaml_emitter_delete_document_and_anchors(yaml_emitter_t *emitter);
+
+/*
+ * Anchor functions.
+ */
+
+static void
+yaml_emitter_anchor_node(yaml_emitter_t *emitter, int index);
+
+static yaml_char_t *
+yaml_emitter_generate_anchor(yaml_emitter_t *emitter, int anchor_id);
+
+
+/*
+ * Serialize functions.
+ */
+
+static int
+yaml_emitter_dump_node(yaml_emitter_t *emitter, int index);
+
+static int
+yaml_emitter_dump_alias(yaml_emitter_t *emitter, yaml_char_t *anchor);
+
+static int
+yaml_emitter_dump_scalar(yaml_emitter_t *emitter, yaml_node_t *node,
+ yaml_char_t *anchor);
+
+static int
+yaml_emitter_dump_sequence(yaml_emitter_t *emitter, yaml_node_t *node,
+ yaml_char_t *anchor);
+
+static int
+yaml_emitter_dump_mapping(yaml_emitter_t *emitter, yaml_node_t *node,
+ yaml_char_t *anchor);
+
+/*
+ * Issue a STREAM-START event.
+ */
+
+YAML_DECLARE(int)
+yaml_emitter_open(yaml_emitter_t *emitter)
+{
+ yaml_event_t event;
+ yaml_mark_t mark = { 0, 0, 0 };
+
+ assert(emitter); /* Non-NULL emitter object is required. */
+ assert(!emitter->opened); /* Emitter should not be opened yet. */
+
+ STREAM_START_EVENT_INIT(event, YAML_ANY_ENCODING, mark, mark);
+
+ if (!yaml_emitter_emit(emitter, &event)) {
+ return 0;
+ }
+
+ emitter->opened = 1;
+
+ return 1;
+}
+
+/*
+ * Issue a STREAM-END event.
+ */
+
+YAML_DECLARE(int)
+yaml_emitter_close(yaml_emitter_t *emitter)
+{
+ yaml_event_t event;
+ yaml_mark_t mark = { 0, 0, 0 };
+
+ assert(emitter); /* Non-NULL emitter object is required. */
+ assert(emitter->opened); /* Emitter should be opened. */
+
+ if (emitter->closed) return 1;
+
+ STREAM_END_EVENT_INIT(event, mark, mark);
+
+ if (!yaml_emitter_emit(emitter, &event)) {
+ return 0;
+ }
+
+ emitter->closed = 1;
+
+ return 1;
+}
+
+/*
+ * Dump a YAML document.
+ */
+
+YAML_DECLARE(int)
+yaml_emitter_dump(yaml_emitter_t *emitter, yaml_document_t *document)
+{
+ yaml_event_t event;
+ yaml_mark_t mark = { 0, 0, 0 };
+
+ assert(emitter); /* Non-NULL emitter object is required. */
+ assert(document); /* Non-NULL emitter object is expected. */
+
+ emitter->document = document;
+
+ if (!emitter->opened) {
+ if (!yaml_emitter_open(emitter)) goto error;
+ }
+
+ if (STACK_EMPTY(emitter, document->nodes)) {
+ if (!yaml_emitter_close(emitter)) goto error;
+ yaml_emitter_delete_document_and_anchors(emitter);
+ return 1;
+ }
+
+ assert(emitter->opened); /* Emitter should be opened. */
+
+ emitter->anchors = yaml_malloc(sizeof(*(emitter->anchors))
+ * (document->nodes.top - document->nodes.start));
+ if (!emitter->anchors) goto error;
+ memset(emitter->anchors, 0, sizeof(*(emitter->anchors))
+ * (document->nodes.top - document->nodes.start));
+
+ DOCUMENT_START_EVENT_INIT(event, document->version_directive,
+ document->tag_directives.start, document->tag_directives.end,
+ document->start_implicit, mark, mark);
+ if (!yaml_emitter_emit(emitter, &event)) goto error;
+
+ yaml_emitter_anchor_node(emitter, 1);
+ if (!yaml_emitter_dump_node(emitter, 1)) goto error;
+
+ DOCUMENT_END_EVENT_INIT(event, document->end_implicit, mark, mark);
+ if (!yaml_emitter_emit(emitter, &event)) goto error;
+
+ yaml_emitter_delete_document_and_anchors(emitter);
+
+ return 1;
+
+error:
+
+ yaml_emitter_delete_document_and_anchors(emitter);
+
+ return 0;
+}
+
+/*
+ * Clean up the emitter object after a document is dumped.
+ */
+
+static void
+yaml_emitter_delete_document_and_anchors(yaml_emitter_t *emitter)
+{
+ int index;
+
+ if (!emitter->anchors) {
+ yaml_document_delete(emitter->document);
+ emitter->document = NULL;
+ return;
+ }
+
+ for (index = 0; emitter->document->nodes.start + index
+ < emitter->document->nodes.top; index ++) {
+ yaml_node_t node = emitter->document->nodes.start[index];
+ if (!emitter->anchors[index].serialized) {
+ yaml_free(node.tag);
+ if (node.type == YAML_SCALAR_NODE) {
+ yaml_free(node.data.scalar.value);
+ }
+ }
+ if (node.type == YAML_SEQUENCE_NODE) {
+ STACK_DEL(emitter, node.data.sequence.items);
+ }
+ if (node.type == YAML_MAPPING_NODE) {
+ STACK_DEL(emitter, node.data.mapping.pairs);
+ }
+ }
+
+ STACK_DEL(emitter, emitter->document->nodes);
+ yaml_free(emitter->anchors);
+
+ emitter->anchors = NULL;
+ emitter->last_anchor_id = 0;
+ emitter->document = NULL;
+}
+
+/*
+ * Check the references of a node and assign the anchor id if needed.
+ */
+
+static void
+yaml_emitter_anchor_node(yaml_emitter_t *emitter, int index)
+{
+ yaml_node_t *node = emitter->document->nodes.start + index - 1;
+ yaml_node_item_t *item;
+ yaml_node_pair_t *pair;
+
+ emitter->anchors[index-1].references ++;
+
+ if (emitter->anchors[index-1].references == 1) {
+ switch (node->type) {
+ case YAML_SEQUENCE_NODE:
+ for (item = node->data.sequence.items.start;
+ item < node->data.sequence.items.top; item ++) {
+ yaml_emitter_anchor_node(emitter, *item);
+ }
+ break;
+ case YAML_MAPPING_NODE:
+ for (pair = node->data.mapping.pairs.start;
+ pair < node->data.mapping.pairs.top; pair ++) {
+ yaml_emitter_anchor_node(emitter, pair->key);
+ yaml_emitter_anchor_node(emitter, pair->value);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ else if (emitter->anchors[index-1].references == 2) {
+ emitter->anchors[index-1].anchor = (++ emitter->last_anchor_id);
+ }
+}
+
+/*
+ * Generate a textual representation for an anchor.
+ */
+
+#define ANCHOR_TEMPLATE "id%03d"
+#define ANCHOR_TEMPLATE_LENGTH 16
+
+static yaml_char_t *
+yaml_emitter_generate_anchor(yaml_emitter_t *emitter, int anchor_id)
+{
+ yaml_char_t *anchor = yaml_malloc(ANCHOR_TEMPLATE_LENGTH);
+
+ if (!anchor) return NULL;
+
+ sprintf((char *)anchor, ANCHOR_TEMPLATE, anchor_id);
+
+ return anchor;
+}
+
+/*
+ * Serialize a node.
+ */
+
+static int
+yaml_emitter_dump_node(yaml_emitter_t *emitter, int index)
+{
+ yaml_node_t *node = emitter->document->nodes.start + index - 1;
+ int anchor_id = emitter->anchors[index-1].anchor;
+ yaml_char_t *anchor = NULL;
+
+ if (anchor_id) {
+ anchor = yaml_emitter_generate_anchor(emitter, anchor_id);
+ if (!anchor) return 0;
+ }
+
+ if (emitter->anchors[index-1].serialized) {
+ return yaml_emitter_dump_alias(emitter, anchor);
+ }
+
+ emitter->anchors[index-1].serialized = 1;
+
+ switch (node->type) {
+ case YAML_SCALAR_NODE:
+ return yaml_emitter_dump_scalar(emitter, node, anchor);
+ case YAML_SEQUENCE_NODE:
+ return yaml_emitter_dump_sequence(emitter, node, anchor);
+ case YAML_MAPPING_NODE:
+ return yaml_emitter_dump_mapping(emitter, node, anchor);
+ default:
+ assert(0); /* Could not happen. */
+ break;
+ }
+
+ return 0; /* Could not happen. */
+}
+
+/*
+ * Serialize an alias.
+ */
+
+static int
+yaml_emitter_dump_alias(yaml_emitter_t *emitter, yaml_char_t *anchor)
+{
+ yaml_event_t event;
+ yaml_mark_t mark = { 0, 0, 0 };
+
+ ALIAS_EVENT_INIT(event, anchor, mark, mark);
+
+ return yaml_emitter_emit(emitter, &event);
+}
+
+/*
+ * Serialize a scalar.
+ */
+
+static int
+yaml_emitter_dump_scalar(yaml_emitter_t *emitter, yaml_node_t *node,
+ yaml_char_t *anchor)
+{
+ yaml_event_t event;
+ yaml_mark_t mark = { 0, 0, 0 };
+
+ int plain_implicit = (strcmp((char *)node->tag,
+ YAML_DEFAULT_SCALAR_TAG) == 0);
+ int quoted_implicit = (strcmp((char *)node->tag,
+ YAML_DEFAULT_SCALAR_TAG) == 0);
+
+ SCALAR_EVENT_INIT(event, anchor, node->tag, node->data.scalar.value,
+ node->data.scalar.length, plain_implicit, quoted_implicit,
+ node->data.scalar.style, mark, mark);
+
+ return yaml_emitter_emit(emitter, &event);
+}
+
+/*
+ * Serialize a sequence.
+ */
+
+static int
+yaml_emitter_dump_sequence(yaml_emitter_t *emitter, yaml_node_t *node,
+ yaml_char_t *anchor)
+{
+ yaml_event_t event;
+ yaml_mark_t mark = { 0, 0, 0 };
+
+ int implicit = (strcmp((char *)node->tag, YAML_DEFAULT_SEQUENCE_TAG) == 0);
+
+ yaml_node_item_t *item;
+
+ SEQUENCE_START_EVENT_INIT(event, anchor, node->tag, implicit,
+ node->data.sequence.style, mark, mark);
+ if (!yaml_emitter_emit(emitter, &event)) return 0;
+
+ for (item = node->data.sequence.items.start;
+ item < node->data.sequence.items.top; item ++) {
+ if (!yaml_emitter_dump_node(emitter, *item)) return 0;
+ }
+
+ SEQUENCE_END_EVENT_INIT(event, mark, mark);
+ if (!yaml_emitter_emit(emitter, &event)) return 0;
+
+ return 1;
+}
+
+/*
+ * Serialize a mapping.
+ */
+
+static int
+yaml_emitter_dump_mapping(yaml_emitter_t *emitter, yaml_node_t *node,
+ yaml_char_t *anchor)
+{
+ yaml_event_t event;
+ yaml_mark_t mark = { 0, 0, 0 };
+
+ int implicit = (strcmp((char *)node->tag, YAML_DEFAULT_MAPPING_TAG) == 0);
+
+ yaml_node_pair_t *pair;
+
+ MAPPING_START_EVENT_INIT(event, anchor, node->tag, implicit,
+ node->data.mapping.style, mark, mark);
+ if (!yaml_emitter_emit(emitter, &event)) return 0;
+
+ for (pair = node->data.mapping.pairs.start;
+ pair < node->data.mapping.pairs.top; pair ++) {
+ if (!yaml_emitter_dump_node(emitter, pair->key)) return 0;
+ if (!yaml_emitter_dump_node(emitter, pair->value)) return 0;
+ }
+
+ MAPPING_END_EVENT_INIT(event, mark, mark);
+ if (!yaml_emitter_emit(emitter, &event)) return 0;
+
+ return 1;
+}
+
diff --git a/src/emitter.c b/src/emitter.c
index 28eadcc..0affaab 100644
--- a/src/emitter.c
+++ b/src/emitter.c
@@ -1160,6 +1160,13 @@ static int
yaml_emitter_select_scalar_style(yaml_emitter_t *emitter, yaml_event_t *event)
{
yaml_scalar_style_t style = event->data.scalar.style;
+ int no_tag = (!emitter->tag_data.handle && !emitter->tag_data.suffix);
+
+ if (no_tag && !event->data.scalar.plain_implicit
+ && !event->data.scalar.quoted_implicit) {
+ return yaml_emitter_set_emitter_error(emitter,
+ "neither tag nor implicit flags are specified");
+ }
if (style == YAML_ANY_SCALAR_STYLE)
style = YAML_PLAIN_SCALAR_STYLE;
@@ -1178,8 +1185,7 @@ yaml_emitter_select_scalar_style(yaml_emitter_t *emitter, yaml_event_t *event)
if (!emitter->scalar_data.length
&& (emitter->flow_level || emitter->simple_key_context))
style = YAML_SINGLE_QUOTED_SCALAR_STYLE;
- if (!event->data.scalar.plain_implicit
- && !emitter->tag_data.handle && !emitter->tag_data.suffix)
+ if (no_tag && !event->data.scalar.plain_implicit)
style = YAML_SINGLE_QUOTED_SCALAR_STYLE;
}
@@ -1196,19 +1202,11 @@ yaml_emitter_select_scalar_style(yaml_emitter_t *emitter, yaml_event_t *event)
style = YAML_DOUBLE_QUOTED_SCALAR_STYLE;
}
- if (!emitter->tag_data.handle && !emitter->tag_data.suffix)
+ if (no_tag && !event->data.scalar.quoted_implicit
+ && style != YAML_PLAIN_SCALAR_STYLE)
{
- if (!event->data.scalar.plain_implicit
- && !event->data.scalar.quoted_implicit) {
- return yaml_emitter_set_emitter_error(emitter,
- "neither tag nor implicit flags are specified");
- }
-
- if (event->data.scalar.plain_implicit
- && style != YAML_PLAIN_SCALAR_STYLE) {
- emitter->tag_data.handle = (yaml_char_t *)"!";
- emitter->tag_data.handle_length = 1;
- }
+ emitter->tag_data.handle = (yaml_char_t *)"!";
+ emitter->tag_data.handle_length = 1;
}
emitter->scalar_data.style = style;
diff --git a/src/loader.c b/src/loader.c
new file mode 100644
index 0000000..7ee0dbd
--- /dev/null
+++ b/src/loader.c
@@ -0,0 +1,429 @@
+
+#include "yaml_private.h"
+
+/*
+ * API functions.
+ */
+
+YAML_DECLARE(int)
+yaml_parser_load(yaml_parser_t *parser, yaml_document_t *document);
+
+/*
+ * Error handling.
+ */
+
+static int
+yaml_parser_set_parser_error(yaml_parser_t *parser,
+ const char *problem, yaml_mark_t problem_mark);
+
+static int
+yaml_parser_set_parser_error_context(yaml_parser_t *parser,
+ const char *context, yaml_mark_t context_mark,
+ const char *problem, yaml_mark_t problem_mark);
+
+
+/*
+ * Alias handling.
+ */
+
+static int
+yaml_parser_register_anchor(yaml_parser_t *parser,
+ int index, yaml_char_t *anchor);
+
+/*
+ * Clean up functions.
+ */
+
+static void
+yaml_parser_delete_aliases(yaml_parser_t *parser);
+
+/*
+ * Composer functions.
+ */
+
+static int
+yaml_parser_load_document(yaml_parser_t *parser, yaml_event_t *first_event);
+
+static int
+yaml_parser_load_node(yaml_parser_t *parser, yaml_event_t *first_event);
+
+static int
+yaml_parser_load_alias(yaml_parser_t *parser, yaml_event_t *first_event);
+
+static int
+yaml_parser_load_scalar(yaml_parser_t *parser, yaml_event_t *first_event);
+
+static int
+yaml_parser_load_sequence(yaml_parser_t *parser, yaml_event_t *first_event);
+
+static int
+yaml_parser_load_mapping(yaml_parser_t *parser, yaml_event_t *first_event);
+
+/*
+ * Load the next document of the stream.
+ */
+
+YAML_DECLARE(int)
+yaml_parser_load(yaml_parser_t *parser, yaml_document_t *document)
+{
+ yaml_event_t event;
+
+ assert(parser); /* Non-NULL parser object is expected. */
+ assert(document); /* Non-NULL document object is expected. */
+
+ memset(document, 0, sizeof(yaml_document_t));
+ if (!STACK_INIT(parser, document->nodes, INITIAL_STACK_SIZE))
+ goto error;
+
+ if (!parser->stream_start_produced) {
+ if (!yaml_parser_parse(parser, &event)) goto error;
+ assert(event.type == YAML_STREAM_START_EVENT);
+ /* STREAM-START is expected. */
+ }
+
+ if (parser->stream_end_produced) {
+ return 1;
+ }
+
+ if (!yaml_parser_parse(parser, &event)) goto error;
+ if (event.type == YAML_STREAM_END_EVENT) {
+ return 1;
+ }
+
+ if (!STACK_INIT(parser, parser->aliases, INITIAL_STACK_SIZE))
+ goto error;
+
+ parser->document = document;
+
+ if (!yaml_parser_load_document(parser, &event)) goto error;
+
+ yaml_parser_delete_aliases(parser);
+ parser->document = NULL;
+
+ return 1;
+
+error:
+
+ yaml_parser_delete_aliases(parser);
+ yaml_document_delete(document);
+ parser->document = NULL;
+
+ return 0;
+}
+
+/*
+ * Set composer error.
+ */
+
+static int
+yaml_parser_set_composer_error(yaml_parser_t *parser,
+ const char *problem, yaml_mark_t problem_mark)
+{
+ parser->error = YAML_COMPOSER_ERROR;
+ parser->problem = problem;
+ parser->problem_mark = problem_mark;
+
+ return 0;
+}
+
+/*
+ * Set composer error with context.
+ */
+
+static int
+yaml_parser_set_composer_error_context(yaml_parser_t *parser,
+ const char *context, yaml_mark_t context_mark,
+ const char *problem, yaml_mark_t problem_mark)
+{
+ parser->error = YAML_COMPOSER_ERROR;
+ parser->context = context;
+ parser->context_mark = context_mark;
+ parser->problem = problem;
+ parser->problem_mark = problem_mark;
+
+ return 0;
+}
+
+/*
+ * Delete the stack of aliases.
+ */
+
+static void
+yaml_parser_delete_aliases(yaml_parser_t *parser)
+{
+ while (!STACK_EMPTY(parser, parser->aliases)) {
+ yaml_free(POP(parser, parser->aliases).anchor);
+ }
+ STACK_DEL(parser, parser->aliases);
+}
+
+/*
+ * Compose a document object.
+ */
+
+static int
+yaml_parser_load_document(yaml_parser_t *parser, yaml_event_t *first_event)
+{
+ yaml_event_t event;
+
+ assert(first_event->type == YAML_DOCUMENT_START_EVENT);
+ /* DOCUMENT-START is expected. */
+
+ parser->document->version_directive
+ = first_event->data.document_start.version_directive;
+ parser->document->tag_directives.start
+ = first_event->data.document_start.tag_directives.start;
+ parser->document->tag_directives.end
+ = first_event->data.document_start.tag_directives.end;
+ parser->document->start_implicit
+ = first_event->data.document_start.implicit;
+ parser->document->start_mark = first_event->start_mark;
+
+ if (!yaml_parser_parse(parser, &event)) return 0;
+
+ if (!yaml_parser_load_node(parser, &event)) return 0;
+
+ if (!yaml_parser_parse(parser, &event)) return 0;
+ assert(event.type == YAML_DOCUMENT_END_EVENT);
+ /* DOCUMENT-END is expected. */
+
+ parser->document->end_implicit = event.data.document_end.implicit;
+ parser->document->end_mark = event.end_mark;
+
+ return 1;
+}
+
+/*
+ * Compose a node.
+ */
+
+static int
+yaml_parser_load_node(yaml_parser_t *parser, yaml_event_t *first_event)
+{
+ switch (first_event->type) {
+ case YAML_ALIAS_EVENT:
+ return yaml_parser_load_alias(parser, first_event);
+ case YAML_SCALAR_EVENT:
+ return yaml_parser_load_scalar(parser, first_event);
+ case YAML_SEQUENCE_START_EVENT:
+ return yaml_parser_load_sequence(parser, first_event);
+ case YAML_MAPPING_START_EVENT:
+ return yaml_parser_load_mapping(parser, first_event);
+ default:
+ assert(0); /* Could not happen. */
+ return 0;
+ }
+
+ return 0;
+}
+
+/*
+ * Add an anchor.
+ */
+
+static int
+yaml_parser_register_anchor(yaml_parser_t *parser,
+ int index, yaml_char_t *anchor)
+{
+ yaml_alias_data_t data = { anchor, index,
+ parser->document->nodes.start[index-1].start_mark };
+ yaml_alias_data_t *alias_data;
+
+ if (!anchor) return 1;
+
+ for (alias_data = parser->aliases.start;
+ alias_data != parser->aliases.top; alias_data ++) {
+ if (strcmp((char *)alias_data->anchor, (char *)anchor) == 0) {
+ yaml_free(anchor);
+ return yaml_parser_set_composer_error_context(parser,
+ "found duplicate anchor; first occurence",
+ alias_data->mark, "second occurence", data.mark);
+ }
+ }
+
+ if (!PUSH(parser, parser->aliases, data)) {
+ yaml_free(anchor);
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * Compose a node corresponding to an alias.
+ */
+
+static int
+yaml_parser_load_alias(yaml_parser_t *parser, yaml_event_t *first_event)
+{
+ yaml_char_t *anchor = first_event->data.alias.anchor;
+ yaml_alias_data_t *alias_data;
+
+ for (alias_data = parser->aliases.start;
+ alias_data != parser->aliases.top; alias_data ++) {
+ if (strcmp((char *)alias_data->anchor, (char *)anchor) == 0) {
+ yaml_free(anchor);
+ return alias_data->index;
+ }
+ }
+
+ yaml_free(anchor);
+ return yaml_parser_set_composer_error(parser, "found undefined alias",
+ first_event->start_mark);
+}
+
+/*
+ * Compose a scalar node.
+ */
+
+static int
+yaml_parser_load_scalar(yaml_parser_t *parser, yaml_event_t *first_event)
+{
+ yaml_node_t node;
+ int index;
+ yaml_char_t *tag = first_event->data.scalar.tag;
+
+ if (!tag || strcmp((char *)tag, "!") == 0) {
+ yaml_free(tag);
+ tag = yaml_strdup(YAML_DEFAULT_SCALAR_TAG);
+ if (!tag) goto error;
+ }
+
+ SCALAR_NODE_INIT(node, tag, first_event->data.scalar.value,
+ first_event->data.scalar.length, first_event->data.scalar.style,
+ first_event->start_mark, first_event->end_mark);
+
+ if (!PUSH(parser, parser->document->nodes, node)) goto error;
+
+ index = parser->document->nodes.top - parser->document->nodes.start;
+
+ if (!yaml_parser_register_anchor(parser, index,
+ first_event->data.scalar.anchor)) return 0;
+
+ return index;
+
+error:
+ yaml_free(tag);
+ yaml_free(first_event->data.scalar.anchor);
+ yaml_free(first_event->data.scalar.value);
+ return 0;
+}
+
+/*
+ * Compose a sequence node.
+ */
+
+static int
+yaml_parser_load_sequence(yaml_parser_t *parser, yaml_event_t *first_event)
+{
+ yaml_event_t event;
+ yaml_node_t node;
+ struct {
+ yaml_node_item_t *start;
+ yaml_node_item_t *end;
+ yaml_node_item_t *top;
+ } items = { NULL, NULL, NULL };
+ int index, item_index;
+ yaml_char_t *tag = first_event->data.sequence_start.tag;
+
+ if (!tag || strcmp((char *)tag, "!") == 0) {
+ yaml_free(tag);
+ tag = yaml_strdup(YAML_DEFAULT_SEQUENCE_TAG);
+ if (!tag) goto error;
+ }
+
+ if (!STACK_INIT(parser, items, INITIAL_STACK_SIZE)) goto error;
+
+ SEQUENCE_NODE_INIT(node, tag, items.start, items.end,
+ first_event->data.sequence_start.style,
+ first_event->start_mark, first_event->end_mark);
+
+ if (!PUSH(parser, parser->document->nodes, node)) goto error;
+
+ index = parser->document->nodes.top - parser->document->nodes.start;
+
+ if (!yaml_parser_register_anchor(parser, index,
+ first_event->data.sequence_start.anchor)) return 0;
+
+ if (!yaml_parser_parse(parser, &event)) return 0;
+
+ while (event.type != YAML_SEQUENCE_END_EVENT) {
+ item_index = yaml_parser_load_node(parser, &event);
+ if (!item_index) return 0;
+ if (!PUSH(parser,
+ parser->document->nodes.start[index-1].data.sequence.items,
+ item_index)) return 0;
+ if (!yaml_parser_parse(parser, &event)) return 0;
+ }
+
+ parser->document->nodes.start[index-1].end_mark = event.end_mark;
+
+ return index;
+
+error:
+ yaml_free(tag);
+ yaml_free(first_event->data.sequence_start.anchor);
+ return 0;
+}
+
+/*
+ * Compose a mapping node.
+ */
+
+static int
+yaml_parser_load_mapping(yaml_parser_t *parser, yaml_event_t *first_event)
+{
+ yaml_event_t event;
+ yaml_node_t node;
+ struct {
+ yaml_node_pair_t *start;
+ yaml_node_pair_t *end;
+ yaml_node_pair_t *top;
+ } pairs = { NULL, NULL, NULL };
+ int index;
+ yaml_node_pair_t pair;
+ yaml_char_t *tag = first_event->data.mapping_start.tag;
+
+ if (!tag || strcmp((char *)tag, "!") == 0) {
+ yaml_free(tag);
+ tag = yaml_strdup(YAML_DEFAULT_MAPPING_TAG);
+ if (!tag) goto error;
+ }
+
+ if (!STACK_INIT(parser, pairs, INITIAL_STACK_SIZE)) goto error;
+
+ MAPPING_NODE_INIT(node, tag, pairs.start, pairs.end,
+ first_event->data.mapping_start.style,
+ first_event->start_mark, first_event->end_mark);
+
+ if (!PUSH(parser, parser->document->nodes, node)) goto error;
+
+ index = parser->document->nodes.top - parser->document->nodes.start;
+
+ if (!yaml_parser_register_anchor(parser, index,
+ first_event->data.mapping_start.anchor)) return 0;
+
+ if (!yaml_parser_parse(parser, &event)) return 0;
+
+ while (event.type != YAML_MAPPING_END_EVENT) {
+ pair.key = yaml_parser_load_node(parser, &event);
+ if (!pair.key) return 0;
+ if (!yaml_parser_parse(parser, &event)) return 0;
+ pair.value = yaml_parser_load_node(parser, &event);
+ if (!pair.value) return 0;
+ if (!PUSH(parser,
+ parser->document->nodes.start[index-1].data.mapping.pairs,
+ pair)) return 0;
+ if (!yaml_parser_parse(parser, &event)) return 0;
+ }
+
+ parser->document->nodes.start[index-1].end_mark = event.end_mark;
+
+ return index;
+
+error:
+ yaml_free(tag);
+ yaml_free(first_event->data.mapping_start.anchor);
+ return 0;
+}
+
diff --git a/src/yaml_private.h b/src/yaml_private.h
index 3378735..10c4219 100644
--- a/src/yaml_private.h
+++ b/src/yaml_private.h
@@ -580,27 +580,44 @@ yaml_queue_extend(void **start, void **head, void **tail, void **end);
(EVENT_INIT((event),YAML_MAPPING_END_EVENT,(start_mark),(end_mark)))
/*
+ * Document initializer.
+ */
+
+#define DOCUMENT_INIT(document,document_nodes_start,document_nodes_end, \
+ document_version_directive,document_tag_directives_start, \
+ document_tag_directives_end,document_start_implicit, \
+ document_end_implicit,start_mark,end_mark) \
+ (memset(&(document), 0, sizeof(yaml_document_t)), \
+ (document).nodes.start = (document_nodes_start), \
+ (document).nodes.end = (document_nodes_end), \
+ (document).nodes.top = (document_nodes_start), \
+ (document).version_directive = (document_version_directive), \
+ (document).tag_directives.start = (document_tag_directives_start), \
+ (document).tag_directives.end = (document_tag_directives_end), \
+ (document).start_implicit = (document_start_implicit), \
+ (document).end_implicit = (document_end_implicit))
+
+/*
* Node initializers.
*/
-#define NODE_INIT(node,node_type,node_start_mark,node_end_mark) \
+#define NODE_INIT(node,node_type,node_tag,node_start_mark,node_end_mark) \
(memset(&(node), 0, sizeof(yaml_node_t)), \
(node).type = (node_type), \
+ (node).tag = (node_tag), \
(node).start_mark = (node_start_mark), \
(node).end_mark = (node_end_mark))
#define SCALAR_NODE_INIT(node,node_tag,node_value,node_length, \
node_style,start_mark,end_mark) \
- (EVENT_INIT((node),YAML_SCALAR_NODE,(start_mark),(end_mark)), \
- (node).data.scalar.tag = (node_tag), \
+ (NODE_INIT((node),YAML_SCALAR_NODE,(node_tag),(start_mark),(end_mark)), \
(node).data.scalar.value = (node_value), \
(node).data.scalar.length = (node_length), \
(node).data.scalar.style = (node_style))
#define SEQUENCE_NODE_INIT(node,node_tag,node_items_start,node_items_end, \
node_style,start_mark,end_mark) \
- (NODE_INIT((node),YAML_SEQUENCE_NODE,(start_mark),(end_mark)), \
- (node).data.sequence.tag = (node_tag), \
+ (NODE_INIT((node),YAML_SEQUENCE_NODE,(node_tag),(start_mark),(end_mark)), \
(node).data.sequence.items.start = (node_items_start), \
(node).data.sequence.items.end = (node_items_end), \
(node).data.sequence.items.top = (node_items_start), \
@@ -608,8 +625,7 @@ yaml_queue_extend(void **start, void **head, void **tail, void **end);
#define MAPPING_NODE_INIT(node,node_tag,node_pairs_start,node_pairs_end, \
node_style,start_mark,end_mark) \
- (NODE_INIT((node),YAML_MAPPING_NODE,(start_mark),(end_mark)), \
- (node).data.mapping.tag = (node_tag), \
+ (NODE_INIT((node),YAML_MAPPING_NODE,(node_tag),(start_mark),(end_mark)), \
(node).data.mapping.pairs.start = (node_pairs_start), \
(node).data.mapping.pairs.end = (node_pairs_end), \
(node).data.mapping.pairs.top = (node_pairs_start), \
diff --git a/tests/Makefile.am b/tests/Makefile.am
index bfc01d7..72e84d2 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -3,4 +3,6 @@ AM_CPPFLAGS = -I$(top_srcdir)/include
LDADD = $(top_builddir)/src/libyaml.la
TESTS = test-version test-reader
check_PROGRAMS = test-version test-reader
-noinst_PROGRAMS = run-scanner run-parser run-emitter example-reformatter example-deconstructor
+noinst_PROGRAMS = run-scanner run-parser run-loader run-emitter run-dumper \
+ example-reformatter example-reformatter-alt \
+ example-deconstructor example-deconstructor-alt
diff --git a/tests/example-deconstructor-alt.c b/tests/example-deconstructor-alt.c
new file mode 100644
index 0000000..7da194a
--- /dev/null
+++ b/tests/example-deconstructor-alt.c
@@ -0,0 +1,800 @@
+
+#include <yaml.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+
+int
+main(int argc, char *argv[])
+{
+ int help = 0;
+ int canonical = 0;
+ int unicode = 0;
+ int k;
+ int done = 0;
+
+ yaml_parser_t parser;
+ yaml_emitter_t emitter;
+ yaml_event_t input_event;
+ yaml_document_t output_document;
+
+ int root;
+
+ /* Clear the objects. */
+
+ memset(&parser, 0, sizeof(parser));
+ memset(&emitter, 0, sizeof(emitter));
+ memset(&input_event, 0, sizeof(input_event));
+ memset(&output_document, 0, sizeof(output_document));
+
+ /* Analyze command line options. */
+
+ for (k = 1; k < argc; k ++)
+ {
+ if (strcmp(argv[k], "-h") == 0
+ || strcmp(argv[k], "--help") == 0) {
+ help = 1;
+ }
+
+ else if (strcmp(argv[k], "-c") == 0
+ || strcmp(argv[k], "--canonical") == 0) {
+ canonical = 1;
+ }
+
+ else if (strcmp(argv[k], "-u") == 0
+ || strcmp(argv[k], "--unicode") == 0) {
+ unicode = 1;
+ }
+
+ else {
+ fprintf(stderr, "Unrecognized option: %s\n"
+ "Try `%s --help` for more information.\n",
+ argv[k], argv[0]);
+ return 1;
+ }
+ }
+
+ /* Display the help string. */
+
+ if (help)
+ {
+ printf("%s <input\n"
+ "or\n%s -h | --help\nDeconstruct a YAML stream\n\nOptions:\n"
+ "-h, --help\t\tdisplay this help and exit\n"
+ "-c, --canonical\t\toutput in the canonical YAML format\n"
+ "-u, --unicode\t\toutput unescaped non-ASCII characters\n",
+ argv[0], argv[0]);
+ return 0;
+ }
+
+ /* Initialize the parser and emitter objects. */
+
+ if (!yaml_parser_initialize(&parser)) {
+ fprintf(stderr, "Could not initialize the parser object\n");
+ return 1;
+ }
+
+ if (!yaml_emitter_initialize(&emitter)) {
+ yaml_parser_delete(&parser);
+ fprintf(stderr, "Could not inialize the emitter object\n");
+ return 1;
+ }
+
+ /* Set the parser parameters. */
+
+ yaml_parser_set_input_file(&parser, stdin);
+
+ /* Set the emitter parameters. */
+
+ yaml_emitter_set_output_file(&emitter, stdout);
+
+ yaml_emitter_set_canonical(&emitter, canonical);
+ yaml_emitter_set_unicode(&emitter, unicode);
+
+ /* Create and emit the STREAM-START event. */
+
+ if (!yaml_emitter_open(&emitter))
+ goto emitter_error;
+
+ /* Create a output_document object. */
+
+ if (!yaml_document_initialize(&output_document, NULL, NULL, NULL, 0, 0))
+ goto document_error;
+
+ /* Create the root sequence. */
+
+ root = yaml_document_add_sequence(&output_document, NULL,
+ YAML_BLOCK_SEQUENCE_STYLE);
+ if (!root) goto document_error;
+
+ /* Loop through the input events. */
+
+ while (!done)
+ {
+ int properties, key, value, map, seq;
+
+ /* Get the next event. */
+
+ if (!yaml_parser_parse(&parser, &input_event))
+ goto parser_error;
+
+ /* Check if this is the stream end. */
+
+ if (input_event.type == YAML_STREAM_END_EVENT) {
+ done = 1;
+ }
+
+ /* Create a mapping node and attach it to the root sequence. */
+
+ properties = yaml_document_add_mapping(&output_document, NULL,
+ YAML_BLOCK_MAPPING_STYLE);
+ if (!properties) goto document_error;
+ if (!yaml_document_append_sequence_item(&output_document,
+ root, properties)) goto document_error;
+
+ /* Analyze the event. */
+
+ switch (input_event.type)
+ {
+ case YAML_STREAM_START_EVENT:
+
+ /* Add 'type': 'STREAM-START'. */
+
+ key = yaml_document_add_scalar(&output_document, NULL,
+ "type", -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!key) goto document_error;
+ value = yaml_document_add_scalar(&output_document, NULL,
+ "STREAM-START", -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!value) goto document_error;
+ if (!yaml_document_append_mapping_pair(&output_document,
+ properties, key, value)) goto document_error;
+
+ /* Add 'encoding': <encoding>. */
+
+ if (input_event.data.stream_start.encoding)
+ {
+ yaml_encoding_t encoding
+ = input_event.data.stream_start.encoding;
+
+ key = yaml_document_add_scalar(&output_document, NULL,
+ "encoding", -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!key) goto document_error;
+ value = yaml_document_add_scalar(&output_document, NULL,
+ (encoding == YAML_UTF8_ENCODING ? "utf-8" :
+ encoding == YAML_UTF16LE_ENCODING ? "utf-16-le" :
+ encoding == YAML_UTF16BE_ENCODING ? "utf-16-be" :
+ "unknown"), -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!value) goto document_error;
+ if (!yaml_document_append_mapping_pair(&output_document,
+ properties, key, value)) goto document_error;
+ }
+
+ break;
+
+ case YAML_STREAM_END_EVENT:
+
+ /* Add 'type': 'STREAM-END'. */
+
+ key = yaml_document_add_scalar(&output_document, NULL,
+ "type", -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!key) goto document_error;
+ value = yaml_document_add_scalar(&output_document, NULL,
+ "STREAM-END", -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!value) goto document_error;
+ if (!yaml_document_append_mapping_pair(&output_document,
+ properties, key, value)) goto document_error;
+
+ break;
+
+ case YAML_DOCUMENT_START_EVENT:
+
+ /* Add 'type': 'DOCUMENT-START'. */
+
+ key = yaml_document_add_scalar(&output_document, NULL,
+ "type", -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!key) goto document_error;
+ value = yaml_document_add_scalar(&output_document, NULL,
+ "DOCUMENT-START", -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!value) goto document_error;
+ if (!yaml_document_append_mapping_pair(&output_document,
+ properties, key, value)) goto document_error;
+
+ /* Display the output_document version numbers. */
+
+ if (input_event.data.document_start.version_directive)
+ {
+ yaml_version_directive_t *version
+ = input_event.data.document_start.version_directive;
+ char number[64];
+
+ /* Add 'version': {}. */
+
+ key = yaml_document_add_scalar(&output_document, NULL,
+ "version", -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!key) goto document_error;
+ map = yaml_document_add_mapping(&output_document, NULL,
+ YAML_FLOW_MAPPING_STYLE);
+ if (!map) goto document_error;
+ if (!yaml_document_append_mapping_pair(&output_document,
+ properties, key, map)) goto document_error;
+
+ /* Add 'major': <number>. */
+
+ key = yaml_document_add_scalar(&output_document, NULL,
+ "major", -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!key) goto document_error;
+ sprintf(number, "%d", version->major);
+ value = yaml_document_add_scalar(&output_document, YAML_INT_TAG,
+ number, -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!value) goto document_error;
+ if (!yaml_document_append_mapping_pair(&output_document,
+ map, key, value)) goto document_error;
+
+ /* Add 'minor': <number>. */
+
+ key = yaml_document_add_scalar(&output_document, NULL,
+ "minor", -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!key) goto document_error;
+ sprintf(number, "%d", version->minor);
+ value = yaml_document_add_scalar(&output_document, YAML_INT_TAG,
+ number, -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!value) goto document_error;
+ if (!yaml_document_append_mapping_pair(&output_document,
+ map, key, value)) goto document_error;
+ }
+
+ /* Display the output_document tag directives. */
+
+ if (input_event.data.document_start.tag_directives.start
+ != input_event.data.document_start.tag_directives.end)
+ {
+ yaml_tag_directive_t *tag;
+
+ /* Add 'tags': []. */
+
+ key = yaml_document_add_scalar(&output_document, NULL,
+ "tags", -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!key) goto document_error;
+ seq = yaml_document_add_sequence(&output_document, NULL,
+ YAML_BLOCK_SEQUENCE_STYLE);
+ if (!seq) goto document_error;
+ if (!yaml_document_append_mapping_pair(&output_document,
+ properties, key, seq)) goto document_error;
+
+ for (tag = input_event.data.document_start.tag_directives.start;
+ tag != input_event.data.document_start.tag_directives.end;
+ tag ++)
+ {
+ /* Add {}. */
+
+ map = yaml_document_add_mapping(&output_document, NULL,
+ YAML_FLOW_MAPPING_STYLE);
+ if (!map) goto document_error;
+ if (!yaml_document_append_sequence_item(&output_document,
+ seq, map)) goto document_error;
+
+ /* Add 'handle': <handle>. */
+
+ key = yaml_document_add_scalar(&output_document, NULL,
+ "handle", -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!key) goto document_error;
+ value = yaml_document_add_scalar(&output_document, NULL,
+ tag->handle, -1, YAML_DOUBLE_QUOTED_SCALAR_STYLE);
+ if (!value) goto document_error;
+ if (!yaml_document_append_mapping_pair(&output_document,
+ map, key, value)) goto document_error;
+
+ /* Add 'prefix': <prefix>. */
+
+ key = yaml_document_add_scalar(&output_document, NULL,
+ "prefix", -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!key) goto document_error;
+ value = yaml_document_add_scalar(&output_document, NULL,
+ tag->prefix, -1, YAML_DOUBLE_QUOTED_SCALAR_STYLE);
+ if (!value) goto document_error;
+ if (!yaml_document_append_mapping_pair(&output_document,
+ map, key, value)) goto document_error;
+ }
+ }
+
+ /* Add 'implicit': <flag>. */
+
+ key = yaml_document_add_scalar(&output_document, NULL,
+ "implicit", -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!key) goto document_error;
+ value = yaml_document_add_scalar(&output_document, YAML_BOOL_TAG,
+ (input_event.data.document_start.implicit ?
+ "true" : "false"), -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!value) goto document_error;
+ if (!yaml_document_append_mapping_pair(&output_document,
+ properties, key, value)) goto document_error;
+
+ break;
+
+ case YAML_DOCUMENT_END_EVENT:
+
+ /* Add 'type': 'DOCUMENT-END'. */
+
+ key = yaml_document_add_scalar(&output_document, NULL,
+ "type", -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!key) goto document_error;
+ value = yaml_document_add_scalar(&output_document, NULL,
+ "DOCUMENT-END", -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!value) goto document_error;
+ if (!yaml_document_append_mapping_pair(&output_document,
+ properties, key, value)) goto document_error;
+
+ /* Add 'implicit': <flag>. */
+
+ key = yaml_document_add_scalar(&output_document, NULL,
+ "implicit", -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!key) goto document_error;
+ value = yaml_document_add_scalar(&output_document, YAML_BOOL_TAG,
+ (input_event.data.document_end.implicit ?
+ "true" : "false"), -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!value) goto document_error;
+ if (!yaml_document_append_mapping_pair(&output_document,
+ properties, key, value)) goto document_error;
+
+ break;
+
+ case YAML_ALIAS_EVENT:
+
+ /* Add 'type': 'ALIAS'. */
+
+ key = yaml_document_add_scalar(&output_document, NULL,
+ "type", -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!key) goto document_error;
+ value = yaml_document_add_scalar(&output_document, NULL,
+ "ALIAS", -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!value) goto document_error;
+ if (!yaml_document_append_mapping_pair(&output_document,
+ properties, key, value)) goto document_error;
+
+ /* Add 'anchor': <anchor>. */
+
+ key = yaml_document_add_scalar(&output_document, NULL,
+ "anchor", -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!key) goto document_error;
+ value = yaml_document_add_scalar(&output_document, NULL,
+ input_event.data.alias.anchor, -1,
+ YAML_DOUBLE_QUOTED_SCALAR_STYLE);
+ if (!value) goto document_error;
+ if (!yaml_document_append_mapping_pair(&output_document,
+ properties, key, value)) goto document_error;
+
+ break;
+
+ case YAML_SCALAR_EVENT:
+
+ /* Add 'type': 'SCALAR'. */
+
+ key = yaml_document_add_scalar(&output_document, NULL,
+ "type", -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!key) goto document_error;
+ value = yaml_document_add_scalar(&output_document, NULL,
+ "SCALAR", -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!value) goto document_error;
+ if (!yaml_document_append_mapping_pair(&output_document,
+ properties, key, value)) goto document_error;
+
+ /* Add 'anchor': <anchor>. */
+
+ if (input_event.data.scalar.anchor)
+ {
+ key = yaml_document_add_scalar(&output_document, NULL,
+ "anchor", -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!key) goto document_error;
+ value = yaml_document_add_scalar(&output_document, NULL,
+ input_event.data.scalar.anchor, -1,
+ YAML_DOUBLE_QUOTED_SCALAR_STYLE);
+ if (!value) goto document_error;
+ if (!yaml_document_append_mapping_pair(&output_document,
+ properties, key, value)) goto document_error;
+ }
+
+ /* Add 'tag': <tag>. */
+
+ if (input_event.data.scalar.tag)
+ {
+ key = yaml_document_add_scalar(&output_document, NULL,
+ "tag", -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!key) goto document_error;
+ value = yaml_document_add_scalar(&output_document, NULL,
+ input_event.data.scalar.tag, -1,
+ YAML_DOUBLE_QUOTED_SCALAR_STYLE);
+ if (!value) goto document_error;
+ if (!yaml_document_append_mapping_pair(&output_document,
+ properties, key, value)) goto document_error;
+ }
+
+ /* Add 'value': <value>. */
+
+ key = yaml_document_add_scalar(&output_document, NULL,
+ "value", -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!key) goto document_error;
+ value = yaml_document_add_scalar(&output_document, NULL,
+ input_event.data.scalar.value,
+ input_event.data.scalar.length,
+ YAML_DOUBLE_QUOTED_SCALAR_STYLE);
+ if (!value) goto document_error;
+ if (!yaml_document_append_mapping_pair(&output_document,
+ properties, key, value)) goto document_error;
+
+ /* Display if the scalar tag is implicit. */
+
+ /* Add 'implicit': {} */
+
+ key = yaml_document_add_scalar(&output_document, NULL,
+ "version", -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!key) goto document_error;
+ map = yaml_document_add_mapping(&output_document, NULL,
+ YAML_FLOW_MAPPING_STYLE);
+ if (!map) goto document_error;
+ if (!yaml_document_append_mapping_pair(&output_document,
+ properties, key, map)) goto document_error;
+
+ /* Add 'plain': <flag>. */
+
+ key = yaml_document_add_scalar(&output_document, NULL,
+ "plain", -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!key) goto document_error;
+ value = yaml_document_add_scalar(&output_document, YAML_BOOL_TAG,
+ (input_event.data.scalar.plain_implicit ?
+ "true" : "false"), -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!value) goto document_error;
+ if (!yaml_document_append_mapping_pair(&output_document,
+ map, key, value)) goto document_error;
+
+ /* Add 'quoted': <flag>. */
+
+ key = yaml_document_add_scalar(&output_document, NULL,
+ "quoted", -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!key) goto document_error;
+ value = yaml_document_add_scalar(&output_document, YAML_BOOL_TAG,
+ (input_event.data.scalar.quoted_implicit ?
+ "true" : "false"), -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!value) goto document_error;
+ if (!yaml_document_append_mapping_pair(&output_document,
+ map, key, value)) goto document_error;
+
+ /* Display the style information. */
+
+ if (input_event.data.scalar.style)
+ {
+ yaml_scalar_style_t style = input_event.data.scalar.style;
+
+ /* Add 'style': <style>. */
+
+ key = yaml_document_add_scalar(&output_document, NULL,
+ "style", -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!key) goto document_error;
+ value = yaml_document_add_scalar(&output_document, NULL,
+ (style == YAML_PLAIN_SCALAR_STYLE ? "plain" :
+ style == YAML_SINGLE_QUOTED_SCALAR_STYLE ?
+ "single-quoted" :
+ style == YAML_DOUBLE_QUOTED_SCALAR_STYLE ?
+ "double-quoted" :
+ style == YAML_LITERAL_SCALAR_STYLE ? "literal" :
+ style == YAML_FOLDED_SCALAR_STYLE ? "folded" :
+ "unknown"), -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!value) goto document_error;
+ if (!yaml_document_append_mapping_pair(&output_document,
+ properties, key, value)) goto document_error;
+ }
+
+ break;
+
+ case YAML_SEQUENCE_START_EVENT:
+
+ /* Add 'type': 'SEQUENCE-START'. */
+
+ key = yaml_document_add_scalar(&output_document, NULL,
+ "type", -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!key) goto document_error;
+ value = yaml_document_add_scalar(&output_document, NULL,
+ "SEQUENCE-START", -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!value) goto document_error;
+ if (!yaml_document_append_mapping_pair(&output_document,
+ properties, key, value)) goto document_error;
+
+ /* Add 'anchor': <anchor>. */
+
+ if (input_event.data.sequence_start.anchor)
+ {
+ key = yaml_document_add_scalar(&output_document, NULL,
+ "anchor", -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!key) goto document_error;
+ value = yaml_document_add_scalar(&output_document, NULL,
+ input_event.data.sequence_start.anchor, -1,
+ YAML_DOUBLE_QUOTED_SCALAR_STYLE);
+ if (!value) goto document_error;
+ if (!yaml_document_append_mapping_pair(&output_document,
+ properties, key, value)) goto document_error;
+ }
+
+ /* Add 'tag': <tag>. */
+
+ if (input_event.data.sequence_start.tag)
+ {
+ key = yaml_document_add_scalar(&output_document, NULL,
+ "tag", -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!key) goto document_error;
+ value = yaml_document_add_scalar(&output_document, NULL,
+ input_event.data.sequence_start.tag, -1,
+ YAML_DOUBLE_QUOTED_SCALAR_STYLE);
+ if (!value) goto document_error;
+ if (!yaml_document_append_mapping_pair(&output_document,
+ properties, key, value)) goto document_error;
+ }
+
+ /* Add 'implicit': <flag>. */
+
+ key = yaml_document_add_scalar(&output_document, NULL,
+ "implicit", -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!key) goto document_error;
+ value = yaml_document_add_scalar(&output_document, YAML_BOOL_TAG,
+ (input_event.data.sequence_start.implicit ?
+ "true" : "false"), -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!value) goto document_error;
+ if (!yaml_document_append_mapping_pair(&output_document,
+ properties, key, value)) goto document_error;
+
+ /* Display the style information. */
+
+ if (input_event.data.sequence_start.style)
+ {
+ yaml_sequence_style_t style
+ = input_event.data.sequence_start.style;
+
+ /* Add 'style': <style>. */
+
+ key = yaml_document_add_scalar(&output_document, NULL,
+ "style", -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!key) goto document_error;
+ value = yaml_document_add_scalar(&output_document, NULL,
+ (style == YAML_BLOCK_SEQUENCE_STYLE ? "block" :
+ style == YAML_FLOW_SEQUENCE_STYLE ? "flow" :
+ "unknown"), -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!value) goto document_error;
+ if (!yaml_document_append_mapping_pair(&output_document,
+ properties, key, value)) goto document_error;
+ }
+
+ break;
+
+ case YAML_SEQUENCE_END_EVENT:
+
+ /* Add 'type': 'SEQUENCE-END'. */
+
+ key = yaml_document_add_scalar(&output_document, NULL,
+ "type", -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!key) goto document_error;
+ value = yaml_document_add_scalar(&output_document, NULL,
+ "SEQUENCE-END", -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!value) goto document_error;
+ if (!yaml_document_append_mapping_pair(&output_document,
+ properties, key, value)) goto document_error;
+
+ break;
+
+ case YAML_MAPPING_START_EVENT:
+
+ /* Add 'type': 'MAPPING-START'. */
+
+ key = yaml_document_add_scalar(&output_document, NULL,
+ "type", -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!key) goto document_error;
+ value = yaml_document_add_scalar(&output_document, NULL,
+ "MAPPING-START", -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!value) goto document_error;
+ if (!yaml_document_append_mapping_pair(&output_document,
+ properties, key, value)) goto document_error;
+
+ /* Add 'anchor': <anchor>. */
+
+ if (input_event.data.mapping_start.anchor)
+ {
+ key = yaml_document_add_scalar(&output_document, NULL,
+ "anchor", -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!key) goto document_error;
+ value = yaml_document_add_scalar(&output_document, NULL,
+ input_event.data.mapping_start.anchor, -1,
+ YAML_DOUBLE_QUOTED_SCALAR_STYLE);
+ if (!value) goto document_error;
+ if (!yaml_document_append_mapping_pair(&output_document,
+ properties, key, value)) goto document_error;
+ }
+
+ /* Add 'tag': <tag>. */
+
+ if (input_event.data.mapping_start.tag)
+ {
+ key = yaml_document_add_scalar(&output_document, NULL,
+ "tag", -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!key) goto document_error;
+ value = yaml_document_add_scalar(&output_document, NULL,
+ input_event.data.mapping_start.tag, -1,
+ YAML_DOUBLE_QUOTED_SCALAR_STYLE);
+ if (!value) goto document_error;
+ if (!yaml_document_append_mapping_pair(&output_document,
+ properties, key, value)) goto document_error;
+ }
+
+ /* Add 'implicit': <flag>. */
+
+ key = yaml_document_add_scalar(&output_document, NULL,
+ "implicit", -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!key) goto document_error;
+ value = yaml_document_add_scalar(&output_document, YAML_BOOL_TAG,
+ (input_event.data.mapping_start.implicit ?
+ "true" : "false"), -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!value) goto document_error;
+ if (!yaml_document_append_mapping_pair(&output_document,
+ properties, key, value)) goto document_error;
+
+ /* Display the style information. */
+
+ if (input_event.data.sequence_start.style)
+ {
+ yaml_sequence_style_t style
+ = input_event.data.mapping_start.style;
+
+ /* Add 'style': <style>. */
+
+ key = yaml_document_add_scalar(&output_document, NULL,
+ "style", -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!key) goto document_error;
+ value = yaml_document_add_scalar(&output_document, NULL,
+ (style == YAML_BLOCK_MAPPING_STYLE ? "block" :
+ style == YAML_FLOW_MAPPING_STYLE ? "flow" :
+ "unknown"), -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!value) goto document_error;
+ if (!yaml_document_append_mapping_pair(&output_document,
+ properties, key, value)) goto document_error;
+ }
+
+ break;
+
+ case YAML_MAPPING_END_EVENT:
+
+ /* Add 'type': 'MAPPING-END'. */
+
+ key = yaml_document_add_scalar(&output_document, NULL,
+ "type", -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!key) goto document_error;
+ value = yaml_document_add_scalar(&output_document, NULL,
+ "MAPPING-END", -1, YAML_PLAIN_SCALAR_STYLE);
+ if (!value) goto document_error;
+ if (!yaml_document_append_mapping_pair(&output_document,
+ properties, key, value)) goto document_error;
+
+ break;
+
+ default:
+ /* It couldn't really happen. */
+ break;
+ }
+
+ /* Delete the event object. */
+
+ yaml_event_delete(&input_event);
+ }
+
+ if (!yaml_emitter_dump(&emitter, &output_document))
+ goto emitter_error;
+ if (!yaml_emitter_close(&emitter))
+ goto emitter_error;
+
+ yaml_parser_delete(&parser);
+ yaml_emitter_delete(&emitter);
+
+ return 0;
+
+parser_error:
+
+ /* Display a parser error message. */
+
+ switch (parser.error)
+ {
+ case YAML_MEMORY_ERROR:
+ fprintf(stderr, "Memory error: Not enough memory for parsing\n");
+ break;
+
+ case YAML_READER_ERROR:
+ if (parser.problem_value != -1) {
+ fprintf(stderr, "Reader error: %s: #%X at %d\n", parser.problem,
+ parser.problem_value, parser.problem_offset);
+ }
+ else {
+ fprintf(stderr, "Reader error: %s at %d\n", parser.problem,
+ parser.problem_offset);
+ }
+ break;
+
+ case YAML_SCANNER_ERROR:
+ if (parser.context) {
+ fprintf(stderr, "Scanner error: %s at line %d, column %d\n"
+ "%s at line %d, column %d\n", parser.context,
+ parser.context_mark.line+1, parser.context_mark.column+1,
+ parser.problem, parser.problem_mark.line+1,
+ parser.problem_mark.column+1);
+ }
+ else {
+ fprintf(stderr, "Scanner error: %s at line %d, column %d\n",
+ parser.problem, parser.problem_mark.line+1,
+ parser.problem_mark.column+1);
+ }
+ break;
+
+ case YAML_PARSER_ERROR:
+ if (parser.context) {
+ fprintf(stderr, "Parser error: %s at line %d, column %d\n"
+ "%s at line %d, column %d\n", parser.context,
+ parser.context_mark.line+1, parser.context_mark.column+1,
+ parser.problem, parser.problem_mark.line+1,
+ parser.problem_mark.column+1);
+ }
+ else {
+ fprintf(stderr, "Parser error: %s at line %d, column %d\n",
+ parser.problem, parser.problem_mark.line+1,
+ parser.problem_mark.column+1);
+ }
+ break;
+
+ default:
+ /* Couldn't happen. */
+ fprintf(stderr, "Internal error\n");
+ break;
+ }
+
+ yaml_event_delete(&input_event);
+ yaml_document_delete(&output_document);
+ yaml_parser_delete(&parser);
+ yaml_emitter_delete(&emitter);
+
+ return 1;
+
+emitter_error:
+
+ /* Display an emitter error message. */
+
+ switch (emitter.error)
+ {
+ case YAML_MEMORY_ERROR:
+ fprintf(stderr, "Memory error: Not enough memory for emitting\n");
+ break;
+
+ case YAML_WRITER_ERROR:
+ fprintf(stderr, "Writer error: %s\n", emitter.problem);
+ break;
+
+ case YAML_EMITTER_ERROR:
+ fprintf(stderr, "Emitter error: %s\n", emitter.problem);
+ break;
+
+ default:
+ /* Couldn't happen. */
+ fprintf(stderr, "Internal error\n");
+ break;
+ }
+
+ yaml_event_delete(&input_event);
+ yaml_document_delete(&output_document);
+ yaml_parser_delete(&parser);
+ yaml_emitter_delete(&emitter);
+
+ return 1;
+
+document_error:
+
+ fprintf(stderr, "Memory error: Not enough memory for creating a document\n");
+
+ yaml_event_delete(&input_event);
+ yaml_document_delete(&output_document);
+ yaml_parser_delete(&parser);
+ yaml_emitter_delete(&emitter);
+
+ return 1;
+}
+
diff --git a/tests/example-deconstructor.c b/tests/example-deconstructor.c
index 57e6693..fec7d59 100644
--- a/tests/example-deconstructor.c
+++ b/tests/example-deconstructor.c
@@ -336,67 +336,67 @@ main(int argc, char *argv[])
tag != input_event.data.document_start.tag_directives.end;
tag ++)
{
- /* Write '{'. */
-
- if (!yaml_mapping_start_event_initialize(&output_event,
- NULL, "tag:yaml.org,2002:map", 1,
- YAML_FLOW_MAPPING_STYLE))
- goto event_error;
- if (!yaml_emitter_emit(&emitter, &output_event))
- goto emitter_error;
-
- /* Write 'handle'. */
-
- if (!yaml_scalar_event_initialize(&output_event,
- NULL, "tag:yaml.org,2002:str", "handle", -1,
- 1, 1, YAML_PLAIN_SCALAR_STYLE))
- goto event_error;
- if (!yaml_emitter_emit(&emitter, &output_event))
- goto emitter_error;
-
- /* Write the tag directive handle. */
-
- if (!yaml_scalar_event_initialize(&output_event,
- NULL, "tag:yaml.org,2002:str",
- tag->handle, -1,
- 0, 1, YAML_DOUBLE_QUOTED_SCALAR_STYLE))
- goto event_error;
- if (!yaml_emitter_emit(&emitter, &output_event))
- goto emitter_error;
-
- /* Write 'prefix'. */
-
- if (!yaml_scalar_event_initialize(&output_event,
- NULL, "tag:yaml.org,2002:str", "prefix", -1,
- 1, 1, YAML_PLAIN_SCALAR_STYLE))
- goto event_error;
- if (!yaml_emitter_emit(&emitter, &output_event))
- goto emitter_error;
-
- /* Write the tag directive prefix. */
-
- if (!yaml_scalar_event_initialize(&output_event,
- NULL, "tag:yaml.org,2002:str",
- tag->prefix, -1,
- 0, 1, YAML_DOUBLE_QUOTED_SCALAR_STYLE))
- goto event_error;
- if (!yaml_emitter_emit(&emitter, &output_event))
- goto emitter_error;
-
- /* Write '}'. */
-
- if (!yaml_mapping_end_event_initialize(&output_event))
- goto event_error;
- if (!yaml_emitter_emit(&emitter, &output_event))
- goto emitter_error;
- }
-
- /* End a block sequence. */
-
- if (!yaml_sequence_end_event_initialize(&output_event))
+ /* Write '{'. */
+
+ if (!yaml_mapping_start_event_initialize(&output_event,
+ NULL, "tag:yaml.org,2002:map", 1,
+ YAML_FLOW_MAPPING_STYLE))
+ goto event_error;
+ if (!yaml_emitter_emit(&emitter, &output_event))
+ goto emitter_error;
+
+ /* Write 'handle'. */
+
+ if (!yaml_scalar_event_initialize(&output_event,
+ NULL, "tag:yaml.org,2002:str", "handle", -1,
+ 1, 1, YAML_PLAIN_SCALAR_STYLE))
+ goto event_error;
+ if (!yaml_emitter_emit(&emitter, &output_event))
+ goto emitter_error;
+
+ /* Write the tag directive handle. */
+
+ if (!yaml_scalar_event_initialize(&output_event,
+ NULL, "tag:yaml.org,2002:str",
+ tag->handle, -1,
+ 0, 1, YAML_DOUBLE_QUOTED_SCALAR_STYLE))
+ goto event_error;
+ if (!yaml_emitter_emit(&emitter, &output_event))
+ goto emitter_error;
+
+ /* Write 'prefix'. */
+
+ if (!yaml_scalar_event_initialize(&output_event,
+ NULL, "tag:yaml.org,2002:str", "prefix", -1,
+ 1, 1, YAML_PLAIN_SCALAR_STYLE))
goto event_error;
if (!yaml_emitter_emit(&emitter, &output_event))
goto emitter_error;
+
+ /* Write the tag directive prefix. */
+
+ if (!yaml_scalar_event_initialize(&output_event,
+ NULL, "tag:yaml.org,2002:str",
+ tag->prefix, -1,
+ 0, 1, YAML_DOUBLE_QUOTED_SCALAR_STYLE))
+ goto event_error;
+ if (!yaml_emitter_emit(&emitter, &output_event))
+ goto emitter_error;
+
+ /* Write '}'. */
+
+ if (!yaml_mapping_end_event_initialize(&output_event))
+ goto event_error;
+ if (!yaml_emitter_emit(&emitter, &output_event))
+ goto emitter_error;
+ }
+
+ /* End a block sequence. */
+
+ if (!yaml_sequence_end_event_initialize(&output_event))
+ goto event_error;
+ if (!yaml_emitter_emit(&emitter, &output_event))
+ goto emitter_error;
}
/* Write 'implicit'. */
diff --git a/tests/example-reformatter-alt.c b/tests/example-reformatter-alt.c
new file mode 100644
index 0000000..550e06c
--- /dev/null
+++ b/tests/example-reformatter-alt.c
@@ -0,0 +1,217 @@
+
+#include <yaml.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+
+int
+main(int argc, char *argv[])
+{
+ int help = 0;
+ int canonical = 0;
+ int unicode = 0;
+ int k;
+ int done = 0;
+
+ yaml_parser_t parser;
+ yaml_emitter_t emitter;
+ yaml_document_t document;
+
+ /* Clear the objects. */
+
+ memset(&parser, 0, sizeof(parser));
+ memset(&emitter, 0, sizeof(emitter));
+ memset(&document, 0, sizeof(document));
+
+ /* Analyze command line options. */
+
+ for (k = 1; k < argc; k ++)
+ {
+ if (strcmp(argv[k], "-h") == 0
+ || strcmp(argv[k], "--help") == 0) {
+ help = 1;
+ }
+
+ else if (strcmp(argv[k], "-c") == 0
+ || strcmp(argv[k], "--canonical") == 0) {
+ canonical = 1;
+ }
+
+ else if (strcmp(argv[k], "-u") == 0
+ || strcmp(argv[k], "--unicode") == 0) {
+ unicode = 1;
+ }
+
+ else {
+ fprintf(stderr, "Unrecognized option: %s\n"
+ "Try `%s --help` for more information.\n",
+ argv[k], argv[0]);
+ return 1;
+ }
+ }
+
+ /* Display the help string. */
+
+ if (help)
+ {
+ printf("%s [--canonical] [--unicode] <input >output\n"
+ "or\n%s -h | --help\nReformat a YAML stream\n\nOptions:\n"
+ "-h, --help\t\tdisplay this help and exit\n"
+ "-c, --canonical\t\toutput in the canonical YAML format\n"
+ "-u, --unicode\t\toutput unescaped non-ASCII characters\n",
+ argv[0], argv[0]);
+ return 0;
+ }
+
+ /* Initialize the parser and emitter objects. */
+
+ if (!yaml_parser_initialize(&parser))
+ goto parser_error;
+
+ if (!yaml_emitter_initialize(&emitter))
+ goto emitter_error;
+
+ /* Set the parser parameters. */
+
+ yaml_parser_set_input_file(&parser, stdin);
+
+ /* Set the emitter parameters. */
+
+ yaml_emitter_set_output_file(&emitter, stdout);
+
+ yaml_emitter_set_canonical(&emitter, canonical);
+ yaml_emitter_set_unicode(&emitter, unicode);
+
+ /* The main loop. */
+
+ while (!done)
+ {
+ /* Get the next event. */
+
+ if (!yaml_parser_load(&parser, &document))
+ goto parser_error;
+
+ /* Check if this is the stream end. */
+
+ if (!yaml_document_get_root_node(&document)) {
+ done = 1;
+ }
+
+ /* Emit the event. */
+
+ if (!yaml_emitter_dump(&emitter, &document))
+ goto emitter_error;
+ }
+
+ yaml_parser_delete(&parser);
+ yaml_emitter_delete(&emitter);
+
+ return 0;
+
+parser_error:
+
+ /* Display a parser error message. */
+
+ switch (parser.error)
+ {
+ case YAML_MEMORY_ERROR:
+ fprintf(stderr, "Memory error: Not enough memory for parsing\n");
+ break;
+
+ case YAML_READER_ERROR:
+ if (parser.problem_value != -1) {
+ fprintf(stderr, "Reader error: %s: #%X at %d\n", parser.problem,
+ parser.problem_value, parser.problem_offset);
+ }
+ else {
+ fprintf(stderr, "Reader error: %s at %d\n", parser.problem,
+ parser.problem_offset);
+ }
+ break;
+
+ case YAML_SCANNER_ERROR:
+ if (parser.context) {
+ fprintf(stderr, "Scanner error: %s at line %d, column %d\n"
+ "%s at line %d, column %d\n", parser.context,
+ parser.context_mark.line+1, parser.context_mark.column+1,
+ parser.problem, parser.problem_mark.line+1,
+ parser.problem_mark.column+1);
+ }
+ else {
+ fprintf(stderr, "Scanner error: %s at line %d, column %d\n",
+ parser.problem, parser.problem_mark.line+1,
+ parser.problem_mark.column+1);
+ }
+ break;
+
+ case YAML_PARSER_ERROR:
+ if (parser.context) {
+ fprintf(stderr, "Parser error: %s at line %d, column %d\n"
+ "%s at line %d, column %d\n", parser.context,
+ parser.context_mark.line+1, parser.context_mark.column+1,
+ parser.problem, parser.problem_mark.line+1,
+ parser.problem_mark.column+1);
+ }
+ else {
+ fprintf(stderr, "Parser error: %s at line %d, column %d\n",
+ parser.problem, parser.problem_mark.line+1,
+ parser.problem_mark.column+1);
+ }
+ break;
+
+ case YAML_COMPOSER_ERROR:
+ if (parser.context) {
+ fprintf(stderr, "Composer error: %s at line %d, column %d\n"
+ "%s at line %d, column %d\n", parser.context,
+ parser.context_mark.line+1, parser.context_mark.column+1,
+ parser.problem, parser.problem_mark.line+1,
+ parser.problem_mark.column+1);
+ }
+ else {
+ fprintf(stderr, "Composer error: %s at line %d, column %d\n",
+ parser.problem, parser.problem_mark.line+1,
+ parser.problem_mark.column+1);
+ }
+ break;
+
+ default:
+ /* Couldn't happen. */
+ fprintf(stderr, "Internal error\n");
+ break;
+ }
+
+ yaml_parser_delete(&parser);
+ yaml_emitter_delete(&emitter);
+
+ return 1;
+
+emitter_error:
+
+ /* Display an emitter error message. */
+
+ switch (emitter.error)
+ {
+ case YAML_MEMORY_ERROR:
+ fprintf(stderr, "Memory error: Not enough memory for emitting\n");
+ break;
+
+ case YAML_WRITER_ERROR:
+ fprintf(stderr, "Writer error: %s\n", emitter.problem);
+ break;
+
+ case YAML_EMITTER_ERROR:
+ fprintf(stderr, "Emitter error: %s\n", emitter.problem);
+ break;
+
+ default:
+ /* Couldn't happen. */
+ fprintf(stderr, "Internal error\n");
+ break;
+ }
+
+ yaml_parser_delete(&parser);
+ yaml_emitter_delete(&emitter);
+
+ return 1;
+}
+
diff --git a/tests/run-dumper.c b/tests/run-dumper.c
new file mode 100644
index 0000000..149dde0
--- /dev/null
+++ b/tests/run-dumper.c
@@ -0,0 +1,305 @@
+#include <yaml.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+
+#define BUFFER_SIZE 65536
+#define MAX_DOCUMENTS 16
+
+int copy_document(yaml_document_t *document_to, yaml_document_t *document_from)
+{
+ yaml_node_t *node;
+ yaml_node_item_t *item;
+ yaml_node_pair_t *pair;
+
+ if (!yaml_document_initialize(document_to, document_from->version_directive,
+ document_from->tag_directives.start,
+ document_from->tag_directives.end,
+ document_from->start_implicit, document_from->end_implicit))
+ return 0;
+
+ for (node = document_from->nodes.start;
+ node < document_from->nodes.top; node ++) {
+ switch (node->type) {
+ case YAML_SCALAR_NODE:
+ if (!yaml_document_add_scalar(document_to, node->tag,
+ node->data.scalar.value, node->data.scalar.length,
+ node->data.scalar.style)) goto error;
+ break;
+ case YAML_SEQUENCE_NODE:
+ if (!yaml_document_add_sequence(document_to, node->tag,
+ node->data.sequence.style)) goto error;
+ break;
+ case YAML_MAPPING_NODE:
+ if (!yaml_document_add_mapping(document_to, node->tag,
+ node->data.mapping.style)) goto error;
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ }
+
+ for (node = document_from->nodes.start;
+ node < document_from->nodes.top; node ++) {
+ switch (node->type) {
+ case YAML_SEQUENCE_NODE:
+ for (item = node->data.sequence.items.start;
+ item < node->data.sequence.items.top; item ++) {
+ if (!yaml_document_append_sequence_item(document_to,
+ node - document_from->nodes.start + 1,
+ *item)) goto error;
+ }
+ break;
+ case YAML_MAPPING_NODE:
+ for (pair = node->data.mapping.pairs.start;
+ pair < node->data.mapping.pairs.top; pair ++) {
+ if (!yaml_document_append_mapping_pair(document_to,
+ node - document_from->nodes.start + 1,
+ pair->key, pair->value)) goto error;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ return 1;
+
+error:
+ yaml_document_delete(document_to);
+ return 0;
+}
+
+int compare_nodes(yaml_document_t *document1, int index1,
+ yaml_document_t *document2, int index2)
+{
+ yaml_node_t *node1 = yaml_document_get_node(document1, index1);
+ yaml_node_t *node2 = yaml_document_get_node(document2, index2);
+ int k;
+
+ assert(node1);
+ assert(node2);
+
+ if (node1->type != node2->type)
+ return 0;
+
+ if (strcmp((char *)node1->tag, (char *)node2->tag) != 0) return 0;
+
+ switch (node1->type) {
+ case YAML_SCALAR_NODE:
+ if (node1->data.scalar.length != node2->data.scalar.length)
+ return 0;
+ if (strncmp((char *)node1->data.scalar.value, (char *)node2->data.scalar.value,
+ node1->data.scalar.length) != 0) return 0;
+ break;
+ case YAML_SEQUENCE_NODE:
+ if ((node1->data.sequence.items.top - node1->data.sequence.items.start) !=
+ (node2->data.sequence.items.top - node2->data.sequence.items.start))
+ return 0;
+ for (k = 0; k < (node1->data.sequence.items.top - node1->data.sequence.items.start); k ++) {
+ if (!compare_nodes(document1, node1->data.sequence.items.start[k],
+ document2, node2->data.sequence.items.start[k])) return 0;
+ }
+ break;
+ case YAML_MAPPING_NODE:
+ if ((node1->data.mapping.pairs.top - node1->data.mapping.pairs.start) !=
+ (node2->data.mapping.pairs.top - node2->data.mapping.pairs.start))
+ return 0;
+ for (k = 0; k < (node1->data.mapping.pairs.top - node1->data.mapping.pairs.start); k ++) {
+ if (!compare_nodes(document1, node1->data.mapping.pairs.start[k].key,
+ document2, node2->data.mapping.pairs.start[k].key)) return 0;
+ if (!compare_nodes(document1, node1->data.mapping.pairs.start[k].value,
+ document2, node2->data.mapping.pairs.start[k].value)) return 0;
+ }
+ break;
+
+ }
+ return 1;
+}
+
+int compare_documents(yaml_document_t *document1, yaml_document_t *document2)
+{
+ int k;
+
+ if ((document1->version_directive && !document2->version_directive)
+ || (!document1->version_directive && document2->version_directive)
+ || (document1->version_directive && document2->version_directive
+ && (document1->version_directive->major != document2->version_directive->major
+ || document1->version_directive->minor != document2->version_directive->minor)))
+ return 0;
+
+ if ((document1->tag_directives.end - document1->tag_directives.start) !=
+ (document2->tag_directives.end - document2->tag_directives.start))
+ return 0;
+ for (k = 0; k < (document1->tag_directives.end - document1->tag_directives.start); k ++) {
+ if ((strcmp((char *)document1->tag_directives.start[k].handle,
+ (char *)document2->tag_directives.start[k].handle) != 0)
+ || (strcmp((char *)document1->tag_directives.start[k].prefix,
+ (char *)document2->tag_directives.start[k].prefix) != 0))
+ return 0;
+ }
+
+ if ((document1->nodes.top - document1->nodes.start) !=
+ (document2->nodes.top - document2->nodes.start))
+ return 0;
+
+ if (document1->nodes.top != document1->nodes.start) {
+ if (!compare_nodes(document1, 1, document2, 1))
+ return 0;
+ }
+
+ return 1;
+}
+
+int print_output(char *name, unsigned char *buffer, size_t size, int count)
+{
+ FILE *file;
+ char data[BUFFER_SIZE];
+ size_t data_size = 1;
+ size_t total_size = 0;
+ if (count >= 0) {
+ printf("FAILED (at the document #%d)\nSOURCE:\n", count+1);
+ }
+ file = fopen(name, "rb");
+ assert(file);
+ while (data_size > 0) {
+ data_size = fread(data, 1, BUFFER_SIZE, file);
+ assert(!ferror(file));
+ if (!data_size) break;
+ assert(fwrite(data, 1, data_size, stdout) == data_size);
+ total_size += data_size;
+ if (feof(file)) break;
+ }
+ fclose(file);
+ printf("#### (length: %d)\n", total_size);
+ printf("OUTPUT:\n%s#### (length: %d)\n", buffer, size);
+ return 0;
+}
+
+int
+main(int argc, char *argv[])
+{
+ int number;
+ int canonical = 0;
+ int unicode = 0;
+
+ number = 1;
+ while (number < argc) {
+ if (strcmp(argv[number], "-c") == 0) {
+ canonical = 1;
+ }
+ else if (strcmp(argv[number], "-u") == 0) {
+ unicode = 1;
+ }
+ else if (argv[number][0] == '-') {
+ printf("Unknown option: '%s'\n", argv[number]);
+ return 0;
+ }
+ if (argv[number][0] == '-') {
+ if (number < argc-1) {
+ memmove(argv+number, argv+number+1, (argc-number-1)*sizeof(char *));
+ }
+ argc --;
+ }
+ else {
+ number ++;
+ }
+ }
+
+ if (argc < 2) {
+ printf("Usage: %s [-c] [-u] file1.yaml ...\n", argv[0]);
+ return 0;
+ }
+
+ for (number = 1; number < argc; number ++)
+ {
+ FILE *file;
+ yaml_parser_t parser;
+ yaml_emitter_t emitter;
+
+ yaml_document_t document;
+ unsigned char buffer[BUFFER_SIZE];
+ size_t written = 0;
+ yaml_document_t documents[MAX_DOCUMENTS];
+ size_t document_number = 0;
+ int done = 0;
+ int count = 0;
+ int error = 0;
+ int k;
+ memset(buffer, 0, BUFFER_SIZE);
+ memset(documents, 0, MAX_DOCUMENTS*sizeof(yaml_document_t));
+
+ printf("[%d] Loading, dumping, and loading again '%s': ", number, argv[number]);
+ fflush(stdout);
+
+ file = fopen(argv[number], "rb");
+ assert(file);
+
+ assert(yaml_parser_initialize(&parser));
+ yaml_parser_set_input_file(&parser, file);
+ assert(yaml_emitter_initialize(&emitter));
+ if (canonical) {
+ yaml_emitter_set_canonical(&emitter, 1);
+ }
+ if (unicode) {
+ yaml_emitter_set_unicode(&emitter, 1);
+ }
+ yaml_emitter_set_output_string(&emitter, buffer, BUFFER_SIZE, &written);
+ yaml_emitter_open(&emitter);
+
+ while (!done)
+ {
+ if (!yaml_parser_load(&parser, &document)) {
+ error = 1;
+ break;
+ }
+
+ done = (!yaml_document_get_root_node(&document));
+ if (!done) {
+ assert(document_number < MAX_DOCUMENTS);
+ assert(copy_document(&(documents[document_number++]), &document));
+ assert(yaml_emitter_dump(&emitter, &document) ||
+ (yaml_emitter_flush(&emitter) && print_output(argv[number], buffer, written, count)));
+ count ++;
+ }
+ else {
+ yaml_document_delete(&document);
+ }
+ }
+
+ yaml_parser_delete(&parser);
+ assert(!fclose(file));
+ yaml_emitter_close(&emitter);
+ yaml_emitter_delete(&emitter);
+
+ if (!error)
+ {
+ count = done = 0;
+ assert(yaml_parser_initialize(&parser));
+ yaml_parser_set_input_string(&parser, buffer, written);
+
+ while (!done)
+ {
+ assert(yaml_parser_load(&parser, &document) || print_output(argv[number], buffer, written, count));
+ done = (!yaml_document_get_root_node(&document));
+ if (!done) {
+ assert(compare_documents(documents+count, &document) || print_output(argv[number], buffer, written, count));
+ count ++;
+ }
+ yaml_document_delete(&document);
+ }
+ yaml_parser_delete(&parser);
+ }
+
+ for (k = 0; k < document_number; k ++) {
+ yaml_document_delete(documents+k);
+ }
+
+ printf("PASSED (length: %d)\n", written);
+ print_output(argv[number], buffer, written, -1);
+ }
+
+ return 0;
+}
diff --git a/tests/run-emitter.c b/tests/run-emitter.c
index 3008ab5..0787895 100644
--- a/tests/run-emitter.c
+++ b/tests/run-emitter.c
@@ -256,7 +256,7 @@ main(int argc, char *argv[])
int error = 0;
int k;
memset(buffer, 0, BUFFER_SIZE);
- memset(events, 0, MAX_EVENTS);
+ memset(events, 0, MAX_EVENTS*sizeof(yaml_event_t));
printf("[%d] Parsing, emitting, and parsing again '%s': ", number, argv[number]);
fflush(stdout);
diff --git a/tests/run-loader.c b/tests/run-loader.c
new file mode 100644
index 0000000..a34ad07
--- /dev/null
+++ b/tests/run-loader.c
@@ -0,0 +1,59 @@
+#include <yaml.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+
+int
+main(int argc, char *argv[])
+{
+ int number;
+
+ if (argc < 2) {
+ printf("Usage: %s file1.yaml ...\n", argv[0]);
+ return 0;
+ }
+
+ for (number = 1; number < argc; number ++)
+ {
+ FILE *file;
+ yaml_parser_t parser;
+ yaml_document_t document;
+ int done = 0;
+ int count = 0;
+ int error = 0;
+
+ printf("[%d] Loading '%s': ", number, argv[number]);
+ fflush(stdout);
+
+ file = fopen(argv[number], "rb");
+ assert(file);
+
+ assert(yaml_parser_initialize(&parser));
+
+ yaml_parser_set_input_file(&parser, file);
+
+ while (!done)
+ {
+ if (!yaml_parser_load(&parser, &document)) {
+ error = 1;
+ break;
+ }
+
+ done = (!yaml_document_get_root_node(&document));
+
+ yaml_document_delete(&document);
+
+ if (!done) count ++;
+ }
+
+ yaml_parser_delete(&parser);
+
+ assert(!fclose(file));
+
+ printf("%s (%d documents)\n", (error ? "FAILURE" : "SUCCESS"), count);
+ }
+
+ return 0;
+}
+