* %TAG !yaml! tag:yaml.org,2002:
* ---
*
- * The correspoding sequence of tokens:
+ * The corresponding sequence of tokens:
*
* STREAM-START(utf-8)
* VERSION-DIRECTIVE(1,1)
* BLOCK-END
*/
-#if HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <yaml/yaml.h>
-
-#include <assert.h>
+#include "yaml_private.h"
/*
* Ensure that the buffer contains the required number of characters.
* Return 1 on success, 0 on failure (reader error or memory error).
*/
-#define UPDATE(parser,length) \
- (parser->unread >= (length) \
- ? 1 \
+#define CACHE(parser,length) \
+ (parser->unread >= (length) \
+ ? 1 \
: yaml_parser_update_buffer(parser, (length)))
-/*
- * Check the octet at the specified position.
- */
-
-#define CHECK_AT(parser,octet,offset) \
- (parser->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->pointer[offset] >= (yaml_char_t) '0' && \
- parser->pointer[offset] <= (yaml_char_t) '9') || \
- (parser->pointer[offset] >= (yaml_char_t) 'A' && \
- parser->pointer[offset] <= (yaml_char_t) 'Z') || \
- (parser->pointer[offset] >= (yaml_char_t) 'a' && \
- parser->pointer[offset] <= (yaml_char_t) 'z') || \
- parser->pointer[offset] == '_' || \
- parser->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->pointer[offset] >= (yaml_char_t) '0' && \
- parser->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->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->pointer[offset] >= (yaml_char_t) '0' && \
- parser->pointer[offset] <= (yaml_char_t) '9') || \
- (parser->pointer[offset] >= (yaml_char_t) 'A' && \
- parser->pointer[offset] <= (yaml_char_t) 'F') || \
- (parser->pointer[offset] >= (yaml_char_t) 'a' && \
- parser->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->pointer[offset] >= (yaml_char_t) 'A' && \
- parser->pointer[offset] <= (yaml_char_t) 'F') ? \
- (parser->pointer[offset] - (yaml_char_t) 'A' + 10) : \
- (parser->pointer[offset] >= (yaml_char_t) 'a' && \
- parser->pointer[offset] <= (yaml_char_t) 'f') ? \
- (parser->pointer[offset] - (yaml_char_t) 'a' + 10) : \
- (parser->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))) /* LS (#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->pointer[(offset)] & 0x80) == 0x00 ? 1 : \
- (parser->pointer[(offset)] & 0xE0) == 0xC0 ? 2 : \
- (parser->pointer[(offset)] & 0xF0) == 0xE0 ? 3 : \
- (parser->pointer[(offset)] & 0xF8) == 0xF0 ? 4 : 0)
-
-#define WIDTH(parser) WIDTH_AT(parser,0)
-
/*
* Advance the buffer pointer.
*/
-#define FORWARD(parser) \
- (parser->index ++, \
- parser->column ++, \
- parser->unread --, \
- parser->pointer += WIDTH(parser))
-
-#define FORWARD_LINE(parser) \
- (IS_CRLF(parser) ? \
- (parser->index += 2, \
- parser->column = 0, \
- parser->unread -= 2, \
- parser->pointer += 2) : \
- IS_BREAK(parser) ? \
- (parser->index ++, \
- parser->column = 0, \
- parser->unread --, \
- parser->pointer += WIDTH(parser)) : 0)
-
-/*
- * Resize a string if needed.
- */
+#define SKIP(parser) \
+ (parser->mark.index ++, \
+ parser->mark.column ++, \
+ parser->unread --, \
+ parser->buffer.pointer += WIDTH(parser->buffer))
-#define RESIZE(parser,string) \
- (string.pointer-string.buffer+5 < string.size ? 1 : \
- yaml_parser_resize_string(parser, &string))
+#define SKIP_LINE(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->buffer) ? \
+ (parser->mark.index ++, \
+ parser->mark.column = 0, \
+ parser->mark.line ++, \
+ parser->unread --, \
+ parser->buffer.pointer += WIDTH(parser->buffer)) : 0)
/*
* Copy a character to a string buffer and advance pointers.
*/
-#define COPY(parser,string) \
- (((*parser->pointer & 0x80) == 0x00 ? \
- (*(string.pointer++) = *(parser->pointer++)) : \
- (*parser->pointer & 0xE0) == 0xC0 ? \
- (*(string.pointer++) = *(parser->pointer++), \
- *(string.pointer++) = *(parser->pointer++)) : \
- (*parser->pointer & 0xF0) == 0xE0 ? \
- (*(string.pointer++) = *(parser->pointer++), \
- *(string.pointer++) = *(parser->pointer++), \
- *(string.pointer++) = *(parser->pointer++)) : \
- (*parser->pointer & 0xF8) == 0xF0 ? \
- (*(string.pointer++) = *(parser->pointer++), \
- *(string.pointer++) = *(parser->pointer++), \
- *(string.pointer++) = *(parser->pointer++), \
- *(string.pointer++) = *(parser->pointer++)) : 0), \
- parser->index ++, \
- parser->column ++, \
- parser->unread --)
-
+#define READ(parser,string) \
+ (STRING_EXTEND(parser,string) ? \
+ (COPY(string,parser->buffer), \
+ parser->mark.index ++, \
+ parser->mark.column ++, \
+ parser->unread --, \
+ 1) : 0)
+
+/*
+ * Copy a line break character to a string buffer and advance pointers.
+ */
+
+#define READ_LINE(parser,string) \
+ (STRING_EXTEND(parser,string) ? \
+ (((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->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->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->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++), \
+ parser->mark.index ++, \
+ parser->mark.column = 0, \
+ parser->mark.line ++, \
+ parser->unread --) : 0), \
+ 1) : 0)
/*
* Public API declarations.
*/
-YAML_DECLARE(yaml_token_t *)
-yaml_parser_get_token(yaml_parser_t *parser);
-
-YAML_DECLARE(yaml_token_t *)
-yaml_parser_peek_token(yaml_parser_t *parser);
+YAML_DECLARE(int)
+yaml_parser_scan(yaml_parser_t *parser, yaml_token_t *token);
/*
* Error handling.
yaml_parser_set_scanner_error(yaml_parser_t *parser, const char *context,
yaml_mark_t context_mark, const char *problem);
-static yaml_mark_t
-yaml_parser_get_mark(yaml_parser_t *parser);
-
-/*
- * Buffers and lists.
- */
-
-typedef struct {
- yaml_char_t *buffer;
- yaml_char_t *pointer;
- size_t size;
-} yaml_string_t;
-
-static yaml_string_t
-yaml_parser_new_string(yaml_parser_t *parser);
-
-static int
-yaml_parser_resize_string(yaml_parser_t *parser, yaml_string_t *string);
-
-static int
-yaml_parser_resize_list(yaml_parser_t *parser, void **buffer, size_t *size,
- size_t item_size);
-
/*
* High-level token API.
*/
-static int
+YAML_DECLARE(int)
yaml_parser_fetch_more_tokens(yaml_parser_t *parser);
static int
static int
yaml_parser_decrease_flow_level(yaml_parser_t *parser);
-/*
- * Token manipulation.
- */
-
-static int
-yaml_parser_append_token(yaml_parser_t *parser, yaml_token_t *token);
-
-static int
-yaml_parser_insert_token(yaml_parser_t *parser,
- int number, yaml_token_t *token);
-
/*
* Indentation treatment.
*/
static int
-yaml_parser_roll_indent(yaml_parser_t *parser, int column,
- int number, yaml_token_type_t type, yaml_mark_t mark);
+yaml_parser_roll_indent(yaml_parser_t *parser, ptrdiff_t column,
+ ptrdiff_t number, yaml_token_type_t type, yaml_mark_t mark);
static int
-yaml_parser_unroll_indent(yaml_parser_t *parser, int column);
+yaml_parser_unroll_indent(yaml_parser_t *parser, ptrdiff_t column);
/*
* Token fetchers.
static int
yaml_parser_scan_to_next_token(yaml_parser_t *parser);
-static yaml_token_t *
-yaml_parser_scan_directive(yaml_parser_t *parser);
+static int
+yaml_parser_scan_directive(yaml_parser_t *parser, yaml_token_t *token);
static int
yaml_parser_scan_directive_name(yaml_parser_t *parser,
yaml_parser_scan_tag_directive_value(yaml_parser_t *parser,
yaml_mark_t mark, yaml_char_t **handle, yaml_char_t **prefix);
-static yaml_token_t *
-yaml_parser_scan_anchor(yaml_parser_t *parser,
+static int
+yaml_parser_scan_anchor(yaml_parser_t *parser, yaml_token_t *token,
yaml_token_type_t type);
-static yaml_token_t *
-yaml_parser_scan_tag(yaml_parser_t *parser);
+static int
+yaml_parser_scan_tag(yaml_parser_t *parser, yaml_token_t *token);
static int
yaml_parser_scan_tag_handle(yaml_parser_t *parser, int directive,
yaml_parser_scan_uri_escapes(yaml_parser_t *parser, int directive,
yaml_mark_t start_mark, yaml_string_t *string);
-static yaml_token_t *
-yaml_parser_scan_block_scalar(yaml_parser_t *parser, int literal);
-
static int
-yaml_parser_scan_block_scalar_indicators(yaml_parser_t *parser,
- yaml_mark_t start_mark, int *chomping, int *increment);
-
-static yaml_token_t *
-yaml_parser_scan_flow_scalar(yaml_parser_t *parser, int single);
-
-static yaml_token_t *
-yaml_parser_scan_plain_scalar(yaml_parser_t *parser);
-
-/*
- * Get the next token and remove it from the tokens queue.
- */
-
-YAML_DECLARE(yaml_token_t *)
-yaml_parser_get_token(yaml_parser_t *parser)
-{
- yaml_token_t *token;
-
- assert(parser); /* Non-NULL parser object is expected. */
- assert(!parser->stream_end_produced); /* No tokens after STREAM-END. */
-
- /* Ensure that the tokens queue contains enough tokens. */
-
- if (!yaml_parser_fetch_more_tokens(parser)) return NULL;
-
- /* Fetch the next token from the queue. */
-
- token = parser->tokens[parser->tokens_head];
-
- /* Move the queue head. */
+yaml_parser_scan_block_scalar(yaml_parser_t *parser, yaml_token_t *token,
+ int literal);
- parser->tokens[parser->tokens_head++] = NULL;
- if (parser->tokens_head == parser->tokens_size)
- parser->tokens_head = 0;
+static int
+yaml_parser_scan_block_scalar_breaks(yaml_parser_t *parser,
+ int *indent, yaml_string_t *breaks,
+ yaml_mark_t start_mark, yaml_mark_t *end_mark);
- parser->tokens_parsed++;
+static int
+yaml_parser_scan_flow_scalar(yaml_parser_t *parser, yaml_token_t *token,
+ int single);
- return token;
-}
+static int
+yaml_parser_scan_plain_scalar(yaml_parser_t *parser, yaml_token_t *token);
/*
- * Get the next token, but don't remove it from the queue.
+ * Get the next token.
*/
-YAML_DECLARE(yaml_token_t *)
-yaml_parser_peek_token(yaml_parser_t *parser)
+YAML_DECLARE(int)
+yaml_parser_scan(yaml_parser_t *parser, yaml_token_t *token)
{
assert(parser); /* Non-NULL parser object is expected. */
- assert(!parser->stream_end_produced); /* No tokens after STREAM-END. */
-
- /* Ensure that the tokens queue contains enough tokens. */
-
- if (!yaml_parser_fetch_more_tokens(parser)) return NULL;
-
- /* Fetch the next token from the queue. */
+ assert(token); /* Non-NULL token object is expected. */
- return parser->tokens[parser->tokens_head];
-}
+ /* Erase the token object. */
-/*
- * Create a new string.
- */
+ memset(token, 0, sizeof(yaml_token_t));
-static yaml_string_t
-yaml_parser_new_string(yaml_parser_t *parser)
-{
- yaml_string_t string = { NULL, NULL, 0 };
+ /* No tokens after STREAM-END or error. */
- string.buffer = yaml_malloc(YAML_DEFAULT_SIZE);
- if (!string.buffer) {
- parser->error = YAML_MEMORY_ERROR;
- return string;
+ if (parser->stream_end_produced || parser->error) {
+ return 1;
}
- memset(string.buffer, 0, YAML_DEFAULT_SIZE);
- string.pointer = string.buffer;
- string.size = YAML_DEFAULT_SIZE;
-
- return string;
-}
-
-/*
- * Double the size of a string.
- */
-
-static int
-yaml_parser_resize_string(yaml_parser_t *parser, yaml_string_t *string)
-{
- yaml_char_t *new_buffer = yaml_realloc(string->buffer, string->size*2);
+ /* Ensure that the tokens queue contains enough tokens. */
- if (!new_buffer) {
- yaml_free(string->buffer);
- string->buffer = NULL;
- string->pointer = NULL;
- string->size = 0;
- parser->error = YAML_MEMORY_ERROR;
- return 0;
+ if (!parser->token_available) {
+ if (!yaml_parser_fetch_more_tokens(parser))
+ return 0;
}
- memset(new_buffer+string->size, 0, string->size);
-
- string->pointer = new_buffer + (string->buffer-string->pointer);
- string->buffer = new_buffer;
- string->size *= 2;
-
- return 1;
-}
-
-/*
- * Double a list.
- */
-
-static int
-yaml_parser_resize_list(yaml_parser_t *parser, void **buffer, size_t *size,
- size_t item_size)
-{
- void *new_buffer = yaml_realloc(*buffer, item_size*(*size)*2);
+ /* Fetch the next token from the queue. */
+
+ *token = DEQUEUE(parser, parser->tokens);
+ parser->token_available = 0;
+ parser->tokens_parsed ++;
- if (!new_buffer) {
- parser->error = YAML_MEMORY_ERROR;
- return 0;
+ if (token->type == YAML_STREAM_END_TOKEN) {
+ parser->stream_end_produced = 1;
}
- memset(new_buffer+(*size), 0, item_size*(*size));
-
- *buffer = new_buffer;
- *size *= 2;
-
return 1;
}
parser->context = context;
parser->context_mark = context_mark;
parser->problem = problem;
- parser->problem_mark = yaml_parser_get_mark(parser);
-}
-
-/*
- * Get the mark for the current buffer position.
- */
-
-static yaml_mark_t
-yaml_parser_get_mark(yaml_parser_t *parser)
-{
- yaml_mark_t mark = { parser->index, parser->line, parser->column };
+ parser->problem_mark = parser->mark;
- return mark;
+ return 0;
}
-
/*
* Ensure that the tokens queue contains at least one token which can be
* returned to the Parser.
*/
-static int
+YAML_DECLARE(int)
yaml_parser_fetch_more_tokens(yaml_parser_t *parser)
{
int need_more_tokens;
- int k;
/* While we need more tokens to fetch, do it. */
need_more_tokens = 0;
- if (parser->tokens_head == parser->tokens_tail)
+ if (parser->tokens.head == parser->tokens.tail)
{
/* Queue is empty. */
}
else
{
+ yaml_simple_key_t *simple_key;
+
/* Check if any potential simple key may occupy the head position. */
- for (k = 0; k <= parser->flow_level; k++) {
- yaml_simple_key_t *simple_key = parser->simple_keys[k];
- if (simple_key
- && (simple_key->token_number == parser->tokens_parsed)) {
+ if (!yaml_parser_stale_simple_keys(parser))
+ return 0;
+
+ for (simple_key = parser->simple_keys.start;
+ simple_key != parser->simple_keys.top; simple_key++) {
+ if (simple_key->possible
+ && simple_key->token_number == parser->tokens_parsed) {
need_more_tokens = 1;
break;
}
return 0;
}
+ parser->token_available = 1;
+
return 1;
}
{
/* Ensure that the buffer is initialized. */
- if (!UPDATE(parser, 1))
+ if (!CACHE(parser, 1))
return 0;
/* Check if we just started scanning. Fetch STREAM-START then. */
if (!yaml_parser_scan_to_next_token(parser))
return 0;
+ /* Remove obsolete potential simple keys. */
+
+ if (!yaml_parser_stale_simple_keys(parser))
+ return 0;
+
/* Check the indentation level against the current column. */
- if (!yaml_parser_unroll_indent(parser, parser->column))
+ if (!yaml_parser_unroll_indent(parser, parser->mark.column))
return 0;
/*
* of the longest indicators ('--- ' and '... ').
*/
- if (!UPDATE(parser, 4))
+ if (!CACHE(parser, 4))
return 0;
/* 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->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->column == 0
- && CHECK_AT(parser, '-', 0)
- && CHECK_AT(parser, '-', 1)
- && CHECK_AT(parser, '-', 2)
- && IS_BLANKZ_AT(parser, 3))
+ if (parser->mark.column == 0
+ && 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->column == 0
- && CHECK_AT(parser, '.', 0)
- && CHECK_AT(parser, '.', 1)
- && CHECK_AT(parser, '.', 2)
- && IS_BLANKZ_AT(parser, 3))
+ if (parser->mark.column == 0
+ && 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);
/*
* '#', '&', '*', '!', '|', '>', '\'', '\"',
* '%', '@', '`'.
*
- * In the block context, it may also start with the characters
+ * In the block context (and, for the '-' indicator, in the flow context
+ * too), it may also start with the characters
*
* '-', '?', ':'
*
* 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, '`')) ||
+ 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, '?') || 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);
/*
* If we don't determine the token type so far, it is an error.
*/
- return yaml_parser_set_scanner_error(parser, "while scanning for the next token",
- yaml_parser_get_mark(parser), "found character that cannot start any token");
+ return yaml_parser_set_scanner_error(parser,
+ "while scanning for the next token", parser->mark,
+ "found character that cannot start any token");
}
/*
static int
yaml_parser_stale_simple_keys(yaml_parser_t *parser)
{
- int level;
+ yaml_simple_key_t *simple_key;
/* Check for a potential simple key for each flow level. */
- for (level = 0; level <= parser->flow_level; level++)
+ for (simple_key = parser->simple_keys.start;
+ simple_key != parser->simple_keys.top; simple_key ++)
{
- yaml_simple_key_t *simple_key = parser->simple_keys[level];
-
/*
* The specification requires that a simple key
*
* - is shorter than 1024 characters.
*/
- if (simple_key && (simple_key->line < parser->line ||
- simple_key->index < parser->index+1024)) {
+ if (simple_key->possible
+ && (simple_key->mark.line < parser->mark.line
+ || simple_key->mark.index+1024 < parser->mark.index)) {
/* Check if the potential simple key to be removed is required. */
if (simple_key->required) {
return yaml_parser_set_scanner_error(parser,
"while scanning a simple key", simple_key->mark,
- "could not found expected ':'");
+ "could not find expected ':'");
}
- yaml_free(simple_key);
- parser->simple_keys[level] = NULL;
+ simple_key->possible = 0;
}
}
* level.
*/
- int required = (!parser->flow_level && parser->indent == parser->column);
-
- /*
- * A simple key is required only when it is the first token in the current
- * line. Therefore it is always allowed. But we add a check anyway.
- */
-
- assert(parser->simple_key_allowed || !required); /* Impossible. */
+ int required = (!parser->flow_level
+ && parser->indent == (ptrdiff_t)parser->mark.column);
/*
* If the current position may start a simple key, save it.
if (parser->simple_key_allowed)
{
- yaml_simple_key_t simple_key = { required,
- parser->tokens_parsed + parser->tokens_tail - parser->tokens_head,
- parser->index, parser->line, parser->column,
- yaml_parser_get_mark(parser) };
+ yaml_simple_key_t simple_key;
+ simple_key.possible = 1;
+ simple_key.required = required;
+ simple_key.token_number =
+ parser->tokens_parsed + (parser->tokens.tail - parser->tokens.head);
+ simple_key.mark = parser->mark;
if (!yaml_parser_remove_simple_key(parser)) return 0;
- parser->simple_keys[parser->flow_level] =
- yaml_malloc(sizeof(yaml_simple_key_t));
- if (!parser->simple_keys[parser->flow_level]) {
- parser->error = YAML_MEMORY_ERROR;
- return 0;
- }
-
- *(parser->simple_keys[parser->flow_level]) = simple_key;
+ *(parser->simple_keys.top-1) = simple_key;
}
return 1;
static int
yaml_parser_remove_simple_key(yaml_parser_t *parser)
{
- yaml_simple_key_t *simple_key = parser->simple_keys[parser->flow_level];
+ yaml_simple_key_t *simple_key = parser->simple_keys.top-1;
- if (simple_key)
+ if (simple_key->possible)
{
/* If the key is required, it is an error. */
if (simple_key->required) {
return yaml_parser_set_scanner_error(parser,
"while scanning a simple key", simple_key->mark,
- "could not found expected ':'");
+ "could not find expected ':'");
}
+ }
- /* Remove the key from the list. */
+ /* Remove the key from the stack. */
- yaml_free(simple_key);
- parser->simple_keys[parser->flow_level] = NULL;
- }
+ simple_key->possible = 0;
return 1;
}
static int
yaml_parser_increase_flow_level(yaml_parser_t *parser)
{
- /* Check if we need to resize the list. */
-
- if (parser->flow_level == parser->simple_keys_size-1) {
- if (!yaml_parser_resize_list(parser, (void **)&parser->simple_keys,
- &parser->simple_keys_size, sizeof(yaml_simple_key_t *)))
- return 0;
- }
-
- /* Increase the flow level and reset the simple key. */
+ yaml_simple_key_t empty_simple_key = { 0, 0, 0, { 0, 0, 0 } };
- parser->simple_keys[++parser->flow_level] = NULL;
+ /* Reset the simple key on the next level. */
- return 1;
-}
+ if (!PUSH(parser, parser->simple_keys, empty_simple_key))
+ return 0;
-/*
- * Decrease the flow level.
- */
+ /* Increase the flow level. */
-static int
-yaml_parser_decrease_flow_level(yaml_parser_t *parser)
-{
- assert(parser->flow_level); /* Greater than 0. */
- assert(!parser->simple_keys[parser->flow_level]); /* Must be removed. */
+ if (parser->flow_level == INT_MAX) {
+ parser->error = YAML_MEMORY_ERROR;
+ return 0;
+ }
- parser->flow_level --;
+ parser->flow_level++;
return 1;
}
/*
- * Add a token to the tail of the tokens queue.
- */
-
-static int
-yaml_parser_append_token(yaml_parser_t *parser, yaml_token_t *token)
-{
- return yaml_parser_insert_token(parser, -1, token);
-}
-
-/*
- * Insert the token into the tokens queue. The number parameter is the
- * ordinal number of the token. If the number is equal to -1, add the token
- * to the tail of the queue.
+ * Decrease the flow level.
*/
static int
-yaml_parser_insert_token(yaml_parser_t *parser,
- int number, yaml_token_t *token)
+yaml_parser_decrease_flow_level(yaml_parser_t *parser)
{
- /* The index of the token in the queue. */
+ yaml_simple_key_t dummy_key; /* Used to eliminate a compiler warning. */
- int index = (number == -1)
- ? parser->tokens_tail - parser->tokens_head
- : number - parser->tokens_parsed;
-
- assert(index >= 0 && index <= (parser->tokens_tail-parser->tokens_head));
-
- /* Check if we need to resize the queue. */
-
- if (parser->tokens_head == 0 && parser->tokens_tail == parser->tokens_size) {
- if (!yaml_parser_resize_list(parser, (void **)&parser->tokens,
- &parser->tokens_size, sizeof(yaml_token_t *)))
- return 0;
- }
-
- /* Check if we need to move the queue to the beginning of the buffer. */
-
- if (parser->tokens_tail == parser->tokens_size)
- {
- if (parser->tokens_head < parser->tokens_tail) {
- memmove(parser->tokens, parser->tokens+parser->tokens_head,
- sizeof(yaml_token_t *)*(parser->tokens_tail-parser->tokens_head));
- }
- parser->tokens_tail -= parser->tokens_head;
- parser->tokens_head = 0;
- }
-
- /* Check if we need to free space within the queue. */
-
- if (index < (parser->tokens_tail-parser->tokens_head)) {
- memmove(parser->tokens+parser->tokens_head+index+1,
- parser->tokens+parser->tokens_head+index,
- sizeof(yaml_token_t *)*(parser->tokens_tail-parser->tokens_head-index));
+ if (parser->flow_level) {
+ parser->flow_level --;
+ dummy_key = POP(parser, parser->simple_keys);
}
- /* Insert the token. */
-
- parser->tokens[parser->tokens_head+index] = token;
- parser->tokens_tail ++;
-
return 1;
}
*/
static int
-yaml_parser_roll_indent(yaml_parser_t *parser, int column,
- int number, yaml_token_type_t type, yaml_mark_t mark)
+yaml_parser_roll_indent(yaml_parser_t *parser, ptrdiff_t column,
+ ptrdiff_t number, yaml_token_type_t type, yaml_mark_t mark)
{
- yaml_token_t *token;
+ yaml_token_t token;
/* In the flow context, do nothing. */
if (parser->indent < column)
{
- /* Check if we need to expand the indents stack. */
-
- if (parser->indents_length == parser->indents_size) {
- if (!yaml_parser_resize_list(parser, (void **)&parser->indents,
- &parser->indents_size, sizeof(int)))
- return 0;
- }
-
/*
* Push the current indentation level to the stack and set the new
* indentation level.
*/
- parser->indents[parser->indents_length++] = parser->indent;
- parser->indent = column;
-
- /* Create a token. */
+ if (!PUSH(parser, parser->indents, parser->indent))
+ return 0;
- token = yaml_token_new(type, mark, mark);
- if (!token) {
+ if (column > INT_MAX) {
parser->error = YAML_MEMORY_ERROR;
return 0;
}
- /* Insert the token into the queue. */
+ parser->indent = column;
+
+ /* Create a token and insert it into the queue. */
- if (!yaml_parser_insert_token(parser, number, token)) {
- yaml_token_delete(token);
- return 0;
+ TOKEN_INIT(token, type, mark, mark);
+
+ if (number == -1) {
+ if (!ENQUEUE(parser, parser->tokens, token))
+ return 0;
+ }
+ else {
+ if (!QUEUE_INSERT(parser,
+ parser->tokens, number - parser->tokens_parsed, token))
+ return 0;
}
}
/*
* Pop indentation levels from the indents stack until the current level
- * becomes less or equal to the column. For each intendation level, append
+ * becomes less or equal to the column. For each indentation level, append
* the BLOCK-END token.
*/
static int
-yaml_parser_unroll_indent(yaml_parser_t *parser, int column)
+yaml_parser_unroll_indent(yaml_parser_t *parser, ptrdiff_t column)
{
- yaml_token_t *token;
+ yaml_token_t token;
/* In the flow context, do nothing. */
if (parser->flow_level)
return 1;
- /* Loop through the intendation levels in the stack. */
+ /* Loop through the indentation levels in the stack. */
while (parser->indent > column)
{
- yaml_mark_t mark = yaml_parser_get_mark(parser);
+ /* Create a token and append it to the queue. */
- /* Create a token. */
+ TOKEN_INIT(token, YAML_BLOCK_END_TOKEN, parser->mark, parser->mark);
- token = yaml_token_new(YAML_BLOCK_END_TOKEN, mark, mark);
- if (!token) {
- parser->error = YAML_MEMORY_ERROR;
+ if (!ENQUEUE(parser, parser->tokens, token))
return 0;
- }
- /* Append the token to the queue. */
+ /* Pop the indentation level. */
- if (!yaml_parser_append_token(parser, token)) {
- yaml_token_delete(token);
- return 0;
- }
-
- /* Pop the indentation level. */
-
- assert(parser->indents_length); /* Non-empty stack expected. */
-
- parser->indent = parser->indents[--parser->indents_length];
+ parser->indent = POP(parser, parser->indents);
}
return 1;
static int
yaml_parser_fetch_stream_start(yaml_parser_t *parser)
{
- yaml_mark_t mark = yaml_parser_get_mark(parser);
- yaml_token_t *token;
+ yaml_simple_key_t simple_key = { 0, 0, 0, { 0, 0, 0 } };
+ yaml_token_t token;
/* Set the initial indentation. */
parser->indent = -1;
+ /* Initialize the simple key stack. */
+
+ if (!PUSH(parser, parser->simple_keys, simple_key))
+ return 0;
+
/* A simple key is allowed at the beginning of the stream. */
parser->simple_key_allowed = 1;
parser->stream_start_produced = 1;
- /* Create the STREAM-START token. */
-
- token = yaml_stream_start_token_new(parser->encoding, mark, mark);
- if (!token) {
- parser->error = YAML_MEMORY_ERROR;
- return 0;
- }
+ /* Create the STREAM-START token and append it to the queue. */
- /* Append the token to the queue. */
+ STREAM_START_TOKEN_INIT(token, parser->encoding,
+ parser->mark, parser->mark);
- if (!yaml_parser_append_token(parser, token)) {
- yaml_token_delete(token);
+ if (!ENQUEUE(parser, parser->tokens, token))
return 0;
- }
return 1;
}
static int
yaml_parser_fetch_stream_end(yaml_parser_t *parser)
{
- yaml_mark_t mark = yaml_parser_get_mark(parser);
- yaml_token_t *token;
+ yaml_token_t token;
+
+ /* Force new line. */
+
+ if (parser->mark.column != 0) {
+ parser->mark.column = 0;
+ parser->mark.line ++;
+ }
/* Reset the indentation level. */
if (!yaml_parser_unroll_indent(parser, -1))
return 0;
- /* We have finished. */
+ /* Reset simple keys. */
- parser->stream_end_produced = 1;
+ if (!yaml_parser_remove_simple_key(parser))
+ return 0;
- /* Create the STREAM-END token. */
+ parser->simple_key_allowed = 0;
- token = yaml_stream_end_token_new(mark, mark);
- if (!token) {
- parser->error = YAML_MEMORY_ERROR;
- return 0;
- }
+ /* Create the STREAM-END token and append it to the queue. */
- /* Append the token to the queue. */
+ STREAM_END_TOKEN_INIT(token, parser->mark, parser->mark);
- if (!yaml_parser_append_token(parser, token)) {
- yaml_token_delete(token);
+ if (!ENQUEUE(parser, parser->tokens, token))
return 0;
- }
return 1;
}
/*
- * Produce the YAML-DIRECTIVE or TAG-DIRECTIVE token.
+ * Produce a VERSION-DIRECTIVE or TAG-DIRECTIVE token.
*/
static int
yaml_parser_fetch_directive(yaml_parser_t *parser)
{
- yaml_token_t *token;
+ yaml_token_t token;
/* Reset the indentation level. */
/* Create the YAML-DIRECTIVE or TAG-DIRECTIVE token. */
- token = yaml_parser_scan_directive(parser);
- if (!token) return 0;
+ if (!yaml_parser_scan_directive(parser, &token))
+ return 0;
/* Append the token to the queue. */
- if (!yaml_parser_append_token(parser, token)) {
- yaml_token_delete(token);
+ if (!ENQUEUE(parser, parser->tokens, token)) {
+ yaml_token_delete(&token);
return 0;
}
yaml_token_type_t type)
{
yaml_mark_t start_mark, end_mark;
- yaml_token_t *token;
+ yaml_token_t token;
/* Reset the indentation level. */
/* Consume the token. */
- start_mark = yaml_parser_get_mark(parser);
+ start_mark = parser->mark;
- FORWARD(parser);
- FORWARD(parser);
- FORWARD(parser);
+ SKIP(parser);
+ SKIP(parser);
+ SKIP(parser);
- end_mark = yaml_parser_get_mark(parser);
+ end_mark = parser->mark;
/* Create the DOCUMENT-START or DOCUMENT-END token. */
- token = yaml_token_new(type, start_mark, end_mark);
- if (!token) {
- parser->error = YAML_MEMORY_ERROR;
- return 0;
- }
+ TOKEN_INIT(token, type, start_mark, end_mark);
/* Append the token to the queue. */
- if (!yaml_parser_append_token(parser, token)) {
- yaml_token_delete(token);
+ if (!ENQUEUE(parser, parser->tokens, token))
return 0;
- }
return 1;
}
yaml_token_type_t type)
{
yaml_mark_t start_mark, end_mark;
- yaml_token_t *token;
+ yaml_token_t token;
/* The indicators '[' and '{' may start a simple key. */
/* Consume the token. */
- start_mark = yaml_parser_get_mark(parser);
- FORWARD(parser);
- end_mark = yaml_parser_get_mark(parser);
+ start_mark = parser->mark;
+ SKIP(parser);
+ end_mark = parser->mark;
/* Create the FLOW-SEQUENCE-START of FLOW-MAPPING-START token. */
- token = yaml_token_new(type, start_mark, end_mark);
- if (!token) {
- parser->error = YAML_MEMORY_ERROR;
- return 0;
- }
+ TOKEN_INIT(token, type, start_mark, end_mark);
/* Append the token to the queue. */
- if (!yaml_parser_append_token(parser, token)) {
- yaml_token_delete(token);
+ if (!ENQUEUE(parser, parser->tokens, token))
return 0;
- }
return 1;
}
yaml_token_type_t type)
{
yaml_mark_t start_mark, end_mark;
- yaml_token_t *token;
+ yaml_token_t token;
/* Reset any potential simple key on the current flow level. */
/* Consume the token. */
- start_mark = yaml_parser_get_mark(parser);
- FORWARD(parser);
- end_mark = yaml_parser_get_mark(parser);
+ start_mark = parser->mark;
+ SKIP(parser);
+ end_mark = parser->mark;
/* Create the FLOW-SEQUENCE-END of FLOW-MAPPING-END token. */
- token = yaml_token_new(type, start_mark, end_mark);
- if (!token) {
- parser->error = YAML_MEMORY_ERROR;
- return 0;
- }
+ TOKEN_INIT(token, type, start_mark, end_mark);
/* Append the token to the queue. */
- if (!yaml_parser_append_token(parser, token)) {
- yaml_token_delete(token);
+ if (!ENQUEUE(parser, parser->tokens, token))
return 0;
- }
return 1;
}
yaml_parser_fetch_flow_entry(yaml_parser_t *parser)
{
yaml_mark_t start_mark, end_mark;
- yaml_token_t *token;
+ yaml_token_t token;
/* Reset any potential simple keys on the current flow level. */
/* Consume the token. */
- start_mark = yaml_parser_get_mark(parser);
- FORWARD(parser);
- end_mark = yaml_parser_get_mark(parser);
-
- /* Create the FLOW-ENTRY token. */
+ start_mark = parser->mark;
+ SKIP(parser);
+ end_mark = parser->mark;
- token = yaml_token_new(YAML_FLOW_ENTRY_TOKEN, start_mark, end_mark);
- if (!token) {
- parser->error = YAML_MEMORY_ERROR;
- return 0;
- }
+ /* Create the FLOW-ENTRY token and append it to the queue. */
- /* Append the token to the queue. */
+ TOKEN_INIT(token, YAML_FLOW_ENTRY_TOKEN, start_mark, end_mark);
- if (!yaml_parser_append_token(parser, token)) {
- yaml_token_delete(token);
+ if (!ENQUEUE(parser, parser->tokens, token))
return 0;
- }
return 1;
}
yaml_parser_fetch_block_entry(yaml_parser_t *parser)
{
yaml_mark_t start_mark, end_mark;
- yaml_token_t *token;
+ yaml_token_t token;
/* Check if the scanner is in the block context. */
/* Check if we are allowed to start a new entry. */
if (!parser->simple_key_allowed) {
- return yaml_parser_set_scanner_error(parser, NULL,
- yaml_parser_get_mark(parser),
+ return yaml_parser_set_scanner_error(parser, NULL, parser->mark,
"block sequence entries are not allowed in this context");
}
/* Add the BLOCK-SEQUENCE-START token if needed. */
- if (!yaml_parser_roll_indent(parser, parser->column, -1,
- YAML_BLOCK_SEQUENCE_START_TOKEN, yaml_parser_get_mark(parser)))
+ if (!yaml_parser_roll_indent(parser, parser->mark.column, -1,
+ YAML_BLOCK_SEQUENCE_START_TOKEN, parser->mark))
return 0;
}
else
/* Consume the token. */
- start_mark = yaml_parser_get_mark(parser);
- FORWARD(parser);
- end_mark = yaml_parser_get_mark(parser);
-
- /* Create the BLOCK-ENTRY token. */
+ start_mark = parser->mark;
+ SKIP(parser);
+ end_mark = parser->mark;
- token = yaml_token_new(YAML_BLOCK_ENTRY_TOKEN, start_mark, end_mark);
- if (!token) {
- parser->error = YAML_MEMORY_ERROR;
- return 0;
- }
+ /* Create the BLOCK-ENTRY token and append it to the queue. */
- /* Append the token to the queue. */
+ TOKEN_INIT(token, YAML_BLOCK_ENTRY_TOKEN, start_mark, end_mark);
- if (!yaml_parser_append_token(parser, token)) {
- yaml_token_delete(token);
+ if (!ENQUEUE(parser, parser->tokens, token))
return 0;
- }
return 1;
}
yaml_parser_fetch_key(yaml_parser_t *parser)
{
yaml_mark_t start_mark, end_mark;
- yaml_token_t *token;
+ yaml_token_t token;
/* In the block context, additional checks are required. */
/* Check if we are allowed to start a new key (not nessesary simple). */
if (!parser->simple_key_allowed) {
- return yaml_parser_set_scanner_error(parser, NULL,
- yaml_parser_get_mark(parser),
+ return yaml_parser_set_scanner_error(parser, NULL, parser->mark,
"mapping keys are not allowed in this context");
}
/* Add the BLOCK-MAPPING-START token if needed. */
- if (!yaml_parser_roll_indent(parser, parser->column, -1,
- YAML_BLOCK_MAPPING_START_TOKEN, yaml_parser_get_mark(parser)))
+ if (!yaml_parser_roll_indent(parser, parser->mark.column, -1,
+ YAML_BLOCK_MAPPING_START_TOKEN, parser->mark))
return 0;
}
/* Consume the token. */
- start_mark = yaml_parser_get_mark(parser);
- FORWARD(parser);
- end_mark = yaml_parser_get_mark(parser);
+ start_mark = parser->mark;
+ SKIP(parser);
+ end_mark = parser->mark;
- /* Create the KEY token. */
+ /* Create the KEY token and append it to the queue. */
- token = yaml_token_new(YAML_KEY_TOKEN, start_mark, end_mark);
- if (!token) {
- parser->error = YAML_MEMORY_ERROR;
- return 0;
- }
+ TOKEN_INIT(token, YAML_KEY_TOKEN, start_mark, end_mark);
- /* Append the token to the queue. */
-
- if (!yaml_parser_append_token(parser, token)) {
- yaml_token_delete(token);
+ if (!ENQUEUE(parser, parser->tokens, token))
return 0;
- }
return 1;
}
yaml_parser_fetch_value(yaml_parser_t *parser)
{
yaml_mark_t start_mark, end_mark;
- yaml_token_t *token;
+ yaml_token_t token;
+ yaml_simple_key_t *simple_key = parser->simple_keys.top-1;
/* Have we found a simple key? */
- if (parser->simple_keys[parser->flow_level])
+ if (simple_key->possible)
{
- yaml_simple_key_t *simple_key = parser->simple_keys[parser->flow_level];
- /* Create the KEY token. */
+ /* Create the KEY token and insert it into the queue. */
- token = yaml_token_new(YAML_KEY_TOKEN, simple_key->mark, simple_key->mark);
- if (!token) {
- parser->error = YAML_MEMORY_ERROR;
- return 0;
- }
+ TOKEN_INIT(token, YAML_KEY_TOKEN, simple_key->mark, simple_key->mark);
- /* Insert the token into the queue. */
-
- if (!yaml_parser_insert_token(parser, simple_key->token_number, token)) {
- yaml_token_delete(token);
+ if (!QUEUE_INSERT(parser, parser->tokens,
+ simple_key->token_number - parser->tokens_parsed, token))
return 0;
- }
/* In the block context, we may need to add the BLOCK-MAPPING-START token. */
- if (!yaml_parser_roll_indent(parser, parser->column,
+ if (!yaml_parser_roll_indent(parser, simple_key->mark.column,
simple_key->token_number,
YAML_BLOCK_MAPPING_START_TOKEN, simple_key->mark))
return 0;
- /* Remove the simple key from the list. */
+ /* Remove the simple key. */
- yaml_free(simple_key);
- parser->simple_keys[parser->flow_level] = NULL;
+ simple_key->possible = 0;
/* A simple key cannot follow another simple key. */
/* Check if we are allowed to start a complex value. */
if (!parser->simple_key_allowed) {
- return yaml_parser_set_scanner_error(parser, NULL,
- yaml_parser_get_mark(parser),
+ return yaml_parser_set_scanner_error(parser, NULL, parser->mark,
"mapping values are not allowed in this context");
}
/* Add the BLOCK-MAPPING-START token if needed. */
- if (!yaml_parser_roll_indent(parser, parser->column, -1,
- YAML_BLOCK_MAPPING_START_TOKEN, yaml_parser_get_mark(parser)))
+ if (!yaml_parser_roll_indent(parser, parser->mark.column, -1,
+ YAML_BLOCK_MAPPING_START_TOKEN, parser->mark))
return 0;
}
/* Consume the token. */
- start_mark = yaml_parser_get_mark(parser);
- FORWARD(parser);
- end_mark = yaml_parser_get_mark(parser);
-
- /* Create the VALUE token. */
+ start_mark = parser->mark;
+ SKIP(parser);
+ end_mark = parser->mark;
- token = yaml_token_new(YAML_VALUE_TOKEN, start_mark, end_mark);
- if (!token) {
- parser->error = YAML_MEMORY_ERROR;
- return 0;
- }
+ /* Create the VALUE token and append it to the queue. */
- /* Append the token to the queue. */
+ TOKEN_INIT(token, YAML_VALUE_TOKEN, start_mark, end_mark);
- if (!yaml_parser_append_token(parser, token)) {
- yaml_token_delete(token);
+ if (!ENQUEUE(parser, parser->tokens, token))
return 0;
- }
return 1;
}
static int
yaml_parser_fetch_anchor(yaml_parser_t *parser, yaml_token_type_t type)
{
- yaml_token_t *token;
+ yaml_token_t token;
/* An anchor or an alias could be a simple key. */
parser->simple_key_allowed = 0;
- /* Create the ALIAS or ANCHOR token. */
-
- token = yaml_parser_scan_anchor(parser, type);
- if (!token) return 0;
+ /* Create the ALIAS or ANCHOR token and append it to the queue. */
- /* Append the token to the queue. */
+ if (!yaml_parser_scan_anchor(parser, &token, type))
+ return 0;
- if (!yaml_parser_append_token(parser, token)) {
- yaml_token_delete(token);
+ if (!ENQUEUE(parser, parser->tokens, token)) {
+ yaml_token_delete(&token);
return 0;
}
-
return 1;
}
static int
yaml_parser_fetch_tag(yaml_parser_t *parser)
{
- yaml_token_t *token;
+ yaml_token_t token;
/* A tag could be a simple key. */
parser->simple_key_allowed = 0;
- /* Create the TAG token. */
-
- token = yaml_parser_scan_tag(parser);
- if (!token) return 0;
+ /* Create the TAG token and append it to the queue. */
- /* Append the token to the queue. */
+ if (!yaml_parser_scan_tag(parser, &token))
+ return 0;
- if (!yaml_parser_append_token(parser, token)) {
- yaml_token_delete(token);
+ if (!ENQUEUE(parser, parser->tokens, token)) {
+ yaml_token_delete(&token);
return 0;
}
static int
yaml_parser_fetch_block_scalar(yaml_parser_t *parser, int literal)
{
- yaml_token_t *token;
+ yaml_token_t token;
/* Remove any potential simple keys. */
parser->simple_key_allowed = 1;
- /* Create the SCALAR token. */
-
- token = yaml_parser_scan_block_scalar(parser, literal);
- if (!token) return 0;
+ /* Create the SCALAR token and append it to the queue. */
- /* Append the token to the queue. */
+ if (!yaml_parser_scan_block_scalar(parser, &token, literal))
+ return 0;
- if (!yaml_parser_append_token(parser, token)) {
- yaml_token_delete(token);
+ if (!ENQUEUE(parser, parser->tokens, token)) {
+ yaml_token_delete(&token);
return 0;
}
static int
yaml_parser_fetch_flow_scalar(yaml_parser_t *parser, int single)
{
- yaml_token_t *token;
+ yaml_token_t token;
/* A plain scalar could be a simple key. */
parser->simple_key_allowed = 0;
- /* Create the SCALAR token. */
+ /* Create the SCALAR token and append it to the queue. */
- token = yaml_parser_scan_flow_scalar(parser, single);
- if (!token) return 0;
-
- /* Append the token to the queue. */
+ if (!yaml_parser_scan_flow_scalar(parser, &token, single))
+ return 0;
- if (!yaml_parser_append_token(parser, token)) {
- yaml_token_delete(token);
+ if (!ENQUEUE(parser, parser->tokens, token)) {
+ yaml_token_delete(&token);
return 0;
}
static int
yaml_parser_fetch_plain_scalar(yaml_parser_t *parser)
{
- yaml_token_t *token;
+ yaml_token_t token;
/* A plain scalar could be a simple key. */
parser->simple_key_allowed = 0;
- /* Create the SCALAR token. */
-
- token = yaml_parser_scan_plain_scalar(parser);
- if (!token) return 0;
+ /* Create the SCALAR token and append it to the queue. */
- /* Append the token to the queue. */
+ if (!yaml_parser_scan_plain_scalar(parser, &token))
+ return 0;
- if (!yaml_parser_append_token(parser, token)) {
- yaml_token_delete(token);
+ if (!ENQUEUE(parser, parser->tokens, token)) {
+ yaml_token_delete(&token);
return 0;
}
{
/* Allow the BOM mark to start a line. */
- if (!UPDATE(parser, 1)) return 0;
+ if (!CACHE(parser, 1)) return 0;
- if (parser->column == 0 && IS_BOM(parser))
- FORWARD(parser);
+ if (parser->mark.column == 0 && IS_BOM(parser->buffer))
+ SKIP(parser);
/*
* Eat whitespaces.
* after '-', '?', or ':' (complex value).
*/
- if (!UPDATE(parser, 1)) return 0;
+ if (!CACHE(parser, 1)) return 0;
- while (CHECK(parser,' ') ||
+ while (CHECK(parser->buffer,' ') ||
((parser->flow_level || !parser->simple_key_allowed) &&
- CHECK(parser, '\t'))) {
- FORWARD(parser);
- if (!UPDATE(parser, 1)) return 0;
+ 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)) {
- FORWARD(parser);
- if (!UPDATE(parser, 1)) return 0;
+ if (CHECK(parser->buffer, '#')) {
+ while (!IS_BREAKZ(parser->buffer)) {
+ SKIP(parser);
+ if (!CACHE(parser, 1)) return 0;
}
}
/* If it is a line break, eat it. */
- if (IS_BREAK(parser))
+ if (IS_BREAK(parser->buffer))
{
- if (!UPDATE(parser, 2)) return 0;
- FORWARD_LINE(parser);
+ if (!CACHE(parser, 2)) return 0;
+ SKIP_LINE(parser);
/* In the block context, a new line may start a simple key. */
* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
*/
-static yaml_token_t *
-yaml_parser_scan_directive(yaml_parser_t *parser)
+int
+yaml_parser_scan_directive(yaml_parser_t *parser, yaml_token_t *token)
{
yaml_mark_t start_mark, end_mark;
yaml_char_t *name = NULL;
int major, minor;
yaml_char_t *handle = NULL, *prefix = NULL;
- yaml_token_t *token = NULL;
/* Eat '%'. */
- start_mark = yaml_parser_get_mark(parser);
+ start_mark = parser->mark;
- FORWARD(parser);
+ SKIP(parser);
/* Scan the directive name. */
&major, &minor))
goto error;
- end_mark = yaml_parser_get_mark(parser);
+ end_mark = parser->mark;
/* Create a VERSION-DIRECTIVE token. */
- token = yaml_version_directive_token_new(major, minor,
+ VERSION_DIRECTIVE_TOKEN_INIT(*token, major, minor,
start_mark, end_mark);
- if (!token) goto error;
}
/* Is it a TAG directive? */
&handle, &prefix))
goto error;
- end_mark = yaml_parser_get_mark(parser);
+ end_mark = parser->mark;
/* Create a TAG-DIRECTIVE token. */
- token = yaml_tag_directive_token_new(handle, prefix,
+ TAG_DIRECTIVE_TOKEN_INIT(*token, handle, prefix,
start_mark, end_mark);
- if (!token) goto error;
}
/* Unknown directive. */
else
{
- yaml_parser_set_scanner_error(parser, "While scanning a directive",
- start_mark, "found uknown directive name");
+ yaml_parser_set_scanner_error(parser, "while scanning a directive",
+ start_mark, "found unknown directive name");
goto error;
}
/* Eat the rest of the line including any comments. */
- while (IS_BLANK(parser)) {
- FORWARD(parser);
- if (!UPDATE(parser, 1)) goto error;
+ if (!CACHE(parser, 1)) goto error;
+
+ while (IS_BLANK(parser->buffer)) {
+ SKIP(parser);
+ if (!CACHE(parser, 1)) goto error;
}
- if (CHECK(parser, '#')) {
- while (!IS_BREAKZ(parser)) {
- FORWARD(parser);
- if (!UPDATE(parser, 1)) goto error;
+ if (CHECK(parser->buffer, '#')) {
+ while (!IS_BREAKZ(parser->buffer)) {
+ SKIP(parser);
+ if (!CACHE(parser, 1)) goto error;
}
}
/* Check if we are at the end of the line. */
- if (!IS_BREAKZ(parser)) {
- yaml_parser_set_scanner_error(parser, "While scanning a directive",
- start_mark, "did not found expected comment or line break");
+ if (!IS_BREAKZ(parser->buffer)) {
+ yaml_parser_set_scanner_error(parser, "while scanning a directive",
+ start_mark, "did not find expected comment or line break");
goto error;
}
/* Eat a line break. */
- if (IS_BREAK(parser)) {
- if (!UPDATE(parser, 2)) goto error;
- FORWARD_LINE(parser);
+ if (IS_BREAK(parser->buffer)) {
+ if (!CACHE(parser, 2)) goto error;
+ SKIP_LINE(parser);
}
yaml_free(name);
- return token;
+ return 1;
error:
- yaml_free(token);
yaml_free(prefix);
yaml_free(handle);
yaml_free(name);
- return NULL;
+ return 0;
}
/*
yaml_parser_scan_directive_name(yaml_parser_t *parser,
yaml_mark_t start_mark, yaml_char_t **name)
{
- yaml_string_t string = yaml_parser_new_string(parser);
+ yaml_string_t string = NULL_STRING;
- if (!string.buffer) goto error;
+ if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error;
/* Consume the directive name. */
- if (!UPDATE(parser, 1)) goto error;
+ if (!CACHE(parser, 1)) goto error;
- while (IS_ALPHA(parser))
+ while (IS_ALPHA(parser->buffer))
{
- if (!RESIZE(parser, string)) goto error;
- COPY(parser, string);
- if (!UPDATE(parser, 1)) goto error;
+ if (!READ(parser, string)) goto error;
+ if (!CACHE(parser, 1)) goto error;
}
/* Check if the name is empty. */
- if (string.buffer == string.pointer) {
+ if (string.start == string.pointer) {
yaml_parser_set_scanner_error(parser, "while scanning a directive",
- start_mark, "cannot found expected directive name");
+ start_mark, "could not find expected directive name");
goto error;
}
/* 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;
}
- *name = string.buffer;
+ *name = string.start;
return 1;
error:
- yaml_free(string.buffer);
+ STRING_DEL(parser, string);
return 0;
}
{
/* Eat whitespaces. */
- if (!UPDATE(parser, 1)) return 0;
+ if (!CACHE(parser, 1)) return 0;
- while (IS_BLANK(parser)) {
- FORWARD(parser);
- if (!UPDATE(parser, 1)) return 0;
+ while (IS_BLANK(parser->buffer)) {
+ SKIP(parser);
+ if (!CACHE(parser, 1)) return 0;
}
/* Consume the major version number. */
/* 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");
}
- FORWARD(parser);
+ SKIP(parser);
/* Consume the minor version number. */
if (!yaml_parser_scan_version_directive_number(parser, start_mark, minor))
return 0;
+
+ return 1;
}
#define MAX_NUMBER_LENGTH 9
/* Repeat while the next character is digit. */
- if (!UPDATE(parser, 1)) return 0;
+ if (!CACHE(parser, 1)) return 0;
- while (IS_DIGIT(parser))
+ while (IS_DIGIT(parser->buffer))
{
/* Check if the number is too long. */
start_mark, "found extremely long version number");
}
- value = value*10 + AS_DIGIT(parser);
+ value = value*10 + AS_DIGIT(parser->buffer);
- FORWARD(parser);
+ SKIP(parser);
- if (!UPDATE(parser, 1)) return 0;
+ if (!CACHE(parser, 1)) return 0;
}
/* Check if the number was present. */
/* Eat whitespaces. */
- if (!UPDATE(parser, 1)) goto error;
+ if (!CACHE(parser, 1)) goto error;
- while (IS_BLANK(parser)) {
- FORWARD(parser);
- if (!UPDATE(parser, 1)) goto error;
+ while (IS_BLANK(parser->buffer)) {
+ SKIP(parser);
+ if (!CACHE(parser, 1)) goto error;
}
/* Scan a handle. */
/* Expect a whitespace. */
- if (!UPDATE(parser, 1)) goto error;
+ 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;
/* Eat whitespaces. */
- while (IS_BLANK(parser)) {
- FORWARD(parser);
- if (!UPDATE(parser, 1)) goto error;
+ while (IS_BLANK(parser->buffer)) {
+ SKIP(parser);
+ if (!CACHE(parser, 1)) goto error;
}
/* Scan a prefix. */
/* Expect a whitespace or line break. */
- if (!UPDATE(parser, 1)) goto error;
+ 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;
return 0;
}
-static yaml_token_t *
-yaml_parser_scan_anchor(yaml_parser_t *parser,
+static int
+yaml_parser_scan_anchor(yaml_parser_t *parser, yaml_token_t *token,
yaml_token_type_t type)
{
int length = 0;
yaml_mark_t start_mark, end_mark;
- yaml_token_t *token = NULL;
- yaml_string_t string = yaml_parser_new_string(parser);
+ yaml_string_t string = NULL_STRING;
- if (!string.buffer) goto error;
+ if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error;
/* Eat the indicator character. */
- start_mark = yaml_parser_get_mark(parser);
+ start_mark = parser->mark;
- FORWARD(parser);
+ SKIP(parser);
/* Consume the value. */
- if (!UPDATE(parser, 1)) goto error;
+ if (!CACHE(parser, 1)) goto error;
- while (IS_ALPHA(parser)) {
- if (!RESIZE(parser, string)) goto error;
- COPY(parser, string);
- if (!UPDATE(parser, 1)) goto error;
+ while (IS_ALPHA(parser->buffer)) {
+ if (!READ(parser, string)) goto error;
+ if (!CACHE(parser, 1)) goto error;
length ++;
}
- end_mark = yaml_parser_get_mark(parser);
+ end_mark = parser->mark;
/*
* Check if length of the anchor is greater than 0 and it is followed by
* '?', ':', ',', ']', '}', '%', '@', '`'.
*/
- 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");
/* Create a token. */
- token = type == YAML_ANCHOR_TOKEN ?
- yaml_anchor_token_new(string.buffer, start_mark, end_mark) :
- yaml_alias_token_new(string.buffer, start_mark, end_mark);
- if (!token) goto error;
+ if (type == YAML_ANCHOR_TOKEN) {
+ ANCHOR_TOKEN_INIT(*token, string.start, start_mark, end_mark);
+ }
+ else {
+ ALIAS_TOKEN_INIT(*token, string.start, start_mark, end_mark);
+ }
- return token;
+ return 1;
error:
- yaml_free(string.buffer);
- yaml_free(token);
+ STRING_DEL(parser, string);
return 0;
}
* Scan a TAG token.
*/
-static yaml_token_t *
-yaml_parser_scan_tag(yaml_parser_t *parser)
+static int
+yaml_parser_scan_tag(yaml_parser_t *parser, yaml_token_t *token)
{
yaml_char_t *handle = NULL;
yaml_char_t *suffix = NULL;
- yaml_token_t *token = NULL;
yaml_mark_t start_mark, end_mark;
- start_mark = yaml_parser_get_mark(parser);
+ start_mark = parser->mark;
/* Check if the tag is in the canonical form. */
- if (!UPDATE(parser, 2)) goto error;
+ if (!CACHE(parser, 2)) goto error;
- if (CHECK_AT(parser, '<', 1))
+ if (CHECK_AT(parser->buffer, '<', 1))
{
/* Set the handle to '' */
/* Eat '!<' */
- FORWARD(parser);
- FORWARD(parser);
+ SKIP(parser);
+ SKIP(parser);
/* Consume the tag value. */
/* 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;
}
- FORWARD(parser);
+ SKIP(parser);
}
else
{
if (!handle) goto error;
handle[0] = '!';
handle[1] = '\0';
+
+ /*
+ * A special case: the '!' tag. Set the handle to '' and the
+ * suffix to '!'.
+ */
+
+ if (suffix[0] == '\0') {
+ yaml_char_t *tmp = handle;
+ handle = suffix;
+ suffix = tmp;
+ }
}
}
/* Check the character which ends the tag. */
- if (!UPDATE(parser, 1)) goto error;
+ 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");
+ start_mark, "did not find expected whitespace or line break");
goto error;
}
- end_mark = yaml_parser_get_mark(parser);
+ end_mark = parser->mark;
/* Create a token. */
- token = yaml_tag_token_new(handle, suffix, start_mark, end_mark);
- if (!token) goto error;
+ TAG_TOKEN_INIT(*token, handle, suffix, start_mark, end_mark);
- return token;
+ return 1;
error:
yaml_free(handle);
yaml_free(suffix);
- return NULL;
+ return 0;
}
/*
yaml_parser_scan_tag_handle(yaml_parser_t *parser, int directive,
yaml_mark_t start_mark, yaml_char_t **handle)
{
- yaml_string_t string = yaml_parser_new_string(parser);
+ yaml_string_t string = NULL_STRING;
- if (!string.buffer) goto error;
+ if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error;
/* Check the initial '!' character. */
- if (!UPDATE(parser, 1)) goto error;
+ 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 '!'");
/* Copy the '!' character. */
- COPY(parser, string);
+ if (!READ(parser, string)) goto error;
/* Copy all subsequent alphabetical and numerical characters. */
- if (!UPDATE(parser, 1)) goto error;
+ if (!CACHE(parser, 1)) goto error;
- while (IS_ALPHA(parser))
+ while (IS_ALPHA(parser->buffer))
{
- if (!RESIZE(parser, string)) goto error;
- COPY(parser, string);
- if (!UPDATE(parser, 1)) goto error;
+ if (!READ(parser, string)) goto error;
+ if (!CACHE(parser, 1)) goto error;
}
/* Check if the trailing character is '!' and copy it. */
- if (CHECK(parser, '!'))
+ if (CHECK(parser->buffer, '!'))
{
- if (!RESIZE(parser, string)) goto error;
- COPY(parser, string);
+ if (!READ(parser, string)) goto error;
}
else
{
/*
- * It's not really a tag handle. If it's a %TAG directive, it's an
- * error. If it's a tag token, it must be a part of URI.
+ * It's either the '!' tag or not really a tag handle. If it's a %TAG
+ * directive, it's an error. If it's a tag token, it must be a part of
+ * URI.
*/
- if (directive) {
- yaml_parser_set_scanner_error(parser, "while parsing a directive",
+ if (directive && !(string.start[0] == '!' && string.start[1] == '\0')) {
+ yaml_parser_set_scanner_error(parser, "while parsing a tag directive",
start_mark, "did not find expected '!'");
goto error;
}
}
- *handle = string.buffer;
+ *handle = string.start;
return 1;
error:
- yaml_free(string.buffer);
+ STRING_DEL(parser, string);
return 0;
}
yaml_char_t *head, yaml_mark_t start_mark, yaml_char_t **uri)
{
size_t length = head ? strlen((char *)head) : 0;
- yaml_string_t string = yaml_parser_new_string(parser);
+ yaml_string_t string = NULL_STRING;
- if (!string.buffer) goto error;
+ if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error;
/* Resize the string to include the head. */
- while (string.size <= length) {
- if (!yaml_parser_resize_string(parser, &string)) goto error;
+ while ((size_t)(string.end - string.start) <= length) {
+ if (!yaml_string_extend(&string.start, &string.pointer, &string.end)) {
+ parser->error = YAML_MEMORY_ERROR;
+ goto error;
+ }
}
- /* Copy the head if needed. */
+ /*
+ * Copy the head if needed.
+ *
+ * Note that we don't copy the leading '!' character.
+ */
- if (length) {
- memcpy(string.buffer, head, length);
- string.pointer += length;
+ if (length > 1) {
+ memcpy(string.start, head+1, length-1);
+ string.pointer += length-1;
}
/* Scan the tag. */
- if (!UPDATE(parser, 1)) goto error;
+ if (!CACHE(parser, 1)) goto error;
/*
* The set of characters that may appear in URI is as follows:
* '%'.
*/
- 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, '%'))
{
- if (!RESIZE(parser, string)) goto error;
-
/* Check if it is a URI-escape sequence. */
- if (CHECK(parser, '%')) {
+ if (CHECK(parser->buffer, '%')) {
+ if (!STRING_EXTEND(parser, string))
+ goto error;
+
if (!yaml_parser_scan_uri_escapes(parser,
directive, start_mark, &string)) goto error;
}
else {
- COPY(parser, string);
+ if (!READ(parser, string)) goto error;
}
length ++;
- if (!UPDATE(parser, 1)) goto error;
+ if (!CACHE(parser, 1)) goto error;
}
/* Check if the tag is non-empty. */
if (!length) {
+ if (!STRING_EXTEND(parser, string))
+ goto error;
+
yaml_parser_set_scanner_error(parser, directive ?
"while parsing a %TAG directive" : "while parsing a tag",
start_mark, "did not find expected tag URI");
goto error;
}
- *uri = string.buffer;
+ *uri = string.start;
return 1;
error:
- yaml_free(string.buffer);
+ STRING_DEL(parser, string);
return 0;
}
/* Check for a URI-escaped octet. */
- if (!UPDATE(parser, 3)) return 0;
+ 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");
/* 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. */
/* Copy the octet and move the pointers. */
*(string->pointer++) = octet;
- FORWARD(parser);
- FORWARD(parser);
- FORWARD(parser);
+ SKIP(parser);
+ SKIP(parser);
+ SKIP(parser);
} while (--width);
return 1;
}
+/*
+ * Scan a block scalar.
+ */
+
+static int
+yaml_parser_scan_block_scalar(yaml_parser_t *parser, yaml_token_t *token,
+ int literal)
+{
+ yaml_mark_t start_mark;
+ yaml_mark_t end_mark;
+ yaml_string_t string = NULL_STRING;
+ yaml_string_t leading_break = NULL_STRING;
+ yaml_string_t trailing_breaks = NULL_STRING;
+ int chomping = 0;
+ int increment = 0;
+ int indent = 0;
+ int leading_blank = 0;
+ int trailing_blank = 0;
+
+ if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error;
+ if (!STRING_INIT(parser, leading_break, INITIAL_STRING_SIZE)) goto error;
+ if (!STRING_INIT(parser, trailing_breaks, INITIAL_STRING_SIZE)) goto error;
+
+ /* Eat the indicator '|' or '>'. */
+
+ start_mark = parser->mark;
+
+ SKIP(parser);
+
+ /* Scan the additional block scalar indicators. */
+
+ if (!CACHE(parser, 1)) goto error;
+
+ /* Check for a chomping indicator. */
+
+ if (CHECK(parser->buffer, '+') || CHECK(parser->buffer, '-'))
+ {
+ /* Set the chomping method and eat the indicator. */
+
+ chomping = CHECK(parser->buffer, '+') ? +1 : -1;
+
+ SKIP(parser);
+
+ /* Check for an indentation indicator. */
+
+ if (!CACHE(parser, 1)) goto error;
+
+ if (IS_DIGIT(parser->buffer))
+ {
+ /* Check that the indentation is greater than 0. */
+
+ if (CHECK(parser->buffer, '0')) {
+ yaml_parser_set_scanner_error(parser, "while scanning a block scalar",
+ start_mark, "found an indentation indicator equal to 0");
+ goto error;
+ }
+
+ /* Get the indentation level and eat the indicator. */
+
+ increment = AS_DIGIT(parser->buffer);
+
+ SKIP(parser);
+ }
+ }
+
+ /* Do the same as above, but in the opposite order. */
+
+ else if (IS_DIGIT(parser->buffer))
+ {
+ if (CHECK(parser->buffer, '0')) {
+ yaml_parser_set_scanner_error(parser, "while scanning a block scalar",
+ start_mark, "found an indentation indicator equal to 0");
+ goto error;
+ }
+
+ increment = AS_DIGIT(parser->buffer);
+
+ SKIP(parser);
+
+ if (!CACHE(parser, 1)) goto error;
+
+ if (CHECK(parser->buffer, '+') || CHECK(parser->buffer, '-')) {
+ chomping = CHECK(parser->buffer, '+') ? +1 : -1;
+
+ SKIP(parser);
+ }
+ }
+
+ /* Eat whitespaces and comments to the end of the line. */
+
+ if (!CACHE(parser, 1)) goto error;
+
+ while (IS_BLANK(parser->buffer)) {
+ SKIP(parser);
+ if (!CACHE(parser, 1)) goto error;
+ }
+
+ if (CHECK(parser->buffer, '#')) {
+ while (!IS_BREAKZ(parser->buffer)) {
+ SKIP(parser);
+ if (!CACHE(parser, 1)) goto error;
+ }
+ }
+
+ /* Check if we are at the end of the line. */
+
+ if (!IS_BREAKZ(parser->buffer)) {
+ yaml_parser_set_scanner_error(parser, "while scanning a block scalar",
+ start_mark, "did not find expected comment or line break");
+ goto error;
+ }
+
+ /* Eat a line break. */
+
+ if (IS_BREAK(parser->buffer)) {
+ if (!CACHE(parser, 2)) goto error;
+ SKIP_LINE(parser);
+ }
+
+ end_mark = parser->mark;
+
+ /* Set the indentation level if it was specified. */
+
+ if (increment) {
+ indent = parser->indent >= 0 ? parser->indent+increment : increment;
+ }
+
+ /* Scan the leading line breaks and determine the indentation level if needed. */
+
+ if (!yaml_parser_scan_block_scalar_breaks(parser, &indent, &trailing_breaks,
+ start_mark, &end_mark)) goto error;
+
+ /* Scan the block scalar content. */
+
+ if (!CACHE(parser, 1)) goto error;
+
+ while ((int)parser->mark.column == indent && !IS_Z(parser->buffer))
+ {
+ /*
+ * We are at the beginning of a non-empty line.
+ */
+
+ /* Is it a trailing whitespace? */
+
+ trailing_blank = IS_BLANK(parser->buffer);
+
+ /* Check if we need to fold the leading line break. */
+
+ if (!literal && (*leading_break.start == '\n')
+ && !leading_blank && !trailing_blank)
+ {
+ /* Do we need to join the lines by space? */
+
+ if (*trailing_breaks.start == '\0') {
+ if (!STRING_EXTEND(parser, string)) goto error;
+ *(string.pointer ++) = ' ';
+ }
+
+ CLEAR(parser, leading_break);
+ }
+ else {
+ if (!JOIN(parser, string, leading_break)) goto error;
+ CLEAR(parser, leading_break);
+ }
+
+ /* Append the remaining line breaks. */
+
+ if (!JOIN(parser, string, trailing_breaks)) goto error;
+ CLEAR(parser, trailing_breaks);
+
+ /* Is it a leading whitespace? */
+
+ leading_blank = IS_BLANK(parser->buffer);
+
+ /* Consume the current line. */
+
+ while (!IS_BREAKZ(parser->buffer)) {
+ if (!READ(parser, string)) goto error;
+ if (!CACHE(parser, 1)) goto error;
+ }
+
+ /* Consume the line break. */
+
+ if (!CACHE(parser, 2)) goto error;
+
+ if (!READ_LINE(parser, leading_break)) goto error;
+
+ /* Eat the following indentation spaces and line breaks. */
+
+ if (!yaml_parser_scan_block_scalar_breaks(parser,
+ &indent, &trailing_breaks, start_mark, &end_mark)) goto error;
+ }
+
+ /* Chomp the tail. */
+
+ if (chomping != -1) {
+ if (!JOIN(parser, string, leading_break)) goto error;
+ }
+ if (chomping == 1) {
+ if (!JOIN(parser, string, trailing_breaks)) goto error;
+ }
+
+ /* Create a token. */
+
+ SCALAR_TOKEN_INIT(*token, string.start, string.pointer-string.start,
+ literal ? YAML_LITERAL_SCALAR_STYLE : YAML_FOLDED_SCALAR_STYLE,
+ start_mark, end_mark);
+
+ STRING_DEL(parser, leading_break);
+ STRING_DEL(parser, trailing_breaks);
+
+ return 1;
+
+error:
+ STRING_DEL(parser, string);
+ STRING_DEL(parser, leading_break);
+ STRING_DEL(parser, trailing_breaks);
+
+ return 0;
+}
+
+/*
+ * Scan indentation spaces and line breaks for a block scalar. Determine the
+ * indentation level if needed.
+ */
+
+static int
+yaml_parser_scan_block_scalar_breaks(yaml_parser_t *parser,
+ int *indent, yaml_string_t *breaks,
+ yaml_mark_t start_mark, yaml_mark_t *end_mark)
+{
+ int max_indent = 0;
+
+ *end_mark = parser->mark;
+
+ /* Eat the indentation spaces and line breaks. */
+
+ while (1)
+ {
+ /* Eat the indentation spaces. */
+
+ if (!CACHE(parser, 1)) return 0;
+
+ while ((!*indent || (int)parser->mark.column < *indent)
+ && IS_SPACE(parser->buffer)) {
+ SKIP(parser);
+ if (!CACHE(parser, 1)) return 0;
+ }
+
+ if ((int)parser->mark.column > max_indent)
+ max_indent = (int)parser->mark.column;
+
+ /* Check for a tab character messing the indentation. */
+
+ if ((!*indent || (int)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 indentation space is expected");
+ }
+
+ /* Have we found a non-empty line? */
+
+ if (!IS_BREAK(parser->buffer)) break;
+
+ /* Consume the line break. */
+
+ if (!CACHE(parser, 2)) return 0;
+ if (!READ_LINE(parser, *breaks)) return 0;
+ *end_mark = parser->mark;
+ }
+
+ /* Determine the indentation level if needed. */
+
+ if (!*indent) {
+ *indent = max_indent;
+ if (*indent < parser->indent + 1)
+ *indent = parser->indent + 1;
+ if (*indent < 1)
+ *indent = 1;
+ }
+
+ return 1;
+}
+
+/*
+ * Scan a quoted scalar.
+ */
+
+static int
+yaml_parser_scan_flow_scalar(yaml_parser_t *parser, yaml_token_t *token,
+ int single)
+{
+ yaml_mark_t start_mark;
+ yaml_mark_t end_mark;
+ yaml_string_t string = NULL_STRING;
+ yaml_string_t leading_break = NULL_STRING;
+ yaml_string_t trailing_breaks = NULL_STRING;
+ yaml_string_t whitespaces = NULL_STRING;
+ int leading_blanks;
+
+ if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error;
+ if (!STRING_INIT(parser, leading_break, INITIAL_STRING_SIZE)) goto error;
+ if (!STRING_INIT(parser, trailing_breaks, INITIAL_STRING_SIZE)) goto error;
+ if (!STRING_INIT(parser, whitespaces, INITIAL_STRING_SIZE)) goto error;
+
+ /* Eat the left quote. */
+
+ start_mark = parser->mark;
+
+ SKIP(parser);
+
+ /* Consume the content of the quoted scalar. */
+
+ while (1)
+ {
+ /* Check that there are no document indicators at the beginning of the line. */
+
+ if (!CACHE(parser, 4)) goto error;
+
+ if (parser->mark.column == 0 &&
+ ((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");
+ goto error;
+ }
+
+ /* Check for EOF. */
+
+ 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;
+ }
+
+ /* Consume non-blank characters. */
+
+ if (!CACHE(parser, 2)) goto error;
+
+ leading_blanks = 0;
+
+ while (!IS_BLANKZ(parser->buffer))
+ {
+ /* Check for an escaped single quote. */
+
+ if (single && CHECK_AT(parser->buffer, '\'', 0)
+ && CHECK_AT(parser->buffer, '\'', 1))
+ {
+ if (!STRING_EXTEND(parser, string)) goto error;
+ *(string.pointer++) = '\'';
+ SKIP(parser);
+ SKIP(parser);
+ }
+
+ /* Check for the right quote. */
+
+ else if (CHECK(parser->buffer, single ? '\'' : '"'))
+ {
+ break;
+ }
+
+ /* Check for an escaped line break. */
+
+ else if (!single && CHECK(parser->buffer, '\\')
+ && IS_BREAK_AT(parser->buffer, 1))
+ {
+ if (!CACHE(parser, 3)) goto error;
+ SKIP(parser);
+ SKIP_LINE(parser);
+ leading_blanks = 1;
+ break;
+ }
+
+ /* Check for an escape sequence. */
+
+ else if (!single && CHECK(parser->buffer, '\\'))
+ {
+ size_t code_length = 0;
+
+ if (!STRING_EXTEND(parser, string)) goto error;
+
+ /* Check the escape character. */
+
+ switch (parser->buffer.pointer[1])
+ {
+ case '0':
+ *(string.pointer++) = '\0';
+ break;
+
+ case 'a':
+ *(string.pointer++) = '\x07';
+ break;
+
+ case 'b':
+ *(string.pointer++) = '\x08';
+ break;
+
+ case 't':
+ case '\t':
+ *(string.pointer++) = '\x09';
+ break;
+
+ case 'n':
+ *(string.pointer++) = '\x0A';
+ break;
+
+ case 'v':
+ *(string.pointer++) = '\x0B';
+ break;
+
+ case 'f':
+ *(string.pointer++) = '\x0C';
+ break;
+
+ case 'r':
+ *(string.pointer++) = '\x0D';
+ break;
+
+ case 'e':
+ *(string.pointer++) = '\x1B';
+ break;
+
+ case ' ':
+ *(string.pointer++) = '\x20';
+ break;
+
+ case '"':
+ *(string.pointer++) = '"';
+ break;
+
+ case '/':
+ *(string.pointer++) = '/';
+ break;
+
+ case '\'':
+ *(string.pointer++) = '\'';
+ break;
+
+ case '\\':
+ *(string.pointer++) = '\\';
+ break;
+
+ case 'N': /* NEL (#x85) */
+ *(string.pointer++) = '\xC2';
+ *(string.pointer++) = '\x85';
+ break;
+
+ case '_': /* #xA0 */
+ *(string.pointer++) = '\xC2';
+ *(string.pointer++) = '\xA0';
+ break;
+
+ case 'L': /* LS (#x2028) */
+ *(string.pointer++) = '\xE2';
+ *(string.pointer++) = '\x80';
+ *(string.pointer++) = '\xA8';
+ break;
+
+ case 'P': /* PS (#x2029) */
+ *(string.pointer++) = '\xE2';
+ *(string.pointer++) = '\x80';
+ *(string.pointer++) = '\xA9';
+ break;
+
+ case 'x':
+ code_length = 2;
+ break;
+
+ case 'u':
+ code_length = 4;
+ break;
+
+ case 'U':
+ code_length = 8;
+ break;
+
+ default:
+ yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar",
+ start_mark, "found unknown escape character");
+ goto error;
+ }
+
+ SKIP(parser);
+ SKIP(parser);
+
+ /* Consume an arbitrary escape code. */
+
+ if (code_length)
+ {
+ unsigned int value = 0;
+ size_t k;
+
+ /* Scan the character value. */
+
+ if (!CACHE(parser, code_length)) goto error;
+
+ for (k = 0; k < code_length; 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->buffer, k);
+ }
+
+ /* Check the value and write the character. */
+
+ if ((value >= 0xD800 && value <= 0xDFFF) || value > 0x10FFFF) {
+ yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar",
+ start_mark, "found invalid Unicode character escape code");
+ goto error;
+ }
+
+ if (value <= 0x7F) {
+ *(string.pointer++) = value;
+ }
+ else if (value <= 0x7FF) {
+ *(string.pointer++) = 0xC0 + (value >> 6);
+ *(string.pointer++) = 0x80 + (value & 0x3F);
+ }
+ else if (value <= 0xFFFF) {
+ *(string.pointer++) = 0xE0 + (value >> 12);
+ *(string.pointer++) = 0x80 + ((value >> 6) & 0x3F);
+ *(string.pointer++) = 0x80 + (value & 0x3F);
+ }
+ else {
+ *(string.pointer++) = 0xF0 + (value >> 18);
+ *(string.pointer++) = 0x80 + ((value >> 12) & 0x3F);
+ *(string.pointer++) = 0x80 + ((value >> 6) & 0x3F);
+ *(string.pointer++) = 0x80 + (value & 0x3F);
+ }
+
+ /* Advance the pointer. */
+
+ for (k = 0; k < code_length; k ++) {
+ SKIP(parser);
+ }
+ }
+ }
+
+ else
+ {
+ /* It is a non-escaped non-blank character. */
+
+ if (!READ(parser, string)) goto error;
+ }
+
+ if (!CACHE(parser, 2)) goto error;
+ }
+
+ /* Check if we are at the end of the scalar. */
+
+ if (CHECK(parser->buffer, single ? '\'' : '"'))
+ break;
+
+ /* Consume blank characters. */
+
+ if (!CACHE(parser, 1)) goto error;
+
+ while (IS_BLANK(parser->buffer) || IS_BREAK(parser->buffer))
+ {
+ if (IS_BLANK(parser->buffer))
+ {
+ /* Consume a space or a tab character. */
+
+ if (!leading_blanks) {
+ if (!READ(parser, whitespaces)) goto error;
+ }
+ else {
+ SKIP(parser);
+ }
+ }
+ else
+ {
+ if (!CACHE(parser, 2)) goto error;
+
+ /* Check if it is a first line break. */
+
+ if (!leading_blanks)
+ {
+ CLEAR(parser, whitespaces);
+ if (!READ_LINE(parser, leading_break)) goto error;
+ leading_blanks = 1;
+ }
+ else
+ {
+ if (!READ_LINE(parser, trailing_breaks)) goto error;
+ }
+ }
+ if (!CACHE(parser, 1)) goto error;
+ }
+
+ /* Join the whitespaces or fold line breaks. */
+
+ if (leading_blanks)
+ {
+ /* Do we need to fold line breaks? */
+
+ if (leading_break.start[0] == '\n') {
+ if (trailing_breaks.start[0] == '\0') {
+ if (!STRING_EXTEND(parser, string)) goto error;
+ *(string.pointer++) = ' ';
+ }
+ else {
+ if (!JOIN(parser, string, trailing_breaks)) goto error;
+ CLEAR(parser, trailing_breaks);
+ }
+ CLEAR(parser, leading_break);
+ }
+ else {
+ if (!JOIN(parser, string, leading_break)) goto error;
+ if (!JOIN(parser, string, trailing_breaks)) goto error;
+ CLEAR(parser, leading_break);
+ CLEAR(parser, trailing_breaks);
+ }
+ }
+ else
+ {
+ if (!JOIN(parser, string, whitespaces)) goto error;
+ CLEAR(parser, whitespaces);
+ }
+ }
+
+ /* Eat the right quote. */
+
+ SKIP(parser);
+
+ end_mark = parser->mark;
+
+ /* Create a token. */
+
+ SCALAR_TOKEN_INIT(*token, string.start, string.pointer-string.start,
+ single ? YAML_SINGLE_QUOTED_SCALAR_STYLE : YAML_DOUBLE_QUOTED_SCALAR_STYLE,
+ start_mark, end_mark);
+
+ STRING_DEL(parser, leading_break);
+ STRING_DEL(parser, trailing_breaks);
+ STRING_DEL(parser, whitespaces);
+
+ return 1;
+
+error:
+ STRING_DEL(parser, string);
+ STRING_DEL(parser, leading_break);
+ STRING_DEL(parser, trailing_breaks);
+ STRING_DEL(parser, whitespaces);
+
+ return 0;
+}
+
+/*
+ * Scan a plain scalar.
+ */
+
+static int
+yaml_parser_scan_plain_scalar(yaml_parser_t *parser, yaml_token_t *token)
+{
+ yaml_mark_t start_mark;
+ yaml_mark_t end_mark;
+ yaml_string_t string = NULL_STRING;
+ yaml_string_t leading_break = NULL_STRING;
+ yaml_string_t trailing_breaks = NULL_STRING;
+ yaml_string_t whitespaces = NULL_STRING;
+ int leading_blanks = 0;
+ int indent = parser->indent+1;
+
+ if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error;
+ if (!STRING_INIT(parser, leading_break, INITIAL_STRING_SIZE)) goto error;
+ if (!STRING_INIT(parser, trailing_breaks, INITIAL_STRING_SIZE)) goto error;
+ if (!STRING_INIT(parser, whitespaces, INITIAL_STRING_SIZE)) goto error;
+
+ start_mark = end_mark = parser->mark;
+
+ /* Consume the content of the plain scalar. */
+
+ while (1)
+ {
+ /* Check for a document indicator. */
+
+ if (!CACHE(parser, 4)) goto error;
+
+ if (parser->mark.column == 0 &&
+ ((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->buffer, '#'))
+ break;
+
+ /* Consume non-blank characters. */
+
+ 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->buffer, ':')
+ && !IS_BLANKZ_AT(parser->buffer, 1)) {
+ yaml_parser_set_scanner_error(parser, "while scanning a plain scalar",
+ start_mark, "found unexpected ':'");
+ goto error;
+ }
+
+ /* Check for indicators that may end a plain scalar. */
+
+ 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. */
+
+ if (leading_blanks || whitespaces.start != whitespaces.pointer)
+ {
+ if (leading_blanks)
+ {
+ /* Do we need to fold line breaks? */
+
+ if (leading_break.start[0] == '\n') {
+ if (trailing_breaks.start[0] == '\0') {
+ if (!STRING_EXTEND(parser, string)) goto error;
+ *(string.pointer++) = ' ';
+ }
+ else {
+ if (!JOIN(parser, string, trailing_breaks)) goto error;
+ CLEAR(parser, trailing_breaks);
+ }
+ CLEAR(parser, leading_break);
+ }
+ else {
+ if (!JOIN(parser, string, leading_break)) goto error;
+ if (!JOIN(parser, string, trailing_breaks)) goto error;
+ CLEAR(parser, leading_break);
+ CLEAR(parser, trailing_breaks);
+ }
+
+ leading_blanks = 0;
+ }
+ else
+ {
+ if (!JOIN(parser, string, whitespaces)) goto error;
+ CLEAR(parser, whitespaces);
+ }
+ }
+
+ /* Copy the character. */
+
+ if (!READ(parser, string)) goto error;
+
+ end_mark = parser->mark;
+
+ if (!CACHE(parser, 2)) goto error;
+ }
+
+ /* Is it the end? */
+
+ if (!(IS_BLANK(parser->buffer) || IS_BREAK(parser->buffer)))
+ break;
+
+ /* Consume blank characters. */
+
+ if (!CACHE(parser, 1)) goto error;
+
+ while (IS_BLANK(parser->buffer) || IS_BREAK(parser->buffer))
+ {
+ if (IS_BLANK(parser->buffer))
+ {
+ /* Check for tab character that abuse indentation. */
+
+ if (leading_blanks && (int)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 indentation");
+ goto error;
+ }
+
+ /* Consume a space or a tab character. */
+
+ if (!leading_blanks) {
+ if (!READ(parser, whitespaces)) goto error;
+ }
+ else {
+ SKIP(parser);
+ }
+ }
+ else
+ {
+ if (!CACHE(parser, 2)) goto error;
+
+ /* Check if it is a first line break. */
+
+ if (!leading_blanks)
+ {
+ CLEAR(parser, whitespaces);
+ if (!READ_LINE(parser, leading_break)) goto error;
+ leading_blanks = 1;
+ }
+ else
+ {
+ if (!READ_LINE(parser, trailing_breaks)) goto error;
+ }
+ }
+ if (!CACHE(parser, 1)) goto error;
+ }
+
+ /* Check indentation level. */
+
+ if (!parser->flow_level && (int)parser->mark.column < indent)
+ break;
+ }
+
+ /* Create a token. */
+
+ SCALAR_TOKEN_INIT(*token, string.start, string.pointer-string.start,
+ YAML_PLAIN_SCALAR_STYLE, start_mark, end_mark);
+
+ /* Note that we change the 'simple_key_allowed' flag. */
+
+ if (leading_blanks) {
+ parser->simple_key_allowed = 1;
+ }
+
+ STRING_DEL(parser, leading_break);
+ STRING_DEL(parser, trailing_breaks);
+ STRING_DEL(parser, whitespaces);
+
+ return 1;
+
+error:
+ STRING_DEL(parser, string);
+ STRING_DEL(parser, leading_break);
+ STRING_DEL(parser, trailing_breaks);
+ STRING_DEL(parser, whitespaces);
+
+ return 0;
+}
+