From 0204c3ef39218f05f75e618e02450ee570a09598 Mon Sep 17 00:00:00 2001 From: xi Date: Wed, 26 Jul 2006 20:32:16 +0000 Subject: Implement Emitter state machine. git-svn-id: http://svn.pyyaml.org/libyaml/trunk@213 18f92427-320e-0410-9341-c67f048884a3 --- include/yaml.h | 343 +++++++++--------- src/api.c | 359 ++++++++++++++++++- src/emitter.c | 1006 ++++++++++++++++++++++++++++++++++++++-------------- src/parser.c | 10 +- src/scanner.c | 6 +- src/yaml_private.h | 1 + 6 files changed, 1278 insertions(+), 447 deletions(-) diff --git a/include/yaml.h b/include/yaml.h index a4fc4e8..6284068 100644 --- a/include/yaml.h +++ b/include/yaml.h @@ -169,8 +169,8 @@ typedef enum { YAML_ANY_MAPPING_STYLE, YAML_BLOCK_MAPPING_STYLE, - YAML_FLOW_MAPPING_STYLE, - YAML_FLOW_SET_MAPPING_STYLE + YAML_FLOW_MAPPING_STYLE +/* YAML_FLOW_SET_MAPPING_STYLE */ } yaml_mapping_style_t; /** @} */ @@ -413,6 +413,169 @@ typedef struct { } yaml_event_t; +/** + * Create the STREAM-START event. + * + * @param[in] event An empty event object. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_stream_start_event_initialize(yaml_event_t *event, + yaml_encoding_t encoding); + +/** + * Create the STREAM-END event. + * + * @param[in] event An empty event object. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_stream_end_event_initialize(yaml_event_t *event); + +/** + * Create the DOCUMENT-START event. + * + * The @a implicit argument is considered as a stylistic parameter and may be + * ignored by the emitter. + * + * @param[in] 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. + */ + +YAML_DECLARE(int) +yaml_document_start_event_initialize(yaml_event_t *event, + yaml_version_directive_t *version_directive, + yaml_tag_directive_t *tag_directives_start, + yaml_tag_directive_t *tag_directives_end, + int implicit); + +/** + * Create the DOCUMENT-END event. + * + * The @a implicit argument is considered as a stylistic parameter and may be + * ignored by the emitter. + * + * @param[in] 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. + */ + +YAML_DECLARE(int) +yaml_document_end_event_initialize(yaml_event_t *event, int implicit); + +/** + * Create an ALIAS event. + * + * @param[in] event An empty event object. + * @param[in] anchor The anchor value. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_alias_event_initialize(yaml_event_t *event, yaml_char_t *anchor); + +/** + * Create a SCALAR event. + * + * The @a style argument may be ignored by the emitter. + * + * Either the @a tag attribute or one of the @a plain_implicit and + * @a quoted_implicit flags must be set. + * + * @param[in] 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. + */ + +YAML_DECLARE(int) +yaml_scalar_event_initialize(yaml_event_t *event, + yaml_char_t *anchor, yaml_char_t *tag, + yaml_char_t *value, size_t length, + int plain_implicit, int quoted_implicit, + yaml_scalar_style_t style); + +/** + * Create a SEQUENCE-START event. + * + * The @a style argument may be ignored by the emitter. + * + * Either the @a tag attribute or the @a implicit flag must be set. + * + * @param[in] 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. + */ + +YAML_DECLARE(int) +yaml_sequence_start_event_initialize(yaml_event_t *event, + yaml_char_t *anchor, yaml_char_t *tag, int implicit, + yaml_sequence_style_t style); + +/** + * Create a SEQUENCE-END event. + * + * @param[in] event An empty event object. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_sequence_end_event_initialize(yaml_event_t *event); + +/** + * Create a MAPPING-START event. + * + * The @a style argument may be ignored by the emitter. + * + * Either the @a tag attribute or the @a implicit flag must be set. + * + * @param[in] 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. + */ + +YAML_DECLARE(int) +yaml_mapping_start_event_initialize(yaml_event_t *event, + yaml_char_t *anchor, yaml_char_t *tag, int implicit, + yaml_mapping_style_t style); + +/** + * Create a MAPPING-END event. + * + * @param[in] event An empty event object. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_mapping_end_event_initialize(yaml_event_t *event); + /** * Free any memory allocated for an event object. * @@ -870,7 +1033,8 @@ typedef enum { YAML_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE, YAML_EMIT_BLOCK_MAPPING_KEY_STATE, YAML_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE, - YAML_EMIT_BLOCK_MAPPING_VALUE_STATE + YAML_EMIT_BLOCK_MAPPING_VALUE_STATE, + YAML_EMIT_END_STATE } yaml_emitter_state_t; /** @@ -995,9 +1159,6 @@ typedef struct { yaml_event_t *tail; } events; - /** The current event. */ - yaml_event_t event; - /** The stack of indentation levels. */ struct { /** The beginning of the stack. */ @@ -1179,9 +1340,9 @@ yaml_emitter_set_break(yaml_emitter_t *emitter, yaml_break_t line_break); * Emit an event. * * The event object may be generated using the @c yaml_parser_parse function. - * The emitter will destroy the event object if the function succeeds. If the - * function fails, the application is responsible for destroing the event - * object. + * The emitter takes the responsibility for the event object and destroys its + * content after it is emitted. The event object is destroyed even if the + * function fails. * * @param[in] emitter An emitter object. * @param[in] event An event object. @@ -1192,170 +1353,6 @@ 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); -/** - * Emit the STREAM-START event. - * - * @param[in] emitter An emitter object. - * @param[in] encoding The stream encoding. - * - * @returns @c 1 if the function succeeded, @c 0 on error. - */ - -YAML_DECLARE(int) -yaml_emitter_emit_stream_start(yaml_emitter_t *emitter, - yaml_encoding_t encoding); - -/** - * Emit the STREAM-END event. - * - * @param[in] emitter An emitter object. - * - * @returns @c 1 if the function succeeded, @c 0 on error. - */ - -YAML_DECLARE(int) -yaml_emitter_emit_stream_end(yaml_emitter_t *emitter); - -/** - * Emit the DOCUMENT-START event. - * - * The @a implicit argument is considered as a stylistic parameter and may be - * ignored by the emitter. - * - * @param[in] emitter An emitter 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. - */ - -YAML_DECLARE(int) -yaml_emitter_emit_document_start(yaml_emitter_t *emitter, - yaml_version_directive_t *version_directive, - yaml_tag_directive_t *tag_directives_start, - yaml_tag_directive_t *tag_directives_end, - int implicit); - -/** - * Emit the DOCUMENT-END event. - * - * The @a implicit argument is considered as a stylistic parameter and may be - * ignored by the emitter. - * - * @param[in] emitter An emitter object. - * @param[in] implicit If the document end indicator is implicit. - * - * @returns @c 1 if the function succeeded, @c 0 on error. - */ - -YAML_DECLARE(int) -yaml_emitter_emit_document_end(yaml_emitter_t *emitter, int implicit); - -/** - * Emit an ALIAS event. - * - * @param[in] emitter An emitter object. - * @param[in] anchor The anchor value. - * - * @returns @c 1 if the function succeeded, @c 0 on error. - */ - -YAML_DECLARE(int) -yaml_emitter_emit_alias(yaml_emitter_t *emitter, yaml_char_t *anchor); - -/** - * Emit a SCALAR event. - * - * The @a style argument may be ignored by the emitter. - * - * Either the @a tag attribute or one of the @a plain_implicit and - * @a quoted_implicit flags must be set. - * - * @param[in] emitter An emitter 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. - */ - -YAML_DECLARE(int) -yaml_emitter_emit_scalar(yaml_emitter_t *emitter, - yaml_char_t *anchor, yaml_char_t *tag, - yaml_char_t *value, size_t length, - int plain_implicit, int quoted_implicit, - yaml_scalar_style_t style); - -/** - * Emit a SEQUENCE-START event. - * - * The @a style argument may be ignored by the emitter. - * - * Either the @a tag attribute or the @a implicit flag must be set. - * - * @param[in] emitter An emitter 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. - */ - -YAML_DECLARE(int) -yaml_emitter_emit_sequence_start(yaml_emitter_t *emitter, - yaml_char_t *anchor, yaml_char_t *tag, int implicit, - yaml_sequence_style_t style); - -/** - * Emit a SEQUENCE-END event. - * - * @param[in] emitter An emitter object. - * - * @returns @c 1 if the function succeeded, @c 0 on error. - */ - -YAML_DECLARE(int) -yaml_emitter_emit_sequence_end(yaml_emitter_t *emitter); - -/** - * Emit a MAPPING-START event. - * - * The @a style argument may be ignored by the emitter. - * - * Either the @a tag attribute or the @a implicit flag must be set. - * - * @param[in] emitter An emitter 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. - */ - -YAML_DECLARE(int) -yaml_emitter_emit_mapping_start(yaml_emitter_t *emitter, - yaml_char_t *anchor, yaml_char_t *tag, int implicit, - yaml_mapping_style_t style); - -/** - * Emit a MAPPING-END event. - * - * @param[in] emitter An emitter object. - * - * @returns @c 1 if the function succeeded, @c 0 on error. - */ - -YAML_DECLARE(int) -yaml_emitter_emit_mapping_end(yaml_emitter_t *emitter); - /** * Flush the accumulated characters to the output. * diff --git a/src/api.c b/src/api.c index 8d5f624..4eaa667 100644 --- a/src/api.c +++ b/src/api.c @@ -392,7 +392,6 @@ yaml_emitter_delete(yaml_emitter_t *emitter) yaml_event_delete(&DEQUEUE(emitter, emitter->events)); } STACK_DEL(emitter, emitter->indents); - yaml_event_delete(&emitter->event); while (!STACK_EMPTY(empty, emitter->tag_directives)) { yaml_tag_directive_t tag_directive = POP(emitter, emitter->tag_directives); yaml_free(tag_directive.handle); @@ -607,6 +606,364 @@ yaml_token_delete(yaml_token_t *token) memset(token, 0, sizeof(yaml_token_t)); } +/* + * Check if a string is a valid UTF-8 sequence. + * + * Check 'reader.c' for more details on UTF-8 encoding. + */ + +static int +yaml_check_utf8(yaml_char_t *start, size_t length) +{ + yaml_char_t *end = start+length; + yaml_char_t *pointer = start; + + while (pointer < end) { + unsigned char octet; + unsigned int width; + unsigned int value; + int k; + + octet = pointer[0]; + width = (octet & 0x80) == 0x00 ? 1 : + (octet & 0xE0) == 0xC0 ? 2 : + (octet & 0xF0) == 0xE0 ? 3 : + (octet & 0xF8) == 0xF0 ? 4 : 0; + value = (octet & 0x80) == 0x00 ? octet & 0x7F : + (octet & 0xE0) == 0xC0 ? octet & 0x1F : + (octet & 0xF0) == 0xE0 ? octet & 0x0F : + (octet & 0xF8) == 0xF0 ? octet & 0x07 : 0; + if (!width) return 0; + if (pointer+width > end) return 0; + for (k = 1; k < width; k ++) { + octet = pointer[k]; + if ((octet & 0xC0) != 0x80) return 0; + value = (value << 6) + (octet & 0x3F); + } + if (!((width == 1) || + (width == 2 && value >= 0x80) || + (width == 3 && value >= 0x800) || + (width == 4 && value >= 0x10000))) return 0; + + pointer += width; + } + + return 1; +} + +/* + * Create STREAM-START. + */ + +YAML_DECLARE(int) +yaml_stream_start_event_initialize(yaml_event_t *event, + yaml_encoding_t encoding) +{ + yaml_mark_t mark = { 0, 0, 0 }; + + assert(event); /* Non-NULL event object is expected. */ + + STREAM_START_EVENT_INIT(*event, encoding, mark, mark); + + return 1; +} + +/* + * Create STREAM-END. + */ + +YAML_DECLARE(int) +yaml_stream_end_event_initialize(yaml_event_t *event) +{ + yaml_mark_t mark = { 0, 0, 0 }; + + assert(event); /* Non-NULL event object is expected. */ + + STREAM_END_EVENT_INIT(*event, mark, mark); + + return 1; +} + +/* + * Create DOCUMENT-START. + */ + +YAML_DECLARE(int) +yaml_document_start_event_initialize(yaml_event_t *event, + yaml_version_directive_t *version_directive, + yaml_tag_directive_t *tag_directives_start, + yaml_tag_directive_t *tag_directives_end, + int implicit) +{ + struct { + yaml_error_type_t error; + } context; + yaml_mark_t mark = { 0, 0, 0 }; + 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 }; + + assert(event); /* Non-NULL event object is expected. */ + assert((tag_directives_start && tag_directives_end) || + (tag_directives_start == tag_directives_end)); + /* Valid tag directives are expected. */ + + 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_START_EVENT_INIT(*event, version_directive_copy, + tag_directives_copy.start, tag_directives_copy.end, + implicit, mark, mark); + + return 1; + +error: + 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; +} + +/* + * Create DOCUMENT-END. + */ + +YAML_DECLARE(int) +yaml_document_end_event_initialize(yaml_event_t *event, int implicit) +{ + yaml_mark_t mark = { 0, 0, 0 }; + + assert(event); /* Non-NULL emitter object is expected. */ + + DOCUMENT_END_EVENT_INIT(*event, implicit, mark, mark); + + return 1; +} + +/* + * Create ALIAS. + */ + +YAML_DECLARE(int) +yaml_alias_event_initialize(yaml_event_t *event, yaml_char_t *anchor) +{ + yaml_mark_t mark = { 0, 0, 0 }; + yaml_char_t *anchor_copy = NULL; + + assert(event); /* Non-NULL event object is expected. */ + assert(anchor); /* Non-NULL anchor is expected. */ + + if (!yaml_check_utf8(anchor, strlen((char *)anchor))) return 0; + + anchor_copy = yaml_strdup(anchor); + if (!anchor_copy) + return 0; + + ALIAS_EVENT_INIT(*event, anchor_copy, mark, mark); + + return 1; +} + +/* + * Create SCALAR. + */ + +YAML_DECLARE(int) +yaml_scalar_event_initialize(yaml_event_t *event, + yaml_char_t *anchor, yaml_char_t *tag, + yaml_char_t *value, size_t length, + int plain_implicit, int quoted_implicit, + yaml_scalar_style_t style) +{ + yaml_mark_t mark = { 0, 0, 0 }; + yaml_char_t *anchor_copy = NULL; + yaml_char_t *tag_copy = NULL; + yaml_char_t *value_copy = NULL; + + assert(event); /* Non-NULL event object is expected. */ + assert(value); /* Non-NULL anchor is expected. */ + + + if (anchor) { + if (!yaml_check_utf8(anchor, strlen((char *)anchor))) goto error; + anchor_copy = yaml_strdup(anchor); + if (!anchor_copy) goto error; + } + + 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(value, length)) goto error; + value_copy = yaml_malloc(length+1); + if (!value_copy) goto error; + memcpy(value_copy, value, length); + value_copy[length] = '\0'; + + SCALAR_EVENT_INIT(*event, anchor_copy, tag_copy, value_copy, length, + plain_implicit, quoted_implicit, style, mark, mark); + + return 1; + +error: + yaml_free(anchor_copy); + yaml_free(tag_copy); + yaml_free(value_copy); + + return 0; +} + +/* + * Create SEQUENCE-START. + */ + +YAML_DECLARE(int) +yaml_sequence_start_event_initialize(yaml_event_t *event, + yaml_char_t *anchor, yaml_char_t *tag, int implicit, + yaml_sequence_style_t style) +{ + yaml_mark_t mark = { 0, 0, 0 }; + yaml_char_t *anchor_copy = NULL; + yaml_char_t *tag_copy = NULL; + + assert(event); /* Non-NULL event object is expected. */ + + if (anchor) { + if (!yaml_check_utf8(anchor, strlen((char *)anchor))) goto error; + anchor_copy = yaml_strdup(anchor); + if (!anchor_copy) goto error; + } + + if (tag) { + if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error; + tag_copy = yaml_strdup(tag); + if (!tag_copy) goto error; + } + + SEQUENCE_START_EVENT_INIT(*event, anchor_copy, tag_copy, + implicit, style, mark, mark); + + return 1; + +error: + yaml_free(anchor_copy); + yaml_free(tag_copy); + + return 0; +} + +/* + * Create SEQUENCE-END. + */ + +YAML_DECLARE(int) +yaml_sequence_end_event_initialize(yaml_event_t *event) +{ + yaml_mark_t mark = { 0, 0, 0 }; + + assert(event); /* Non-NULL event object is expected. */ + + SEQUENCE_END_EVENT_INIT(*event, mark, mark); + + return 1; +} + +/* + * Create MAPPING-START. + */ + +YAML_DECLARE(int) +yaml_mapping_start_event_initialize(yaml_event_t *event, + yaml_char_t *anchor, yaml_char_t *tag, int implicit, + yaml_mapping_style_t style) +{ + yaml_mark_t mark = { 0, 0, 0 }; + yaml_char_t *anchor_copy = NULL; + yaml_char_t *tag_copy = NULL; + + assert(event); /* Non-NULL event object is expected. */ + + if (anchor) { + if (!yaml_check_utf8(anchor, strlen((char *)anchor))) goto error; + anchor_copy = yaml_strdup(anchor); + if (!anchor_copy) goto error; + } + + if (tag) { + if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error; + tag_copy = yaml_strdup(tag); + if (!tag_copy) goto error; + } + + MAPPING_START_EVENT_INIT(*event, anchor_copy, tag_copy, + implicit, style, mark, mark); + + return 1; + +error: + yaml_free(anchor_copy); + yaml_free(tag_copy); + + return 0; +} + +/* + * Create MAPPING-END. + */ + +YAML_DECLARE(int) +yaml_mapping_end_event_initialize(yaml_event_t *event) +{ + yaml_mark_t mark = { 0, 0, 0 }; + + assert(event); /* Non-NULL event object is expected. */ + + MAPPING_END_EVENT_INIT(*event, mark, mark); + + return 1; +} + /* * Destroy an event object. */ diff --git a/src/emitter.c b/src/emitter.c index e659e3e..41ed3fc 100644 --- a/src/emitter.c +++ b/src/emitter.c @@ -8,401 +8,869 @@ YAML_DECLARE(int) yaml_emitter_emit(yaml_emitter_t *emitter, yaml_event_t *event); -YAML_DECLARE(int) -yaml_emitter_emit_stream_start(yaml_emitter_t *emitter, - yaml_encoding_t encoding); +/* + * Utility functions. + */ -YAML_DECLARE(int) -yaml_emitter_emit_stream_end(yaml_emitter_t *emitter); +static int +yaml_emitter_set_emitter_error(yaml_emitter_t *emitter, const char *problem); -YAML_DECLARE(int) +static int +yaml_emitter_need_more_events(yaml_emitter_t *emitter); + +static int +yaml_emitter_append_tag_directive(yaml_emitter_t *emitter, + yaml_tag_directive_t value, int allow_duplicates); + +static int +yaml_emitter_increase_indent(yaml_emitter_t *emitter, + int flow, int indentless); + +/* + * State functions. + */ + +static int +yaml_emitter_state_machine(yaml_emitter_t *emitter, yaml_event_t *event); + +static int +yaml_emitter_emit_stream_start(yaml_emitter_t *emitter, + yaml_event_t *event); + +static int yaml_emitter_emit_document_start(yaml_emitter_t *emitter, - yaml_version_directive_t *version_directive, - yaml_tag_directive_t *tag_directives_start, - yaml_tag_directive_t *tag_directives_end, - int implicit); + yaml_event_t *event, int first); -YAML_DECLARE(int) -yaml_emitter_emit_document_end(yaml_emitter_t *emitter, int implicit); +static int +yaml_emitter_emit_document_content(yaml_emitter_t *emitter, + yaml_event_t *event); -YAML_DECLARE(int) -yaml_emitter_emit_alias(yaml_emitter_t *emitter, yaml_char_t *anchor); +static int +yaml_emitter_emit_document_end(yaml_emitter_t *emitter, + yaml_event_t *event); -YAML_DECLARE(int) -yaml_emitter_emit_scalar(yaml_emitter_t *emitter, - yaml_char_t *anchor, yaml_char_t *tag, +static int +yaml_emitter_emit_flow_sequence_item(yaml_emitter_t *emitter, + yaml_event_t *event, int first); + +static int +yaml_emitter_emit_flow_mapping_key(yaml_emitter_t *emitter, + yaml_event_t *event, int first); + +static int +yaml_emitter_emit_flow_mapping_value(yaml_emitter_t *emitter, + yaml_event_t *event, int simple); + +static int +yaml_emitter_emit_block_sequence_item(yaml_emitter_t *emitter, + yaml_event_t *event, int first); + +static int +yaml_emitter_emit_block_mapping_key(yaml_emitter_t *emitter, + yaml_event_t *event, int first); + +static int +yaml_emitter_emit_block_mapping_value(yaml_emitter_t *emitter, + yaml_event_t *event, int simple); + +static int +yaml_emitter_emit_node(yaml_emitter_t *emitter, yaml_event_t *event, + int root, int sequence, int mapping, int simple_key); + +static int +yaml_emitter_emit_alias(yaml_emitter_t *emitter, yaml_event_t *event); + +static int +yaml_emitter_emit_scalar(yaml_emitter_t *emitter, yaml_event_t *event); + +static int +yaml_emitter_emit_sequence_start(yaml_emitter_t *emitter, yaml_event_t *event); + +static int +yaml_emitter_emit_mapping_start(yaml_emitter_t *emitter, yaml_event_t *event); + +/* + * Checkers. + */ + +static int +yaml_emitter_check_empty_document(yaml_emitter_t *emitter); + +static int +yaml_emitter_check_empty_sequence(yaml_emitter_t *emitter); + +static int +yaml_emitter_check_empty_mapping(yaml_emitter_t *emitter); + +static int +yaml_emitter_check_simple_key(yaml_emitter_t *emitter); + +/* + * Processors. + */ + +static int +yaml_emitter_process_anchor(yaml_emitter_t *emitter, + yaml_char_t *anchor, int alias); + +static int +yaml_emitter_process_tag(yaml_emitter_t *emitter, + yaml_char_t *tag); + +static int +yaml_emitter_process_scalar(yaml_emitter_t *emitter, yaml_char_t *value, size_t length, int plain_implicit, int quoted_implicit, yaml_scalar_style_t style); -YAML_DECLARE(int) -yaml_emitter_emit_sequence_start(yaml_emitter_t *emitter, - yaml_char_t *anchor, yaml_char_t *tag, int implicit, - yaml_sequence_style_t style); +/* + * Writers. + */ -YAML_DECLARE(int) -yaml_emitter_emit_sequence_end(yaml_emitter_t *emitter); +static int +yaml_emitter_write_bom(yaml_emitter_t *emitter); -YAML_DECLARE(int) -yaml_emitter_emit_mapping_start(yaml_emitter_t *emitter, - yaml_char_t *anchor, yaml_char_t *tag, int implicit, - yaml_mapping_style_t style); +static int +yaml_emitter_write_version_directive(yaml_emitter_t *emitter, + yaml_version_directive_t version_directive); -YAML_DECLARE(int) -yaml_emitter_emit_mapping_end(yaml_emitter_t *emitter); +static int +yaml_emitter_write_tag_directive(yaml_emitter_t *emitter, + yaml_tag_directive_t tag_directive); + +static int +yaml_emitter_write_indent(yaml_emitter_t *emitter); + +static int +yaml_emitter_write_indicator(yaml_emitter_t *emitter, + char *indicator, int need_whitespace, + int is_whitespace, int is_indention); /* - * Emit STREAM-START. + * Set an emitter error and return 0. */ -YAML_DECLARE(int) -yaml_emitter_emit_stream_start(yaml_emitter_t *emitter, - yaml_encoding_t encoding) +static int +yaml_emitter_set_emitter_error(yaml_emitter_t *emitter, const char *problem) { - yaml_event_t event; - yaml_mark_t mark = { 0, 0, 0 }; + emitter->error = YAML_EMITTER_ERROR; + emitter->problem = problem; - assert(emitter); /* Non-NULL emitter object is expected. */ - - STREAM_START_EVENT_INIT(event, encoding, mark, mark); - - return yaml_emitter_emit(emitter, &event); + return 0; } /* - * Emit STREAM-END. + * Emit an event. */ YAML_DECLARE(int) -yaml_emitter_emit_stream_end(yaml_emitter_t *emitter) +yaml_emitter_emit(yaml_emitter_t *emitter, yaml_event_t *event) { - yaml_event_t event; - yaml_mark_t mark = { 0, 0, 0 }; - - assert(emitter); /* Non-NULL emitter object is expected. */ + if (!ENQUEUE(emitter, emitter->events, *event)) { + yaml_event_delete(event); + return 0; + } - STREAM_END_EVENT_INIT(event, mark, mark); + while (!yaml_emitter_need_more_events(emitter)) { + if (!yaml_emitter_state_machine(emitter, emitter->events.head)) { + return 0; + } + DEQUEUE(emitter, emitter->events); + } - return yaml_emitter_emit(emitter, &event); + return 1; } /* - * Emit DOCUMENT-START. + * Check if we need to accumulate more events before emitting. + * + * We accumulate extra + * - 1 event for DOCUMENT-START + * - 2 events for SEQUENCE-START + * - 3 events for MAPPING-START */ -YAML_DECLARE(int) -yaml_emitter_emit_document_start(yaml_emitter_t *emitter, - yaml_version_directive_t *version_directive, - yaml_tag_directive_t *tag_directives_start, - yaml_tag_directive_t *tag_directives_end, - int implicit) +static int +yaml_emitter_need_more_events(yaml_emitter_t *emitter) { - yaml_event_t event; - yaml_mark_t mark = { 0, 0, 0 }; - 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 }; - - assert(emitter); /* Non-NULL emitter object is expected. */ - assert((tag_directives_start && tag_directives_end) || - (tag_directives_start == tag_directives_end)); - /* Valid tag directives are expected. */ - - if (version_directive) { - version_directive_copy = yaml_malloc(sizeof(yaml_version_directive_t)); - if (!version_directive_copy) { - emitter->error = YAML_MEMORY_ERROR; - goto error; - } - version_directive_copy->major = version_directive->major; - version_directive_copy->minor = version_directive->minor; + int level = 0; + int accumulate = 0; + yaml_event_t *event; + + if (QUEUE_EMPTY(emitter, emitter->events)) + return 1; + + switch (emitter->events.head->type) { + case YAML_DOCUMENT_START_EVENT: + accumulate = 1; + break; + case YAML_SEQUENCE_START_EVENT: + accumulate = 2; + break; + case YAML_MAPPING_START_EVENT: + accumulate = 3; + break; + default: + return 0; } - if (tag_directives_start != tag_directives_end) { - yaml_tag_directive_t *tag_directive; - if (!STACK_INIT(emitter, tag_directives_copy, INITIAL_STACK_SIZE)) - goto error; - for (tag_directive = tag_directives_start; - tag_directive != tag_directives_end; tag_directive ++) { - value.handle = yaml_strdup(tag_directive->handle); - value.prefix = yaml_strdup(tag_directive->prefix); - if (!value.handle || !value.prefix) { - emitter->error = YAML_MEMORY_ERROR; - goto error; - } - if (!PUSH(emitter, tag_directives_copy, value)) - goto error; - value.handle = NULL; - value.prefix = NULL; + if (emitter->events.tail - emitter->events.head > accumulate) + return 0; + + for (event = emitter->events.head; event != emitter->events.tail; event ++) { + switch (event->type) { + case YAML_STREAM_START_EVENT: + case YAML_DOCUMENT_START_EVENT: + case YAML_SEQUENCE_START_EVENT: + case YAML_MAPPING_START_EVENT: + level += 1; + break; + case YAML_STREAM_END_EVENT: + case YAML_DOCUMENT_END_EVENT: + case YAML_SEQUENCE_END_EVENT: + case YAML_MAPPING_END_EVENT: + level -= 1; + break; + default: + break; } + if (!level) + return 0; } - DOCUMENT_START_EVENT_INIT(event, version_directive_copy, - tag_directives_copy.start, tag_directives_copy.end, - implicit, mark, mark); + return 1; +} - if (yaml_emitter_emit(emitter, &event)) { - return 1; +/* + * Append a directive to the directives stack. + */ + +static int +yaml_emitter_append_tag_directive(yaml_emitter_t *emitter, + yaml_tag_directive_t value, int allow_duplicates) +{ + yaml_tag_directive_t *tag_directive; + yaml_tag_directive_t copy = { NULL, NULL }; + + for (tag_directive = emitter->tag_directives.start; + tag_directive != emitter->tag_directives.top; tag_directive ++) { + if (strcmp((char *)value.handle, (char *)tag_directive->handle) == 0) { + if (allow_duplicates) + return 1; + return yaml_emitter_set_emitter_error(emitter, + "duplicate %TAG directive"); + } } -error: - yaml_free(version_directive_copy); - while (!STACK_EMPTY(emitter, tag_directives_copy)) { - yaml_tag_directive_t value = POP(emitter, tag_directives_copy); - yaml_free(value.handle); - yaml_free(value.prefix); + copy.handle = yaml_strdup(value.handle); + copy.prefix = yaml_strdup(value.prefix); + if (!copy.handle || !copy.prefix) { + emitter->error = YAML_MEMORY_ERROR; + goto error; } - STACK_DEL(emitter, tag_directives_copy); - yaml_free(value.handle); - yaml_free(value.prefix); + if (!PUSH(emitter, emitter->tag_directives, copy)) + goto error; + + return 1; + +error: + yaml_free(copy.handle); + yaml_free(copy.prefix); return 0; } /* - * Emit DOCUMENT-END. + * Increase the indentation level. */ -YAML_DECLARE(int) -yaml_emitter_emit_document_end(yaml_emitter_t *emitter, int implicit) +static int +yaml_emitter_increase_indent(yaml_emitter_t *emitter, + int flow, int indentless) { - yaml_event_t event; - yaml_mark_t mark = { 0, 0, 0 }; - - assert(emitter); /* Non-NULL emitter object is expected. */ + if (!PUSH(emitter, emitter->indents, emitter->indent)) + return 0; - DOCUMENT_END_EVENT_INIT(event, implicit, mark, mark); + if (emitter->indent < 0) { + emitter->indent = flow ? emitter->best_indent : 0; + } + else if (!indentless) { + emitter->indent += emitter->best_indent; + } - return yaml_emitter_emit(emitter, &event); + return 1; } /* - * Emit ALIAS. + * State dispatcher. */ -YAML_DECLARE(int) -yaml_emitter_emit_alias(yaml_emitter_t *emitter, yaml_char_t *anchor) +static int +yaml_emitter_state_machine(yaml_emitter_t *emitter, yaml_event_t *event) { - yaml_event_t event; - yaml_mark_t mark = { 0, 0, 0 }; - yaml_char_t *anchor_copy = NULL; + switch (emitter->state) + { + case YAML_EMIT_STREAM_START_STATE: + return yaml_emitter_emit_stream_start(emitter, event); - assert(emitter); /* Non-NULL emitter object is expected. */ - assert(anchor); /* Non-NULL anchor is expected. */ + case YAML_EMIT_FIRST_DOCUMENT_START_STATE: + return yaml_emitter_emit_document_start(emitter, event, 1); - anchor_copy = yaml_strdup(anchor); - if (!anchor_copy) { - emitter->error = YAML_MEMORY_ERROR; - return 0; - } + case YAML_EMIT_DOCUMENT_START_STATE: + return yaml_emitter_emit_document_start(emitter, event, 0); - ALIAS_EVENT_INIT(event, anchor_copy, mark, mark); + case YAML_EMIT_DOCUMENT_CONTENT_STATE: + return yaml_emitter_emit_document_content(emitter, event); - if (yaml_emitter_emit(emitter, &event)) { - return 1; - } + case YAML_EMIT_DOCUMENT_END_STATE: + return yaml_emitter_emit_document_end(emitter, event); + + case YAML_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE: + return yaml_emitter_emit_flow_sequence_item(emitter, event, 1); + + case YAML_EMIT_FLOW_SEQUENCE_ITEM_STATE: + return yaml_emitter_emit_flow_sequence_item(emitter, event, 0); + + case YAML_EMIT_FLOW_MAPPING_FIRST_KEY_STATE: + return yaml_emitter_emit_flow_mapping_key(emitter, event, 1); + + case YAML_EMIT_FLOW_MAPPING_KEY_STATE: + return yaml_emitter_emit_flow_mapping_key(emitter, event, 0); + + case YAML_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE: + return yaml_emitter_emit_flow_mapping_value(emitter, event, 1); + + case YAML_EMIT_FLOW_MAPPING_VALUE_STATE: + return yaml_emitter_emit_flow_mapping_value(emitter, event, 0); - yaml_free(anchor_copy); + case YAML_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE: + return yaml_emitter_emit_block_sequence_item(emitter, event, 1); + + case YAML_EMIT_BLOCK_SEQUENCE_ITEM_STATE: + return yaml_emitter_emit_block_sequence_item(emitter, event, 0); + + case YAML_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE: + return yaml_emitter_emit_block_mapping_key(emitter, event, 1); + + case YAML_EMIT_BLOCK_MAPPING_KEY_STATE: + return yaml_emitter_emit_block_mapping_key(emitter, event, 0); + + case YAML_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE: + return yaml_emitter_emit_block_mapping_value(emitter, event, 1); + + case YAML_EMIT_BLOCK_MAPPING_VALUE_STATE: + return yaml_emitter_emit_block_mapping_value(emitter, event, 0); + + case YAML_EMIT_END_STATE: + return yaml_emitter_set_emitter_error(emitter, + "expected nothing after STREAM-END"); + + default: + assert(1); /* Invalid state. */ + } return 0; } /* - * Emit SCALAR. + * Expect STREAM-START. */ -YAML_DECLARE(int) -yaml_emitter_emit_scalar(yaml_emitter_t *emitter, - yaml_char_t *anchor, yaml_char_t *tag, - yaml_char_t *value, size_t length, - int plain_implicit, int quoted_implicit, - yaml_scalar_style_t style) +static int +yaml_emitter_emit_stream_start(yaml_emitter_t *emitter, + yaml_event_t *event) { - yaml_event_t event; - yaml_mark_t mark = { 0, 0, 0 }; - yaml_char_t *anchor_copy = NULL; - yaml_char_t *tag_copy = NULL; - yaml_char_t *value_copy = NULL; - - assert(emitter); /* Non-NULL emitter object is expected. */ - assert(value); /* Non-NULL anchor is expected. */ - - if (anchor) { - anchor_copy = yaml_strdup(anchor); - if (!anchor_copy) { - emitter->error = YAML_MEMORY_ERROR; - goto error; + if (event->type == YAML_STREAM_START_EVENT) + { + if (!emitter->encoding) { + emitter->encoding = event->data.stream_start.encoding; } - } - if (tag) { - tag_copy = yaml_strdup(tag); - if (!tag_copy) { - emitter->error = YAML_MEMORY_ERROR; - goto error; + if (!emitter->encoding) { + emitter->encoding = YAML_UTF8_ENCODING; } - } - value_copy = yaml_malloc(length+1); - if (!value_copy) { - emitter->error = YAML_MEMORY_ERROR; - goto error; + if (emitter->best_indent < 2 || emitter->best_indent > 9) { + emitter->best_indent = 2; + } + + if (emitter->best_width >= 0 + && emitter->best_width <= emitter->best_indent*2) { + emitter->best_width = 80; + } + + if (emitter->best_width < 0) { + emitter->best_width = INT_MAX; + } + + if (!emitter->line_break) { + emitter->line_break = YAML_LN_BREAK; + } + + emitter->indent = -1; + + emitter->line = 0; + emitter->column = 0; + emitter->whitespace = 1; + emitter->indention = 1; + + if (emitter->encoding != YAML_UTF8_ENCODING) { + if (!yaml_emitter_write_bom(emitter)) + return 0; + } + + emitter->state = YAML_EMIT_FIRST_DOCUMENT_START_STATE; + + return 1; } - memcpy(value_copy, value, length); - value_copy[length] = '\0'; - SCALAR_EVENT_INIT(event, anchor_copy, tag_copy, value_copy, length, - plain_implicit, quoted_implicit, style, mark, mark); + return yaml_emitter_set_emitter_error(emitter, + "expected STREAM-START"); +} + +static int +yaml_emitter_emit_document_start(yaml_emitter_t *emitter, + yaml_event_t *event, int first) +{ + if (event->type == YAML_DOCUMENT_START_EVENT) + { + yaml_tag_directive_t default_tag_directives[] = { + {(yaml_char_t *)"!", (yaml_char_t *)"!"}, + {(yaml_char_t *)"!!", (yaml_char_t *)"tag:yaml.org,2002:"}, + {NULL, NULL} + }; + yaml_tag_directive_t *tag_directive; + int implicit; + + if (event->data.document_start.version_directive) { + if (event->data.document_start.version_directive->major != 1 + || event->data.document_start.version_directive-> minor != 1) { + return yaml_emitter_set_emitter_error(emitter, + "incompatible %YAML directive"); + } + } + + for (tag_directive = event->data.document_start.tag_directives.start; + tag_directive != event->data.document_start.tag_directives.end; + tag_directive ++) { + if (!yaml_emitter_append_tag_directive(emitter, *tag_directive, 0)) + return 0; + } + + for (tag_directive = default_tag_directives; + tag_directive->handle; tag_directive ++) { + if (!yaml_emitter_append_tag_directive(emitter, *tag_directive, 1)) + return 0; + } + + implicit = event->data.document_start.implicit; + if (!first || emitter->canonical) { + implicit = 0; + } + + if (event->data.document_start.version_directive) { + implicit = 0; + if (!yaml_emitter_write_version_directive(emitter, + *event->data.document_start.version_directive)) + return 0; + } + + if (event->data.document_start.tag_directives.start + != event->data.document_start.tag_directives.end) { + implicit = 0; + for (tag_directive = event->data.document_start.tag_directives.start; + tag_directive != event->data.document_start.tag_directives.end; + tag_directive ++) { + if (!yaml_emitter_write_tag_directive(emitter, *tag_directive)) + return 0; + } + } + + if (yaml_emitter_check_empty_document(emitter)) { + implicit = 0; + } + + if (!implicit) { + if (!yaml_emitter_write_indent(emitter)) + return 0; + if (!yaml_emitter_write_indicator(emitter, "---", 1, 0, 0)) + return 0; + if (emitter->canonical) { + if (!yaml_emitter_write_indent(emitter)) + return 0; + } + } + + emitter->state = YAML_EMIT_DOCUMENT_CONTENT_STATE; - if (yaml_emitter_emit(emitter, &event)) { return 1; } -error: - yaml_free(anchor_copy); - yaml_free(tag_copy); - yaml_free(value_copy); + else if (event->type == YAML_STREAM_END_EVENT) + { + if (!yaml_emitter_flush(emitter)) + return 0; - return 0; + emitter->state = YAML_EMIT_END_STATE; + + return 1; + } + + return yaml_emitter_set_emitter_error(emitter, + "expected DOCUMENT-START or STREAM-END"); } -/* - * Emit SEQUENCE-START. - */ +static int +yaml_emitter_emit_document_content(yaml_emitter_t *emitter, + yaml_event_t *event) +{ + if (!PUSH(emitter, emitter->states, YAML_EMIT_DOCUMENT_END_STATE)) + return 0; -YAML_DECLARE(int) -yaml_emitter_emit_sequence_start(yaml_emitter_t *emitter, - yaml_char_t *anchor, yaml_char_t *tag, int implicit, - yaml_sequence_style_t style) + return yaml_emitter_emit_node(emitter, event, 1, 0, 0, 0); +} + +static int +yaml_emitter_emit_document_end(yaml_emitter_t *emitter, + yaml_event_t *event) { - yaml_event_t event; - yaml_mark_t mark = { 0, 0, 0 }; - yaml_char_t *anchor_copy = NULL; - yaml_char_t *tag_copy = NULL; - - assert(emitter); /* Non-NULL emitter object is expected. */ - - if (anchor) { - anchor_copy = yaml_strdup(anchor); - if (!anchor_copy) { - emitter->error = YAML_MEMORY_ERROR; - goto error; + if (event->type == YAML_DOCUMENT_END_EVENT) + { + if (!yaml_emitter_write_indent(emitter)) + return 0; + if (!event->data.document_end.implicit) { + if (!yaml_emitter_write_indicator(emitter, "...", 1, 0, 0)) + return 0; + if (!yaml_emitter_write_indent(emitter)) + return 0; } + if (!yaml_emitter_flush(emitter)) + return 0; + + emitter->state = YAML_EMIT_DOCUMENT_START_STATE; + + return 1; } - if (tag) { - tag_copy = yaml_strdup(tag); - if (!tag_copy) { - emitter->error = YAML_MEMORY_ERROR; - goto error; - } + return yaml_emitter_set_emitter_error(emitter, + "expected DOCUMENT-END"); +} + +static int +yaml_emitter_emit_flow_sequence_item(yaml_emitter_t *emitter, + yaml_event_t *event, int first) +{ + if (first) + { + if (!yaml_emitter_write_indicator(emitter, "[", 1, 1, 0)) + return 0; + if (!yaml_emitter_increase_indent(emitter, 1, 0)) + return 0; + emitter->flow_level ++; } - SEQUENCE_START_EVENT_INIT(event, anchor_copy, tag_copy, - implicit, style, mark, mark); + if (event->type == YAML_SEQUENCE_END_EVENT) + { + emitter->flow_level --; + emitter->indent = POP(emitter, emitter->indents); + if (emitter->canonical && !first) { + if (!yaml_emitter_write_indicator(emitter, ",", 0, 0, 0)) + return 0; + if (!yaml_emitter_write_indent(emitter)) + return 0; + } + if (!yaml_emitter_write_indicator(emitter, "]", 0, 0, 0)) + return 0; + emitter->state = POP(emitter, emitter->states); - if (yaml_emitter_emit(emitter, &event)) { return 1; } -error: - yaml_free(anchor_copy); - yaml_free(tag_copy); + if (emitter->canonical || emitter->column > emitter->best_width) { + if (!yaml_emitter_write_indent(emitter)) + return 0; + } + if (PUSH(emitter, emitter->states, YAML_EMIT_FLOW_SEQUENCE_ITEM_STATE)) + return 0; - return 0; + return yaml_emitter_emit_node(emitter, event, 0, 1, 0, 0); } -/* - * Emit SEQUENCE-END. - */ - -YAML_DECLARE(int) -yaml_emitter_emit_sequence_end(yaml_emitter_t *emitter) +static int +yaml_emitter_emit_flow_mapping_key(yaml_emitter_t *emitter, + yaml_event_t *event, int first) { - yaml_event_t event; - yaml_mark_t mark = { 0, 0, 0 }; + if (first) + { + if (!yaml_emitter_write_indicator(emitter, "{", 1, 1, 0)) + return 0; + if (!yaml_emitter_increase_indent(emitter, 1, 0)) + return 0; + emitter->flow_level ++; + } - assert(emitter); /* Non-NULL emitter object is expected. */ + if (event->type == YAML_MAPPING_END_EVENT) + { + emitter->flow_level --; + emitter->indent = POP(emitter, emitter->indents); + if (emitter->canonical && !first) { + if (!yaml_emitter_write_indicator(emitter, ",", 0, 0, 0)) + return 0; + if (!yaml_emitter_write_indent(emitter)) + return 0; + } + if (!yaml_emitter_write_indicator(emitter, "}", 0, 0, 0)) + return 0; + emitter->state = POP(emitter, emitter->states); - SEQUENCE_END_EVENT_INIT(event, mark, mark); + return 1; + } - return yaml_emitter_emit(emitter, &event); -} + if (!first) { + if (!yaml_emitter_write_indicator(emitter, ",", 0, 0, 0)) + return 0; + } + if (emitter->canonical || emitter->column > emitter->best_width) { + if (!yaml_emitter_write_indent(emitter)) + return 0; + } -/* - * Emit MAPPING-START. - */ + if (!emitter->canonical && yaml_emitter_check_simple_key(emitter)) + { + if (!PUSH(emitter, emitter->states, + YAML_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE)) + return 0; -YAML_DECLARE(int) -yaml_emitter_emit_mapping_start(yaml_emitter_t *emitter, - yaml_char_t *anchor, yaml_char_t *tag, int implicit, - yaml_mapping_style_t style) + return yaml_emitter_emit_node(emitter, event, 0, 0, 1, 1); + } + else + { + if (!yaml_emitter_write_indicator(emitter, "?", 1, 0, 0)) + return 0; + if (!PUSH(emitter, emitter->states, + YAML_EMIT_FLOW_MAPPING_VALUE_STATE)) + return 0; + + return yaml_emitter_emit_node(emitter, event, 0, 0, 1, 0); + } +} + +static int +yaml_emitter_emit_flow_mapping_value(yaml_emitter_t *emitter, + yaml_event_t *event, int simple) { - yaml_event_t event; - yaml_mark_t mark = { 0, 0, 0 }; - yaml_char_t *anchor_copy = NULL; - yaml_char_t *tag_copy = NULL; - - assert(emitter); /* Non-NULL emitter object is expected. */ - - if (anchor) { - anchor_copy = yaml_strdup(anchor); - if (!anchor_copy) { - emitter->error = YAML_MEMORY_ERROR; - goto error; + if (simple) { + if (!yaml_emitter_write_indicator(emitter, ":", 0, 0, 0)) + return 0; + } + else { + if (emitter->canonical || emitter->column > emitter->best_width) { + if (!yaml_emitter_write_indent(emitter)) + return 0; } + if (!yaml_emitter_write_indicator(emitter, ":", 1, 0, 0)) + return 0; } + if (!PUSH(emitter, emitter->states, YAML_EMIT_FLOW_MAPPING_KEY_STATE)) + return 0; + return yaml_emitter_emit_node(emitter, event, 0, 0, 1, 0); +} - if (tag) { - tag_copy = yaml_strdup(tag); - if (!tag_copy) { - emitter->error = YAML_MEMORY_ERROR; - goto error; - } +static int +yaml_emitter_emit_block_sequence_item(yaml_emitter_t *emitter, + yaml_event_t *event, int first) +{ + if (first) + { + if (!yaml_emitter_increase_indent(emitter, 0, + (emitter->mapping_context && !emitter->indention))) + return 0; } - MAPPING_START_EVENT_INIT(event, anchor_copy, tag_copy, - implicit, style, mark, mark); + if (event->type == YAML_SEQUENCE_END_EVENT) + { + emitter->indent = POP(emitter, emitter->indents); + emitter->state = POP(emitter, emitter->states); - if (yaml_emitter_emit(emitter, &event)) { return 1; } -error: - yaml_free(anchor_copy); - yaml_free(tag_copy); + if (!yaml_emitter_write_indent(emitter)) + return 0; + if (!yaml_emitter_write_indicator(emitter, "-", 1, 0, 1)) + return 0; + if (!PUSH(emitter, emitter->states, + YAML_EMIT_BLOCK_SEQUENCE_ITEM_STATE)) + return 0; - return 0; + return yaml_emitter_emit_node(emitter, event, 0, 1, 0, 0); } -/* - * Emit MAPPING-END. - */ - -YAML_DECLARE(int) -yaml_emitter_emit_mapping_end(yaml_emitter_t *emitter) +static int +yaml_emitter_emit_block_mapping_key(yaml_emitter_t *emitter, + yaml_event_t *event, int first) { - yaml_event_t event; - yaml_mark_t mark = { 0, 0, 0 }; + if (first) + { + if (!yaml_emitter_increase_indent(emitter, 0, 0)) + return 0; + } + + if (event->type == YAML_MAPPING_END_EVENT) + { + emitter->indent = POP(emitter, emitter->indents); + emitter->state = POP(emitter, emitter->states); + + return 1; + } - assert(emitter); /* Non-NULL emitter object is expected. */ + if (!yaml_emitter_write_indent(emitter)) + return 0; - MAPPING_END_EVENT_INIT(event, mark, mark); + if (yaml_emitter_check_simple_key(emitter)) + { + if (!PUSH(emitter, emitter->states, + YAML_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE)) + return 0; - return yaml_emitter_emit(emitter, &event); + return yaml_emitter_emit_node(emitter, event, 0, 0, 1, 1); + } + else + { + if (!yaml_emitter_write_indicator(emitter, "?", 1, 0, 1)) + return 0; + if (!PUSH(emitter, emitter->states, + YAML_EMIT_BLOCK_MAPPING_VALUE_STATE)) + return 0; + + return yaml_emitter_emit_node(emitter, event, 0, 0, 1, 0); + } } -/* - * Emit an event. - */ +static int +yaml_emitter_emit_block_mapping_value(yaml_emitter_t *emitter, + yaml_event_t *event, int simple) +{ + if (simple) { + if (!yaml_emitter_write_indicator(emitter, ":", 0, 0, 0)) + return 0; + } + else { + if (!yaml_emitter_write_indent(emitter)) + return 0; + if (!yaml_emitter_write_indicator(emitter, ":", 1, 0, 1)) + return 0; + } + if (!PUSH(emitter, emitter->states, + YAML_EMIT_BLOCK_MAPPING_KEY_STATE)) + return 0; -YAML_DECLARE(int) -yaml_emitter_emit(yaml_emitter_t *emitter, yaml_event_t *event) + return yaml_emitter_emit_node(emitter, event, 0, 0, 1, 0); +} + +static int +yaml_emitter_emit_node(yaml_emitter_t *emitter, yaml_event_t *event, + int root, int sequence, int mapping, int simple_key) { + emitter->root_context = root; + emitter->sequence_context = sequence; + emitter->mapping_context = mapping; + emitter->simple_key_context = simple_key; + + switch (event->type) + { + case YAML_ALIAS_EVENT: + return yaml_emitter_emit_alias(emitter, event); + + case YAML_SCALAR_EVENT: + return yaml_emitter_emit_scalar(emitter, event); + + case YAML_SEQUENCE_START_EVENT: + return yaml_emitter_emit_sequence_start(emitter, event); + + case YAML_MAPPING_START_EVENT: + return yaml_emitter_emit_mapping_start(emitter, event); + + default: + return yaml_emitter_set_emitter_error(emitter, + "expected SCALAR, SEQUENCE-START, MAPPING-START, or ALIAS"); + } + return 0; } +static int +yaml_emitter_emit_alias(yaml_emitter_t *emitter, yaml_event_t *event) +{ + if (!yaml_emitter_process_anchor(emitter, event->data.alias.anchor, 1)) + return 0; + emitter->state = POP(emitter, emitter->states); + + return 1; +} + +static int +yaml_emitter_emit_scalar(yaml_emitter_t *emitter, yaml_event_t *event) +{ + if (!yaml_emitter_process_anchor(emitter, event->data.scalar.anchor, 0)) + return 0; + if (!yaml_emitter_process_tag(emitter, event->data.scalar.tag)) + return 0; + if (!yaml_emitter_increase_indent(emitter, 1, 0)) + return 0; + if (!yaml_emitter_process_scalar(emitter, + event->data.scalar.value, event->data.scalar.length, + event->data.scalar.plain_implicit, + event->data.scalar.quoted_implicit, + event->data.scalar.style)) + return 0; + emitter->indent = POP(emitter, emitter->indents); + emitter->state = POP(emitter, emitter->states); + + return 1; +} + +static int +yaml_emitter_emit_sequence_start(yaml_emitter_t *emitter, yaml_event_t *event) +{ + if (!yaml_emitter_process_anchor(emitter, + event->data.sequence_start.anchor, 0)) + return 0; + if (!yaml_emitter_process_tag(emitter, + event->data.sequence_start.tag)) + return 0; + + if (emitter->flow_level || emitter->canonical + || event->data.sequence_start.style == YAML_FLOW_SEQUENCE_STYLE + || yaml_emitter_check_empty_sequence(emitter)) { + emitter->state = YAML_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE; + } + else { + emitter->state = YAML_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE; + } + + return 1; +} + +static int +yaml_emitter_emit_mapping_start(yaml_emitter_t *emitter, yaml_event_t *event) +{ + if (!yaml_emitter_process_anchor(emitter, + event->data.mapping_start.anchor, 0)) + return 0; + if (!yaml_emitter_process_tag(emitter, + event->data.mapping_start.tag)) + return 0; + + if (emitter->flow_level || emitter->canonical + || event->data.mapping_start.style == YAML_FLOW_MAPPING_STYLE + || yaml_emitter_check_empty_mapping(emitter)) { + emitter->state = YAML_EMIT_FLOW_MAPPING_FIRST_KEY_STATE; + } + else { + emitter->state = YAML_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE; + } + + return 1; +} + diff --git a/src/parser.c b/src/parser.c index ed3c019..0b5b543 100644 --- a/src/parser.c +++ b/src/parser.c @@ -172,12 +172,14 @@ yaml_parser_parse(yaml_parser_t *parser, yaml_event_t *event) assert(parser); /* Non-NULL parser object is expected. */ assert(event); /* Non-NULL event object is expected. */ + /* Erase the event object. */ + + memset(event, 0, sizeof(yaml_event_t)); + /* No events after the end of the stream or error. */ if (parser->stream_end_produced || parser->error || parser->state == YAML_PARSE_END_STATE) { - memset(event, 0, sizeof(yaml_event_t)); - return 1; } @@ -1318,6 +1320,10 @@ error: return 0; } +/* + * Append a tag directive to the directives stack. + */ + static int yaml_parser_append_tag_directive(yaml_parser_t *parser, yaml_tag_directive_t value, int allow_duplicates, yaml_mark_t mark) diff --git a/src/scanner.c b/src/scanner.c index bb81127..4265763 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -938,11 +938,13 @@ yaml_parser_scan(yaml_parser_t *parser, yaml_token_t *token) assert(parser); /* Non-NULL parser object is expected. */ assert(token); /* Non-NULL token object is expected. */ + /* Erase the token object. */ + + memset(token, 0, sizeof(yaml_token_t)); + /* No tokens after STREAM-END or error. */ if (parser->stream_end_produced || parser->error) { - memset(token, 0, sizeof(yaml_token_t)); - return 1; } diff --git a/src/yaml_private.h b/src/yaml_private.h index faa855b..efd1d43 100644 --- a/src/yaml_private.h +++ b/src/yaml_private.h @@ -6,6 +6,7 @@ #include #include +#include /* * Memory management. -- cgit v1.2.1