summaryrefslogtreecommitdiff
path: root/src/emitter.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/emitter.c')
-rw-r--r--src/emitter.c1044
1 files changed, 1004 insertions, 40 deletions
diff --git a/src/emitter.c b/src/emitter.c
index 41ed3fc..b8d3dc9 100644
--- a/src/emitter.c
+++ b/src/emitter.c
@@ -2,6 +2,62 @@
#include "yaml_private.h"
/*
+ * Flush the buffer if needed.
+ */
+
+#define FLUSH(emitter) \
+ ((emitter->buffer.pointer+5 < emitter->buffer.end) \
+ || yaml_emitter_flush(emitter))
+
+/*
+ * Put a character to the output buffer.
+ */
+
+#define PUT(emitter,value) \
+ (FLUSH(emitter) \
+ && (*(emitter->buffer.pointer++) = (yaml_char_t)(value), \
+ emitter->column ++, \
+ 1))
+
+/*
+ * Put a line break to the output buffer.
+ */
+
+#define PUT_BREAK(emitter) \
+ (FLUSH(emitter) \
+ && ((emitter->line_break == YAML_CR_BREAK ? \
+ (*(emitter->buffer.pointer++) = (yaml_char_t) '\r') : \
+ emitter->line_break == YAML_LN_BREAK ? \
+ (*(emitter->buffer.pointer++) = (yaml_char_t) '\n') : \
+ emitter->line_break == YAML_CRLN_BREAK ? \
+ (*(emitter->buffer.pointer++) = (yaml_char_t) '\r', \
+ *(emitter->buffer.pointer++) = (yaml_char_t) '\n') : 0), \
+ emitter->column = 0, \
+ emitter->line ++, \
+ 1))
+
+/*
+ * Copy a character from a string into buffer.
+ */
+
+#define WRITE(emitter,string) \
+ (FLUSH(emitter) \
+ && (COPY(emitter->buffer,string), \
+ emitter->column ++, \
+ 1))
+
+/*
+ * Copy a line break character from a string into buffer.
+ */
+
+#define WRITE_BREAK(emitter,string) \
+ (FLUSH(emitter) \
+ && (COPY(emitter->buffer,string), \
+ emitter->column = 0, \
+ emitter->line ++, \
+ 1))
+
+/*
* API functions.
*/
@@ -105,40 +161,58 @@ yaml_emitter_check_empty_mapping(yaml_emitter_t *emitter);
static int
yaml_emitter_check_simple_key(yaml_emitter_t *emitter);
+static int
+yaml_emitter_select_scalar_style(yaml_emitter_t *emitter, yaml_event_t *event);
+
/*
* Processors.
*/
static int
-yaml_emitter_process_anchor(yaml_emitter_t *emitter,
- yaml_char_t *anchor, int alias);
+yaml_emitter_process_anchor(yaml_emitter_t *emitter);
static int
-yaml_emitter_process_tag(yaml_emitter_t *emitter,
- yaml_char_t *tag);
+yaml_emitter_process_tag(yaml_emitter_t *emitter);
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_emitter_process_scalar(yaml_emitter_t *emitter);
/*
- * Writers.
+ * Analyzers.
*/
static int
-yaml_emitter_write_bom(yaml_emitter_t *emitter);
-
-static int
-yaml_emitter_write_version_directive(yaml_emitter_t *emitter,
+yaml_emitter_analyze_version_directive(yaml_emitter_t *emitter,
yaml_version_directive_t version_directive);
static int
-yaml_emitter_write_tag_directive(yaml_emitter_t *emitter,
+yaml_emitter_analyze_tag_directive(yaml_emitter_t *emitter,
yaml_tag_directive_t tag_directive);
static int
+yaml_emitter_analyze_anchor(yaml_emitter_t *emitter,
+ yaml_char_t *anchor, int alias);
+
+static int
+yaml_emitter_analyze_tag(yaml_emitter_t *emitter,
+ yaml_char_t *tag);
+
+static int
+yaml_emitter_analyze_scalar(yaml_emitter_t *emitter,
+ yaml_char_t *value, size_t length);
+
+static int
+yaml_emitter_analyze_event(yaml_emitter_t *emitter,
+ yaml_event_t *event);
+
+/*
+ * Writers.
+ */
+
+static int
+yaml_emitter_write_bom(yaml_emitter_t *emitter);
+
+static int
yaml_emitter_write_indent(yaml_emitter_t *emitter);
static int
@@ -146,6 +220,38 @@ yaml_emitter_write_indicator(yaml_emitter_t *emitter,
char *indicator, int need_whitespace,
int is_whitespace, int is_indention);
+static int
+yaml_emitter_write_anchor(yaml_emitter_t *emitter,
+ yaml_char_t *value, size_t length);
+
+static int
+yaml_emitter_write_tag_handle(yaml_emitter_t *emitter,
+ yaml_char_t *value, size_t length);
+
+static int
+yaml_emitter_write_tag_content(yaml_emitter_t *emitter,
+ yaml_char_t *value, size_t length);
+
+static int
+yaml_emitter_write_plain_scalar(yaml_emitter_t *emitter,
+ yaml_char_t *value, size_t length, int allow_breaks);
+
+static int
+yaml_emitter_write_single_quoted_scalar(yaml_emitter_t *emitter,
+ yaml_char_t *value, size_t length, int allow_breaks);
+
+static int
+yaml_emitter_write_double_quoted_scalar(yaml_emitter_t *emitter,
+ yaml_char_t *value, size_t length, int allow_breaks);
+
+static int
+yaml_emitter_write_literal_scalar(yaml_emitter_t *emitter,
+ yaml_char_t *value, size_t length);
+
+static int
+yaml_emitter_write_folded_scalar(yaml_emitter_t *emitter,
+ yaml_char_t *value, size_t length);
+
/*
* Set an emitter error and return 0.
*/
@@ -172,9 +278,10 @@ yaml_emitter_emit(yaml_emitter_t *emitter, yaml_event_t *event)
}
while (!yaml_emitter_need_more_events(emitter)) {
- if (!yaml_emitter_state_machine(emitter, emitter->events.head)) {
+ if (!yaml_emitter_analyze_event(emitter, emitter->events.head))
+ return 0;
+ if (!yaml_emitter_state_machine(emitter, emitter->events.head))
return 0;
- }
DEQUEUE(emitter, emitter->events);
}
@@ -428,6 +535,10 @@ yaml_emitter_emit_stream_start(yaml_emitter_t *emitter,
"expected STREAM-START");
}
+/*
+ * Expect DOCUMENT-START or STREAM-END.
+ */
+
static int
yaml_emitter_emit_document_start(yaml_emitter_t *emitter,
yaml_event_t *event, int first)
@@ -443,16 +554,16 @@ yaml_emitter_emit_document_start(yaml_emitter_t *emitter,
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");
- }
+ if (!yaml_emitter_analyze_version_directive(emitter,
+ *event->data.document_start.version_directive))
+ return 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_analyze_tag_directive(emitter, *tag_directive))
+ return 0;
if (!yaml_emitter_append_tag_directive(emitter, *tag_directive, 0))
return 0;
}
@@ -470,8 +581,11 @@ yaml_emitter_emit_document_start(yaml_emitter_t *emitter,
if (event->data.document_start.version_directive) {
implicit = 0;
- if (!yaml_emitter_write_version_directive(emitter,
- *event->data.document_start.version_directive))
+ if (!yaml_emitter_write_indicator(emitter, "%YAML", 1, 0, 0))
+ return 0;
+ if (!yaml_emitter_write_indicator(emitter, "1.1", 1, 0, 0))
+ return 0;
+ if (!yaml_emitter_write_indent(emitter))
return 0;
}
@@ -481,7 +595,15 @@ yaml_emitter_emit_document_start(yaml_emitter_t *emitter,
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))
+ if (!yaml_emitter_write_indicator(emitter, "%TAG", 1, 0, 0))
+ return 0;
+ if (!yaml_emitter_write_tag_handle(emitter, tag_directive->handle,
+ strlen((char *)tag_directive->handle)))
+ return 0;
+ if (!yaml_emitter_write_tag_content(emitter, tag_directive->prefix,
+ strlen((char *)tag_directive->prefix)))
+ return 0;
+ if (!yaml_emitter_write_indent(emitter))
return 0;
}
}
@@ -520,6 +642,10 @@ yaml_emitter_emit_document_start(yaml_emitter_t *emitter,
"expected DOCUMENT-START or STREAM-END");
}
+/*
+ * Expect the root node.
+ */
+
static int
yaml_emitter_emit_document_content(yaml_emitter_t *emitter,
yaml_event_t *event)
@@ -530,6 +656,10 @@ yaml_emitter_emit_document_content(yaml_emitter_t *emitter,
return yaml_emitter_emit_node(emitter, event, 1, 0, 0, 0);
}
+/*
+ * Expect DOCUMENT-END.
+ */
+
static int
yaml_emitter_emit_document_end(yaml_emitter_t *emitter,
yaml_event_t *event)
@@ -556,6 +686,10 @@ yaml_emitter_emit_document_end(yaml_emitter_t *emitter,
"expected DOCUMENT-END");
}
+/*
+ * Expect a flow item node.
+ */
+
static int
yaml_emitter_emit_flow_sequence_item(yaml_emitter_t *emitter,
yaml_event_t *event, int first)
@@ -596,6 +730,10 @@ yaml_emitter_emit_flow_sequence_item(yaml_emitter_t *emitter,
return yaml_emitter_emit_node(emitter, event, 0, 1, 0, 0);
}
+/*
+ * Expect a flow key node.
+ */
+
static int
yaml_emitter_emit_flow_mapping_key(yaml_emitter_t *emitter,
yaml_event_t *event, int first)
@@ -655,6 +793,10 @@ yaml_emitter_emit_flow_mapping_key(yaml_emitter_t *emitter,
}
}
+/*
+ * Expect a flow value node.
+ */
+
static int
yaml_emitter_emit_flow_mapping_value(yaml_emitter_t *emitter,
yaml_event_t *event, int simple)
@@ -676,6 +818,10 @@ yaml_emitter_emit_flow_mapping_value(yaml_emitter_t *emitter,
return yaml_emitter_emit_node(emitter, event, 0, 0, 1, 0);
}
+/*
+ * Expect a block item node.
+ */
+
static int
yaml_emitter_emit_block_sequence_item(yaml_emitter_t *emitter,
yaml_event_t *event, int first)
@@ -706,6 +852,10 @@ yaml_emitter_emit_block_sequence_item(yaml_emitter_t *emitter,
return yaml_emitter_emit_node(emitter, event, 0, 1, 0, 0);
}
+/*
+ * Expect a block key node.
+ */
+
static int
yaml_emitter_emit_block_mapping_key(yaml_emitter_t *emitter,
yaml_event_t *event, int first)
@@ -747,6 +897,10 @@ yaml_emitter_emit_block_mapping_key(yaml_emitter_t *emitter,
}
}
+/*
+ * Expect a block value node.
+ */
+
static int
yaml_emitter_emit_block_mapping_value(yaml_emitter_t *emitter,
yaml_event_t *event, int simple)
@@ -768,6 +922,10 @@ yaml_emitter_emit_block_mapping_value(yaml_emitter_t *emitter,
return yaml_emitter_emit_node(emitter, event, 0, 0, 1, 0);
}
+/*
+ * Expect a node.
+ */
+
static int
yaml_emitter_emit_node(yaml_emitter_t *emitter, yaml_event_t *event,
int root, int sequence, int mapping, int simple_key)
@@ -799,30 +957,36 @@ yaml_emitter_emit_node(yaml_emitter_t *emitter, yaml_event_t *event,
return 0;
}
+/*
+ * Expect ALIAS.
+ */
+
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))
+ if (!yaml_emitter_process_anchor(emitter))
return 0;
emitter->state = POP(emitter, emitter->states);
return 1;
}
+/*
+ * Expect SCALAR.
+ */
+
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))
+ if (!yaml_emitter_select_scalar_style(emitter, event))
return 0;
- if (!yaml_emitter_process_tag(emitter, event->data.scalar.tag))
+ if (!yaml_emitter_process_anchor(emitter))
+ return 0;
+ if (!yaml_emitter_process_tag(emitter))
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))
+ if (!yaml_emitter_process_scalar(emitter))
return 0;
emitter->indent = POP(emitter, emitter->indents);
emitter->state = POP(emitter, emitter->states);
@@ -830,14 +994,16 @@ yaml_emitter_emit_scalar(yaml_emitter_t *emitter, yaml_event_t *event)
return 1;
}
+/*
+ * Expect SEQUENCE-START.
+ */
+
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))
+ if (!yaml_emitter_process_anchor(emitter))
return 0;
- if (!yaml_emitter_process_tag(emitter,
- event->data.sequence_start.tag))
+ if (!yaml_emitter_process_tag(emitter))
return 0;
if (emitter->flow_level || emitter->canonical
@@ -852,14 +1018,16 @@ yaml_emitter_emit_sequence_start(yaml_emitter_t *emitter, yaml_event_t *event)
return 1;
}
+/*
+ * Expect MAPPING-START.
+ */
+
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))
+ if (!yaml_emitter_process_anchor(emitter))
return 0;
- if (!yaml_emitter_process_tag(emitter,
- event->data.mapping_start.tag))
+ if (!yaml_emitter_process_tag(emitter))
return 0;
if (emitter->flow_level || emitter->canonical
@@ -874,3 +1042,799 @@ yaml_emitter_emit_mapping_start(yaml_emitter_t *emitter, yaml_event_t *event)
return 1;
}
+/*
+ * Check if the document content is an empty scalar.
+ */
+
+static int
+yaml_emitter_check_empty_document(yaml_emitter_t *emitter)
+{
+ return 0;
+}
+
+/*
+ * Check if the next events represent an empty sequence.
+ */
+
+static int
+yaml_emitter_check_empty_sequence(yaml_emitter_t *emitter)
+{
+ if (emitter->events.tail - emitter->events.head < 2)
+ return 0;
+
+ return (emitter->events.head[0].type == YAML_SEQUENCE_START_EVENT
+ && emitter->events.head[1].type == YAML_SEQUENCE_END_EVENT);
+}
+
+/*
+ * Check if the next events represent an empty mapping.
+ */
+
+static int
+yaml_emitter_check_empty_mapping(yaml_emitter_t *emitter)
+{
+ if (emitter->events.tail - emitter->events.head < 2)
+ return 0;
+
+ return (emitter->events.head[0].type == YAML_MAPPING_START_EVENT
+ && emitter->events.head[1].type == YAML_MAPPING_END_EVENT);
+}
+
+/*
+ * Check if the next node can be expressed as a simple key.
+ */
+
+static int
+yaml_emitter_check_simple_key(yaml_emitter_t *emitter)
+{
+ yaml_event_t *event = emitter->events.head;
+ size_t length = 0;
+
+ switch (event->type)
+ {
+ case YAML_ALIAS_EVENT:
+ length += emitter->anchor_data.anchor_length;
+ break;
+
+ case YAML_SCALAR_EVENT:
+ if (emitter->scalar_data.multiline)
+ return 0;
+ length += emitter->anchor_data.anchor_length
+ + emitter->tag_data.handle_length
+ + emitter->tag_data.suffix_length
+ + emitter->scalar_data.length;
+ break;
+
+ case YAML_SEQUENCE_START_EVENT:
+ if (!yaml_emitter_check_empty_sequence(emitter))
+ return 0;
+ length += emitter->anchor_data.anchor_length
+ + emitter->tag_data.handle_length
+ + emitter->tag_data.suffix_length;
+ break;
+
+ case YAML_MAPPING_START_EVENT:
+ if (!yaml_emitter_check_empty_sequence(emitter))
+ return 0;
+ length += emitter->anchor_data.anchor_length
+ + emitter->tag_data.handle_length
+ + emitter->tag_data.suffix_length;
+ break;
+
+ default:
+ return 0;
+ }
+
+ if (length > 128)
+ return 0;
+
+ return 1;
+}
+
+/*
+ * Determine an acceptable scalar style.
+ */
+
+static int
+yaml_emitter_select_scalar_style(yaml_emitter_t *emitter, yaml_event_t *event)
+{
+ yaml_scalar_style_t style = event->data.scalar.style;
+
+ if (style == YAML_ANY_SCALAR_STYLE)
+ style = YAML_PLAIN_SCALAR_STYLE;
+
+ if (emitter->canonical)
+ style = YAML_DOUBLE_QUOTED_SCALAR_STYLE;
+
+ if (emitter->simple_key_context && emitter->scalar_data.multiline)
+ style = YAML_DOUBLE_QUOTED_SCALAR_STYLE;
+
+ if (style == YAML_PLAIN_SCALAR_STYLE)
+ {
+ if ((emitter->flow_level && !emitter->scalar_data.flow_plain_allowed)
+ || (!emitter->flow_level && !emitter->scalar_data.block_plain_allowed))
+ style = YAML_SINGLE_QUOTED_SCALAR_STYLE;
+ if (!emitter->scalar_data.length
+ && (emitter->flow_level || emitter->simple_key_context))
+ style = YAML_SINGLE_QUOTED_SCALAR_STYLE;
+ if (!event->data.scalar.plain_implicit
+ && !emitter->tag_data.handle && !emitter->tag_data.suffix)
+ style = YAML_SINGLE_QUOTED_SCALAR_STYLE;
+ }
+
+ if (style == YAML_SINGLE_QUOTED_SCALAR_STYLE)
+ {
+ if (!emitter->scalar_data.single_quoted_allowed)
+ style = YAML_DOUBLE_QUOTED_SCALAR_STYLE;
+ }
+
+ if (style == YAML_LITERAL_SCALAR_STYLE || style == YAML_FOLDED_SCALAR_STYLE)
+ {
+ if (!emitter->scalar_data.block_allowed)
+ style = YAML_DOUBLE_QUOTED_SCALAR_STYLE;
+ }
+
+ if (!emitter->tag_data.handle && !emitter->tag_data.suffix)
+ {
+ if (!event->data.scalar.plain_implicit
+ && !event->data.scalar.quoted_implicit) {
+ return yaml_emitter_set_emitter_error(emitter,
+ "neither tag nor implicit flags are specified");
+ }
+
+ if (event->data.scalar.plain_implicit
+ && style != YAML_PLAIN_SCALAR_STYLE) {
+ emitter->tag_data.handle = (yaml_char_t *)"!";
+ emitter->tag_data.handle_length = 1;
+ }
+ }
+
+ emitter->scalar_data.style = style;
+
+ return 1;
+}
+
+/*
+ * Write an achor.
+ */
+
+static int
+yaml_emitter_process_anchor(yaml_emitter_t *emitter)
+{
+ if (!emitter->anchor_data.anchor)
+ return 1;
+
+ if (!yaml_emitter_write_indicator(emitter,
+ (emitter->anchor_data.alias ? "*" : "&"), 1, 0, 0))
+ return 0;
+
+ return yaml_emitter_write_anchor(emitter,
+ emitter->anchor_data.anchor, emitter->anchor_data.anchor_length);
+}
+
+/*
+ * Write a tag.
+ */
+
+static int
+yaml_emitter_process_tag(yaml_emitter_t *emitter)
+{
+ if (!emitter->tag_data.handle && !emitter->tag_data.suffix)
+ return 1;
+
+ if (emitter->tag_data.handle)
+ {
+ if (!yaml_emitter_write_tag_handle(emitter, emitter->tag_data.handle,
+ emitter->tag_data.handle_length))
+ return 0;
+ if (emitter->tag_data.suffix) {
+ if (!yaml_emitter_write_tag_content(emitter, emitter->tag_data.suffix,
+ emitter->tag_data.suffix_length))
+ return 0;
+ }
+ }
+ else
+ {
+ if (!yaml_emitter_write_indicator(emitter, "!<", 1, 0, 0))
+ return 0;
+ if (!yaml_emitter_write_tag_content(emitter, emitter->tag_data.suffix,
+ emitter->tag_data.suffix_length))
+ return 0;
+ if (!yaml_emitter_write_indicator(emitter, ">", 0, 0, 0))
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * Write a scalar.
+ */
+
+static int
+yaml_emitter_process_scalar(yaml_emitter_t *emitter)
+{
+ switch (emitter->scalar_data.style)
+ {
+ case YAML_PLAIN_SCALAR_STYLE:
+ return yaml_emitter_write_plain_scalar(emitter,
+ emitter->scalar_data.value, emitter->scalar_data.length,
+ !emitter->simple_key_context);
+
+ case YAML_SINGLE_QUOTED_SCALAR_STYLE:
+ return yaml_emitter_write_single_quoted_scalar(emitter,
+ emitter->scalar_data.value, emitter->scalar_data.length,
+ !emitter->simple_key_context);
+
+ case YAML_DOUBLE_QUOTED_SCALAR_STYLE:
+ return yaml_emitter_write_double_quoted_scalar(emitter,
+ emitter->scalar_data.value, emitter->scalar_data.length,
+ !emitter->simple_key_context);
+
+ case YAML_LITERAL_SCALAR_STYLE:
+ return yaml_emitter_write_literal_scalar(emitter,
+ emitter->scalar_data.value, emitter->scalar_data.length);
+
+ case YAML_FOLDED_SCALAR_STYLE:
+ return yaml_emitter_write_folded_scalar(emitter,
+ emitter->scalar_data.value, emitter->scalar_data.length);
+
+ default:
+ assert(1); /* Impossible. */
+ }
+
+ return 0;
+}
+
+/*
+ * Check if a %YAML directive is valid.
+ */
+
+static int
+yaml_emitter_analyze_version_directive(yaml_emitter_t *emitter,
+ yaml_version_directive_t version_directive)
+{
+ if (version_directive.major != 1 || version_directive.minor != 1) {
+ return yaml_emitter_set_emitter_error(emitter,
+ "incompatible %YAML directive");
+ }
+
+ return 1;
+}
+
+/*
+ * Check if a %TAG directive is valid.
+ */
+
+static int
+yaml_emitter_analyze_tag_directive(yaml_emitter_t *emitter,
+ yaml_tag_directive_t tag_directive)
+{
+ yaml_string_t handle = STRING(tag_directive.handle,
+ strlen((char *)tag_directive.handle));
+ yaml_string_t prefix = STRING(tag_directive.prefix,
+ strlen((char *)tag_directive.prefix));
+
+ if (handle.start == handle.end) {
+ return yaml_emitter_set_emitter_error(emitter,
+ "tag handle must not be empty");
+ }
+
+ if (handle.start[0] != '!') {
+ return yaml_emitter_set_emitter_error(emitter,
+ "tag handle must start with '!'");
+ }
+
+ if (handle.end[-1] != '!') {
+ return yaml_emitter_set_emitter_error(emitter,
+ "tag handle must end with '!'");
+ }
+
+ handle.pointer ++;
+
+ while (handle.pointer != handle.end-1) {
+ if (!IS_ALPHA(handle)) {
+ return yaml_emitter_set_emitter_error(emitter,
+ "tag handle must contain alphanumerical characters only");
+ }
+ MOVE(handle);
+ }
+
+ if (prefix.start == prefix.end) {
+ return yaml_emitter_set_emitter_error(emitter,
+ "tag prefix must not be empty");
+ }
+
+ return 1;
+}
+
+/*
+ * Check if an anchor is valid.
+ */
+
+static int
+yaml_emitter_analyze_anchor(yaml_emitter_t *emitter,
+ yaml_char_t *anchor, int alias)
+{
+ yaml_string_t string = STRING(anchor, strlen((char *)anchor));
+
+ if (string.start == string.end) {
+ return yaml_emitter_set_emitter_error(emitter, alias ?
+ "alias value must not be empty" :
+ "anchor value must not be empty");
+ }
+
+ while (string.pointer != string.end) {
+ if (!IS_ALPHA(string)) {
+ return yaml_emitter_set_emitter_error(emitter, alias ?
+ "alias value must contain alphanumerical characters only" :
+ "anchor value must contain alphanumerical characters only");
+ }
+ MOVE(string);
+ }
+}
+
+/*
+ * Check if a tag is valid.
+ */
+
+static int
+yaml_emitter_analyze_tag(yaml_emitter_t *emitter,
+ yaml_char_t *tag)
+{
+ yaml_string_t string = STRING(tag, strlen((char *)tag));
+ yaml_tag_directive_t *tag_directive;
+
+ if (string.start == string.end) {
+ return yaml_emitter_set_emitter_error(emitter,
+ "tag value must not be empty");
+ }
+
+ for (tag_directive = emitter->tag_directives.start;
+ tag_directive != emitter->tag_directives.end; tag_directive ++) {
+ size_t prefix_length = strlen((char *)tag_directive->prefix);
+ if (prefix_length < (string.end - string.start)
+ && strncmp((char *)tag_directive->prefix, (char *)string.start,
+ prefix_length) == 0)
+ {
+ emitter->tag_data.handle = tag_directive->handle;
+ emitter->tag_data.handle_length =
+ strlen((char *)tag_directive->handle);
+ emitter->tag_data.suffix = string.start + prefix_length;
+ emitter->tag_data.suffix_length =
+ (string.end - string.start) - prefix_length;
+ return 1;
+ }
+ }
+
+ emitter->tag_data.suffix = string.start;
+ emitter->tag_data.suffix_length = string.end - string.start;
+
+ return 1;
+}
+
+/*
+ * Check if a scalar is valid.
+ */
+
+static int
+yaml_emitter_analyze_scalar(yaml_emitter_t *emitter,
+ yaml_char_t *value, size_t length)
+{
+ yaml_string_t string = STRING(value, length);
+
+ int block_indicators = 0;
+ int flow_indicators = 0;
+ int line_breaks = 0;
+ int special_characters = 0;
+
+ int inline_spaces = 0;
+ int inline_breaks = 0;
+ int leading_spaces = 0;
+ int leading_breaks = 0;
+ int trailing_spaces = 0;
+ int trailing_breaks = 0;
+ int inline_breaks_spaces = 0;
+ int mixed_breaks_spaces = 0;
+
+ int preceeded_by_space = 0;
+ int followed_by_space = 0;
+ int spaces = 0;
+ int breaks = 0;
+ int mixed = 0;
+ int leading = 0;
+
+ emitter->scalar_data.value = value;
+ emitter->scalar_data.length = length;
+
+ if (string.start == string.end)
+ {
+ emitter->scalar_data.multiline = 0;
+ emitter->scalar_data.flow_plain_allowed = 0;
+ emitter->scalar_data.block_plain_allowed = 1;
+ emitter->scalar_data.single_quoted_allowed = 1;
+ emitter->scalar_data.block_allowed = 0;
+
+ return 1;
+ }
+
+ if ((CHECK_AT(string, '-', 0)
+ && CHECK_AT(string, '-', 1)
+ && CHECK_AT(string, '-', 2))
+ || (CHECK_AT(string, '.', 0)
+ && CHECK_AT(string, '.', 1)
+ && CHECK_AT(string, '.', 2))) {
+ block_indicators = 1;
+ flow_indicators = 1;
+ }
+
+ preceeded_by_space = 1;
+ followed_by_space = IS_BLANKZ_AT(string, WIDTH(string));
+
+ while (string.pointer != string.end)
+ {
+ if (string.start == string.pointer)
+ {
+ if (CHECK(string, '#') || CHECK(string, ',')
+ || CHECK(string, '[') || CHECK(string, ']')
+ || CHECK(string, '{') || CHECK(string, '}')
+ || CHECK(string, '&') || CHECK(string, '*')
+ || CHECK(string, '!') || CHECK(string, '|')
+ || CHECK(string, '>') || CHECK(string, '\'')
+ || CHECK(string, '"') || CHECK(string, '%')
+ || CHECK(string, '@') || CHECK(string, '`')) {
+ flow_indicators = 1;
+ block_indicators = 1;
+ }
+
+ if (CHECK(string, '?') || CHECK(string, ':')) {
+ flow_indicators = 1;
+ if (followed_by_space) {
+ block_indicators = 1;
+ }
+ }
+
+ if (CHECK(string, '-') && followed_by_space) {
+ flow_indicators = 1;
+ block_indicators = 1;
+ }
+ }
+ else
+ {
+ if (CHECK(string, ',') || CHECK(string, '?')
+ || CHECK(string, '[') || CHECK(string, ']')
+ || CHECK(string, '{') || CHECK(string, '}')) {
+ flow_indicators = 1;
+ }
+
+ if (CHECK(string, ':')) {
+ flow_indicators = 1;
+ if (followed_by_space) {
+ block_indicators = 1;
+ }
+ }
+
+ if (CHECK(string, '#') && preceeded_by_space) {
+ flow_indicators = 1;
+ block_indicators = 1;
+ }
+ }
+
+ if (!IS_PRINTABLE(string)
+ || (!IS_ASCII(string) && !emitter->unicode)) {
+ special_characters = 1;
+ }
+
+ if (IS_BREAK(string)) {
+ line_breaks = 1;
+ }
+
+ if (IS_SPACE(string))
+ {
+ spaces = 1;
+ if (string.start == string.pointer) {
+ leading = 1;
+ }
+ }
+
+ else if (IS_BREAK(string))
+ {
+ if (spaces) {
+ mixed = 1;
+ }
+ breaks = 1;
+ if (string.start == string.pointer) {
+ leading = 1;
+ }
+ }
+
+ else if (spaces || breaks)
+ {
+ if (leading) {
+ if (spaces && breaks) {
+ mixed_breaks_spaces = 1;
+ }
+ else if (spaces) {
+ leading_spaces = 1;
+ }
+ else if (breaks) {
+ leading_breaks = 1;
+ }
+ }
+ else {
+ if (mixed) {
+ mixed_breaks_spaces = 1;
+ }
+ else if (spaces && breaks) {
+ inline_breaks_spaces = 1;
+ }
+ else if (spaces) {
+ inline_spaces = 1;
+ }
+ else if (breaks) {
+ inline_breaks = 1;
+ }
+ }
+ spaces = breaks = mixed = leading = 0;
+ }
+
+ preceeded_by_space = IS_BLANKZ(string);
+ MOVE(string);
+ if (string.pointer != string.end) {
+ followed_by_space = IS_BLANKZ_AT(string, WIDTH(string));
+ }
+ }
+
+ emitter->scalar_data.multiline = line_breaks;
+
+ emitter->scalar_data.flow_plain_allowed = 1;
+ emitter->scalar_data.block_plain_allowed = 1;
+ emitter->scalar_data.single_quoted_allowed = 1;
+ emitter->scalar_data.block_allowed = 1;
+
+ if (leading_spaces || leading_breaks || trailing_spaces) {
+ emitter->scalar_data.flow_plain_allowed = 0;
+ emitter->scalar_data.block_plain_allowed = 0;
+ emitter->scalar_data.block_allowed = 0;
+ }
+
+ if (trailing_breaks) {
+ emitter->scalar_data.flow_plain_allowed = 0;
+ emitter->scalar_data.block_plain_allowed = 0;
+ }
+
+ if (inline_breaks_spaces) {
+ emitter->scalar_data.flow_plain_allowed = 0;
+ emitter->scalar_data.block_plain_allowed = 0;
+ emitter->scalar_data.single_quoted_allowed = 0;
+ }
+
+ if (mixed_breaks_spaces || special_characters) {
+ emitter->scalar_data.flow_plain_allowed = 0;
+ emitter->scalar_data.block_plain_allowed = 0;
+ emitter->scalar_data.single_quoted_allowed = 0;
+ emitter->scalar_data.block_allowed = 0;
+ }
+
+ if (line_breaks) {
+ emitter->scalar_data.flow_plain_allowed = 0;
+ emitter->scalar_data.block_plain_allowed = 0;
+ }
+
+ if (flow_indicators) {
+ emitter->scalar_data.flow_plain_allowed = 0;
+ }
+
+ if (block_indicators) {
+ emitter->scalar_data.block_plain_allowed = 0;
+ }
+
+ return 1;
+}
+
+/*
+ * Check if the event data is valid.
+ */
+
+static int
+yaml_emitter_analyze_event(yaml_emitter_t *emitter,
+ yaml_event_t *event)
+{
+ emitter->anchor_data.anchor = NULL;
+ emitter->anchor_data.anchor_length = 0;
+ emitter->tag_data.handle = NULL;
+ emitter->tag_data.handle_length = 0;
+ emitter->tag_data.suffix = NULL;
+ emitter->tag_data.suffix_length = 0;
+ emitter->scalar_data.value = NULL;
+ emitter->scalar_data.length = 0;
+
+ switch (event->type)
+ {
+ case YAML_ALIAS_EVENT:
+ if (!yaml_emitter_analyze_anchor(emitter,
+ event->data.alias.anchor, 1))
+ return 0;
+ return 1;
+
+ case YAML_SCALAR_EVENT:
+ if (event->data.scalar.anchor) {
+ if (!yaml_emitter_analyze_anchor(emitter,
+ event->data.scalar.anchor, 0))
+ return 0;
+ }
+ if (event->data.scalar.tag && (emitter->canonical ||
+ (!event->data.scalar.plain_implicit
+ && !event->data.scalar.quoted_implicit))) {
+ if (!yaml_emitter_analyze_tag(emitter, event->data.scalar.tag))
+ return 0;
+ }
+ if (!yaml_emitter_analyze_scalar(emitter,
+ event->data.scalar.value, event->data.scalar.length))
+ return 0;
+ return 1;
+
+ case YAML_SEQUENCE_START_EVENT:
+ if (event->data.sequence_start.anchor) {
+ if (!yaml_emitter_analyze_anchor(emitter,
+ event->data.sequence_start.anchor, 0))
+ return 0;
+ }
+ if (event->data.sequence_start.tag && (emitter->canonical ||
+ !event->data.sequence_start.implicit)) {
+ if (!yaml_emitter_analyze_tag(emitter,
+ event->data.sequence_start.tag))
+ return 0;
+ }
+ return 1;
+
+ case YAML_MAPPING_START_EVENT:
+ if (event->data.mapping_start.anchor) {
+ if (!yaml_emitter_analyze_anchor(emitter,
+ event->data.mapping_start.anchor, 0))
+ return 0;
+ }
+ if (event->data.mapping_start.tag && (emitter->canonical ||
+ !event->data.mapping_start.implicit)) {
+ if (!yaml_emitter_analyze_tag(emitter,
+ event->data.mapping_start.tag))
+ return 0;
+ }
+ return 1;
+
+ default:
+ return 1;
+ }
+}
+
+/*
+ * Write the BOM character.
+ */
+
+static int
+yaml_emitter_write_bom(yaml_emitter_t *emitter)
+{
+ if (!FLUSH(emitter)) return 0;
+
+ *(emitter->buffer.pointer++) = (yaml_char_t) '\xEF';
+ *(emitter->buffer.pointer++) = (yaml_char_t) '\xBB';
+ *(emitter->buffer.pointer++) = (yaml_char_t) '\xBF';
+
+ return 1;
+}
+
+static int
+yaml_emitter_write_indent(yaml_emitter_t *emitter)
+{
+ int indent = (emitter->indent >= 0) ? emitter->indent : 0;
+
+ if (!emitter->indention || emitter->column > indent
+ || (emitter->column == indent && !emitter->whitespace)) {
+ if (!PUT_BREAK(emitter)) return 0;
+ }
+
+ while (emitter->column < indent) {
+ if (!PUT(emitter, ' ')) return 0;
+ }
+
+ emitter->whitespace = 1;
+ emitter->indention = 1;
+
+ return 1;
+}
+
+static int
+yaml_emitter_write_indicator(yaml_emitter_t *emitter,
+ char *indicator, int need_whitespace,
+ int is_whitespace, int is_indention)
+{
+ yaml_string_t string = STRING((yaml_char_t *)indicator, strlen(indicator));
+
+ if (need_whitespace && !emitter->whitespace) {
+ if (!PUT(emitter, ' ')) return 0;
+ }
+
+ while (string.pointer != string.end) {
+ if (!WRITE(emitter, string)) return 0;
+ }
+
+ emitter->whitespace = is_whitespace;
+ emitter->indention = (emitter->indention && is_indention);
+
+ return 1;
+}
+
+static int
+yaml_emitter_write_anchor(yaml_emitter_t *emitter,
+ yaml_char_t *value, size_t length)
+{
+ yaml_string_t string = STRING(value, length);
+
+ while (string.pointer != string.end) {
+ if (!WRITE(emitter, string)) return 0;
+ }
+
+ emitter->whitespace = 0;
+ emitter->indention = 0;
+
+ return 1;
+}
+
+static int
+yaml_emitter_write_tag_handle(yaml_emitter_t *emitter,
+ yaml_char_t *value, size_t length)
+{
+ yaml_string_t string = STRING(value, length);
+
+ while (string.pointer != string.end) {
+ if (!WRITE(emitter, string)) return 0;
+ }
+
+ emitter->whitespace = 0;
+ emitter->indention = 0;
+
+ return 1;
+}
+
+static int
+yaml_emitter_write_tag_content(yaml_emitter_t *emitter,
+ yaml_char_t *value, size_t length)
+{
+ return 0;
+}
+
+static int
+yaml_emitter_write_plain_scalar(yaml_emitter_t *emitter,
+ yaml_char_t *value, size_t length, int allow_breaks)
+{
+ return 0;
+}
+
+static int
+yaml_emitter_write_single_quoted_scalar(yaml_emitter_t *emitter,
+ yaml_char_t *value, size_t length, int allow_breaks)
+{
+ return 0;
+}
+
+static int
+yaml_emitter_write_double_quoted_scalar(yaml_emitter_t *emitter,
+ yaml_char_t *value, size_t length, int allow_breaks)
+{
+ return 0;
+}
+
+static int
+yaml_emitter_write_literal_scalar(yaml_emitter_t *emitter,
+ yaml_char_t *value, size_t length)
+{
+ return 0;
+}
+
+static int
+yaml_emitter_write_folded_scalar(yaml_emitter_t *emitter,
+ yaml_char_t *value, size_t length)
+{
+ return 0;
+}
+