Commits

Kirill Simonov committed 58d7005

Implement Emitter state machine.

Comments (0)

Files changed (6)

     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;
 
 /** @} */
 } 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.
  *
  * @param[in]   event   An event object.
     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;
 
 /**
         yaml_event_t *tail;
     } events;
 
-    /** The current event. */
-    yaml_event_t event;
-
     /** The stack of indentation levels. */
     struct {
         /** The beginning of the stack. */
  * 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.
 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.
  *
  * @param[in]   emitter     An emitter object.
         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);
 }
 
 /*
+ * 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.
  */
 
 YAML_DECLARE(int)
 yaml_emitter_emit(yaml_emitter_t *emitter, yaml_event_t *event);
 
-YAML_DECLARE(int)
+/*
+ * Utility functions.
+ */
+
+static int
+yaml_emitter_set_emitter_error(yaml_emitter_t *emitter, const char *problem);
+
+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_encoding_t encoding);
+        yaml_event_t *event);
 
-YAML_DECLARE(int)
-yaml_emitter_emit_stream_end(yaml_emitter_t *emitter);
+static int
+yaml_emitter_emit_document_start(yaml_emitter_t *emitter,
+        yaml_event_t *event, int first);
 
-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_emit_document_content(yaml_emitter_t *emitter,
+        yaml_event_t *event);
 
