summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxi <xi@18f92427-320e-0410-9341-c67f048884a3>2006-07-28 20:09:34 +0000
committerxi <xi@18f92427-320e-0410-9341-c67f048884a3>2006-07-28 20:09:34 +0000
commit14e898dae1b62bfc87043fdf9c902942fa834673 (patch)
tree852b353dfaeb1afad77497c1a84dd73c5578f6bd
parent0204c3ef39218f05f75e618e02450ee570a09598 (diff)
downloadlibyaml-14e898dae1b62bfc87043fdf9c902942fa834673.tar.gz
Implement everything except tag and scalar writers.
git-svn-id: http://svn.pyyaml.org/libyaml/trunk@214 18f92427-320e-0410-9341-c67f048884a3
-rw-r--r--include/yaml.h42
-rw-r--r--src/emitter.c1044
-rw-r--r--src/scanner.c515
-rw-r--r--src/writer.c3
-rw-r--r--src/yaml_private.h249
5 files changed, 1469 insertions, 384 deletions
diff --git a/include/yaml.h b/include/yaml.h
index 6284068..0408a67 100644
--- a/include/yaml.h
+++ b/include/yaml.h
@@ -1203,6 +1203,48 @@ typedef struct {
/** If the last character was an indentation character (' ', '-', '?', ':')? */
int indention;
+ /** Anchor analysis. */
+ struct {
+ /** The anchor value. */
+ yaml_char_t *anchor;
+ /** The anchor length. */
+ size_t anchor_length;
+ /** Is it an alias? */
+ int alias;
+ } anchor_data;
+
+ /** Tag analysis. */
+ struct {
+ /** The tag handle. */
+ yaml_char_t *handle;
+ /** The tag handle length. */
+ size_t handle_length;
+ /** The tag suffix. */
+ yaml_char_t *suffix;
+ /** The tag suffix length. */
+ size_t suffix_length;
+ } tag_data;
+
+ /** Scalar analysis. */
+ struct {
+ /** The scalar value. */
+ yaml_char_t *value;
+ /** The scalar length. */
+ size_t length;
+ /** Does the scalar contain line breaks? */
+ int multiline;
+ /** Can the scalar be expessed in the flow plain style? */
+ int flow_plain_allowed;
+ /** Can the scalar be expressed in the block plain style? */
+ int block_plain_allowed;
+ /** Can the scalar be expressed in the single quoted style? */
+ int single_quoted_allowed;
+ /** Can the scalar be expressed in the literal or folded styles? */
+ int block_allowed;
+ /** The output style. */
+ yaml_scalar_style_t style;
+ } scalar_data;
+
/**
* @}
*/
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;
+}
+
diff --git a/src/scanner.c b/src/scanner.c
index 4265763..1414401 100644
--- a/src/scanner.c
+++ b/src/scanner.c
@@ -488,190 +488,6 @@
: yaml_parser_update_buffer(parser, (length)))
/*
- * Check the octet at the specified position.
- */
-
-#define CHECK_AT(parser,octet,offset) \
- (parser->buffer.pointer[offset] == (yaml_char_t)(octet))
-
-/*
- * Check the current octet in the buffer.
- */
-
-#define CHECK(parser,octet) CHECK_AT(parser,(octet),0)
-
-/*
- * Check if the character at the specified position is an alphabetical
- * character, a digit, '_', or '-'.
- */
-
-#define IS_ALPHA_AT(parser,offset) \
- ((parser->buffer.pointer[offset] >= (yaml_char_t) '0' && \
- parser->buffer.pointer[offset] <= (yaml_char_t) '9') || \
- (parser->buffer.pointer[offset] >= (yaml_char_t) 'A' && \
- parser->buffer.pointer[offset] <= (yaml_char_t) 'Z') || \
- (parser->buffer.pointer[offset] >= (yaml_char_t) 'a' && \
- parser->buffer.pointer[offset] <= (yaml_char_t) 'z') || \
- parser->buffer.pointer[offset] == '_' || \
- parser->buffer.pointer[offset] == '-')
-
-#define IS_ALPHA(parser) IS_ALPHA_AT(parser,0)
-
-/*
- * Check if the character at the specified position is a digit.
- */
-
-#define IS_DIGIT_AT(parser,offset) \
- ((parser->buffer.pointer[offset] >= (yaml_char_t) '0' && \
- parser->buffer.pointer[offset] <= (yaml_char_t) '9'))
-
-#define IS_DIGIT(parser) IS_DIGIT_AT(parser,0)
-
-/*
- * Get the value of a digit.
- */
-
-#define AS_DIGIT_AT(parser,offset) \
- (parser->buffer.pointer[offset] - (yaml_char_t) '0')
-
-#define AS_DIGIT(parser) AS_DIGIT_AT(parser,0)
-
-/*
- * Check if the character at the specified position is a hex-digit.
- */
-
-#define IS_HEX_AT(parser,offset) \
- ((parser->buffer.pointer[offset] >= (yaml_char_t) '0' && \
- parser->buffer.pointer[offset] <= (yaml_char_t) '9') || \
- (parser->buffer.pointer[offset] >= (yaml_char_t) 'A' && \
- parser->buffer.pointer[offset] <= (yaml_char_t) 'F') || \
- (parser->buffer.pointer[offset] >= (yaml_char_t) 'a' && \
- parser->buffer.pointer[offset] <= (yaml_char_t) 'f'))
-
-#define IS_HEX(parser) IS_HEX_AT(parser,0)
-
-/*
- * Get the value of a hex-digit.
- */
-
-#define AS_HEX_AT(parser,offset) \
- ((parser->buffer.pointer[offset] >= (yaml_char_t) 'A' && \
- parser->buffer.pointer[offset] <= (yaml_char_t) 'F') ? \
- (parser->buffer.pointer[offset] - (yaml_char_t) 'A' + 10) : \
- (parser->buffer.pointer[offset] >= (yaml_char_t) 'a' && \
- parser->buffer.pointer[offset] <= (yaml_char_t) 'f') ? \
- (parser->buffer.pointer[offset] - (yaml_char_t) 'a' + 10) : \
- (parser->buffer.pointer[offset] - (yaml_char_t) '0'))
-
-#define AS_HEX(parser) AS_HEX_AT(parser,0)
-
-/*
- * Check if the character at the specified position is NUL.
- */
-
-#define IS_Z_AT(parser,offset) CHECK_AT(parser,'\0',(offset))
-
-#define IS_Z(parser) IS_Z_AT(parser,0)
-
-/*
- * Check if the character at the specified position is BOM.
- */
-
-#define IS_BOM_AT(parser,offset) \
- (CHECK_AT(parser,'\xEF',(offset)) \
- && CHECK_AT(parser,'\xBB',(offset)+1) \
- && CHECK_AT(parser,'\xBF',(offset)+1)) /* BOM (#xFEFF) */
-
-#define IS_BOM(parser) IS_BOM_AT(parser,0)
-
-/*
- * Check if the character at the specified position is space.
- */
-
-#define IS_SPACE_AT(parser,offset) CHECK_AT(parser,' ',(offset))
-
-#define IS_SPACE(parser) IS_SPACE_AT(parser,0)
-
-/*
- * Check if the character at the specified position is tab.
- */
-
-#define IS_TAB_AT(parser,offset) CHECK_AT(parser,'\t',(offset))
-
-#define IS_TAB(parser) IS_TAB_AT(parser,0)
-
-/*
- * Check if the character at the specified position is blank (space or tab).
- */
-
-#define IS_BLANK_AT(parser,offset) \
- (IS_SPACE_AT(parser,(offset)) || IS_TAB_AT(parser,(offset)))
-
-#define IS_BLANK(parser) IS_BLANK_AT(parser,0)
-
-/*
- * Check if the character at the specified position is a line break.
- */
-
-#define IS_BREAK_AT(parser,offset) \
- (CHECK_AT(parser,'\r',(offset)) /* CR (#xD)*/ \
- || CHECK_AT(parser,'\n',(offset)) /* LF (#xA) */ \
- || (CHECK_AT(parser,'\xC2',(offset)) \
- && CHECK_AT(parser,'\x85',(offset)+1)) /* NEL (#x85) */ \
- || (CHECK_AT(parser,'\xE2',(offset)) \
- && CHECK_AT(parser,'\x80',(offset)+1) \
- && CHECK_AT(parser,'\xA8',(offset)+2)) /* LS (#x2028) */ \
- || (CHECK_AT(parser,'\xE2',(offset)) \
- && CHECK_AT(parser,'\x80',(offset)+1) \
- && CHECK_AT(parser,'\xA9',(offset)+2))) /* PS (#x2029) */
-
-#define IS_BREAK(parser) IS_BREAK_AT(parser,0)
-
-#define IS_CRLF_AT(parser,offset) \
- (CHECK_AT(parser,'\r',(offset)) && CHECK_AT(parser,'\n',(offset)+1))
-
-#define IS_CRLF(parser) IS_CRLF_AT(parser,0)
-
-/*
- * Check if the character is a line break or NUL.
- */
-
-#define IS_BREAKZ_AT(parser,offset) \
- (IS_BREAK_AT(parser,(offset)) || IS_Z_AT(parser,(offset)))
-
-#define IS_BREAKZ(parser) IS_BREAKZ_AT(parser,0)
-
-/*
- * Check if the character is a line break, space, or NUL.
- */
-
-#define IS_SPACEZ_AT(parser,offset) \
- (IS_SPACE_AT(parser,(offset)) || IS_BREAKZ_AT(parser,(offset)))
-
-#define IS_SPACEZ(parser) IS_SPACEZ_AT(parser,0)
-
-/*
- * Check if the character is a line break, space, tab, or NUL.
- */
-
-#define IS_BLANKZ_AT(parser,offset) \
- (IS_BLANK_AT(parser,(offset)) || IS_BREAKZ_AT(parser,(offset)))
-
-#define IS_BLANKZ(parser) IS_BLANKZ_AT(parser,0)
-
-/*
- * Determine the width of the character.
- */
-
-#define WIDTH_AT(parser,offset) \
- ((parser->buffer.pointer[offset] & 0x80) == 0x00 ? 1 : \
- (parser->buffer.pointer[offset] & 0xE0) == 0xC0 ? 2 : \
- (parser->buffer.pointer[offset] & 0xF0) == 0xE0 ? 3 : \
- (parser->buffer.pointer[offset] & 0xF8) == 0xF0 ? 4 : 0)
-
-#define WIDTH(parser) WIDTH_AT(parser,0)
-
-/*
* Advance the buffer pointer.
*/
@@ -679,21 +495,21 @@
(parser->mark.index ++, \
parser->mark.column ++, \
parser->unread --, \
- parser->buffer.pointer += WIDTH(parser))
+ parser->buffer.pointer += WIDTH(parser->buffer))
#define SKIP_LINE(parser) \
- (IS_CRLF(parser) ? \
+ (IS_CRLF(parser->buffer) ? \
(parser->mark.index += 2, \
parser->mark.column = 0, \
parser->mark.line ++, \
parser->unread -= 2, \
parser->buffer.pointer += 2) : \
- IS_BREAK(parser) ? \
+ IS_BREAK(parser->buffer) ? \
(parser->mark.index ++, \
parser->mark.column = 0, \
parser->mark.line ++, \
parser->unread --, \
- parser->buffer.pointer += WIDTH(parser)) : 0)
+ parser->buffer.pointer += WIDTH(parser->buffer)) : 0)
/*
* Copy a character to a string buffer and advance pointers.
@@ -701,20 +517,7 @@
#define READ(parser,string) \
(STRING_EXTEND(parser,string) ? \
- (((*parser->buffer.pointer & 0x80) == 0x00 ? \
- (*((string).pointer++) = *(parser->buffer.pointer++)) : \
- (*parser->buffer.pointer & 0xE0) == 0xC0 ? \
- (*((string).pointer++) = *(parser->buffer.pointer++), \
- *((string).pointer++) = *(parser->buffer.pointer++)) : \
- (*parser->buffer.pointer & 0xF0) == 0xE0 ? \
- (*((string).pointer++) = *(parser->buffer.pointer++), \
- *((string).pointer++) = *(parser->buffer.pointer++), \
- *((string).pointer++) = *(parser->buffer.pointer++)) : \
- (*parser->buffer.pointer & 0xF8) == 0xF0 ? \
- (*((string).pointer++) = *(parser->buffer.pointer++), \
- *((string).pointer++) = *(parser->buffer.pointer++), \
- *((string).pointer++) = *(parser->buffer.pointer++), \
- *((string).pointer++) = *(parser->buffer.pointer++)) : 0), \
+ (COPY(string,parser->buffer), \
parser->mark.index ++, \
parser->mark.column ++, \
parser->unread --, \
@@ -726,31 +529,34 @@
#define READ_LINE(parser,string) \
(STRING_EXTEND(parser,string) ? \
- (((CHECK_AT(parser,'\r',0) && CHECK_AT(parser,'\n',1)) ? /* CR LF -> LF */ \
+ (((CHECK_AT(parser->buffer,'\r',0) \
+ && CHECK_AT(parser->buffer,'\n',1)) ? /* CR LF -> LF */ \
(*((string).pointer++) = (yaml_char_t) '\n', \
parser->buffer.pointer += 2, \
parser->mark.index += 2, \
parser->mark.column = 0, \
parser->mark.line ++, \
parser->unread -= 2) : \
- (CHECK_AT(parser,'\r',0) || CHECK_AT(parser,'\n',0)) ? /* CR|LF -> LF */ \
+ (CHECK_AT(parser->buffer,'\r',0) \
+ || CHECK_AT(parser->buffer,'\n',0)) ? /* CR|LF -> LF */ \
(*((string).pointer++) = (yaml_char_t) '\n', \
parser->buffer.pointer ++, \
parser->mark.index ++, \
parser->mark.column = 0, \
parser->mark.line ++, \
parser->unread --) : \
- (CHECK_AT(parser,'\xC2',0) && CHECK_AT(parser,'\x85',1)) ? /* NEL -> LF */ \
+ (CHECK_AT(parser->buffer,'\xC2',0) \
+ && CHECK_AT(parser->buffer,'\x85',1)) ? /* NEL -> LF */ \
(*((string).pointer++) = (yaml_char_t) '\n', \
parser->buffer.pointer += 2, \
parser->mark.index ++, \
parser->mark.column = 0, \
parser->mark.line ++, \
parser->unread --) : \
- (CHECK_AT(parser,'\xE2',0) && \
- CHECK_AT(parser,'\x80',1) && \
- (CHECK_AT(parser,'\xA8',2) || \
- CHECK_AT(parser,'\xA9',2))) ? /* LS|PS -> LS|PS */ \
+ (CHECK_AT(parser->buffer,'\xE2',0) && \
+ CHECK_AT(parser->buffer,'\x80',1) && \
+ (CHECK_AT(parser->buffer,'\xA8',2) || \
+ CHECK_AT(parser->buffer,'\xA9',2))) ? /* LS|PS -> LS|PS */ \
(*((string).pointer++) = *(parser->buffer.pointer++), \
*((string).pointer++) = *(parser->buffer.pointer++), \
*((string).pointer++) = *(parser->buffer.pointer++), \
@@ -1088,111 +894,113 @@ yaml_parser_fetch_next_token(yaml_parser_t *parser)
/* Is it the end of the stream? */
- if (IS_Z(parser))
+ if (IS_Z(parser->buffer))
return yaml_parser_fetch_stream_end(parser);
/* Is it a directive? */
- if (parser->mark.column == 0 && CHECK(parser, '%'))
+ if (parser->mark.column == 0 && CHECK(parser->buffer, '%'))
return yaml_parser_fetch_directive(parser);
/* Is it the document start indicator? */
if (parser->mark.column == 0
- && CHECK_AT(parser, '-', 0)
- && CHECK_AT(parser, '-', 1)
- && CHECK_AT(parser, '-', 2)
- && IS_BLANKZ_AT(parser, 3))
+ && CHECK_AT(parser->buffer, '-', 0)
+ && CHECK_AT(parser->buffer, '-', 1)
+ && CHECK_AT(parser->buffer, '-', 2)
+ && IS_BLANKZ_AT(parser->buffer, 3))
return yaml_parser_fetch_document_indicator(parser,
YAML_DOCUMENT_START_TOKEN);
/* Is it the document end indicator? */
if (parser->mark.column == 0
- && CHECK_AT(parser, '.', 0)
- && CHECK_AT(parser, '.', 1)
- && CHECK_AT(parser, '.', 2)
- && IS_BLANKZ_AT(parser, 3))
+ && CHECK_AT(parser->buffer, '.', 0)
+ && CHECK_AT(parser->buffer, '.', 1)
+ && CHECK_AT(parser->buffer, '.', 2)
+ && IS_BLANKZ_AT(parser->buffer, 3))
return yaml_parser_fetch_document_indicator(parser,
YAML_DOCUMENT_END_TOKEN);
/* Is it the flow sequence start indicator? */
- if (CHECK(parser, '['))
+ if (CHECK(parser->buffer, '['))
return yaml_parser_fetch_flow_collection_start(parser,
YAML_FLOW_SEQUENCE_START_TOKEN);
/* Is it the flow mapping start indicator? */
- if (CHECK(parser, '{'))
+ if (CHECK(parser->buffer, '{'))
return yaml_parser_fetch_flow_collection_start(parser,
YAML_FLOW_MAPPING_START_TOKEN);
/* Is it the flow sequence end indicator? */
- if (CHECK(parser, ']'))
+ if (CHECK(parser->buffer, ']'))
return yaml_parser_fetch_flow_collection_end(parser,
YAML_FLOW_SEQUENCE_END_TOKEN);
/* Is it the flow mapping end indicator? */
- if (CHECK(parser, '}'))
+ if (CHECK(parser->buffer, '}'))
return yaml_parser_fetch_flow_collection_end(parser,
YAML_FLOW_MAPPING_END_TOKEN);
/* Is it the flow entry indicator? */
- if (CHECK(parser, ','))
+ if (CHECK(parser->buffer, ','))
return yaml_parser_fetch_flow_entry(parser);
/* Is it the block entry indicator? */
- if (CHECK(parser, '-') && IS_BLANKZ_AT(parser, 1))
+ if (CHECK(parser->buffer, '-') && IS_BLANKZ_AT(parser->buffer, 1))
return yaml_parser_fetch_block_entry(parser);
/* Is it the key indicator? */
- if (CHECK(parser, '?') && (parser->flow_level || IS_BLANKZ_AT(parser, 1)))
+ if (CHECK(parser->buffer, '?')
+ && (parser->flow_level || IS_BLANKZ_AT(parser->buffer, 1)))
return yaml_parser_fetch_key(parser);
/* Is it the value indicator? */
- if (CHECK(parser, ':') && (parser->flow_level || IS_BLANKZ_AT(parser, 1)))
+ if (CHECK(parser->buffer, ':')
+ && (parser->flow_level || IS_BLANKZ_AT(parser->buffer, 1)))
return yaml_parser_fetch_value(parser);
/* Is it an alias? */
- if (CHECK(parser, '*'))
+ if (CHECK(parser->buffer, '*'))
return yaml_parser_fetch_anchor(parser, YAML_ALIAS_TOKEN);
/* Is it an anchor? */
- if (CHECK(parser, '&'))
+ if (CHECK(parser->buffer, '&'))
return yaml_parser_fetch_anchor(parser, YAML_ANCHOR_TOKEN);
/* Is it a tag? */
- if (CHECK(parser, '!'))
+ if (CHECK(parser->buffer, '!'))
return yaml_parser_fetch_tag(parser);
/* Is it a literal scalar? */
- if (CHECK(parser, '|') && !parser->flow_level)
+ if (CHECK(parser->buffer, '|') && !parser->flow_level)
return yaml_parser_fetch_block_scalar(parser, 1);
/* Is it a folded scalar? */
- if (CHECK(parser, '>') && !parser->flow_level)
+ if (CHECK(parser->buffer, '>') && !parser->flow_level)
return yaml_parser_fetch_block_scalar(parser, 0);
/* Is it a single-quoted scalar? */
- if (CHECK(parser, '\''))
+ if (CHECK(parser->buffer, '\''))
return yaml_parser_fetch_flow_scalar(parser, 1);
/* Is it a double-quoted scalar? */
- if (CHECK(parser, '"'))
+ if (CHECK(parser->buffer, '"'))
return yaml_parser_fetch_flow_scalar(parser, 0);
/*
@@ -1214,16 +1022,20 @@ yaml_parser_fetch_next_token(yaml_parser_t *parser)
* The last rule is more restrictive than the specification requires.
*/
- if (!(IS_BLANKZ(parser) || CHECK(parser, '-') || CHECK(parser, '?')
- || CHECK(parser, ':') || CHECK(parser, ',') || CHECK(parser, '[')
- || CHECK(parser, ']') || CHECK(parser, '{') || CHECK(parser, '}')
- || CHECK(parser, '#') || CHECK(parser, '&') || CHECK(parser, '*')
- || CHECK(parser, '!') || CHECK(parser, '|') || CHECK(parser, '>')
- || CHECK(parser, '\'') || CHECK(parser, '"') || CHECK(parser, '%')
- || CHECK(parser, '@') || CHECK(parser, '`')) ||
- (CHECK(parser, '-') && !IS_BLANK_AT(parser, 1)) ||
+ if (!(IS_BLANKZ(parser->buffer) || CHECK(parser->buffer, '-')
+ || CHECK(parser->buffer, '?') || CHECK(parser->buffer, ':')
+ || CHECK(parser->buffer, ',') || CHECK(parser->buffer, '[')
+ || CHECK(parser->buffer, ']') || CHECK(parser->buffer, '{')
+ || CHECK(parser->buffer, '}') || CHECK(parser->buffer, '#')
+ || CHECK(parser->buffer, '&') || CHECK(parser->buffer, '*')
+ || CHECK(parser->buffer, '!') || CHECK(parser->buffer, '|')
+ || CHECK(parser->buffer, '>') || CHECK(parser->buffer, '\'')
+ || CHECK(parser->buffer, '"') || CHECK(parser->buffer, '%')
+ || CHECK(parser->buffer, '@') || CHECK(parser->buffer, '`')) ||
+ (CHECK(parser->buffer, '-') && !IS_BLANK_AT(parser->buffer, 1)) ||
(!parser->flow_level &&
- (CHECK(parser, '?') || CHECK(parser, ':')) && !IS_BLANKZ_AT(parser, 1)))
+ (CHECK(parser->buffer, '?') || CHECK(parser->buffer, ':'))
+ && !IS_BLANKZ_AT(parser->buffer, 1)))
return yaml_parser_fetch_plain_scalar(parser);
/*
@@ -2101,7 +1913,7 @@ yaml_parser_scan_to_next_token(yaml_parser_t *parser)
if (!CACHE(parser, 1)) return 0;
- if (parser->mark.column == 0 && IS_BOM(parser))
+ if (parser->mark.column == 0 && IS_BOM(parser->buffer))
SKIP(parser);
/*
@@ -2116,17 +1928,17 @@ yaml_parser_scan_to_next_token(yaml_parser_t *parser)
if (!CACHE(parser, 1)) return 0;
- while (CHECK(parser,' ') ||
+ while (CHECK(parser->buffer,' ') ||
((parser->flow_level || !parser->simple_key_allowed) &&
- CHECK(parser, '\t'))) {
+ CHECK(parser->buffer, '\t'))) {
SKIP(parser);
if (!CACHE(parser, 1)) return 0;
}
/* Eat a comment until a line break. */
- if (CHECK(parser, '#')) {
- while (!IS_BREAKZ(parser)) {
+ if (CHECK(parser->buffer, '#')) {
+ while (!IS_BREAKZ(parser->buffer)) {
SKIP(parser);
if (!CACHE(parser, 1)) return 0;
}
@@ -2134,7 +1946,7 @@ yaml_parser_scan_to_next_token(yaml_parser_t *parser)
/* If it is a line break, eat it. */
- if (IS_BREAK(parser))
+ if (IS_BREAK(parser->buffer))
{
if (!CACHE(parser, 2)) return 0;
SKIP_LINE(parser);
@@ -2234,13 +2046,13 @@ yaml_parser_scan_directive(yaml_parser_t *parser, yaml_token_t *token)
if (!CACHE(parser, 1)) goto error;
- while (IS_BLANK(parser)) {
+ while (IS_BLANK(parser->buffer)) {
SKIP(parser);
if (!CACHE(parser, 1)) goto error;
}
- if (CHECK(parser, '#')) {
- while (!IS_BREAKZ(parser)) {
+ if (CHECK(parser->buffer, '#')) {
+ while (!IS_BREAKZ(parser->buffer)) {
SKIP(parser);
if (!CACHE(parser, 1)) goto error;
}
@@ -2248,7 +2060,7 @@ yaml_parser_scan_directive(yaml_parser_t *parser, yaml_token_t *token)
/* Check if we are at the end of the line. */
- if (!IS_BREAKZ(parser)) {
+ if (!IS_BREAKZ(parser->buffer)) {
yaml_parser_set_scanner_error(parser, "while scanning a directive",
start_mark, "did not found expected comment or line break");
goto error;
@@ -2256,7 +2068,7 @@ yaml_parser_scan_directive(yaml_parser_t *parser, yaml_token_t *token)
/* Eat a line break. */
- if (IS_BREAK(parser)) {
+ if (IS_BREAK(parser->buffer)) {
if (!CACHE(parser, 2)) goto error;
SKIP_LINE(parser);
}
@@ -2294,7 +2106,7 @@ yaml_parser_scan_directive_name(yaml_parser_t *parser,
if (!CACHE(parser, 1)) goto error;
- while (IS_ALPHA(parser))
+ while (IS_ALPHA(parser->buffer))
{
if (!READ(parser, string)) goto error;
if (!CACHE(parser, 1)) goto error;
@@ -2310,7 +2122,7 @@ yaml_parser_scan_directive_name(yaml_parser_t *parser,
/* Check for an blank character after the name. */
- if (!IS_BLANKZ(parser)) {
+ if (!IS_BLANKZ(parser->buffer)) {
yaml_parser_set_scanner_error(parser, "while scanning a directive",
start_mark, "found unexpected non-alphabetical character");
goto error;
@@ -2341,7 +2153,7 @@ yaml_parser_scan_version_directive_value(yaml_parser_t *parser,
if (!CACHE(parser, 1)) return 0;
- while (IS_BLANK(parser)) {
+ while (IS_BLANK(parser->buffer)) {
SKIP(parser);
if (!CACHE(parser, 1)) return 0;
}
@@ -2353,7 +2165,7 @@ yaml_parser_scan_version_directive_value(yaml_parser_t *parser,
/* Eat '.'. */
- if (!CHECK(parser, '.')) {
+ if (!CHECK(parser->buffer, '.')) {
return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive",
start_mark, "did not find expected digit or '.' character");
}
@@ -2391,7 +2203,7 @@ yaml_parser_scan_version_directive_number(yaml_parser_t *parser,
if (!CACHE(parser, 1)) return 0;
- while (IS_DIGIT(parser))
+ while (IS_DIGIT(parser->buffer))
{
/* Check if the number is too long. */
@@ -2400,7 +2212,7 @@ yaml_parser_scan_version_directive_number(yaml_parser_t *parser,
start_mark, "found extremely long version number");
}
- value = value*10 + AS_DIGIT(parser);
+ value = value*10 + AS_DIGIT(parser->buffer);
SKIP(parser);
@@ -2438,7 +2250,7 @@ yaml_parser_scan_tag_directive_value(yaml_parser_t *parser,
if (!CACHE(parser, 1)) goto error;
- while (IS_BLANK(parser)) {
+ while (IS_BLANK(parser->buffer)) {
SKIP(parser);
if (!CACHE(parser, 1)) goto error;
}
@@ -2452,7 +2264,7 @@ yaml_parser_scan_tag_directive_value(yaml_parser_t *parser,
if (!CACHE(parser, 1)) goto error;
- if (!IS_BLANK(parser)) {
+ if (!IS_BLANK(parser->buffer)) {
yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive",
start_mark, "did not find expected whitespace");
goto error;
@@ -2460,7 +2272,7 @@ yaml_parser_scan_tag_directive_value(yaml_parser_t *parser,
/* Eat whitespaces. */
- while (IS_BLANK(parser)) {
+ while (IS_BLANK(parser->buffer)) {
SKIP(parser);
if (!CACHE(parser, 1)) goto error;
}
@@ -2474,7 +2286,7 @@ yaml_parser_scan_tag_directive_value(yaml_parser_t *parser,
if (!CACHE(parser, 1)) goto error;
- if (!IS_BLANKZ(parser)) {
+ if (!IS_BLANKZ(parser->buffer)) {
yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive",
start_mark, "did not find expected whitespace or line break");
goto error;
@@ -2511,7 +2323,7 @@ yaml_parser_scan_anchor(yaml_parser_t *parser, yaml_token_t *token,
if (!CACHE(parser, 1)) goto error;
- while (IS_ALPHA(parser)) {
+ while (IS_ALPHA(parser->buffer)) {
if (!READ(parser, string)) goto error;
if (!CACHE(parser, 1)) goto error;
length ++;
@@ -2526,9 +2338,11 @@ yaml_parser_scan_anchor(yaml_parser_t *parser, yaml_token_t *token,
* '?', ':', ',', ']', '}', '%', '@', '`'.
*/
- if (!length || !(IS_BLANKZ(parser) || CHECK(parser, '?') || CHECK(parser, ':') ||
- CHECK(parser, ',') || CHECK(parser, ']') || CHECK(parser, '}') ||
- CHECK(parser, '%') || CHECK(parser, '@') || CHECK(parser, '`'))) {
+ if (!length || !(IS_BLANKZ(parser->buffer) || CHECK(parser->buffer, '?')
+ || CHECK(parser->buffer, ':') || CHECK(parser->buffer, ',')
+ || CHECK(parser->buffer, ']') || CHECK(parser->buffer, '}')
+ || CHECK(parser->buffer, '%') || CHECK(parser->buffer, '@')
+ || CHECK(parser->buffer, '`'))) {
yaml_parser_set_scanner_error(parser, type == YAML_ANCHOR_TOKEN ?
"while scanning an anchor" : "while scanning an alias", start_mark,
"did not find expected alphabetic or numeric character");
@@ -2568,7 +2382,7 @@ yaml_parser_scan_tag(yaml_parser_t *parser, yaml_token_t *token)
if (!CACHE(parser, 2)) goto error;
- if (CHECK_AT(parser, '<', 1))
+ if (CHECK_AT(parser->buffer, '<', 1))
{
/* Set the handle to '' */
@@ -2588,7 +2402,7 @@ yaml_parser_scan_tag(yaml_parser_t *parser, yaml_token_t *token)
/* Check for '>' and eat it. */
- if (!CHECK(parser, '>')) {
+ if (!CHECK(parser->buffer, '>')) {
yaml_parser_set_scanner_error(parser, "while scanning a tag",
start_mark, "did not find the expected '>'");
goto error;
@@ -2646,7 +2460,7 @@ yaml_parser_scan_tag(yaml_parser_t *parser, yaml_token_t *token)
if (!CACHE(parser, 1)) goto error;
- if (!IS_BLANKZ(parser)) {
+ if (!IS_BLANKZ(parser->buffer)) {
yaml_parser_set_scanner_error(parser, "while scanning a tag",
start_mark, "did not found expected whitespace or line break");
goto error;
@@ -2682,7 +2496,7 @@ yaml_parser_scan_tag_handle(yaml_parser_t *parser, int directive,
if (!CACHE(parser, 1)) goto error;
- if (!CHECK(parser, '!')) {
+ if (!CHECK(parser->buffer, '!')) {
yaml_parser_set_scanner_error(parser, directive ?
"while scanning a tag directive" : "while scanning a tag",
start_mark, "did not find expected '!'");
@@ -2697,7 +2511,7 @@ yaml_parser_scan_tag_handle(yaml_parser_t *parser, int directive,
if (!CACHE(parser, 1)) goto error;
- while (IS_ALPHA(parser))
+ while (IS_ALPHA(parser->buffer))
{
if (!READ(parser, string)) goto error;
if (!CACHE(parser, 1)) goto error;
@@ -2705,7 +2519,7 @@ yaml_parser_scan_tag_handle(yaml_parser_t *parser, int directive,
/* Check if the trailing character is '!' and copy it. */
- if (CHECK(parser, '!'))
+ if (CHECK(parser->buffer, '!'))
{
if (!READ(parser, string)) goto error;
}
@@ -2778,17 +2592,21 @@ yaml_parser_scan_tag_uri(yaml_parser_t *parser, int directive,
* '%'.
*/
- while (IS_ALPHA(parser) || CHECK(parser, ';') || CHECK(parser, '/') ||
- CHECK(parser, '?') || CHECK(parser, ':') || CHECK(parser, '@') ||
- CHECK(parser, '&') || CHECK(parser, '=') || CHECK(parser, '+') ||
- CHECK(parser, '$') || CHECK(parser, ',') || CHECK(parser, '.') ||
- CHECK(parser, '!') || CHECK(parser, '~') || CHECK(parser, '*') ||
- CHECK(parser, '\'') || CHECK(parser, '(') || CHECK(parser, ')') ||
- CHECK(parser, '[') || CHECK(parser, ']') || CHECK(parser, '%'))
+ while (IS_ALPHA(parser->buffer) || CHECK(parser->buffer, ';')
+ || CHECK(parser->buffer, '/') || CHECK(parser->buffer, '?')
+ || CHECK(parser->buffer, ':') || CHECK(parser->buffer, '@')
+ || CHECK(parser->buffer, '&') || CHECK(parser->buffer, '=')
+ || CHECK(parser->buffer, '+') || CHECK(parser->buffer, '$')
+ || CHECK(parser->buffer, ',') || CHECK(parser->buffer, '.')
+ || CHECK(parser->buffer, '!') || CHECK(parser->buffer, '~')
+ || CHECK(parser->buffer, '*') || CHECK(parser->buffer, '\'')
+ || CHECK(parser->buffer, '(') || CHECK(parser->buffer, ')')
+ || CHECK(parser->buffer, '[') || CHECK(parser->buffer, ']')
+ || CHECK(parser->buffer, '%'))
{
/* Check if it is a URI-escape sequence. */
- if (CHECK(parser, '%')) {
+ if (CHECK(parser->buffer, '%')) {
if (!yaml_parser_scan_uri_escapes(parser,
directive, start_mark, &string)) goto error;
}
@@ -2841,7 +2659,9 @@ yaml_parser_scan_uri_escapes(yaml_parser_t *parser, int directive,
if (!CACHE(parser, 3)) return 0;
- if (!(CHECK(parser, '%') && IS_HEX_AT(parser, 1) && IS_HEX_AT(parser, 2))) {
+ if (!(CHECK(parser->buffer, '%')
+ && IS_HEX_AT(parser->buffer, 1)
+ && IS_HEX_AT(parser->buffer, 2))) {
return yaml_parser_set_scanner_error(parser, directive ?
"while parsing a %TAG directive" : "while parsing a tag",
start_mark, "did not find URI escaped octet");
@@ -2849,7 +2669,7 @@ yaml_parser_scan_uri_escapes(yaml_parser_t *parser, int directive,
/* Get the octet. */
- octet = (AS_HEX_AT(parser, 1) << 4) + AS_HEX_AT(parser, 2);
+ octet = (AS_HEX_AT(parser->buffer, 1) << 4) + AS_HEX_AT(parser->buffer, 2);
/* If it is the leading octet, determine the length of the UTF-8 sequence. */
@@ -2923,11 +2743,11 @@ yaml_parser_scan_block_scalar(yaml_parser_t *parser, yaml_token_t *token,
/* Check for a chomping indicator. */
- if (CHECK(parser, '+') || CHECK(parser, '-'))
+ if (CHECK(parser->buffer, '+') || CHECK(parser->buffer, '-'))
{
/* Set the chomping method and eat the indicator. */
- chomping = CHECK(parser, '+') ? +1 : -1;
+ chomping = CHECK(parser->buffer, '+') ? +1 : -1;
SKIP(parser);
@@ -2935,11 +2755,11 @@ yaml_parser_scan_block_scalar(yaml_parser_t *parser, yaml_token_t *token,
if (!CACHE(parser, 1)) goto error;
- if (IS_DIGIT(parser))
+ if (IS_DIGIT(parser->buffer))
{
/* Check that the intendation is greater than 0. */
- if (CHECK(parser, '0')) {
+ if (CHECK(parser->buffer, '0')) {
yaml_parser_set_scanner_error(parser, "while scanning a block scalar",
start_mark, "found an intendation indicator equal to 0");
goto error;
@@ -2947,7 +2767,7 @@ yaml_parser_scan_block_scalar(yaml_parser_t *parser, yaml_token_t *token,
/* Get the intendation level and eat the indicator. */
- increment = AS_DIGIT(parser);
+ increment = AS_DIGIT(parser->buffer);
SKIP(parser);
}
@@ -2955,22 +2775,22 @@ yaml_parser_scan_block_scalar(yaml_parser_t *parser, yaml_token_t *token,
/* Do the same as above, but in the opposite order. */
- else if (IS_DIGIT(parser))
+ else if (IS_DIGIT(parser->buffer))
{
- if (CHECK(parser, '0')) {
+ if (CHECK(parser->buffer, '0')) {
yaml_parser_set_scanner_error(parser, "while scanning a block scalar",
start_mark, "found an intendation indicator equal to 0");
goto error;
}
- increment = AS_DIGIT(parser);
+ increment = AS_DIGIT(parser->buffer);
SKIP(parser);
if (!CACHE(parser, 1)) goto error;
- if (CHECK(parser, '+') || CHECK(parser, '-')) {
- chomping = CHECK(parser, '+') ? +1 : -1;
+ if (CHECK(parser->buffer, '+') || CHECK(parser->buffer, '-')) {
+ chomping = CHECK(parser->buffer, '+') ? +1 : -1;
SKIP(parser);
}
@@ -2980,13 +2800,13 @@ yaml_parser_scan_block_scalar(yaml_parser_t *parser, yaml_token_t *token,
if (!CACHE(parser, 1)) goto error;
- while (IS_BLANK(parser)) {
+ while (IS_BLANK(parser->buffer)) {
SKIP(parser);
if (!CACHE(parser, 1)) goto error;
}
- if (CHECK(parser, '#')) {
- while (!IS_BREAKZ(parser)) {
+ if (CHECK(parser->buffer, '#')) {
+ while (!IS_BREAKZ(parser->buffer)) {
SKIP(parser);
if (!CACHE(parser, 1)) goto error;
}
@@ -2994,7 +2814,7 @@ yaml_parser_scan_block_scalar(yaml_parser_t *parser, yaml_token_t *token,
/* Check if we are at the end of the line. */
- if (!IS_BREAKZ(parser)) {
+ if (!IS_BREAKZ(parser->buffer)) {
yaml_parser_set_scanner_error(parser, "while scanning a block scalar",
start_mark, "did not found expected comment or line break");
goto error;
@@ -3002,7 +2822,7 @@ yaml_parser_scan_block_scalar(yaml_parser_t *parser, yaml_token_t *token,
/* Eat a line break. */
- if (IS_BREAK(parser)) {
+ if (IS_BREAK(parser->buffer)) {
if (!CACHE(parser, 2)) goto error;
SKIP_LINE(parser);
}
@@ -3024,7 +2844,7 @@ yaml_parser_scan_block_scalar(yaml_parser_t *parser, yaml_token_t *token,
if (!CACHE(parser, 1)) goto error;
- while (parser->mark.column == indent && !IS_Z(parser))
+ while (parser->mark.column == indent && !IS_Z(parser->buffer))
{
/*
* We are at the beginning of a non-empty line.
@@ -3032,7 +2852,7 @@ yaml_parser_scan_block_scalar(yaml_parser_t *parser, yaml_token_t *token,
/* Is it a trailing whitespace? */
- trailing_blank = IS_BLANK(parser);
+ trailing_blank = IS_BLANK(parser->buffer);
/* Check if we need to fold the leading line break. */
@@ -3060,11 +2880,11 @@ yaml_parser_scan_block_scalar(yaml_parser_t *parser, yaml_token_t *token,
/* Is it a leading whitespace? */
- leading_blank = IS_BLANK(parser);
+ leading_blank = IS_BLANK(parser->buffer);
/* Consume the current line. */
- while (!IS_BREAKZ(parser)) {
+ while (!IS_BREAKZ(parser->buffer)) {
if (!READ(parser, string)) goto error;
if (!CACHE(parser, 1)) goto error;
}
@@ -3131,7 +2951,8 @@ yaml_parser_scan_block_scalar_breaks(yaml_parser_t *parser,
if (!CACHE(parser, 1)) return 0;
- while ((!*indent || parser->mark.column < *indent) && IS_SPACE(parser)) {
+ while ((!*indent || parser->mark.column < *indent)
+ && IS_SPACE(parser->buffer)) {
SKIP(parser);
if (!CACHE(parser, 1)) return 0;
}
@@ -3141,14 +2962,15 @@ yaml_parser_scan_block_scalar_breaks(yaml_parser_t *parser,
/* Check for a tab character messing the intendation. */
- if ((!*indent || parser->mark.column < *indent) && IS_TAB(parser)) {
+ if ((!*indent || parser->mark.column < *indent)
+ && IS_TAB(parser->buffer)) {
return yaml_parser_set_scanner_error(parser, "while scanning a block scalar",
start_mark, "found a tab character where an intendation space is expected");
}
/* Have we found a non-empty line? */
- if (!IS_BREAK(parser)) break;
+ if (!IS_BREAK(parser->buffer)) break;
/* Consume the line break. */
@@ -3206,13 +3028,13 @@ yaml_parser_scan_flow_scalar(yaml_parser_t *parser, yaml_token_t *token,
if (!CACHE(parser, 4)) goto error;
if (parser->mark.column == 0 &&
- ((CHECK_AT(parser, '-', 0) &&
- CHECK_AT(parser, '-', 1) &&
- CHECK_AT(parser, '-', 2)) ||
- (CHECK_AT(parser, '.', 0) &&
- CHECK_AT(parser, '.', 1) &&
- CHECK_AT(parser, '.', 2))) &&
- IS_BLANKZ_AT(parser, 3))
+ ((CHECK_AT(parser->buffer, '-', 0) &&
+ CHECK_AT(parser->buffer, '-', 1) &&
+ CHECK_AT(parser->buffer, '-', 2)) ||
+ (CHECK_AT(parser->buffer, '.', 0) &&
+ CHECK_AT(parser->buffer, '.', 1) &&
+ CHECK_AT(parser->buffer, '.', 2))) &&
+ IS_BLANKZ_AT(parser->buffer, 3))
{
yaml_parser_set_scanner_error(parser, "while scanning a quoted scalar",
start_mark, "found unexpected document indicator");
@@ -3221,7 +3043,7 @@ yaml_parser_scan_flow_scalar(yaml_parser_t *parser, yaml_token_t *token,
/* Check for EOF. */
- if (IS_Z(parser)) {
+ if (IS_Z(parser->buffer)) {
yaml_parser_set_scanner_error(parser, "while scanning a quoted scalar",
start_mark, "found unexpected end of stream");
goto error;
@@ -3233,11 +3055,12 @@ yaml_parser_scan_flow_scalar(yaml_parser_t *parser, yaml_token_t *token,
leading_blanks = 0;
- while (!IS_BLANKZ(parser))
+ while (!IS_BLANKZ(parser->buffer))
{
/* Check for an escaped single quote. */
- if (single && CHECK_AT(parser, '\'', 0) && CHECK_AT(parser, '\'', 1))
+ if (single && CHECK_AT(parser->buffer, '\'', 0)
+ && CHECK_AT(parser->buffer, '\'', 1))
{
if (!STRING_EXTEND(parser, string)) goto error;
*(string.pointer++) = '\'';
@@ -3247,14 +3070,15 @@ yaml_parser_scan_flow_scalar(yaml_parser_t *parser, yaml_token_t *token,
/* Check for the right quote. */
- else if (CHECK(parser, single ? '\'' : '"'))
+ else if (CHECK(parser->buffer, single ? '\'' : '"'))
{
break;
}
/* Check for an escaped line break. */
- else if (!single && CHECK(parser, '\\') && IS_BREAK_AT(parser, 1))
+ else if (!single && CHECK(parser->buffer, '\\')
+ && IS_BREAK_AT(parser->buffer, 1))
{
if (!CACHE(parser, 3)) goto error;
SKIP(parser);
@@ -3265,7 +3089,7 @@ yaml_parser_scan_flow_scalar(yaml_parser_t *parser, yaml_token_t *token,
/* Check for an escape sequence. */
- else if (!single && CHECK(parser, '\\'))
+ else if (!single && CHECK(parser->buffer, '\\'))
{
int code_length = 0;
@@ -3383,12 +3207,12 @@ yaml_parser_scan_flow_scalar(yaml_parser_t *parser, yaml_token_t *token,
if (!CACHE(parser, code_length)) goto error;
for (k = 0; k < code_length; k ++) {
- if (!IS_HEX_AT(parser, k)) {
+ if (!IS_HEX_AT(parser->buffer, k)) {
yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar",
start_mark, "did not find expected hexdecimal number");
goto error;
}
- value = (value << 4) + AS_HEX_AT(parser, k);
+ value = (value << 4) + AS_HEX_AT(parser->buffer, k);
}
/* Check the value and write the character. */
@@ -3438,16 +3262,16 @@ yaml_parser_scan_flow_scalar(yaml_parser_t *parser, yaml_token_t *token,
/* Check if we are at the end of the scalar. */
- if (CHECK(parser, single ? '\'' : '"'))
+ if (CHECK(parser->buffer, single ? '\'' : '"'))
break;
/* Consume blank characters. */
if (!CACHE(parser, 1)) goto error;
- while (IS_BLANK(parser) || IS_BREAK(parser))
+ while (IS_BLANK(parser->buffer) || IS_BREAK(parser->buffer))
{
- if (IS_BLANK(parser))
+ if (IS_BLANK(parser->buffer))
{
/* Consume a space or a tab character. */
@@ -3568,26 +3392,28 @@ yaml_parser_scan_plain_scalar(yaml_parser_t *parser, yaml_token_t *token)
if (!CACHE(parser, 4)) goto error;
if (parser->mark.column == 0 &&
- ((CHECK_AT(parser, '-', 0) &&
- CHECK_AT(parser, '-', 1) &&
- CHECK_AT(parser, '-', 2)) ||
- (CHECK_AT(parser, '.', 0) &&
- CHECK_AT(parser, '.', 1) &&
- CHECK_AT(parser, '.', 2))) &&
- IS_BLANKZ_AT(parser, 3)) break;
+ ((CHECK_AT(parser->buffer, '-', 0) &&
+ CHECK_AT(parser->buffer, '-', 1) &&
+ CHECK_AT(parser->buffer, '-', 2)) ||
+ (CHECK_AT(parser->buffer, '.', 0) &&
+ CHECK_AT(parser->buffer, '.', 1) &&
+ CHECK_AT(parser->buffer, '.', 2))) &&
+ IS_BLANKZ_AT(parser->buffer, 3)) break;
/* Check for a comment. */
- if (CHECK(parser, '#'))
+ if (CHECK(parser->buffer, '#'))
break;
/* Consume non-blank characters. */
- while (!IS_BLANKZ(parser))
+ while (!IS_BLANKZ(parser->buffer))
{
/* Check for 'x:x' in the flow context. TODO: Fix the test "spec-08-13". */
- if (parser->flow_level && CHECK(parser, ':') && !IS_BLANKZ_AT(parser, 1)) {
+ if (parser->flow_level
+ && CHECK(parser->buffer, ':')
+ && !IS_BLANKZ_AT(parser->buffer, 1)) {
yaml_parser_set_scanner_error(parser, "while scanning a plain scalar",
start_mark, "found unexpected ':'");
goto error;
@@ -3595,12 +3421,12 @@ yaml_parser_scan_plain_scalar(yaml_parser_t *parser, yaml_token_t *token)
/* Check for indicators that may end a plain scalar. */
- if ((CHECK(parser, ':') && IS_BLANKZ_AT(parser, 1)) ||
- (parser->flow_level &&
- (CHECK(parser, ',') || CHECK(parser, ':') ||
- CHECK(parser, '?') || CHECK(parser, '[') ||
- CHECK(parser, ']') || CHECK(parser, '{') ||
- CHECK(parser, '}'))))
+ if ((CHECK(parser->buffer, ':') && IS_BLANKZ_AT(parser->buffer, 1))
+ || (parser->flow_level &&
+ (CHECK(parser->buffer, ',') || CHECK(parser->buffer, ':')
+ || CHECK(parser->buffer, '?') || CHECK(parser->buffer, '[')
+ || CHECK(parser->buffer, ']') || CHECK(parser->buffer, '{')
+ || CHECK(parser->buffer, '}'))))
break;
/* Check if we need to join whitespaces and breaks. */
@@ -3649,20 +3475,21 @@ yaml_parser_scan_plain_scalar(yaml_parser_t *parser, yaml_token_t *token)
/* Is it the end? */
- if (!(IS_BLANK(parser) || IS_BREAK(parser)))
+ if (!(IS_BLANK(parser->buffer) || IS_BREAK(parser->buffer)))
break;
/* Consume blank characters. */
if (!CACHE(parser, 1)) goto error;
- while (IS_BLANK(parser) || IS_BREAK(parser))
+ while (IS_BLANK(parser->buffer) || IS_BREAK(parser->buffer))
{
- if (IS_BLANK(parser))
+ if (IS_BLANK(parser->buffer))
{
/* Check for tab character that abuse intendation. */
- if (leading_blanks && parser->mark.column < indent && IS_TAB(parser)) {
+ if (leading_blanks && parser->mark.column < indent
+ && IS_TAB(parser->buffer)) {
yaml_parser_set_scanner_error(parser, "while scanning a plain scalar",
start_mark, "found a tab character that violate intendation");
goto error;
diff --git a/src/writer.c b/src/writer.c
index 2131372..ec0e477 100644
--- a/src/writer.c
+++ b/src/writer.c
@@ -37,6 +37,9 @@ yaml_emitter_flush(yaml_emitter_t *emitter)
assert(emitter->write_handler); /* Write handler must be set. */
assert(emitter->encoding); /* Output encoding must be set. */
+ emitter->buffer.last = emitter->buffer.pointer;
+ emitter->buffer.pointer = emitter->buffer.start;
+
/* Check if the buffer is empty. */
if (emitter->buffer.start == emitter->buffer.last) {
diff --git a/src/yaml_private.h b/src/yaml_private.h
index efd1d43..08a0232 100644
--- a/src/yaml_private.h
+++ b/src/yaml_private.h
@@ -111,6 +111,8 @@ yaml_string_join(
#define NULL_STRING { NULL, NULL, NULL }
+#define STRING(string,length) { (string), (string)+(length), (string) }
+
#define STRING_INIT(context,string,size) \
(((string).start = yaml_malloc(size)) ? \
((string).pointer = (string).start, \
@@ -143,6 +145,253 @@ yaml_string_join(
0))
/*
+ * String check operations.
+ */
+
+/*
+ * Check the octet at the specified position.
+ */
+
+#define CHECK_AT(string,octet,offset) \
+ ((string).pointer[offset] == (yaml_char_t)(octet))
+
+/*
+ * Check the current octet in the buffer.
+ */
+
+#define CHECK(string,octet) CHECK_AT((string),(octet),0)
+
+/*
+ * Check if the character at the specified position is an alphabetical
+ * character, a digit, '_', or '-'.
+ */
+
+#define IS_ALPHA_AT(string,offset) \
+ (((string).pointer[offset] >= (yaml_char_t) '0' && \
+ (string).pointer[offset] <= (yaml_char_t) '9') || \
+ ((string).pointer[offset] >= (yaml_char_t) 'A' && \
+ (string).pointer[offset] <= (yaml_char_t) 'Z') || \
+ ((string).pointer[offset] >= (yaml_char_t) 'a' && \
+ (string).pointer[offset] <= (yaml_char_t) 'z') || \
+ (string).pointer[offset] == '_' || \
+ (string).pointer[offset] == '-')
+
+#define IS_ALPHA(string) IS_ALPHA_AT((string),0)
+
+/*
+ * Check if the character at the specified position is a digit.
+ */
+
+#define IS_DIGIT_AT(string,offset) \
+ (((string).pointer[offset] >= (yaml_char_t) '0' && \
+ (string).pointer[offset] <= (yaml_char_t) '9'))
+
+#define IS_DIGIT(string) IS_DIGIT_AT((string),0)
+
+/*
+ * Get the value of a digit.
+ */
+
+#define AS_DIGIT_AT(string,offset) \
+ ((string).pointer[offset] - (yaml_char_t) '0')
+
+#define AS_DIGIT(string) AS_DIGIT_AT((string),0)
+
+/*
+ * Check if the character at the specified position is a hex-digit.
+ */
+
+#define IS_HEX_AT(string,offset) \
+ (((string).pointer[offset] >= (yaml_char_t) '0' && \
+ (string).pointer[offset] <= (yaml_char_t) '9') || \
+ ((string).pointer[offset] >= (yaml_char_t) 'A' && \
+ (string).pointer[offset] <= (yaml_char_t) 'F') || \
+ ((string).pointer[offset] >= (yaml_char_t) 'a' && \
+ (string).pointer[offset] <= (yaml_char_t) 'f'))
+
+#define IS_HEX(string) IS_HEX_AT((string),0)
+
+/*
+ * Get the value of a hex-digit.
+ */
+
+#define AS_HEX_AT(string,offset) \
+ (((string).pointer[offset] >= (yaml_char_t) 'A' && \
+ (string).pointer[offset] <= (yaml_char_t) 'F') ? \
+ ((string).pointer[offset] - (yaml_char_t) 'A' + 10) : \
+ ((string).pointer[offset] >= (yaml_char_t) 'a' && \
+ (string).pointer[offset] <= (yaml_char_t) 'f') ? \
+ ((string).pointer[offset] - (yaml_char_t) 'a' + 10) : \
+ ((string).pointer[offset] - (yaml_char_t) '0'))
+
+#define AS_HEX(string) AS_HEX_AT((string),0)
+
+/*
+ * Check if the character is ASCII.
+ */
+
+#define IS_ASCII_AT(string,offset) \
+ ((string).pointer[offset] <= (yaml_char_t) '\x7F')
+
+#define IS_ASCII(string) IS_ASCII_AT((string),0)
+
+/*
+ * Check if the character can be printed unescaped.
+ */
+
+#define IS_PRINTABLE_AT(string,offset) \
+ (((string).pointer[offset] == 0x0A) /* . == #x0A */ \
+ || ((string).pointer[offset] >= 0x20 /* #x20 <= . <= #x7E */ \
+ && (string).pointer[offset] <= 0x7E) \
+ || ((string).pointer[offset] == 0xC2 /* #0xA0 <= . <= #xD7FF */ \
+ && (string).pointer[offset+1] >= 0xA0) \
+ || ((string).pointer[offset] > 0xC2 \
+ && (string).pointer[offset] < 0xED) \
+ || ((string).pointer[offset] == 0xED \
+ && (string).pointer[offset+1] < 0xA0) \
+ || ((string).pointer[offset] == 0xEE) \
+ || ((string).pointer[offset] == 0xEF /* #xE000 <= . <= #xFFFD */ \
+ && !((string).pointer[offset+1] == 0xBB /* && . != #xFEFF */ \
+ && (string).pointer[offset+2] == 0xBF) \
+ && !((string).pointer[offset+1] == 0xBF \
+ && ((string).pointer[offset+2] == 0xBE \
+ || (string).pointer[offset+2] == 0xBF))))
+
+#define IS_PRINTABLE(string) IS_PRINTABLE_AT((string),0)
+
+/*
+ * Check if the character at the specified position is NUL.
+ */
+
+#define IS_Z_AT(string,offset) CHECK_AT((string),'\0',(offset))
+
+#define IS_Z(string) IS_Z_AT((string),0)
+
+/*
+ * Check if the character at the specified position is BOM.
+ */
+
+#define IS_BOM_AT(string,offset) \
+ (CHECK_AT((string),'\xEF',(offset)) \
+ && CHECK_AT((string),'\xBB',(offset)+1) \
+ && CHECK_AT((string),'\xBF',(offset)+2)) /* BOM (#xFEFF) */
+
+#define IS_BOM(string) IS_BOM_AT(string,0)
+
+/*
+ * Check if the character at the specified position is space.
+ */
+
+#define IS_SPACE_AT(string,offset) CHECK_AT((string),' ',(offset))
+
+#define IS_SPACE(string) IS_SPACE_AT((string),0)
+
+/*
+ * Check if the character at the specified position is tab.
+ */
+
+#define IS_TAB_AT(string,offset) CHECK_AT((string),'\t',(offset))
+
+#define IS_TAB(string) IS_TAB_AT((string),0)
+
+/*
+ * Check if the character at the specified position is blank (space or tab).
+ */
+
+#define IS_BLANK_AT(string,offset) \
+ (IS_SPACE_AT((string),(offset)) || IS_TAB_AT((string),(offset)))
+
+#define IS_BLANK(string) IS_BLANK_AT((string),0)
+
+/*
+ * Check if the character at the specified position is a line break.
+ */
+
+#define IS_BREAK_AT(string,offset) \
+ (CHECK_AT((string),'\r',(offset)) /* CR (#xD)*/ \
+ || CHECK_AT((string),'\n',(offset)) /* LF (#xA) */ \
+ || (CHECK_AT((string),'\xC2',(offset)) \
+ && CHECK_AT((string),'\x85',(offset)+1)) /* NEL (#x85) */ \
+ || (CHECK_AT((string),'\xE2',(offset)) \
+ && CHECK_AT((string),'\x80',(offset)+1) \
+ && CHECK_AT((string),'\xA8',(offset)+2)) /* LS (#x2028) */ \
+ || (CHECK_AT((string),'\xE2',(offset)) \
+ && CHECK_AT((string),'\x80',(offset)+1) \
+ && CHECK_AT((string),'\xA9',(offset)+2))) /* PS (#x2029) */
+
+#define IS_BREAK(string) IS_BREAK_AT((string),0)
+
+#define IS_CRLF_AT(string,offset) \
+ (CHECK_AT((string),'\r',(offset)) && CHECK_AT((string),'\n',(offset)+1))
+
+#define IS_CRLF(string) IS_CRLF_AT((string),0)
+
+/*
+ * Check if the character is a line break or NUL.
+ */
+
+#define IS_BREAKZ_AT(string,offset) \
+ (IS_BREAK_AT((string),(offset)) || IS_Z_AT((string),(offset)))
+
+#define IS_BREAKZ(string) IS_BREAKZ_AT((string),0)
+
+/*
+ * Check if the character is a line break, space, or NUL.
+ */
+
+#define IS_SPACEZ_AT(string,offset) \
+ (IS_SPACE_AT((string),(offset)) || IS_BREAKZ_AT((string),(offset)))
+
+#define IS_SPACEZ(string) IS_SPACEZ_AT((string),0)
+
+/*
+ * Check if the character is a line break, space, tab, or NUL.
+ */
+
+#define IS_BLANKZ_AT(string,offset) \
+ (IS_BLANK_AT((string),(offset)) || IS_BREAKZ_AT((string),(offset)))
+
+#define IS_BLANKZ(string) IS_BLANKZ_AT((string),0)
+
+/*
+ * Determine the width of the character.
+ */
+
+#define WIDTH_AT(string,offset) \
+ (((string).pointer[offset] & 0x80) == 0x00 ? 1 : \
+ ((string).pointer[offset] & 0xE0) == 0xC0 ? 2 : \
+ ((string).pointer[offset] & 0xF0) == 0xE0 ? 3 : \
+ ((string).pointer[offset] & 0xF8) == 0xF0 ? 4 : 0)
+
+#define WIDTH(string) WIDTH_AT((string),0)
+
+/*
+ * Move the string pointer to the next character.
+ */
+
+#define MOVE(string) ((string).pointer += WIDTH((string)))
+
+/*
+ * Copy a character and move the pointers of both strings.
+ */
+
+#define COPY(string_a,string_b) \
+ ((*(string_b).pointer & 0x80) == 0x00 ? \
+ (*((string_a).pointer++) = *((string_b).pointer++)) : \
+ (*(string_b).pointer & 0xE0) == 0xC0 ? \
+ (*((string_a).pointer++) = *((string_b).pointer++), \
+ *((string_a).pointer++) = *((string_b).pointer++)) : \
+ (*(string_b).pointer & 0xF0) == 0xE0 ? \
+ (*((string_a).pointer++) = *((string_b).pointer++), \
+ *((string_a).pointer++) = *((string_b).pointer++), \
+ *((string_a).pointer++) = *((string_b).pointer++)) : \
+ (*(string_b).pointer & 0xF8) == 0xF0 ? \
+ (*((string_a).pointer++) = *((string_b).pointer++), \
+ *((string_a).pointer++) = *((string_b).pointer++), \
+ *((string_a).pointer++) = *((string_b).pointer++), \
+ *((string_a).pointer++) = *((string_b).pointer++)) : 0)
+
+/*
* Stack and queue management.
*/