-YAML_DECLARE(int)
-yaml_emitter_emit_document_end(yaml_emitter_t *emitter, int implicit);
+static int
+yaml_emitter_emit_document_end(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_flow_sequence_item(yaml_emitter_t *emitter,
+        yaml_event_t *event, int first);
 
-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_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 };
-
-    assert(emitter);    /* Non-NULL emitter object is expected. */
-
-    STREAM_START_EVENT_INIT(event, encoding, mark, mark);
-
-    return yaml_emitter_emit(emitter, &event);
-}
-
-/*
- * Emit STREAM-END.
- */
-
-YAML_DECLARE(int)
-yaml_emitter_emit_stream_end(yaml_emitter_t *emitter)
-{
-    yaml_event_t event;
-    yaml_mark_t mark = { 0, 0, 0 };
-
-    assert(emitter);    /* Non-NULL emitter object is expected. */
-
-    STREAM_END_EVENT_INIT(event, mark, mark);
-
-    return yaml_emitter_emit(emitter, &event);
-}
-
-/*
- * Emit DOCUMENT-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)
-{
-    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;
-    }
-
-    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;
-        }
-    }
-
-    DOCUMENT_START_EVENT_INIT(event, version_directive_copy,
-            tag_directives_copy.start, tag_directives_copy.end,
-            implicit, mark, mark);
-
-    if (yaml_emitter_emit(emitter, &event)) {
-        return 1;
-    }
-
-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);
-    }
-    STACK_DEL(emitter, tag_directives_copy);
-    yaml_free(value.handle);
-    yaml_free(value.prefix);
+    emitter->error = YAML_EMITTER_ERROR;
+    emitter->problem = problem;
 
     return 0;
 }
 
 /*
- * Emit DOCUMENT-END.
- */
-
-YAML_DECLARE(int)
-yaml_emitter_emit_document_end(yaml_emitter_t *emitter, int implicit)
-{
-    yaml_event_t event;
-    yaml_mark_t mark = { 0, 0, 0 };
-
-    assert(emitter);    /* Non-NULL emitter object is expected. */
-
-    DOCUMENT_END_EVENT_INIT(event, implicit, mark, mark);
-
-    return yaml_emitter_emit(emitter, &event);
-}
-
-/*
- * Emit ALIAS.
- */
-
-YAML_DECLARE(int)
-yaml_emitter_emit_alias(yaml_emitter_t *emitter, yaml_char_t *anchor)
-{
-    yaml_event_t event;
-    yaml_mark_t mark = { 0, 0, 0 };
-    yaml_char_t *anchor_copy = NULL;
-
-    assert(emitter);    /* Non-NULL emitter object is expected. */
-    assert(anchor);     /* Non-NULL anchor is expected. */
-
-    anchor_copy = yaml_strdup(anchor);
-    if (!anchor_copy) {
-        emitter->error = YAML_MEMORY_ERROR;
-        return 0;
-    }
-
-    ALIAS_EVENT_INIT(event, anchor_copy, mark, mark);
-
-    if (yaml_emitter_emit(emitter, &event)) {
-        return 1;
-    }
-
-    yaml_free(anchor_copy);
-
-    return 0;
-}
-
-/*
- * Emit SCALAR.
- */
-
-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)
-{
-    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 (tag) {
-        tag_copy = yaml_strdup(tag);
-        if (!tag_copy) {
-            emitter->error = YAML_MEMORY_ERROR;
-            goto error;
-        }
-    }
-
-    value_copy = yaml_malloc(length+1);
-    if (!value_copy) {
-        emitter->error = YAML_MEMORY_ERROR;
-        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);
-
-    if (yaml_emitter_emit(emitter, &event)) {
-        return 1;
-    }
-
-error:
-    yaml_free(anchor_copy);
-    yaml_free(tag_copy);
-    yaml_free(value_copy);
-
-    return 0;
-}
-
-/*
- * Emit SEQUENCE-START.
- */
-
-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)
-{
-    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 (tag) {
-        tag_copy = yaml_strdup(tag);
-        if (!tag_copy) {
-            emitter->error = YAML_MEMORY_ERROR;
-            goto error;
-        }
-    }
-
-    SEQUENCE_START_EVENT_INIT(event, anchor_copy, tag_copy,
-            implicit, style, mark, mark);
-
-    if (yaml_emitter_emit(emitter, &event)) {
-        return 1;
-    }
-
-error:
-    yaml_free(anchor_copy);
-    yaml_free(tag_copy);
-
-    return 0;
-}
-
-/*
- * Emit SEQUENCE-END.
- */
-
-YAML_DECLARE(int)
-yaml_emitter_emit_sequence_end(yaml_emitter_t *emitter)
-{
-    yaml_event_t event;
-    yaml_mark_t mark = { 0, 0, 0 };
-
-    assert(emitter);    /* Non-NULL emitter object is expected. */
-
-    SEQUENCE_END_EVENT_INIT(event, mark, mark);
-
-    return yaml_emitter_emit(emitter, &event);
-}
-
-/*
- * Emit MAPPING-START.
- */
-
-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)
-{
-    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 (tag) {
-        tag_copy = yaml_strdup(tag);
-        if (!tag_copy) {
-            emitter->error = YAML_MEMORY_ERROR;
-            goto error;
-        }
-    }
-
-    MAPPING_START_EVENT_INIT(event, anchor_copy, tag_copy,
-            implicit, style, mark, mark);
-
-    if (yaml_emitter_emit(emitter, &event)) {
-        return 1;
-    }
-
-error:
-    yaml_free(anchor_copy);
-    yaml_free(tag_copy);
-
-    return 0;
-}
-
-/*
- * Emit MAPPING-END.
- */
-
-YAML_DECLARE(int)
-yaml_emitter_emit_mapping_end(yaml_emitter_t *emitter)
-{
-    yaml_event_t event;
-    yaml_mark_t mark = { 0, 0, 0 };
-
-    assert(emitter);    /* Non-NULL emitter object is expected. */
-
-    MAPPING_END_EVENT_INIT(event, mark, mark);
-
-    return yaml_emitter_emit(emitter, &event);
-}
-
-/*
  * Emit an event.
  */
 
 YAML_DECLARE(int)
 yaml_emitter_emit(yaml_emitter_t *emitter, yaml_event_t *event)
 {
+    if (!ENQUEUE(emitter, emitter->events, *event)) {
+        yaml_event_delete(event);
+        return 0;
+    }
+
+    while (!yaml_emitter_need_more_events(emitter)) {
+        if (!yaml_emitter_state_machine(emitter, emitter->events.head)) {
+            return 0;
+        }
+        DEQUEUE(emitter, emitter->events);
+    }
+
+    return 1;
+}
+
+/*
+ * 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
+ */
+
+static int
+yaml_emitter_need_more_events(yaml_emitter_t *emitter)
+{
+    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 (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;
+    }
+
+    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");
+        }
+    }
+
+    copy.handle = yaml_strdup(value.handle);
+    copy.prefix = yaml_strdup(value.prefix);
+    if (!copy.handle || !copy.prefix) {
+        emitter->error = YAML_MEMORY_ERROR;
+        goto error;
+    }
+
+    if (!PUSH(emitter, emitter->tag_directives, copy))
+        goto error;
+
+    return 1;
+
+error:
+    yaml_free(copy.handle);
+    yaml_free(copy.prefix);
     return 0;
 }
 
+/*
+ * Increase the indentation level.
+ */
+
+static int
+yaml_emitter_increase_indent(yaml_emitter_t *emitter,
+        int flow, int indentless)
+{
+    if (!PUSH(emitter, emitter->indents, emitter->indent))
+        return 0;
+
+    if (emitter->indent < 0) {
+        emitter->indent = flow ? emitter->best_indent : 0;
+    }
+    else if (!indentless) {
+        emitter->indent += emitter->best_indent;
+    }
+
+    return 1;
+}
+
+/*
+ * State dispatcher.
+ */
+
+static int
+yaml_emitter_state_machine(yaml_emitter_t *emitter, yaml_event_t *event)
+{
+    switch (emitter->state)
+    {
+        case YAML_EMIT_STREAM_START_STATE:
+            return yaml_emitter_emit_stream_start(emitter, event);
+
+        case YAML_EMIT_FIRST_DOCUMENT_START_STATE:
+            return yaml_emitter_emit_document_start(emitter, event, 1);
+
+        case YAML_EMIT_DOCUMENT_START_STATE:
+            return yaml_emitter_emit_document_start(emitter, event, 0);
+
+        case YAML_EMIT_DOCUMENT_CONTENT_STATE:
+            return yaml_emitter_emit_document_content(emitter, event);
+
+        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);
+
+        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;
+}
+
+/*
+ * Expect STREAM-START.
+ */
+
+static int
+yaml_emitter_emit_stream_start(yaml_emitter_t *emitter,
+        yaml_event_t *event)
+{
+    if (event->type == YAML_STREAM_START_EVENT)
+    {
+        if (!emitter->encoding) {
+            emitter->encoding = event->data.stream_start.encoding;
+        }
+
+        if (!emitter->encoding) {
+            emitter->encoding = YAML_UTF8_ENCODING;
+        }
+
+        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;
+    }
+
+    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;
+
+        return 1;
+    }
+
+    else if (event->type == YAML_STREAM_END_EVENT)
+    {
+        if (!yaml_emitter_flush(emitter))
+            return 0;
+
+        emitter->state = YAML_EMIT_END_STATE;
+
+        return 1;
+    }
+
+    return yaml_emitter_set_emitter_error(emitter,
+            "expected DOCUMENT-START or STREAM-END");
+}
+
+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;
+
+    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)
+{
+    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;
+    }
+
+    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 ++;
+    }
+
+    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);
+
+        return 1;
+    }
+
+    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 yaml_emitter_emit_node(emitter, event, 0, 1, 0, 0);
+}
+
+static int
+yaml_emitter_emit_flow_mapping_key(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 ++;
+    }
+
+    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);
+
+        return 1;
+    }
+
+    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;
+    }
+
+    if (!emitter->canonical && yaml_emitter_check_simple_key(emitter))
+    {
+        if (!PUSH(emitter, emitter->states,
+                    YAML_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE))
+            return 0;
+
+        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)
+{
+    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);
+}
+
+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;
+    }
+
+    if (event->type == YAML_SEQUENCE_END_EVENT)
+    {
+        emitter->indent = POP(emitter, emitter->indents);
+        emitter->state = POP(emitter, emitter->states);
+
+        return 1;
+    }
+
+    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 yaml_emitter_emit_node(emitter, event, 0, 1, 0, 0);
+}
+
+static int
+yaml_emitter_emit_block_mapping_key(yaml_emitter_t *emitter,
+        yaml_event_t *event, int first)
+{
+    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;
+    }
+
+    if (!yaml_emitter_write_indent(emitter))
+        return 0;
+
+    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_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);
+    }
+}
+
+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;
+
+    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;
+}
+
     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;
     }
 
     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)
     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;
     }
 

src/yaml_private.h

 #include <yaml.h>
 
 #include <assert.h>
+#include <limits.h>
 
 /*
  * Memory management.
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.