diff options
author | xi <xi@18f92427-320e-0410-9341-c67f048884a3> | 2008-01-19 13:54:22 +0000 |
---|---|---|
committer | xi <xi@18f92427-320e-0410-9341-c67f048884a3> | 2008-01-19 13:54:22 +0000 |
commit | 6608dc4b2c6f0c7f0761ebdee74e4022c09bbf76 (patch) | |
tree | 53ca93a29808b00f7771206a1687469940d9a986 | |
parent | 80dc45b6360138db8c3a2c75648d24de03c7d778 (diff) | |
download | libyaml-6608dc4b2c6f0c7f0761ebdee74e4022c09bbf76.tar.gz |
Minor API updates.
git-svn-id: http://svn.pyyaml.org/libyaml/trunk@267 18f92427-320e-0410-9341-c67f048884a3
-rw-r--r-- | include/yaml.h | 204 | ||||
-rw-r--r-- | src/api.c | 2342 | ||||
-rw-r--r-- | src/emitter.c | 91 | ||||
-rw-r--r-- | src/yaml_private.h | 364 |
4 files changed, 2070 insertions, 931 deletions
diff --git a/include/yaml.h b/include/yaml.h index 582d822..f009bf6 100644 --- a/include/yaml.h +++ b/include/yaml.h @@ -7,17 +7,43 @@ * the terms of the MIT license; see the file LICENCE for more details. *****************************************************************************/ -/* +/***************************************************************************** * General guidelines. + *****************************************************************************/ + +/* + * Basic conventions. + * + * All functions exported by exported by LibYAML starts with the the prefix + * `yaml_`; types starts with `yaml_` and ends with `_t`; macros and + * enumeration values start with `YAML_`. + * + * A function may serve as method for an object or a particular type; such + * functions start with `yaml_<type>`. A type constructor is named + * `yaml_<type>_new()`, a type destructor is named `yaml_<type>_delete()`. + * + * A function signifies whether it succeeded or failed with its return value; + * typically it is `1` for success, `0` for failure. Functions that return a + * pointer may indicate an error condition by returning `NULL`. Functions that + * never fail commonly do not return any value. For most of the functions, an + * error value means that the function is unable to allocate some memory + * buffer. For parsing and emitting functions, detailed information on the + * nature of the error could be obtained. + * + * LibYAML provides two active objects: parsers and emitters and three passive + * objects: tokens, events and documents. + * + * * - * Naming conventions: all functions exported by LibYAML starts with the `yaml_` prefix; - * types starts with `yaml_` and ends with `_t`; macros and enumerations starts - * with `YAML_`. * * FIXME: Calling conventions. * FIXME: Memory allocation. * FIXME: Errors and exceptions. * FIXME: And so on, and so forth. + * + * + * + * */ @@ -269,9 +295,9 @@ typedef struct yaml_error_s { YAML_DECLARE(int) yaml_error_message(yaml_error_t *error, char *buffer, size_t capacity); -/****************************************************************************** +/***************************************************************************** * Basic Types - ******************************************************************************/ + *****************************************************************************/ /* * The character type (UTF-8 octet). @@ -347,9 +373,9 @@ typedef enum yaml_break_e { YAML_CRLN_BREAK } yaml_break_t; -/****************************************************************************** +/***************************************************************************** * Node Styles - ******************************************************************************/ + *****************************************************************************/ /* * Scalar styles. @@ -402,9 +428,9 @@ typedef enum yaml_sequence_style_e { YAML_ANY_SEQUENCE_STYLE, /* The flow sequence style. */ - YAML_FLOW_SEQUENCE_STYLE + YAML_FLOW_SEQUENCE_STYLE, /* The block sequence style. */ - YAML_BLOCK_SEQUENCE_STYLE, + YAML_BLOCK_SEQUENCE_STYLE } yaml_sequence_style_t; /* @@ -430,9 +456,9 @@ typedef enum yaml_mapping_style_e { YAML_FLOW_MAPPING_STYLE } yaml_mapping_style_t; -/****************************************************************************** +/***************************************************************************** * Tokens - ******************************************************************************/ + *****************************************************************************/ /* * Token types. @@ -680,9 +706,9 @@ yaml_token_duplicate(yaml_token_t *token, const yaml_token_t *model); YAML_DECLARE(void) yaml_token_clear(yaml_token_t *token); -/****************************************************************************** +/***************************************************************************** * Events - ******************************************************************************/ + *****************************************************************************/ /* * Event types. @@ -1220,9 +1246,9 @@ yaml_event_create_mapping_start(yaml_event_t *event, YAML_DECLARE(int) yaml_event_create_mapping_end(yaml_event_t *event); -/****************************************************************************** +/***************************************************************************** * Documents and Nodes - ******************************************************************************/ + *****************************************************************************/ /* * Well-known scalar tags. @@ -1260,7 +1286,7 @@ yaml_event_create_mapping_end(yaml_event_t *event); typedef enum yaml_document_type_e { /* An empty uninitialized document. */ - YAML_NO_DOCUMENT. + YAML_NO_DOCUMENT, /* A YAML document. */ YAML_DOCUMENT @@ -1382,7 +1408,7 @@ typedef struct yaml_arc_s { * node object is destroyed when the document containing it is destroyed. */ -struct yaml_node_s { +typedef struct yaml_node_s { /* The node type. */ yaml_node_type_t type; @@ -1442,7 +1468,7 @@ struct yaml_node_s { /* The end of the node. */ yaml_mark_t end_mark; -}; +} yaml_node_t; /* * The incomplete node object. @@ -1818,6 +1844,62 @@ yaml_document_add_mapping(yaml_document_t *document, int *node_id, yaml_mapping_style_t style); /* + * Add an item to a SEQUENCE node. + * + * The order in which items are added to a sequence coincides with the order + * they are emitted into the output stream. + * + * Arguments: + * + * - `document`: a document object. + * + * - `sequence_id`: the id of a sequence node; could be negative. It is a + * fatal error if `sequence_id` does not refer to an existing sequence node. + * + * - `item_id`: the id of an item node; could be negative. It is a fatal error + * if `item_id` does not refer to an existing node. Note that it is possible + * for `item_id` to coincide with `sequence_id`, which means that the + * sequence recursively contains itself. + * + * Returns: `1` on success, `0` on error. The function may fail if it cannot + * allocate memory for internal buffers. + */ + +YAML_DECLARE(int) +yaml_document_append_sequence_item(yaml_document_t *document, + int sequence_id, int item_id); + +/* + * Add a pair of a key and a value to a MAPPING node. + * + * The order in which (key, value) pairs are added to a mapping coincides with + * the order in which they are presented in the output stream. Note that the + * mapping key order is a presentation detail and should not used to convey any + * information. An ordered mapping could be represented as a sequence of + * single-paired mappings. + * + * Arguments: + * + * - `document`: a document object. + * + * - `mapping_id`: the id of a mapping node; could be negative. It is a + * fatal error if `mapping_id` does not refer to an existing mapping node. + * + * - `key_id`: the id of a key node; could be negative. It is a fatal error + * if `key_id` does not refer to an existing node. + * + * - `value_id`: the id of a value node; could be negative. It is a fatal + * error if `value_id` does not refer to an existing node. + * + * Returns: `1` on success, `0` on error. The function may fail if it cannot + * allocate memory for internal buffers. + */ + +YAML_DECLARE(int) +yaml_document_append_mapping_pair(yaml_document_t *document, + int mapping_id, int key_id, int value_id); + +/* * Get the value of a `!!null` SCALAR node. * * Use this function to ensure that the given node is a scalar, the node tag is @@ -1893,7 +1975,7 @@ yaml_document_get_str_node(yaml_document_t *document, int node_id, * `tag:yaml.org,2002:int` and the node value is a valid integer. In this * case, the function parses the node value and returns an integer number. The * function recognizes decimal, hexdecimal and octal numbers including negative - * numbers. + * numbers. The function uses `strtol()` for string-to-integer conversion. * * Arguments: * @@ -1910,7 +1992,7 @@ yaml_document_get_str_node(yaml_document_t *document, int node_id, YAML_DECLARE(int) yaml_document_get_int_node(yaml_document_t *document, int node_id, - int *value); + long *value); /* * Get the value of a `!!float` SCALAR node. @@ -1919,7 +2001,9 @@ yaml_document_get_int_node(yaml_document_t *document, int node_id, * `tag:yaml.org,2002:float` and the node value is a valid float value. In * this case, the function parses the node value and returns a float number. * The function recognizes float values in exponential and fixed notation as - * well as special values `.nan`, `.inf` and `-.inf`. + * well as special values `.nan`, `.inf` and `-.inf`. The function uses + * `strtod()` for string-to-float conversion. The `.nan`, `.inf` and `-.inf` + * values are generated as `0.0/0.0`, `1.0/0.0` and `-1.0/0.0` respectively. * * Arguments: * @@ -2094,7 +2178,7 @@ yaml_document_add_str_node(yaml_document_t *document, int *node_id, YAML_DECLARE(int) yaml_document_add_int_node(yaml_document_t *document, int *node_id, - int value); + long value); /* * Add a `!!float` SCALAR node to the document. @@ -2166,65 +2250,9 @@ yaml_document_add_seq_node(yaml_document_t *document, int *node_id); YAML_DECLARE(int) yaml_document_add_map_node(yaml_document_t *document, int *node_id); -/* - * Add an item to a SEQUENCE node. - * - * The order in which items are added to a sequence coincides with the order - * they are emitted into the output stream. - * - * Arguments: - * - * - `document`: a document object. - * - * - `sequence_id`: the id of a sequence node; could be negative. It is a - * fatal error if `sequence_id` does not refer to an existing sequence node. - * - * - `item_id`: the id of an item node; could be negative. It is a fatal error - * if `item_id` does not refer to an existing node. Note that it is possible - * for `item_id` to coincide with `sequence_id`, which means that the - * sequence recursively contains itself. - * - * Returns: `1` on success, `0` on error. The function may fail if it cannot - * allocate memory for internal buffers. - */ - -YAML_DECLARE(int) -yaml_document_append_sequence_item(yaml_document_t *document, - int sequence_id, int item_id); - -/* - * Add a pair of a key and a value to a MAPPING node. - * - * The order in which (key, value) pairs are added to a mapping coincides with - * the order in which they are presented in the output stream. Note that the - * mapping key order is a presentation detail and should not used to convey any - * information. An ordered mapping could be represented as a sequence of - * single-paired mappings. - * - * Arguments: - * - * - `document`: a document object. - * - * - `mapping_id`: the id of a mapping node; could be negative. It is a - * fatal error if `mapping_id` does not refer to an existing mapping node. - * - * - `key_id`: the id of a key node; could be negative. It is a fatal error - * if `key_id` does not refer to an existing node. - * - * - `value_id`: the id of a value node; could be negative. It is a fatal - * error if `value_id` does not refer to an existing node. - * - * Returns: `1` on success, `0` on error. The function may fail if it cannot - * allocate memory for internal buffers. - */ - -YAML_DECLARE(int) -yaml_document_append_mapping_pair(yaml_document_t *document, - int mapping_id, int key_id, int value_id); - -/****************************************************************************** +/***************************************************************************** * Callback Definitions - ******************************************************************************/ + *****************************************************************************/ /* * The prototype of a read handler. @@ -2305,11 +2333,11 @@ typedef int yaml_writer_t(void *data, const unsigned char *buffer, */ typedef int yaml_resolver_t(void *data, yaml_incomplete_node_t *node, - yaml_char_t **tag); + const yaml_char_t **tag); -/****************************************************************************** +/***************************************************************************** * Parser Definitions - ******************************************************************************/ + *****************************************************************************/ /* * An opaque definition of the parser object. @@ -2359,7 +2387,7 @@ yaml_parser_delete(yaml_parser_t *parser); */ YAML_DECLARE(void) -yaml_parser_clear(yaml_parser_t *parser); +yaml_parser_reset(yaml_parser_t *parser); /* * Get the parser error. @@ -2617,9 +2645,9 @@ YAML_DECLARE(int) yaml_parser_parse_single_document(yaml_parser_t *parser, yaml_document_t *document); -/****************************************************************************** +/***************************************************************************** * Emitter Definitions - ******************************************************************************/ + *****************************************************************************/ /* * An opaque definition of the emitter object. @@ -2669,7 +2697,7 @@ yaml_emitter_delete(yaml_emitter_t *emitter); */ YAML_DECLARE(void) -yaml_emitter_clear(yaml_emitter_t *emitter); +yaml_emitter_reset(yaml_emitter_t *emitter); /* * Get the emitter error. @@ -1,8 +1,20 @@ +/***************************************************************************** + * LibYAML API Implementation + * + * Copyright (c) 2006 Kirill Simonov + * + * LibYAML is free software; you can use, modify and/or redistribute it under + * the terms of the MIT license; see the file LICENCE for more details. + *****************************************************************************/ #include "yaml_private.h" +/***************************************************************************** + * Version Information + *****************************************************************************/ + /* - * Get the library version. + * Get the library version as a static string. */ YAML_DECLARE(const char *) @@ -23,6 +35,10 @@ yaml_get_version(int *major, int *minor, int *patch) *patch = YAML_VERSION_PATCH; } +/***************************************************************************** + * Memory Management + *****************************************************************************/ + /* * Allocate a dynamic memory block. */ @@ -66,6 +82,10 @@ yaml_strdup(const yaml_char_t *str) return (yaml_char_t *)strdup((char *)str); } +/***************************************************************************** + * Error Handling + *****************************************************************************/ + /* * Format an error message. */ @@ -170,6 +190,9 @@ yaml_error_message(yaml_error_t *error, char *buffer, size_t capacity) return (length >= 0 && length < capacity); } +/***************************************************************************** + * String, Stack and Queue Management + *****************************************************************************/ /* * Extend a string. @@ -263,428 +286,9 @@ yaml_queue_extend(void **list, size_t size, return 1; } - -/* - * Create a new parser object. - */ - -YAML_DECLARE(yaml_parser_t *) -yaml_parser_new(void) -{ - yaml_parser_t *parser = yaml_malloc(sizeof(yaml_parser_t)); - - if (!parser) - return NULL; - - memset(parser, 0, sizeof(yaml_parser_t)); - if (!IOSTRING_INIT(parser, parser->raw_input, RAW_INPUT_BUFFER_CAPACITY)) - goto error; - if (!IOSTRING_INIT(parser, parser->input, INPUT_BUFFER_CAPACITY)) - goto error; - if (!QUEUE_INIT(parser, parser->tokens, INITIAL_QUEUE_CAPACITY)) - goto error; - if (!STACK_INIT(parser, parser->indents, INITIAL_STACK_CAPACITY)) - goto error; - if (!STACK_INIT(parser, parser->simple_keys, INITIAL_STACK_CAPACITY)) - goto error; - if (!STACK_INIT(parser, parser->states, INITIAL_STACK_CAPACITY)) - goto error; - if (!STACK_INIT(parser, parser->marks, INITIAL_STACK_CAPACITY)) - goto error; - if (!STACK_INIT(parser, parser->tag_directives, INITIAL_STACK_CAPACITY)) - goto error; - - return parser; - -error: - yaml_parser_delete(parser); - - return NULL; -} - -/* - * Destroy a parser object. - */ - -YAML_DECLARE(void) -yaml_parser_delete(yaml_parser_t *parser) -{ - assert(parser); /* Non-NULL parser object expected. */ - - IOSTRING_DEL(parser, parser->raw_input); - IOSTRING_DEL(parser, parser->input); - while (!QUEUE_EMPTY(parser, parser->tokens)) { - yaml_token_destroy(&DEQUEUE(parser, parser->tokens)); - } - QUEUE_DEL(parser, parser->tokens); - STACK_DEL(parser, parser->indents); - STACK_DEL(parser, parser->simple_keys); - STACK_DEL(parser, parser->states); - STACK_DEL(parser, parser->marks); - while (!STACK_EMPTY(parser, parser->tag_directives)) { - yaml_tag_directive_t tag_directive = POP(parser, parser->tag_directives); - yaml_free(tag_directive.handle); - yaml_free(tag_directive.prefix); - } - STACK_DEL(parser, parser->tag_directives); - - memset(parser, 0, sizeof(yaml_parser_t)); - yaml_free(parser); -} - -/* - * Get the current parser error. - */ - -YAML_DECLARE(void) -yaml_parser_get_error(yaml_parser_t *parser, yaml_error_t *error) -{ - assert(parser); /* Non-NULL parser object expected. */ - - *error = parser->error; -} - -/* - * Standard string read handler. - */ - -static int -yaml_string_reader(void *untyped_data, unsigned char *buffer, size_t capacity, - size_t *length) -{ - yaml_standard_reader_data_t *data = untyped_data; - - if (data->string.pointer == data->string.length) { - *length = 0; - return 1; - } - - if (capacity > (size_t)(data->string.length - data->string.pointer)) { - capacity = data->string.length - data->string.pointer; - } - - memcpy(buffer, data->string.buffer + data->string.pointer, capacity); - data->string.pointer += capacity; - *length = capacity; - return 1; -} - -/* - * Standard file read handler. - */ - -static int -yaml_file_reader(void *untyped_data, unsigned char *buffer, size_t capacity, - size_t *length) -{ - yaml_standard_reader_data_t *data = untyped_data; - - *length = fread(buffer, 1, capacity, data->file); - return !ferror(data->file); -} - -/* - * Set a string input. - */ - -YAML_DECLARE(void) -yaml_parser_set_string_reader(yaml_parser_t *parser, - const unsigned char *buffer, size_t length) -{ - assert(parser); /* Non-NULL parser object expected. */ - assert(!parser->reader); /* You can set the input handler only once. */ - assert(buffer); /* Non-NULL input string expected. */ - - parser->reader = yaml_string_reader; - parser->reader_data = &(parser->standard_reader_data); - - parser->standard_reader_data.string.buffer = buffer; - parser->standard_reader_data.string.pointer = 0; - parser->standard_reader_data.string.length = length; -} - -/* - * Set a file input. - */ - -YAML_DECLARE(void) -yaml_parser_set_file_reader(yaml_parser_t *parser, FILE *file) -{ - assert(parser); /* Non-NULL parser object expected. */ - assert(!parser->reader); /* You can set the input handler only once. */ - assert(file); /* Non-NULL file object expected. */ - - parser->reader = yaml_file_reader; - parser->reader_data = &(parser->standard_reader_data); - - parser->standard_reader_data.file = file; -} - -/* - * Set a generic input. - */ - -YAML_DECLARE(void) -yaml_parser_set_reader(yaml_parser_t *parser, - yaml_reader_t *reader, void *data) -{ - assert(parser); /* Non-NULL parser object expected. */ - assert(!parser->reader); /* You can set the input handler only once. */ - assert(reader); /* Non-NULL read handler expected. */ - - parser->reader = reader; - parser->reader_data = data; -} - -/* - * Set the source encoding. - */ - -YAML_DECLARE(void) -yaml_parser_set_encoding(yaml_parser_t *parser, yaml_encoding_t encoding) -{ - assert(parser); /* Non-NULL parser object expected. */ - assert(!parser->encoding); /* Encoding is already set or detected. */ - - parser->encoding = encoding; -} - -/* - * Create a new emitter object. - */ - -YAML_DECLARE(yaml_emitter_t *) -yaml_emitter_new(void) -{ - yaml_emitter_t *emitter = yaml_malloc(sizeof(yaml_emitter_t)); - - if (!emitter) - return NULL; - - memset(emitter, 0, sizeof(yaml_emitter_t)); - if (!IOSTRING_INIT(emitter, emitter->output, OUTPUT_BUFFER_CAPACITY)) - goto error; - if (!IOSTRING_INIT(emitter, emitter->raw_output, RAW_OUTPUT_BUFFER_CAPACITY)) - goto error; - if (!STACK_INIT(emitter, emitter->states, INITIAL_STACK_CAPACITY)) - goto error; - if (!QUEUE_INIT(emitter, emitter->events, INITIAL_QUEUE_CAPACITY)) - goto error; - if (!STACK_INIT(emitter, emitter->indents, INITIAL_STACK_CAPACITY)) - goto error; - if (!STACK_INIT(emitter, emitter->tag_directives, INITIAL_STACK_CAPACITY)) - goto error; - - return emitter; - -error: - yaml_emitter_delete(emitter); - - return NULL; -} - -/* - * Destroy an emitter object. - */ - -YAML_DECLARE(void) -yaml_emitter_delete(yaml_emitter_t *emitter) -{ - assert(emitter); /* Non-NULL emitter object expected. */ - - IOSTRING_DEL(emitter, emitter->output); - IOSTRING_DEL(emitter, emitter->raw_output); - STACK_DEL(emitter, emitter->states); - while (!QUEUE_EMPTY(emitter, emitter->events)) { - yaml_event_destroy(&DEQUEUE(emitter, emitter->events)); - } - QUEUE_DEL(emitter, emitter->events); - STACK_DEL(emitter, emitter->indents); - while (!STACK_EMPTY(empty, emitter->tag_directives)) { - yaml_tag_directive_t tag_directive = POP(emitter, emitter->tag_directives); - yaml_free(tag_directive.handle); - yaml_free(tag_directive.prefix); - } - STACK_DEL(emitter, emitter->tag_directives); - yaml_free(emitter->anchors); - - memset(emitter, 0, sizeof(yaml_emitter_t)); - yaml_free(emitter); -} - -/* - * Get the current emitter error. - */ - -YAML_DECLARE(void) -yaml_emitter_get_error(yaml_emitter_t *emitter, yaml_error_t *error) -{ - assert(emitter); /* Non-NULL emitter object expected. */ - - *error = emitter->error; -} - -/* - * String write handler. - */ - -static int -yaml_string_writer(void *untyped_data, const unsigned char *buffer, size_t length) -{ - yaml_standard_writer_data_t *data = untyped_data; - int result = 1; - - if (data->string.capacity - data->string.pointer < length) { - length = data->string.capacity - data->string.pointer; - result = 0; - } - - memcpy(data->string.buffer + data->string.pointer, buffer, length); - data->string.pointer += length; - *data->length += length; - - return result; -} - -/* - * File write handler. - */ - -static int -yaml_file_writer(void *untyped_data, const unsigned char *buffer, size_t length) -{ - yaml_standard_writer_data_t *data = untyped_data; - - return (fwrite(buffer, 1, length, data->file) == length); -} -/* - * Set a string output. - */ - -YAML_DECLARE(void) -yaml_emitter_set_string_writer(yaml_emitter_t *emitter, - unsigned char *buffer, size_t capacity, size_t *length) -{ - assert(emitter); /* Non-NULL emitter object expected. */ - assert(!emitter->writer); /* You can set the output only once. */ - assert(buffer); /* Non-NULL output string expected. */ - - emitter->writer = yaml_string_writer; - emitter->writer_data = &(emitter->standard_writer_data); - - emitter->standard_writer_data.string.buffer = buffer; - emitter->standard_writer_data.string.pointer = 0; - emitter->standard_writer_data.string.capacity = capacity; - emitter->standard_writer_data.length = length; - - *length = 0; -} - -/* - * Set a file output. - */ - -YAML_DECLARE(void) -yaml_emitter_set_file_writer(yaml_emitter_t *emitter, FILE *file) -{ - assert(emitter); /* Non-NULL emitter object expected. */ - assert(!emitter->writer); /* You can set the output only once. */ - assert(file); /* Non-NULL file object expected. */ - - emitter->writer = yaml_string_writer; - emitter->writer_data = &(emitter->standard_writer_data); - - emitter->standard_writer_data.file = file; -} - -/* - * Set a generic output handler. - */ - -YAML_DECLARE(void) -yaml_emitter_set_writer(yaml_emitter_t *emitter, - yaml_writer_t *writer, void *data) -{ - assert(emitter); /* Non-NULL emitter object expected. */ - assert(!emitter->writer); /* You can set the output only once. */ - assert(writer); /* Non-NULL handler object expected. */ - - emitter->writer = writer; - emitter->writer_data = data; -} - -/* - * Set the output encoding. - */ - -YAML_DECLARE(void) -yaml_emitter_set_encoding(yaml_emitter_t *emitter, yaml_encoding_t encoding) -{ - assert(emitter); /* Non-NULL emitter object expected. */ - assert(!emitter->encoding); /* You can set encoding only once. */ - - emitter->encoding = encoding; -} - -/* - * Set the canonical output style. - */ - -YAML_DECLARE(void) -yaml_emitter_set_canonical(yaml_emitter_t *emitter, int is_canonical) -{ - assert(emitter); /* Non-NULL emitter object expected. */ - - emitter->is_canonical = (is_canonical != 0); -} - -/* - * Set the indentation increment. - */ - -YAML_DECLARE(void) -yaml_emitter_set_indent(yaml_emitter_t *emitter, int indent) -{ - assert(emitter); /* Non-NULL emitter object expected. */ - - emitter->best_indent = (1 < indent && indent < 10) ? indent : 2; -} - -/* - * Set the preferred line width. - */ - -YAML_DECLARE(void) -yaml_emitter_set_width(yaml_emitter_t *emitter, int width) -{ - assert(emitter); /* Non-NULL emitter object expected. */ - - emitter->best_width = (width >= 0) ? width : -1; -} - -/* - * Set if unescaped non-ASCII characters are allowed. - */ - -YAML_DECLARE(void) -yaml_emitter_set_unicode(yaml_emitter_t *emitter, int is_unicode) -{ - assert(emitter); /* Non-NULL emitter object expected. */ - - emitter->is_unicode = (is_unicode != 0); -} - -/* - * Set the preferred line break character. - */ - -YAML_DECLARE(void) -yaml_emitter_set_break(yaml_emitter_t *emitter, yaml_break_t line_break) -{ - assert(emitter); /* Non-NULL emitter object expected. */ - - emitter->line_break = line_break; -} +/***************************************************************************** + * Token API + *****************************************************************************/ /* * Allocate a token object. @@ -712,7 +316,7 @@ yaml_token_delete(yaml_token_t *token) { assert(token); /* Non-NULL token object expected. */ - yaml_token_destroy(token); + yaml_token_clear(token); yaml_free(token); } @@ -725,10 +329,13 @@ yaml_token_duplicate(yaml_token_t *token, const yaml_token_t *model) { assert(token); /* Non-NULL token object is expected. */ assert(model); /* Non-NULL model token object is expected. */ + assert(!token->type); /* The token must be empty. */ memset(token, 0, sizeof(yaml_token_t)); token->type = model->type; + token->start_mark = model->start_mark; + token->end_mark = model->end_mark; switch (token->type) { @@ -789,17 +396,17 @@ yaml_token_duplicate(yaml_token_t *token, const yaml_token_t *model) return 1; error: - yaml_token_destroy(token); + yaml_token_clear(token); return 0; } /* - * Destroy a token object. + * Clear a token object. */ YAML_DECLARE(void) -yaml_token_destroy(yaml_token_t *token) +yaml_token_clear(yaml_token_t *token) { assert(token); /* Non-NULL token object expected. */ @@ -834,49 +441,9 @@ yaml_token_destroy(yaml_token_t *token) memset(token, 0, sizeof(yaml_token_t)); } -/* - * Check if a string is a valid UTF-8 sequence. - * - * Check 'reader.c' for more details on UTF-8 encoding. - */ - -static int -yaml_valid_utf8(const yaml_char_t *buffer, size_t length) -{ - size_t pointer = 0; - - while (pointer < length) { - unsigned char octet; - unsigned int width; - unsigned int value; - size_t k; - - octet = buffer[pointer]; - width = (octet & 0x80) == 0x00 ? 1 : - (octet & 0xE0) == 0xC0 ? 2 : - (octet & 0xF0) == 0xE0 ? 3 : - (octet & 0xF8) == 0xF0 ? 4 : 0; - value = (octet & 0x80) == 0x00 ? octet & 0x7F : - (octet & 0xE0) == 0xC0 ? octet & 0x1F : - (octet & 0xF0) == 0xE0 ? octet & 0x0F : - (octet & 0xF8) == 0xF0 ? octet & 0x07 : 0; - if (!width) return 0; - if (pointer+width > length) return 0; - for (k = 1; k < width; k ++) { - octet = buffer[pointer+k]; - if ((octet & 0xC0) != 0x80) return 0; - value = (value << 6) + (octet & 0x3F); - } - if (!((width == 1) || - (width == 2 && value >= 0x80) || - (width == 3 && value >= 0x800) || - (width == 4 && value >= 0x10000))) return 0; - - pointer += width; - } - - return 1; -} +/***************************************************************************** + * Event API + *****************************************************************************/ /* * Allocate an event object. @@ -904,7 +471,7 @@ yaml_event_delete(yaml_event_t *event) { assert(event); /* Non-NULL event object expected. */ - yaml_event_destroy(event); + yaml_event_clear(event); yaml_free(event); } @@ -921,10 +488,13 @@ yaml_event_duplicate(yaml_event_t *event, const yaml_event_t *model) assert(event); /* Non-NULL event object is expected. */ assert(model); /* Non-NULL model event object is expected. */ + assert(!event->type); /* The event must be empty. */ memset(event, 0, sizeof(yaml_event_t)); event->type = model->type; + event->start_mark = model->start_mark; + event->end_mark = model->end_mark; switch (event->type) { @@ -988,10 +558,10 @@ yaml_event_duplicate(yaml_event_t *event, const yaml_event_t *model) memcpy(event->data.scalar.value, model->data.scalar.value, model->data.scalar.length+1); event->data.scalar.length = model->data.scalar.length; - event->data.scalar.is_plain_implicit = - model->data.scalar.is_plain_implicit; - event->data.scalar.is_quoted_implicit = - model->data.scalar.is_quoted_implicit; + event->data.scalar.is_plain_nonspecific = + model->data.scalar.is_plain_nonspecific; + event->data.scalar.is_quoted_nonspecific = + model->data.scalar.is_quoted_nonspecific; event->data.scalar.style = model->data.scalar.style; break; @@ -1004,8 +574,8 @@ yaml_event_duplicate(yaml_event_t *event, const yaml_event_t *model) !(event->data.sequence_start.tag = yaml_strdup(model->data.sequence_start.tag))) goto error; - event->data.sequence_start.is_implicit = - model->data.sequence_start.is_implicit; + event->data.sequence_start.is_nonspecific = + model->data.sequence_start.is_nonspecific; event->data.sequence_start.style = model->data.sequence_start.style; break; @@ -1019,8 +589,8 @@ yaml_event_duplicate(yaml_event_t *event, const yaml_event_t *model) !(event->data.mapping_start.tag = yaml_strdup(model->data.mapping_start.tag))) goto error; - event->data.mapping_start.is_implicit = - model->data.mapping_start.is_implicit; + event->data.mapping_start.is_nonspecific = + model->data.mapping_start.is_nonspecific; event->data.mapping_start.style = model->data.mapping_start.style; break; @@ -1032,12 +602,65 @@ yaml_event_duplicate(yaml_event_t *event, const yaml_event_t *model) return 1; error: - yaml_event_destroy(event); + yaml_event_clear(event); return 0; } /* + * Clear an event object. + */ + +YAML_DECLARE(void) +yaml_event_clear(yaml_event_t *event) +{ + struct { + yaml_error_t error; + } self; + + assert(event); /* Non-NULL event object expected. */ + + switch (event->type) + { + case YAML_DOCUMENT_START_EVENT: + yaml_free(event->data.document_start.version_directive); + while (!STACK_EMPTY(&self, event->data.document_start.tag_directives)) { + yaml_tag_directive_t value = POP(&self, + event->data.document_start.tag_directives); + yaml_free(value.handle); + yaml_free(value.prefix); + } + STACK_DEL(&self, event->data.document_start.tag_directives); + break; + + case YAML_ALIAS_EVENT: + yaml_free(event->data.alias.anchor); + break; + + case YAML_SCALAR_EVENT: + yaml_free(event->data.scalar.anchor); + yaml_free(event->data.scalar.tag); + yaml_free(event->data.scalar.value); + break; + + case YAML_SEQUENCE_START_EVENT: + yaml_free(event->data.sequence_start.anchor); + yaml_free(event->data.sequence_start.tag); + break; + + case YAML_MAPPING_START_EVENT: + yaml_free(event->data.mapping_start.anchor); + yaml_free(event->data.mapping_start.tag); + break; + + default: + break; + } + + memset(event, 0, sizeof(yaml_event_t)); +} + +/* * Create STREAM-START. */ @@ -1048,6 +671,7 @@ yaml_event_create_stream_start(yaml_event_t *event, yaml_mark_t mark = { 0, 0, 0 }; assert(event); /* Non-NULL event object is expected. */ + assert(!event->type); /* The event must be empty. */ STREAM_START_EVENT_INIT(*event, encoding, mark, mark); @@ -1064,6 +688,7 @@ yaml_event_create_stream_end(yaml_event_t *event) yaml_mark_t mark = { 0, 0, 0 }; assert(event); /* Non-NULL event object is expected. */ + assert(!event->type); /* The event must be empty. */ STREAM_END_EVENT_INIT(*event, mark, mark); @@ -1077,8 +702,8 @@ yaml_event_create_stream_end(yaml_event_t *event) YAML_DECLARE(int) yaml_event_create_document_start(yaml_event_t *event, const yaml_version_directive_t *version_directive, - const yaml_tag_directive_t *tag_directives, - int is_implicit) + const yaml_tag_directive_t *tag_directives_list, + size_t tag_directives_length, int is_implicit) { struct { yaml_error_t error; @@ -1090,8 +715,10 @@ yaml_event_create_document_start(yaml_event_t *event, size_t length; size_t capacity; } tag_directives_copy = { NULL, 0, 0 }; + int idx; assert(event); /* Non-NULL event object is expected. */ + assert(!event->type); /* The event must be empty. */ if (version_directive) { version_directive_copy = yaml_malloc(sizeof(yaml_version_directive_t)); @@ -1099,22 +726,16 @@ yaml_event_create_document_start(yaml_event_t *event, *version_directive_copy = *version_directive; } - if (tag_directives && (tag_directives->handle || tag_directives->prefix)) { - if (!STACK_INIT(&self, tag_directives_copy, INITIAL_STACK_CAPACITY)) + if (tag_directives_list && tag_directives_length) { + if (!STACK_INIT(&self, tag_directives_copy, tag_directives_length)) goto error; - while (tag_directives->handle || tag_directives->prefix) { - yaml_tag_directive_t value = *tag_directives; + for (idx = 0; idx < tag_directives_length; idx++) { + yaml_tag_directive_t value = tag_directives_list[idx]; assert(value.handle); assert(value.prefix); - if (!yaml_valid_utf8(value.handle, strlen((char *)value.handle))) - goto error; - if (!yaml_valid_utf8(value.prefix, strlen((char *)value.prefix))) - goto error; - if (!PUSH(&self, tag_directives_copy, value)) - goto error; value.handle = yaml_strdup(value.handle); value.prefix = yaml_strdup(value.prefix); - tag_directives_copy.list[tag_directives_copy.length-1] = value; + PUSH(&self, tag_directives_copy, value); if (!value.handle || !value.prefix) goto error; } @@ -1148,6 +769,7 @@ yaml_event_create_document_end(yaml_event_t *event, int is_implicit) yaml_mark_t mark = { 0, 0, 0 }; assert(event); /* Non-NULL emitter object is expected. */ + assert(!event->type); /* The event must be empty. */ DOCUMENT_END_EVENT_INIT(*event, is_implicit, mark, mark); @@ -1165,10 +787,9 @@ yaml_event_create_alias(yaml_event_t *event, const yaml_char_t *anchor) yaml_char_t *anchor_copy = NULL; assert(event); /* Non-NULL event object is expected. */ + assert(!event->type); /* The event must be empty. */ assert(anchor); /* Non-NULL anchor is expected. */ - if (!yaml_valid_utf8(anchor, strlen((char *)anchor))) return 0; - anchor_copy = yaml_strdup(anchor); if (!anchor_copy) return 0; @@ -1185,8 +806,8 @@ yaml_event_create_alias(yaml_event_t *event, const yaml_char_t *anchor) YAML_DECLARE(int) yaml_event_create_scalar(yaml_event_t *event, const yaml_char_t *anchor, const yaml_char_t *tag, - const yaml_char_t *value, size_t length, - int is_plain_implicit, int is_quoted_implicit, + const yaml_char_t *value, int length, + int is_plain_nonspecific, int is_quoted_nonspecific, yaml_scalar_style_t style) { yaml_mark_t mark = { 0, 0, 0 }; @@ -1195,19 +816,16 @@ yaml_event_create_scalar(yaml_event_t *event, yaml_char_t *value_copy = NULL; assert(event); /* Non-NULL event object is expected. */ + assert(!event->type); /* The event must be empty. */ assert(value); /* Non-NULL anchor is expected. */ if (anchor) { - if (!yaml_valid_utf8(anchor, strlen((char *)anchor))) - goto error; anchor_copy = yaml_strdup(anchor); if (!anchor_copy) goto error; } if (tag) { - if (!yaml_valid_utf8(tag, strlen((char *)tag))) - goto error; tag_copy = yaml_strdup(tag); if (!tag_copy) goto error; @@ -1217,8 +835,6 @@ yaml_event_create_scalar(yaml_event_t *event, length = strlen((char *)value); } - if (!yaml_valid_utf8(value, length)) - goto error; value_copy = yaml_malloc(length+1); if (!value_copy) goto error; @@ -1226,7 +842,7 @@ yaml_event_create_scalar(yaml_event_t *event, value_copy[length] = '\0'; SCALAR_EVENT_INIT(*event, anchor_copy, tag_copy, value_copy, length, - is_plain_implicit, is_quoted_implicit, style, mark, mark); + is_plain_nonspecific, is_quoted_nonspecific, style, mark, mark); return 1; @@ -1245,32 +861,29 @@ error: YAML_DECLARE(int) yaml_event_create_sequence_start(yaml_event_t *event, const yaml_char_t *anchor, const yaml_char_t *tag, - int is_implicit, yaml_sequence_style_t style) + int is_nonspecific, yaml_sequence_style_t style) { yaml_mark_t mark = { 0, 0, 0 }; yaml_char_t *anchor_copy = NULL; yaml_char_t *tag_copy = NULL; assert(event); /* Non-NULL event object is expected. */ + assert(!event->type); /* The event must be empty. */ if (anchor) { - if (!yaml_valid_utf8(anchor, strlen((char *)anchor))) - goto error; anchor_copy = yaml_strdup(anchor); if (!anchor_copy) goto error; } if (tag) { - if (!yaml_valid_utf8(tag, strlen((char *)tag))) - goto error; tag_copy = yaml_strdup(tag); if (!tag_copy) goto error; } SEQUENCE_START_EVENT_INIT(*event, anchor_copy, tag_copy, - is_implicit, style, mark, mark); + is_nonspecific, style, mark, mark); return 1; @@ -1291,6 +904,7 @@ yaml_event_create_sequence_end(yaml_event_t *event) yaml_mark_t mark = { 0, 0, 0 }; assert(event); /* Non-NULL event object is expected. */ + assert(!event->type); /* The event must be empty. */ SEQUENCE_END_EVENT_INIT(*event, mark, mark); @@ -1304,32 +918,29 @@ yaml_event_create_sequence_end(yaml_event_t *event) YAML_DECLARE(int) yaml_event_create_mapping_start(yaml_event_t *event, const yaml_char_t *anchor, const yaml_char_t *tag, - int is_implicit, yaml_mapping_style_t style) + int is_nonspecific, yaml_mapping_style_t style) { yaml_mark_t mark = { 0, 0, 0 }; yaml_char_t *anchor_copy = NULL; yaml_char_t *tag_copy = NULL; assert(event); /* Non-NULL event object is expected. */ + assert(!event->type); /* The event must be empty. */ if (anchor) { - if (!yaml_valid_utf8(anchor, strlen((char *)anchor))) - goto error; anchor_copy = yaml_strdup(anchor); if (!anchor_copy) goto error; } if (tag) { - if (!yaml_valid_utf8(tag, strlen((char *)tag))) - goto error; tag_copy = yaml_strdup(tag); if (!tag_copy) goto error; } MAPPING_START_EVENT_INIT(*event, anchor_copy, tag_copy, - is_implicit, style, mark, mark); + is_nonspecific, style, mark, mark); return 1; @@ -1350,170 +961,176 @@ yaml_event_create_mapping_end(yaml_event_t *event) yaml_mark_t mark = { 0, 0, 0 }; assert(event); /* Non-NULL event object is expected. */ + assert(!event->type); /* The event must be empty. */ MAPPING_END_EVENT_INIT(*event, mark, mark); return 1; } +/***************************************************************************** + * Document API + *****************************************************************************/ + /* - * Destroy an event object. + * Allocate a document object. */ -YAML_DECLARE(void) -yaml_event_destroy(yaml_event_t *event) +YAML_DECLARE(yaml_document_t *) +yaml_document_new(void) { - struct { - yaml_error_t error; - } self; + yaml_document_t *document = yaml_malloc(sizeof(yaml_document_t)); - assert(event); /* Non-NULL event object expected. */ - - switch (event->type) - { - case YAML_DOCUMENT_START_EVENT: - yaml_free(event->data.document_start.version_directive); - while (!STACK_EMPTY(&self, event->data.document_start.tag_directives)) { - yaml_tag_directive_t value = POP(&self, - event->data.document_start.tag_directives); - yaml_free(value.handle); - yaml_free(value.prefix); - } - STACK_DEL(&self, event->data.document_start.tag_directives); - break; - - case YAML_ALIAS_EVENT: - yaml_free(event->data.alias.anchor); - break; + if (!document) + return NULL; - case YAML_SCALAR_EVENT: - yaml_free(event->data.scalar.anchor); - yaml_free(event->data.scalar.tag); - yaml_free(event->data.scalar.value); - break; + memset(document, 0, sizeof(yaml_document_t)); - case YAML_SEQUENCE_START_EVENT: - yaml_free(event->data.sequence_start.anchor); - yaml_free(event->data.sequence_start.tag); - break; + return document; +} - case YAML_MAPPING_START_EVENT: - yaml_free(event->data.mapping_start.anchor); - yaml_free(event->data.mapping_start.tag); - break; +/* + * Deallocate a document object. + */ - default: - break; - } +YAML_DECLARE(void) +yaml_document_delete(yaml_document_t *document) +{ + assert(document); /* Non-NULL document object is expected. */ - memset(event, 0, sizeof(yaml_event_t)); + yaml_document_clear(document); + yaml_free(document); } -#if 0 - /* - * Create a document object. + * Duplicate a document object. */ YAML_DECLARE(int) -yaml_document_initialize(yaml_document_t *document, - yaml_version_directive_t *version_directive, - yaml_tag_directive_t *tag_directives_start, - yaml_tag_directive_t *tag_directives_end, - int start_implicit, int end_implicit) +yaml_document_duplicate(yaml_document_t *document, yaml_document_t *model) { struct { - yaml_error_type_t error; - } context; - struct { - yaml_node_t *start; - yaml_node_t *end; - yaml_node_t *top; - } nodes = { NULL, NULL, NULL }; - yaml_version_directive_t *version_directive_copy = NULL; - struct { - yaml_tag_directive_t *start; - yaml_tag_directive_t *end; - yaml_tag_directive_t *top; - } tag_directives_copy = { NULL, NULL, NULL }; - yaml_tag_directive_t value = { NULL, NULL }; - yaml_mark_t mark = { 0, 0, 0 }; + yaml_error_t error; + } self; + yaml_char_t *anchor = NULL; + yaml_char_t *tag = NULL; + yaml_char_t *value = NULL; + yaml_node_item_t *item_list = NULL; + yaml_node_pair_t *pair_list = NULL; + int idx; - assert(document); /* Non-NULL document object is expected. */ - assert((tag_directives_start && tag_directives_end) || - (tag_directives_start == tag_directives_end)); - /* Valid tag directives are expected. */ + assert(document); /* Non-NULL document object is expected. */ + assert(!document->type); /* The document must be empty. */ + assert(model); /* Non-NULL model object is expected. */ - if (!STACK_INIT(&context, nodes, INITIAL_STACK_SIZE)) goto error; + if (model->type != YAML_DOCUMENT) + return 1; - if (version_directive) { - version_directive_copy = yaml_malloc(sizeof(yaml_version_directive_t)); - if (!version_directive_copy) goto error; - version_directive_copy->major = version_directive->major; - version_directive_copy->minor = version_directive->minor; - } + if (!yaml_document_create(document, model->version_directive, + model->tag_directives.list, model->tag_directives.length, + model->is_start_implicit, model->is_end_implicit)) + return 0; - if (tag_directives_start != tag_directives_end) { - yaml_tag_directive_t *tag_directive; - if (!STACK_INIT(&context, tag_directives_copy, INITIAL_STACK_SIZE)) - goto error; - for (tag_directive = tag_directives_start; - tag_directive != tag_directives_end; tag_directive ++) { - assert(tag_directive->handle); - assert(tag_directive->prefix); - if (!yaml_valid_utf8(tag_directive->handle, - strlen((char *)tag_directive->handle))) - goto error; - if (!yaml_valid_utf8(tag_directive->prefix, - strlen((char *)tag_directive->prefix))) - goto error; - value.handle = yaml_strdup(tag_directive->handle); - value.prefix = yaml_strdup(tag_directive->prefix); - if (!value.handle || !value.prefix) goto error; - if (!PUSH(&context, tag_directives_copy, value)) - goto error; - value.handle = NULL; - value.prefix = NULL; + document->start_mark = model->start_mark; + document->end_mark = model->end_mark; + + for (idx = 0; idx < model->nodes.length; idx++) + { + yaml_node_t *node = STACK_ITER(&self, model->nodes, idx); + yaml_node_t copy; + if (node->anchor) { + anchor = yaml_strdup(node->anchor); + if (!anchor) goto error; } - } + tag = yaml_strdup(node->tag); + if (!tag) goto error; + switch (node->type) + { + case YAML_SCALAR_NODE: + value = yaml_malloc(node->data.scalar.length+1); + if (!value) + goto error; + memcpy(value, node->data.scalar.value, + node->data.scalar.length); + value[node->data.scalar.length] = '\0'; + SCALAR_NODE_INIT(copy, anchor, tag, value, + node->data.scalar.length, node->data.scalar.style, + node->start_mark, node->end_mark); + break; - DOCUMENT_INIT(*document, nodes.start, nodes.end, version_directive_copy, - tag_directives_copy.start, tag_directives_copy.top, - start_implicit, end_implicit, mark, mark); + case YAML_SEQUENCE_NODE: + item_list = yaml_malloc(node->data.sequence.items.capacity + * sizeof(yaml_node_item_t)); + if (!item_list) goto error; + memcpy(item_list, node->data.sequence.items.list, + node->data.sequence.items.capacity + * sizeof(yaml_node_item_t)); + SEQUENCE_NODE_INIT(copy, anchor, tag, item_list, + node->data.sequence.items.length, + node->data.sequence.items.capacity, + node->data.sequence.style, + node->start_mark, node->end_mark); + break; - return 1; + case YAML_MAPPING_NODE: + pair_list = yaml_malloc(node->data.mapping.pairs.capacity + * sizeof(yaml_node_pair_t)); + if (!pair_list) goto error; + memcpy(pair_list, node->data.mapping.pairs.list, + node->data.mapping.pairs.capacity + * sizeof(yaml_node_pair_t)); + MAPPING_NODE_INIT(copy, anchor, tag, pair_list, + node->data.mapping.pairs.length, + node->data.mapping.pairs.capacity, + node->data.mapping.style, + node->start_mark, node->end_mark); + break; -error: - STACK_DEL(&context, nodes); - yaml_free(version_directive_copy); - while (!STACK_EMPTY(&context, tag_directives_copy)) { - yaml_tag_directive_t value = POP(&context, tag_directives_copy); - yaml_free(value.handle); - yaml_free(value.prefix); + default: + assert(0); /* Should never happen. */ + } + + if (!PUSH(&self, document->nodes, copy)) + goto error; + + anchor = NULL; + tag = NULL; + value = NULL; + item_list = NULL; + pair_list = NULL; } - STACK_DEL(&context, tag_directives_copy); - yaml_free(value.handle); - yaml_free(value.prefix); + +error: + yaml_free(anchor); + yaml_free(tag); + yaml_free(value); + yaml_free(item_list); + yaml_free(pair_list); + + yaml_document_clear(document); return 0; } /* - * Destroy a document object. + * Clear a document object. */ YAML_DECLARE(void) -yaml_document_delete(yaml_document_t *document) +yaml_document_clear(yaml_document_t *document) { struct { yaml_error_type_t error; - } context; + } self; yaml_tag_directive_t *tag_directive; - context.error = YAML_NO_ERROR; /* Eliminate a compliler warning. */ + self.error = YAML_NO_ERROR; /* Eliminate a compliler warning. */ assert(document); /* Non-NULL document object is expected. */ + if (!document->type) + return; + while (!STACK_EMPTY(&context, document->nodes)) { yaml_node_t node = POP(&context, document->nodes); yaml_free(node.tag); @@ -1531,46 +1148,112 @@ yaml_document_delete(yaml_document_t *document) assert(0); /* Should not happen. */ } } - STACK_DEL(&context, document->nodes); + STACK_DEL(&self, document->nodes); yaml_free(document->version_directive); - for (tag_directive = document->tag_directives.start; - tag_directive != document->tag_directives.end; - tag_directive++) { - yaml_free(tag_directive->handle); - yaml_free(tag_directive->prefix); + while (!STACK_EMPTY(&self, document->tag_directives)) { + yaml_tag_directive_t tag_directive = POP(&self, document->tag_directives); + yaml_free(tag_directive.handle); + yaml_free(tag_directive.prefix); } - yaml_free(document->tag_directives.start); + STACK_DEL(&self, document->tag_directives); memset(document, 0, sizeof(yaml_document_t)); } -/** - * Get a document node. +/* + * Create a document. */ -YAML_DECLARE(yaml_node_t *) -yaml_document_get_node(yaml_document_t *document, int index) +YAML_DECLARE(int) +yaml_document_create(yaml_document_t *document, + const yaml_version_directive_t *version_directive, + const yaml_tag_directive_t *tag_directives_list, + size_t tag_directives_length, + int is_start_implicit, int is_end_implicit) { - assert(document); /* Non-NULL document object is expected. */ + struct { + yaml_error_t error; + } self; + yaml_mark_t mark = { 0, 0, 0 }; + struct { + yaml_node_t *list; + size_t length; + size_t capacity; + } nodes; + yaml_version_directive_t *version_directive_copy = NULL; + struct { + yaml_tag_directive_t *list; + size_t length; + size_t capacity; + } tag_directives_copy = { NULL, 0, 0 }; + int idx; - if (index > 0 && document->nodes.start + index <= document->nodes.top) { - return document->nodes.start + index - 1; + assert(document); /* Non-NULL event object is expected. */ + assert(!document->type); /* The document must be empty. */ + + if (!STACK_INIT(&self, nodes, INITIAL_STACK_CAPACITY)) + goto error; + + if (version_directive) { + version_directive_copy = yaml_malloc(sizeof(yaml_version_directive_t)); + if (!version_directive_copy) goto error; + *version_directive_copy = *version_directive; } - return NULL; + + if (tag_directives_list && tag_directives_length) { + if (!STACK_INIT(&self, tag_directives_copy, tag_directives_length)) + goto error; + for (idx = 0; idx < tag_directives_length; idx++) { + yaml_tag_directive_t value = tag_directives_list[idx]; + assert(value.handle); + assert(value.prefix); + value.handle = yaml_strdup(value.handle); + value.prefix = yaml_strdup(value.prefix); + PUSH(&self, tag_directives_copy, value); + if (!value.handle || !value.prefix) + goto error; + } + } + + DOCUMENT_INIT(*document, nodes.list, nodes.length, nodes.capacity, + version_directive_copy, tag_directives_copy.list, + tag_directives_copy.length, tag_directives_copy.capacity, + is_start_implicit, is_end_implicit, mark, mark); + + return 1; + +error: + STACK_DEL(&self, nodes); + + yaml_free(version_directive_copy); + + while (!STACK_EMPTY(&self, tag_directives_copy)) { + yaml_tag_directive_t value = POP(&self, tag_directives_copy); + yaml_free(value.handle); + yaml_free(value.prefix); + } + STACK_DEL(&self, tag_directives_copy); + + return 0; } -/** - * Get the root object. +/* + * Get a document node. */ YAML_DECLARE(yaml_node_t *) -yaml_document_get_root_node(yaml_document_t *document) +yaml_document_get_node(yaml_document_t *document, int node_id) { assert(document); /* Non-NULL document object is expected. */ + assert(document->type); /* Initialized document is expected. */ + + if (node_id < 0) { + node_id += document->nodes.length; + } - if (document->nodes.top != document->nodes.start) { - return document->nodes.start; + if (node_id >= 0 && node_id < document->nodes.length) { + return document->nodes.list + node_id; } return NULL; } @@ -1580,26 +1263,30 @@ yaml_document_get_root_node(yaml_document_t *document) */ YAML_DECLARE(int) -yaml_document_add_scalar(yaml_document_t *document, - yaml_char_t *tag, yaml_char_t *value, int length, +yaml_document_add_scalar(yaml_document_t *document, int *node_id, + const yaml_char_t *anchor, const yaml_char_t *tag, + const yaml_char_t *value, int length, yaml_scalar_style_t style) { struct { - yaml_error_type_t error; - } context; + yaml_error_t error; + } self; yaml_mark_t mark = { 0, 0, 0 }; + yaml_char_t *anchor_copy = NULL; yaml_char_t *tag_copy = NULL; yaml_char_t *value_copy = NULL; yaml_node_t node; assert(document); /* Non-NULL document object is expected. */ + assert(document->type); /* Initialized document is required. */ + assert(tag); /* Non-NULL tag is expected. */ assert(value); /* Non-NULL value is expected. */ - if (!tag) { - tag = (yaml_char_t *)YAML_DEFAULT_SCALAR_TAG; + if (anchor) { + anchor_copy = yaml_strdup(anchor); + if (!anchor_copy) goto error; } - if (!yaml_valid_utf8(tag, strlen((char *)tag))) goto error; tag_copy = yaml_strdup(tag); if (!tag_copy) goto error; @@ -1607,18 +1294,23 @@ yaml_document_add_scalar(yaml_document_t *document, length = strlen((char *)value); } - if (!yaml_valid_utf8(value, length)) goto error; value_copy = yaml_malloc(length+1); if (!value_copy) goto error; memcpy(value_copy, value, length); value_copy[length] = '\0'; - SCALAR_NODE_INIT(node, tag_copy, value_copy, length, style, mark, mark); - if (!PUSH(&context, document->nodes, node)) goto error; + SCALAR_NODE_INIT(node, anchor_copy, tag_copy, value_copy, length, + style, mark, mark); + if (!PUSH(&self, document->nodes, node)) goto error; - return document->nodes.top - document->nodes.start; + if (node_id) { + *node_id = document->nodes.length-1; + } + + return 1; error: + yaml_free(anchor_copy); yaml_free(tag_copy); yaml_free(value_copy); @@ -1630,41 +1322,50 @@ error: */ YAML_DECLARE(int) -yaml_document_add_sequence(yaml_document_t *document, - yaml_char_t *tag, yaml_sequence_style_t style) +yaml_document_add_sequence(yaml_document_t *document, int *node_id, + const yaml_char_t *anchor, const yaml_char_t *tag, + yaml_sequence_style_t style) { struct { - yaml_error_type_t error; - } context; + yaml_error_t error; + } self; yaml_mark_t mark = { 0, 0, 0 }; + yaml_char_t *anchor_copy = NULL; yaml_char_t *tag_copy = NULL; struct { - yaml_node_item_t *start; - yaml_node_item_t *end; - yaml_node_item_t *top; - } items = { NULL, NULL, NULL }; + yaml_node_item_t *list; + size_t length; + size_t capacity; + } items = { NULL, 0, 0 }; yaml_node_t node; assert(document); /* Non-NULL document object is expected. */ + assert(document->type); /* Initialized document is required. */ + assert(tag); /* Non-NULL tag is expected. */ - if (!tag) { - tag = (yaml_char_t *)YAML_DEFAULT_SEQUENCE_TAG; + if (anchor) { + anchor_copy = yaml_strdup(anchor); + if (!anchor_copy) goto error; } - if (!yaml_valid_utf8(tag, strlen((char *)tag))) goto error; tag_copy = yaml_strdup(tag); if (!tag_copy) goto error; - if (!STACK_INIT(&context, items, INITIAL_STACK_SIZE)) goto error; + if (!STACK_INIT(&self, items, INITIAL_STACK_CAPACITY)) goto error; - SEQUENCE_NODE_INIT(node, tag_copy, items.start, items.end, - style, mark, mark); - if (!PUSH(&context, document->nodes, node)) goto error; + SEQUENCE_NODE_INIT(node, anchor_copy, tag_copy, + items.list, items.length, items.capacity, style, mark, mark); + if (!PUSH(&self, document->nodes, node)) goto error; - return document->nodes.top - document->nodes.start; + if (node_id) { + *node_id = document->nodes.length-1; + } + + return 1; error: - STACK_DEL(&context, items); + STACK_DEL(&self, items); + yaml_free(anchor_copy); yaml_free(tag_copy); return 0; @@ -1675,41 +1376,50 @@ error: */ YAML_DECLARE(int) -yaml_document_add_mapping(yaml_document_t *document, - yaml_char_t *tag, yaml_mapping_style_t style) +yaml_document_add_mapping(yaml_document_t *document, int *node_id, + const yaml_char_t *anchor, const yaml_char_t *tag, + yaml_mapping_style_t style) { struct { - yaml_error_type_t error; - } context; + yaml_error_t error; + } self; yaml_mark_t mark = { 0, 0, 0 }; + yaml_char_t *anchor_copy = NULL; yaml_char_t *tag_copy = NULL; struct { - yaml_node_pair_t *start; - yaml_node_pair_t *end; - yaml_node_pair_t *top; - } pairs = { NULL, NULL, NULL }; + yaml_node_pair_t *list; + size_t length; + size_t capacity; + } pairs = { NULL, 0, 0 }; yaml_node_t node; assert(document); /* Non-NULL document object is expected. */ + assert(document->type); /* Initialized document is required. */ + assert(tag); /* Non-NULL tag is expected. */ - if (!tag) { - tag = (yaml_char_t *)YAML_DEFAULT_MAPPING_TAG; + if (anchor) { + anchor_copy = yaml_strdup(anchor); + if (!anchor_copy) goto error; } - if (!yaml_valid_utf8(tag, strlen((char *)tag))) goto error; tag_copy = yaml_strdup(tag); if (!tag_copy) goto error; - if (!STACK_INIT(&context, pairs, INITIAL_STACK_SIZE)) goto error; + if (!STACK_INIT(&self, pairs, INITIAL_STACK_CAPACITY)) goto error; - MAPPING_NODE_INIT(node, tag_copy, pairs.start, pairs.end, - style, mark, mark); - if (!PUSH(&context, document->nodes, node)) goto error; + MAPPING_NODE_INIT(node, anchor_copy, tag_copy, + pairs.list, pairs.length, pairs.capacity, style, mark, mark); + if (!PUSH(&self, document->nodes, node)) goto error; + + if (node_id) { + *node_id = document->nodes.length-1; + } - return document->nodes.top - document->nodes.start; + return 1; error: - STACK_DEL(&context, pairs); + STACK_DEL(&self, pairs); + yaml_free(anchor_copy); yaml_free(tag_copy); return 0; @@ -1721,23 +1431,31 @@ error: YAML_DECLARE(int) yaml_document_append_sequence_item(yaml_document_t *document, - int sequence, int item) + int sequence_id, int item_id) { struct { - yaml_error_type_t error; - } context; + yaml_error_t error; + } self; assert(document); /* Non-NULL document is required. */ - assert(sequence > 0 - && document->nodes.start + sequence <= document->nodes.top); + assert(document->type); /* Initialized document is expected. */ + + if (sequence_id) { + sequence_id += document->nodes.length; + } + if (item_id) { + item_id += document->nodes.length; + } + + assert(sequence_id >= 0 && sequence_id < document->nodes.length); /* Valid sequence id is required. */ - assert(document->nodes.start[sequence-1].type == YAML_SEQUENCE_NODE); - /* A sequence node is required. */ - assert(item > 0 && document->nodes.start + item <= document->nodes.top); + assert(item_id >= 0 && item_id < document->nodes.length); /* Valid item id is required. */ + assert(document->nodes.list[sequence_id].type == YAML_SEQUENCE_NODE); + /* A sequence node is expected. */ - if (!PUSH(&context, - document->nodes.start[sequence-1].data.sequence.items, item)) + if (!PUSH(&self, + document->nodes.list[sequence_id].data.sequence.items, item_id)) return 0; return 1; @@ -1749,30 +1467,1216 @@ yaml_document_append_sequence_item(yaml_document_t *document, YAML_DECLARE(int) yaml_document_append_mapping_pair(yaml_document_t *document, - int mapping, int key, int value) + int mapping_id, int key_id, int value_id) { struct { - yaml_error_type_t error; - } context; - yaml_node_pair_t pair = { key, value }; + yaml_error_t error; + } self; + yaml_node_pair_t pair = { key_id, value_id }; assert(document); /* Non-NULL document is required. */ - assert(mapping > 0 - && document->nodes.start + mapping <= document->nodes.top); + assert(document->type); /* Initialized document is expected. */ + + if (mapping_id < 0) { + mapping_id += document->nodes.length; + } + if (key_id < 0) { + key_id += document->nodes.length; + } + if (value_id < 0) { + value_id += document->nodes.length; + } + + assert(mapping_id >= 0 && mapping_id < document->nodes.length); /* Valid mapping id is required. */ - assert(document->nodes.start[mapping-1].type == YAML_MAPPING_NODE); - /* A mapping node is required. */ - assert(key > 0 && document->nodes.start + key <= document->nodes.top); + assert(key_id >= 0 && key_id < document->nodes.length); /* Valid key id is required. */ - assert(value > 0 && document->nodes.start + value <= document->nodes.top); + assert(value_id >= 0 && value_id < document->nodes.length); /* Valid value id is required. */ + assert(document->nodes.list[mapping_id].type == YAML_MAPPING_NODE); + /* A mapping node is expected. */ - if (!PUSH(&context, - document->nodes.start[mapping-1].data.mapping.pairs, pair)) + if (!PUSH(&self, + document->nodes.list[mapping_id].data.mapping.pairs, pair)) return 0; return 1; } -#endif +/* + * Ensure that the node is a `!!null` SCALAR node. + */ + +YAML_DECLARE(int) +yaml_document_get_null_node(yaml_document_t *document, int node_id) +{ + yaml_node_t *node; + yaml_char_t *scalar; + + assert(document); /* Non-NULL document is required. */ + assert(document->type); /* Initialized document is expected. */ + + if (node_id < 0) { + node_id += document->nodes.length; + } + + assert(node_id >= 0 && node_id < document->nodes.length); + /* Valid node id is required. */ + + node = document->nodes.list + node_id; + + if (node->type != YAML_SCALAR_NODE) + return 0; + + if (strcmp(node->tag, YAML_NULL_TAG)) + return 0; + + if (node->data.scalar.length != strlen(node->data.scalar.value)) + return 0; + + scalar = node->data.scalar.value; + + if (!strcmp(scalar, "") || !strcmp(scalar, "~") || !strcmp(scalar, "null") + || !strcmp(scalar, "Null") || !strcmp(scalar, "NULL")) + return 1; + + return 0; +} + +/* + * Ensure that the node is a `!!bool` SCALAR node. + */ + +YAML_DECLARE(int) +yaml_document_get_bool_node(yaml_document_t *document, int node_id, int *value) +{ + yaml_node_t *node; + yaml_char_t *scalar; + + assert(document); /* Non-NULL document is required. */ + assert(document->type); /* Initialized document is expected. */ + + if (node_id < 0) { + node_id += document->nodes.length; + } + + assert(node_id >= 0 && node_id < document->nodes.length); + /* Valid node id is required. */ + + node = document->nodes.list + node_id; + + if (node->type != YAML_SCALAR_NODE) + return 0; + + if (strcmp(node->tag, YAML_BOOL_TAG)) + return 0; + + if (node->data.scalar.length != strlen(node->data.scalar.value)) + return 0; + + scalar = node->data.scalar.value; + + if (!strcmp(scalar, "yes") || !strcmp(scalar, "Yes") || !strcmp(scalar, "YES") || + !strcmp(scalar, "true") || !strcmp(scalar, "True") || !strcmp(scalar, "TRUE") || + !strcmp(scalar, "on") || !strcmp(scalar, "On") || !strcmp(scalar, "ON")) { + if (value) { + *value = 1; + } + return 1; + } + + if (!strcmp(scalar, "no") || !strcmp(scalar, "No") || !strcmp(scalar, "NO") || + !strcmp(scalar, "false") || !strcmp(scalar, "False") || !strcmp(scalar, "FALSE") || + !strcmp(scalar, "off") || !strcmp(scalar, "Off") || !strcmp(scalar, "OFF")) { + if (value) { + *value = 0; + } + return 1; + } + + return 0; +} + +/* + * Ensure that the node is a `!!str` SCALAR node. + */ + +YAML_DECLARE(int) +yaml_document_get_str_node(yaml_document_t *document, int node_id, + char **value) +{ + yaml_node_t *node; + + assert(document); /* Non-NULL document is required. */ + assert(document->type); /* Initialized document is expected. */ + + if (node_id < 0) { + node_id += document->nodes.length; + } + + assert(node_id >= 0 && node_id < document->nodes.length); + /* Valid node id is required. */ + + node = document->nodes.list + node_id; + + if (node->type != YAML_SCALAR_NODE) + return 0; + + if (strcmp(node->tag, YAML_STR_TAG)) + return 0; + + if (node->data.scalar.length != strlen(node->data.scalar.value)) + return 0; + + if (value) { + *value = node->data.scalar.value; + } + + return 1; +} + +/* + * Ensure that the node is an `!!int` SCALAR node. + */ + +YAML_DECLARE(int) +yaml_document_get_int_node(yaml_document_t *document, int node_id, + long *value) +{ + yaml_node_t *node; + yaml_char_t *scalar; + char *tail; + long integer; + int old_errno = errno, new_errno; + + assert(document); /* Non-NULL document is required. */ + assert(document->type); /* Initialized document is expected. */ + + if (node_id < 0) { + node_id += document->nodes.length; + } + + assert(node_id >= 0 && node_id < document->nodes.length); + /* Valid node id is required. */ + + node = document->nodes.list + node_id; + + if (node->type != YAML_SCALAR_NODE) + return 0; + + if (strcmp(node->tag, YAML_INT_TAG)) + return 0; + + if (node->data.scalar.length != strlen(node->data.scalar.value)) + return 0; + + if (!node->data.scalar.length) + return 0; + + scalar = node->data.scalar.value; + + errno = 0; + + integer = strtol((char *)scalar, &tail, 0); + + new_errno = errno; + errno = old_errno; + + if (new_errno || *tail) { + return 0; + } + + if (value) { + *value = integer; + } + + return 1; +} + +/* + * Ensure that the node is a `!!float` SCALAR node. + */ + +YAML_DECLARE(int) +yaml_document_get_float_node(yaml_document_t *document, int node_id, + double *value) +{ + yaml_node_t *node; + yaml_char_t *scalar; + char buffer[128]; + char *pointer; + char *tail; + double real; + int old_errno = errno, new_errno; + char decimal_point = localeconv()->decimal_point[0]; + + assert(document); /* Non-NULL document is required. */ + assert(document->type); /* Initialized document is expected. */ + + if (node_id < 0) { + node_id += document->nodes.length; + } + + assert(node_id >= 0 && node_id < document->nodes.length); + /* Valid node id is required. */ + + node = document->nodes.list + node_id; + + if (node->type != YAML_SCALAR_NODE) + return 0; + + if (strcmp(node->tag, YAML_FLOAT_TAG) && strcmp(node->tag, YAML_INT_TAG)) + return 0; + + if (node->data.scalar.length != strlen(node->data.scalar.value)) + return 0; + + if (!node->data.scalar.length) + return 0; + + scalar = node->data.scalar.value; + + if (!strcmp(scalar, ".nan") || !strcmp(scalar, ".NaN") || !strcmp(scalar, ".NAN")) { + if (value) { + *value = 0.0/0.0; + } + return 1; + } + + if (!strcmp(scalar, ".inf") || !strcmp(scalar, ".Inf") || !strcmp(scalar, ".INF") || + !strcmp(scalar, "+.inf") || !strcmp(scalar, "+.Inf") || !strcmp(scalar, "+.INF")) { + if (value) { + *value = 1.0/0.0; + } + return 1; + } + + if (!strcmp(scalar, "-.inf") || !strcmp(scalar, "-.Inf") || !strcmp(scalar, "-.INF")) { + if (value) { + *value = -1.0/0.0; + } + return 1; + } + + if (strlen(scalar) >= sizeof(buffer)) + return 0; + + strcpy(buffer, (const char *)scalar); + + /* Replace a locale-dependent decimal point with a dot. */ + + for (pointer = buffer; *pointer; pointer++) { + if (*pointer == decimal_point) { + *pointer = '.'; + break; + } + } + + errno = 0; + + real = strtod(buffer, &tail); + + new_errno = errno; + errno = old_errno; + + if (new_errno || *tail) { + return 0; + } + + if (value) { + *value = real; + } + + return 1; +} + +/* + * Ensure that the node is a `!!seq` SEQUENCE node. + */ + +YAML_DECLARE(int) +yaml_document_get_seq_node(yaml_document_t *document, int node_id, + yaml_node_item_t **items, size_t *length) +{ + yaml_node_t *node; + + assert(document); /* Non-NULL document is required. */ + assert(document->type); /* Initialized document is expected. */ + + assert((items && length) || (!items && !length)); + /* items and length must be equal to NULL simultaneously. */ + + if (node_id < 0) { + node_id += document->nodes.length; + } + + assert(node_id >= 0 && node_id < document->nodes.length); + /* Valid node id is required. */ + + node = document->nodes.list + node_id; + + if (node->type != YAML_SEQUENCE_NODE) + return 0; + + if (strcmp(node->tag, YAML_SEQ_TAG)) + return 0; + + if (items && length) { + *items = node->data.sequence.items.list; + *length = node->data.sequence.items.length; + } + + return 1; +} + +/* + * Ensure that the node is a `!!map` MAPPING node. + */ + +YAML_DECLARE(int) +yaml_document_get_map_node(yaml_document_t *document, int node_id, + yaml_node_pair_t **pairs, size_t *length) +{ + yaml_node_t *node; + + assert(document); /* Non-NULL document is required. */ + assert(document->type); /* Initialized document is expected. */ + + assert((pairs && length) || (!pairs && !length)); + /* pairs and length must be equal to NULL simultaneously. */ + + if (node_id < 0) { + node_id += document->nodes.length; + } + + assert(node_id >= 0 && node_id < document->nodes.length); + /* Valid node id is required. */ + + node = document->nodes.list + node_id; + + if (node->type != YAML_MAPPING_NODE) + return 0; + + if (strcmp(node->tag, YAML_MAP_TAG)) + return 0; + + if (pairs && length) { + *pairs = node->data.mapping.pairs.list; + *length = node->data.mapping.pairs.length; + } + + return 1; +} + +/* + * Add a `!!null` SCALAR node. + */ + +YAML_DECLARE(int) +yaml_document_add_null_node(yaml_document_t *document, int *node_id) +{ + return yaml_document_add_scalar(document, node_id, NULL, + YAML_NULL_TAG, "null", -1, YAML_ANY_SCALAR_STYLE); +} + +/* + * Add a `!!bool` SCALAR node. + */ + +YAML_DECLARE(int) +yaml_document_add_bool_node(yaml_document_t *document, int *node_id, + int value) +{ + return yaml_document_add_scalar(document, node_id, NULL, YAML_BOOL_TAG, + (value ? "true" : "false"), -1, YAML_ANY_SCALAR_STYLE); +} + +/* + * Add a `!!str` SCALAR node. + */ + +YAML_DECLARE(int) +yaml_document_add_str_node(yaml_document_t *document, int *node_id, + const char *value) +{ + return yaml_document_add_scalar(document, node_id, NULL, YAML_STR_TAG, + (const yaml_char_t *) value, -1, YAML_ANY_SCALAR_STYLE); +} + +/* + * Add an `!!int` SCALAR node. + */ + +YAML_DECLARE(int) +yaml_document_add_int_node(yaml_document_t *document, int *node_id, + long value) +{ + char buffer[128]; /* 128 bytes should be enough for everybody. */ + int length; + + length = snprintf(buffer, sizeof(buffer), "%ld", value); + if (length < 0 || length >= sizeof(buffer)) return 0; + + return yaml_document_add_scalar(document, node_id, NULL, YAML_INT_TAG, + (const yaml_char_t *) buffer, -1, YAML_ANY_SCALAR_STYLE); +} + +/* + * Add a `!!float` SCALAR node. + */ + +YAML_DECLARE(int) +yaml_document_add_float_node(yaml_document_t *document, int *node_id, + double value) +{ + char buffer[128]; /* 128 bytes should be enough for everybody. */ + char *pointer; + int length; + char decimal_point = *localeconv()->decimal_point; + + length = snprintf(buffer, sizeof(buffer), "%.12g", value); + /* .12 is a reasonable precision; it is used by str(float) in Python. */ + if (length < 0 || length >= sizeof(buffer)-3) return 0; + + /* Replace a locale-dependent decimal point with a dot. */ + + for (pointer = buffer; *pointer; pointer++) { + if (*pointer == decimal_point) { + *pointer = '.'; + break; + } + } + + /* Check if the formatted number contains a decimal dot. */ + + for (pointer = buffer; *pointer; pointer++) { + if (*pointer != '+' && *pointer != '-' && !isdigit(*pointer)) { + break; + } + } + + /* Add .0 at the end of the buffer if needed. */ + + if (!*pointer) { + *(pointer++) = '.'; + *(pointer++) = '0'; + *(pointer++) = '\0'; + } + + return yaml_document_add_scalar(document, node_id, NULL, YAML_FLOAT_TAG, + (const yaml_char_t *) buffer, -1, YAML_ANY_SCALAR_STYLE); +} + +/* + * Add a `!!seq` SEQUENCE node. + */ + +YAML_DECLARE(int) +yaml_document_add_seq_node(yaml_document_t *document, int *node_id) +{ + return yaml_document_add_sequence(document, node_id, NULL, + YAML_SEQ_TAG, YAML_ANY_SEQUENCE_STYLE); +} + +/* + * Add a `!!map` MAPPING node. + */ + +YAML_DECLARE(int) +yaml_document_add_map_node(yaml_document_t *document, int *node_id) +{ + return yaml_document_add_mapping(document, node_id, NULL, + YAML_MAP_TAG, YAML_ANY_MAPPING_STYLE); +} + +/***************************************************************************** + * Standard Handlers + *****************************************************************************/ + +/* + * Standard string read handler. + */ + +static int +yaml_string_reader(void *untyped_data, unsigned char *buffer, size_t capacity, + size_t *length) +{ + yaml_standard_reader_data_t *data = untyped_data; + + if (data->string.pointer == data->string.length) { + *length = 0; + return 1; + } + + if (capacity > (size_t)(data->string.length - data->string.pointer)) { + capacity = data->string.length - data->string.pointer; + } + + memcpy(buffer, data->string.buffer + data->string.pointer, capacity); + data->string.pointer += capacity; + *length = capacity; + return 1; +} + +/* + * Standard file read handler. + */ + +static int +yaml_file_reader(void *untyped_data, unsigned char *buffer, size_t capacity, + size_t *length) +{ + yaml_standard_reader_data_t *data = untyped_data; + + *length = fread(buffer, 1, capacity, data->file); + return !ferror(data->file); +} + +/* + * String write handler. + */ + +static int +yaml_string_writer(void *untyped_data, const unsigned char *buffer, size_t length) +{ + yaml_standard_writer_data_t *data = untyped_data; + int result = 1; + + if (data->string.capacity - data->string.pointer < length) { + length = data->string.capacity - data->string.pointer; + result = 0; + } + + memcpy(data->string.buffer + data->string.pointer, buffer, length); + data->string.pointer += length; + *data->length += length; + + return result; +} + +/* + * File write handler. + */ + +static int +yaml_file_writer(void *untyped_data, const unsigned char *buffer, size_t length) +{ + yaml_standard_writer_data_t *data = untyped_data; + + return (fwrite(buffer, 1, length, data->file) == length); +} + +/* + * Standard resolve handler. + * + * The standard resolve handler recognizes the following scalars: + * + * - `!!null`: `~|null|Null|NULL|<empty string>`. + * + * - `!!bool`: `yes|Yes|YES|no|No|NO|true|True|TRUE|false|False|FALSE| + * on|On|ON|off|Off|OFF` + * + * - `!!int`: any string that is successfully converted using `strtol()`. + * + * - `!!float`: `[+-]?(.inf|.Inf|.INF)|.nan|.NaN|.NAN` or any string + * successfully converted using `strtod()`. + */ + +static int +yaml_standard_resolver(void *untyped_data, yaml_incomplete_node_t *node, + const yaml_char_t **tag) +{ + if (node->type == YAML_SCALAR_NODE && node->data.scalar.is_plain) + { + yaml_char_t *value = node->data.scalar.value; + char buffer[128]; + char *pointer; + char *tail; + int old_errno, new_errno; + char decimal_point = *(localeconv()->decimal_point); + + if (strlen(value) != node->data.scalar.length) { + *tag = YAML_STR_TAG; + return 1; + } + + if (!strcmp(value, "") || !strcmp(value, "~") || + !strcmp(value, "null") || !strcmp(value, "Null") || !strcmp(value, "NULL")) { + *tag = YAML_NULL_TAG; + return 1; + } + + if (!strcmp(value, "yes") || !strcmp(value, "Yes") || !strcmp(value, "YES") || + !strcmp(value, "no") || !strcmp(value, "No") || !strcmp(value, "NO") || + !strcmp(value, "true") || !strcmp(value, "True") || !strcmp(value, "TRUE") || + !strcmp(value, "false") || !strcmp(value, "False") || !strcmp(value, "FALSE") || + !strcmp(value, "on") || !strcmp(value, "On") || !strcmp(value, "ON") || + !strcmp(value, "off") || !strcmp(value, "Off") || !strcmp(value, "OFF")) { + *tag = YAML_BOOL_TAG; + return 1; + } + + if (!strcmp(value, ".inf") || !strcmp(value, ".Inf") || !strcmp(value, ".INF") || + !strcmp(value, "+.inf") || !strcmp(value, "+.Inf") || !strcmp(value, "+.INF") || + !strcmp(value, "-.inf") || !strcmp(value, "-.Inf") || !strcmp(value, "-.INF") || + !strcmp(value, ".nan") || !strcmp(value, ".NaN") || !strcmp(value, ".NAN")) { + *tag = YAML_FLOAT_TAG; + return 1; + } + + old_errno = errno; + errno = 0; + + strtol((const char *)value, &tail, 0); + + new_errno = errno; + errno = old_errno; + + if (!new_errno && !*tail) { + *tag = YAML_INT_TAG; + return 1; + } + + if (strlen(value) < sizeof(buffer)) + { + strcpy(buffer, (const char *)value); + + /* Replace a locale-dependent decimal point with a dot. */ + + for (pointer = buffer; *pointer; pointer++) { + if (*pointer == decimal_point) { + *pointer = '.'; + break; + } + } + + old_errno = errno; + errno = 0; + + strtod(buffer, &tail); + + new_errno = errno; + errno = old_errno; + + if (!new_errno && !*tail) { + *tag = YAML_FLOAT_TAG; + return 1; + } + } + } + + switch (node->type) + { + case YAML_SCALAR_NODE: + *tag = YAML_STR_TAG; + break; + case YAML_SEQUENCE_NODE: + *tag = YAML_SEQ_TAG; + break; + case YAML_MAPPING_NODE: + *tag = YAML_MAP_TAG; + break; + default: + assert(0); /* Should never happen. */ + } + + return 1; +} + + +/***************************************************************************** + * Parser API + *****************************************************************************/ + +/* + * Allocate a new parser object. + */ + +YAML_DECLARE(yaml_parser_t *) +yaml_parser_new(void) +{ + yaml_parser_t *parser = yaml_malloc(sizeof(yaml_parser_t)); + + if (!parser) + return NULL; + + memset(parser, 0, sizeof(yaml_parser_t)); + + if (!IOSTRING_INIT(parser, parser->raw_input, RAW_INPUT_BUFFER_CAPACITY)) + goto error; + if (!IOSTRING_INIT(parser, parser->input, INPUT_BUFFER_CAPACITY)) + goto error; + if (!QUEUE_INIT(parser, parser->tokens, INITIAL_QUEUE_CAPACITY)) + goto error; + if (!STACK_INIT(parser, parser->indents, INITIAL_STACK_CAPACITY)) + goto error; + if (!STACK_INIT(parser, parser->simple_keys, INITIAL_STACK_CAPACITY)) + goto error; + if (!STACK_INIT(parser, parser->states, INITIAL_STACK_CAPACITY)) + goto error; + if (!STACK_INIT(parser, parser->marks, INITIAL_STACK_CAPACITY)) + goto error; + if (!STACK_INIT(parser, parser->tag_directives, INITIAL_STACK_CAPACITY)) + goto error; + + return parser; + +error: + yaml_parser_delete(parser); + + return NULL; +} + +/* + * Deallocate a parser object. + */ + +YAML_DECLARE(void) +yaml_parser_delete(yaml_parser_t *parser) +{ + assert(parser); /* Non-NULL parser object expected. */ + + IOSTRING_DEL(parser, parser->raw_input); + IOSTRING_DEL(parser, parser->input); + while (!QUEUE_EMPTY(parser, parser->tokens)) { + yaml_token_destroy(&DEQUEUE(parser, parser->tokens)); + } + QUEUE_DEL(parser, parser->tokens); + STACK_DEL(parser, parser->indents); + STACK_DEL(parser, parser->simple_keys); + STACK_DEL(parser, parser->states); + STACK_DEL(parser, parser->marks); + while (!STACK_EMPTY(parser, parser->tag_directives)) { + yaml_tag_directive_t tag_directive = POP(parser, parser->tag_directives); + yaml_free(tag_directive.handle); + yaml_free(tag_directive.prefix); + } + STACK_DEL(parser, parser->tag_directives); + + memset(parser, 0, sizeof(yaml_parser_t)); + + yaml_free(parser); +} + +/* + * Reset a parser object. + */ + +YAML_DECLARE(void) +yaml_parser_reset(yaml_parser_t *parser) +{ + yaml_parser_t copy = *parser; + + assert(parser); /* Non-NULL parser object expected. */ + + while (!QUEUE_EMPTY(parser, parser->tokens)) { + yaml_token_destroy(&DEQUEUE(parser, parser->tokens)); + } + while (!STACK_EMPTY(parser, parser->tag_directives)) { + yaml_tag_directive_t tag_directive = POP(parser, parser->tag_directives); + yaml_free(tag_directive.handle); + yaml_free(tag_directive.prefix); + } + + memset(parser, 0, sizeof(yaml_parser_t)); + + IOSTRING_SET(parser, parser->raw_input, + copy.raw_input.buffer, copy.raw_input.capacity); + IOSTRING_SET(parser, parser->input, + copy.input.buffer, copy.input.capacity); + QUEUE_SET(parser, parser->tokens, + copy.tokens.list, copy.tokens.capacity); + STACK_SET(parser, parser->indents, + copy.indents.list, copy.indents.capacity); + STACK_SET(parser, parser->simple_keys, + copy.simple_keys.list, copy.simple_keys.capacity); + STACK_SET(parser, parser->states, + copy.states.list, copy.states.capacity); + STACK_SET(parser, parser->marks, + copy.marks.list, copy.marks.capacity); + STACK_SET(parse, parser->tag_directives, + copy.tag_directives.list, copy.tag_directives.capacity); +} + +/* + * Get the current parser error. + */ + +YAML_DECLARE(yaml_error_t *) +yaml_parser_get_error(yaml_parser_t *parser) +{ + assert(parser); /* Non-NULL parser object expected. */ + + return &(parser->error); +} + +/* + * Set a string input. + */ + +YAML_DECLARE(void) +yaml_parser_set_string_reader(yaml_parser_t *parser, + const unsigned char *buffer, size_t length) +{ + assert(parser); /* Non-NULL parser object expected. */ + assert(!parser->reader); /* You can set the input handler only once. */ + assert(buffer); /* Non-NULL input string expected. */ + + parser->reader = yaml_string_reader; + parser->reader_data = &(parser->standard_reader_data); + + parser->standard_reader_data.string.buffer = buffer; + parser->standard_reader_data.string.pointer = 0; + parser->standard_reader_data.string.length = length; +} + +/* + * Set a file input. + */ + +YAML_DECLARE(void) +yaml_parser_set_file_reader(yaml_parser_t *parser, FILE *file) +{ + assert(parser); /* Non-NULL parser object expected. */ + assert(!parser->reader); /* You can set the input handler only once. */ + assert(file); /* Non-NULL file object expected. */ + + parser->reader = yaml_file_reader; + parser->reader_data = &(parser->standard_reader_data); + + parser->standard_reader_data.file = file; +} + +/* + * Set a generic input. + */ + +YAML_DECLARE(void) +yaml_parser_set_reader(yaml_parser_t *parser, + yaml_reader_t *reader, void *data) +{ + assert(parser); /* Non-NULL parser object expected. */ + assert(!parser->reader); /* You can set the input handler only once. */ + assert(reader); /* Non-NULL read handler expected. */ + + parser->reader = reader; + parser->reader_data = data; +} + +/* + * Set a standard tag resolver. + */ + +YAML_DECLARE(void) +yaml_parser_set_standard_resolver(yaml_parser_t *parser) +{ + assert(parser); /* Non-NULL parser object expected. */ + assert(!parser->resolver); /* You can set the tag resolver only once. */ + + parser->resolver = yaml_standard_resolver; + parser->resolver_data = NULL; +} + +/* + * Set a generic tag resolver. + */ + +YAML_DECLARE(void) +yaml_parser_set_resolver(yaml_parser_t *parser, + yaml_resolver_t *resolver, void *data) +{ + assert(parser); /* Non-NULL parser object expected. */ + assert(!parser->resolver); /* You can set the tag resolver only once. */ + assert(resolver); /* Non-NULL resolver is expected. */ + + parser->resolver = resolver; + parser->resolver_data = data; +} + +/* + * Set the source encoding. + */ + +YAML_DECLARE(void) +yaml_parser_set_encoding(yaml_parser_t *parser, yaml_encoding_t encoding) +{ + assert(parser); /* Non-NULL parser object expected. */ + assert(!parser->encoding); /* Encoding is already set or detected. */ + + parser->encoding = encoding; +} + +/***************************************************************************** + * Parser API + *****************************************************************************/ + +/* + * Create a new emitter object. + */ + +YAML_DECLARE(yaml_emitter_t *) +yaml_emitter_new(void) +{ + yaml_emitter_t *emitter = yaml_malloc(sizeof(yaml_emitter_t)); + + if (!emitter) + return NULL; + + memset(emitter, 0, sizeof(yaml_emitter_t)); + if (!IOSTRING_INIT(emitter, emitter->output, OUTPUT_BUFFER_CAPACITY)) + goto error; + if (!IOSTRING_INIT(emitter, emitter->raw_output, RAW_OUTPUT_BUFFER_CAPACITY)) + goto error; + if (!STACK_INIT(emitter, emitter->states, INITIAL_STACK_CAPACITY)) + goto error; + if (!QUEUE_INIT(emitter, emitter->events, INITIAL_QUEUE_CAPACITY)) + goto error; + if (!STACK_INIT(emitter, emitter->indents, INITIAL_STACK_CAPACITY)) + goto error; + if (!STACK_INIT(emitter, emitter->tag_directives, INITIAL_STACK_CAPACITY)) + goto error; + + return emitter; + +error: + yaml_emitter_delete(emitter); + + return NULL; +} + +/* + * Destroy an emitter object. + */ + +YAML_DECLARE(void) +yaml_emitter_delete(yaml_emitter_t *emitter) +{ + assert(emitter); /* Non-NULL emitter object expected. */ + + IOSTRING_DEL(emitter, emitter->output); + IOSTRING_DEL(emitter, emitter->raw_output); + STACK_DEL(emitter, emitter->states); + while (!QUEUE_EMPTY(emitter, emitter->events)) { + yaml_event_destroy(&DEQUEUE(emitter, emitter->events)); + } + QUEUE_DEL(emitter, emitter->events); + STACK_DEL(emitter, emitter->indents); + while (!STACK_EMPTY(empty, emitter->tag_directives)) { + yaml_tag_directive_t tag_directive = POP(emitter, emitter->tag_directives); + yaml_free(tag_directive.handle); + yaml_free(tag_directive.prefix); + } + STACK_DEL(emitter, emitter->tag_directives); + yaml_free(emitter->anchors); + + memset(emitter, 0, sizeof(yaml_emitter_t)); + yaml_free(emitter); +} + +/* + * Reset an emitter object. + */ + +YAML_DECLARE(void) +yaml_emitter_reset(yaml_emitter_t *emitter) +{ + yaml_emitter_t copy = *emitter; + + assert(emitter); /* Non-NULL emitter object expected. */ + + while (!QUEUE_EMPTY(emitter, emitter->events)) { + yaml_event_destroy(&DEQUEUE(emitter, emitter->events)); + } + while (!STACK_EMPTY(empty, emitter->tag_directives)) { + yaml_tag_directive_t tag_directive = POP(emitter, emitter->tag_directives); + yaml_free(tag_directive.handle); + yaml_free(tag_directive.prefix); + } + + memset(emitter, 0, sizeof(yaml_emitter_t)); + + IOSTRING_SET(emitter, emitter->output, + copy.output.buffer, copy.output.capacity); + IOSTRING_SET(emitter, emitter->raw_output, + copy.raw_output.buffer, copy.raw_output.capacity); + STACK_SET(emitter, emitter->states, + copy.states.list, copy.states.capacity); + QUEUE_SET(emitter, emitter->events, + copy.events.list, copy.events.capacity); + STACK_SET(emitter, emitter->indents, + copy.indents.list, copy.indents.capacity); + STACK_SET(emitter, emitter->tag_directives, + copy.tag_directives.list, copy.tag_directives.capacity); +} + +/* + * Get the current emitter error. + */ + +YAML_DECLARE(yaml_error_t *) +yaml_emitter_get_error(yaml_emitter_t *emitter) +{ + assert(emitter); /* Non-NULL emitter object expected. */ + + return &(emitter->error); +} + +/* + * Set a string output. + */ + +YAML_DECLARE(void) +yaml_emitter_set_string_writer(yaml_emitter_t *emitter, + unsigned char *buffer, size_t capacity, size_t *length) +{ + assert(emitter); /* Non-NULL emitter object expected. */ + assert(!emitter->writer); /* You can set the output only once. */ + assert(buffer); /* Non-NULL output string expected. */ + + emitter->writer = yaml_string_writer; + emitter->writer_data = &(emitter->standard_writer_data); + + emitter->standard_writer_data.string.buffer = buffer; + emitter->standard_writer_data.string.pointer = 0; + emitter->standard_writer_data.string.capacity = capacity; + emitter->standard_writer_data.length = length; + + *length = 0; +} + +/* + * Set a file output. + */ + +YAML_DECLARE(void) +yaml_emitter_set_file_writer(yaml_emitter_t *emitter, FILE *file) +{ + assert(emitter); /* Non-NULL emitter object expected. */ + assert(!emitter->writer); /* You can set the output only once. */ + assert(file); /* Non-NULL file object expected. */ + + emitter->writer = yaml_string_writer; + emitter->writer_data = &(emitter->standard_writer_data); + + emitter->standard_writer_data.file = file; +} + +/* + * Set a generic output handler. + */ + +YAML_DECLARE(void) +yaml_emitter_set_writer(yaml_emitter_t *emitter, + yaml_writer_t *writer, void *data) +{ + assert(emitter); /* Non-NULL emitter object expected. */ + assert(!emitter->writer); /* You can set the output only once. */ + assert(writer); /* Non-NULL handler object expected. */ + + emitter->writer = writer; + emitter->writer_data = data; +} + +/* + * Set a standard tag resolver. + */ + +YAML_DECLARE(void) +yaml_emitter_set_standard_resolver(yaml_emitter_t *emitter) +{ + assert(emitter); /* Non-NULL emitter object expected. */ + assert(!emitter->resolver); /* You can set the tag resolver only once. */ + + emitter->resolver = yaml_standard_resolver; + emitter->resolver_data = NULL; +} + +/* + * Set a generic tag resolver. + */ + +YAML_DECLARE(void) +yaml_emitter_set_resolver(yaml_emitter_t *emitter, + yaml_resolver_t *resolver, void *data) +{ + assert(emitter); /* Non-NULL emitter object expected. */ + assert(!emitter->resolver); /* You can set the tag resolver only once. */ + assert(resolver); /* Non-NULL resolver is expected. */ + + emitter->resolver = resolver; + emitter->resolver_data = data; +} + +/* + * Set the output encoding. + */ + +YAML_DECLARE(void) +yaml_emitter_set_encoding(yaml_emitter_t *emitter, yaml_encoding_t encoding) +{ + assert(emitter); /* Non-NULL emitter object expected. */ + assert(!emitter->encoding); /* You can set encoding only once. */ + + emitter->encoding = encoding; +} + +/* + * Set the canonical output style. + */ + +YAML_DECLARE(void) +yaml_emitter_set_canonical(yaml_emitter_t *emitter, int is_canonical) +{ + assert(emitter); /* Non-NULL emitter object expected. */ + + emitter->is_canonical = (is_canonical != 0); +} + +/* + * Set the indentation increment. + */ + +YAML_DECLARE(void) +yaml_emitter_set_indent(yaml_emitter_t *emitter, int indent) +{ + assert(emitter); /* Non-NULL emitter object expected. */ + + emitter->best_indent = (1 < indent && indent < 10) ? indent : 2; +} + +/* + * Set the preferred line width. + */ + +YAML_DECLARE(void) +yaml_emitter_set_width(yaml_emitter_t *emitter, int width) +{ + assert(emitter); /* Non-NULL emitter object expected. */ + + emitter->best_width = (width >= 0) ? width : -1; +} + +/* + * Set if unescaped non-ASCII characters are allowed. + */ + +YAML_DECLARE(void) +yaml_emitter_set_unicode(yaml_emitter_t *emitter, int is_unicode) +{ + assert(emitter); /* Non-NULL emitter object expected. */ + + emitter->is_unicode = (is_unicode != 0); +} + +/* + * Set the preferred line break character. + */ + +YAML_DECLARE(void) +yaml_emitter_set_break(yaml_emitter_t *emitter, yaml_break_t line_break) +{ + assert(emitter); /* Non-NULL emitter object expected. */ + + emitter->line_break = line_break; +} diff --git a/src/emitter.c b/src/emitter.c index 4093e41..dfb59dc 100644 --- a/src/emitter.c +++ b/src/emitter.c @@ -183,6 +183,9 @@ yaml_emitter_process_scalar(yaml_emitter_t *emitter); */ static int +yaml_emitter_valid_utf8(yaml_emitter_t *emitter, yaml_istring_t string); + +static int yaml_emitter_analyze_version_directive(yaml_emitter_t *emitter, yaml_version_directive_t version_directive); @@ -1148,10 +1151,10 @@ yaml_emitter_select_scalar_style(yaml_emitter_t *emitter, yaml_event_t *event) yaml_scalar_style_t style = event->data.scalar.style; int no_tag = (!emitter->tag_data.handle && !emitter->tag_data.suffix); - if (no_tag && !event->data.scalar.is_plain_implicit - && !event->data.scalar.is_quoted_implicit) { + if (no_tag && !event->data.scalar.is_plain_nonspecific + && !event->data.scalar.is_quoted_nonspecific) { return EMITTER_ERROR_INIT(emitter, - "neither tag nor implicit flags are specified"); + "neither tag nor nonspecific flags are specified"); } if (style == YAML_ANY_SCALAR_STYLE) @@ -1171,7 +1174,7 @@ yaml_emitter_select_scalar_style(yaml_emitter_t *emitter, yaml_event_t *event) if (!emitter->scalar_data.length && (emitter->flow_level || emitter->is_simple_key_context)) style = YAML_SINGLE_QUOTED_SCALAR_STYLE; - if (no_tag && !event->data.scalar.is_plain_implicit) + if (no_tag && !event->data.scalar.is_plain_nonspecific) style = YAML_SINGLE_QUOTED_SCALAR_STYLE; } @@ -1188,7 +1191,7 @@ yaml_emitter_select_scalar_style(yaml_emitter_t *emitter, yaml_event_t *event) style = YAML_DOUBLE_QUOTED_SCALAR_STYLE; } - if (no_tag && !event->data.scalar.is_quoted_implicit + if (no_tag && !event->data.scalar.is_quoted_nonspecific && style != YAML_PLAIN_SCALAR_STYLE) { emitter->tag_data.handle = (yaml_char_t *)"!"; @@ -1308,6 +1311,50 @@ yaml_emitter_analyze_version_directive(yaml_emitter_t *emitter, } /* + * Verify that a string is a valid UTF-8 sequence. + * + * Check 'reader.c' for more details on UTF-8 encoding. + */ + +static int +yaml_emitter_valid_utf8(yaml_emitter_t *emitter, yaml_istring_t string) +{ + while (string.pointer < string.length) + { + unsigned char octet; + unsigned int width; + unsigned int value; + size_t idx; + + octet = OCTET(string); + width = (octet & 0x80) == 0x00 ? 1 : + (octet & 0xE0) == 0xC0 ? 2 : + (octet & 0xF0) == 0xE0 ? 3 : + (octet & 0xF8) == 0xF0 ? 4 : 0; + value = (octet & 0x80) == 0x00 ? octet & 0x7F : + (octet & 0xE0) == 0xC0 ? octet & 0x1F : + (octet & 0xF0) == 0xE0 ? octet & 0x0F : + (octet & 0xF8) == 0xF0 ? octet & 0x07 : 0; + if (!width) return 0; + if (string.pointer+width > string.length) return 0; + for (idx = 1; idx < width; idx ++) { + octet = OCTET_AT(string, idx); + if ((octet & 0xC0) != 0x80) return 0; + value = (value << 6) + (octet & 0x3F); + } + if (!((width == 1) || + (width == 2 && value >= 0x80) || + (width == 3 && value >= 0x800) || + (width == 4 && value >= 0x10000))) return 0; + + string.pointer += width; + } + + return 1; +} + + +/* * Check if a %TAG directive is valid. */ @@ -1320,6 +1367,16 @@ yaml_emitter_analyze_tag_directive(yaml_emitter_t *emitter, yaml_istring_t prefix = ISTRING(tag_directive.prefix, strlen((char *)tag_directive.prefix)); + if (!yaml_emitter_valid_utf8(emitter, handle)) { + return EMITTER_ERROR_INIT(emitter, + "tag handle is not a valid UTF-8 string"); + } + + if (!yaml_emitter_valid_utf8(emitter, prefix)) { + return EMITTER_ERROR_INIT(emitter, + "tag prefix is not a valid UTF-8 string"); + } + if (!handle.length) { return EMITTER_ERROR_INIT(emitter, "tag handle must not be empty"); } @@ -1359,6 +1416,12 @@ yaml_emitter_analyze_anchor(yaml_emitter_t *emitter, { yaml_istring_t string = ISTRING(anchor, strlen((char *)anchor)); + if (!yaml_emitter_valid_utf8(emitter, string)) { + return EMITTER_ERROR_INIT(emitter, is_alias ? + "alias value is not a valid UTF-8 string" : + "anchor value is not a valid UTF-8 string"); + } + if (!string.length) { return EMITTER_ERROR_INIT(emitter, is_alias ? "alias value must not be empty" : @@ -1392,6 +1455,11 @@ yaml_emitter_analyze_tag(yaml_emitter_t *emitter, yaml_istring_t string = ISTRING(tag, strlen((char *)tag)); size_t idx; + if (!yaml_emitter_valid_utf8(emitter, string)) { + return EMITTER_ERROR_INIT(emitter, + "tag value is not a valid UTF-8 string"); + } + if (!string.length) { return EMITTER_ERROR_INIT(emitter, "tag value must not be empty"); } @@ -1450,6 +1518,11 @@ yaml_emitter_analyze_scalar(yaml_emitter_t *emitter, int mixed = 0; int leading = 0; + if (!yaml_emitter_valid_utf8(emitter, string)) { + return EMITTER_ERROR_INIT(emitter, + "scalar value is not a valid UTF-8 string"); + } + emitter->scalar_data.value = value; emitter->scalar_data.length = length; @@ -1689,8 +1762,8 @@ yaml_emitter_analyze_event(yaml_emitter_t *emitter, return 0; } if (event->data.scalar.tag && (emitter->is_canonical || - (!event->data.scalar.is_plain_implicit - && !event->data.scalar.is_quoted_implicit))) { + (!event->data.scalar.is_plain_nonspecific + && !event->data.scalar.is_quoted_nonspecific))) { if (!yaml_emitter_analyze_tag(emitter, event->data.scalar.tag)) return 0; } @@ -1706,7 +1779,7 @@ yaml_emitter_analyze_event(yaml_emitter_t *emitter, return 0; } if (event->data.sequence_start.tag && (emitter->is_canonical || - !event->data.sequence_start.is_implicit)) { + !event->data.sequence_start.is_nonspecific)) { if (!yaml_emitter_analyze_tag(emitter, event->data.sequence_start.tag)) return 0; @@ -1720,7 +1793,7 @@ yaml_emitter_analyze_event(yaml_emitter_t *emitter, return 0; } if (event->data.mapping_start.tag && (emitter->is_canonical || - !event->data.mapping_start.is_implicit)) { + !event->data.mapping_start.is_nonspecific)) { if (!yaml_emitter_analyze_tag(emitter, event->data.mapping_start.tag)) return 0; diff --git a/src/yaml_private.h b/src/yaml_private.h index 3ae24a2..b1eea24 100644 --- a/src/yaml_private.h +++ b/src/yaml_private.h @@ -1,3 +1,11 @@ +/***************************************************************************** + * Private Definitions for LibYAML + * + * Copyright (c) 2006 Kirill Simonov + * + * LibYAML is free software; you can use, modify and/or redistribute it under + * the terms of the MIT license; see the file LICENCE for more details. + *****************************************************************************/ #if HAVE_CONFIG_H #include <config.h> @@ -7,10 +15,13 @@ #include <assert.h> #include <limits.h> +#include <errno.h> +#include <ctype.h> +#include <locale.h> -/* - * Memory management. - */ +/***************************************************************************** + * Memory Management + *****************************************************************************/ YAML_DECLARE(void *) yaml_malloc(size_t size); @@ -24,9 +35,9 @@ yaml_free(void *ptr); YAML_DECLARE(yaml_char_t *) yaml_strdup(const yaml_char_t *); -/* - * Error management. - */ +/***************************************************************************** + * Error Management + *****************************************************************************/ /* * Generic error initializers; not to be used directly. @@ -128,6 +139,10 @@ yaml_strdup(const yaml_char_t *); #define RESOLVER_ERROR_INIT(self, _problem) \ RESOLVER_ERROR_INIT((self)->error, YAML_RESOLVER_ERROR, _problem) +/***************************************************************************** + * Buffer Sizes + *****************************************************************************/ + /* * The size of the input raw buffer. */ @@ -138,7 +153,10 @@ yaml_strdup(const yaml_char_t *); * The size of the input buffer. * * The input buffer should be large enough to hold the content of the raw - * buffer after it is decoded. + * buffer after it is decoded. The raw input buffer could be encoded in UTF-8 + * or UTF-16 while the input buffer is always encoded in UTF-8. A UTF-16 + * character may take 2 or 4 bytes, and a UTF-8 character takes up to 4 bytes. + * We use the *3 multiplier just to be safe. */ #define INPUT_BUFFER_CAPACITY (RAW_INPUT_BUFFER_CAPACITY*3) @@ -166,9 +184,9 @@ yaml_strdup(const yaml_char_t *); #define INITIAL_QUEUE_CAPACITY 16 #define INITIAL_STRING_CAPACITY 16 -/* - * String management. - */ +/***************************************************************************** + * String Management + *****************************************************************************/ /* * An immutable string used as an input buffer. @@ -202,7 +220,7 @@ typedef struct yaml_iostring_s { } yaml_iostring_t; /* - * Separate type for non-UTF-8 i/o strings. + * A separate type for non-UTF-8 i/o strings. */ typedef struct yaml_raw_iostring_s { @@ -212,14 +230,26 @@ typedef struct yaml_raw_iostring_s { size_t capacity; } yaml_raw_iostring_t; +/* + * Double the string capacity. + */ + YAML_DECLARE(int) yaml_ostring_extend(yaml_char_t **buffer, size_t *capacity); +/* + * Append a string to the end of the base string expanding it if needed. + */ + YAML_DECLARE(int) yaml_ostring_join( yaml_char_t **base_buffer, size_t *base_pointer, size_t *base_capacity, yaml_char_t *adj_buffer, size_t adj_pointer); +/* + * Basic string operations. + */ + #define ISTRING(buffer, length) { (buffer), 0, (length) } #define NULL_OSTRING { NULL, 0, 0 } @@ -238,6 +268,12 @@ yaml_ostring_join( (string).buffer = NULL, \ ((string).pointer = (string).length = (string).capacity = 0)) +#define IOSTRING_SET(self, string, _buffer, _capacity) \ + (memset((_buffer), 0, (_capacity)), \ + (string).buffer = (_buffer), \ + (string).pointer = (string).length = 0, \ + (string).capacity = (_capacity)) + #define OSTRING_INIT(self, string, _capacity) \ (((string).buffer = yaml_malloc(_capacity)) ? \ ((string).pointer = 0, \ @@ -272,9 +308,9 @@ yaml_ostring_join( ((self)->error.type = YAML_MEMORY_ERROR, \ 0)) -/* - * String check operations. - */ +/***************************************************************************** + * String Tests + *****************************************************************************/ /* * Get the octet at the specified position. @@ -547,17 +583,29 @@ yaml_ostring_join( COPY_OCTET((target_string), (source_string)), \ COPY_OCTET((target_string), (source_string))) : 0) +/***************************************************************************** + * Stack and Queue Management + *****************************************************************************/ + /* - * Stack and queue management. + * Double the stack capacity. */ YAML_DECLARE(int) yaml_stack_extend(void **list, size_t size, size_t *length, size_t *capacity); +/* + * Double the queue capacity. + */ + YAML_DECLARE(int) yaml_queue_extend(void **list, size_t size, size_t *head, size_t *tail, size_t *capacity); +/* + * Basic stack operations. + */ + #define STACK_INIT(self, stack, _capacity) \ (((stack).list = yaml_malloc((_capacity)*sizeof(*(stack).list))) ? \ ((stack).length = 0, \ @@ -571,6 +619,11 @@ yaml_queue_extend(void **list, size_t size, (stack).list = NULL, \ (stack).length = (stack).capacity = 0) +#define STACK_SET(self, stack, _list, _capacity) \ + ((stack).list = (_list), \ + (stack).length = 0, \ + (stack).capacity = (_capacity)) + #define STACK_EMPTY(self, stack) \ ((stack).length == 0) @@ -589,6 +642,10 @@ yaml_queue_extend(void **list, size_t size, #define POP(self, stack) \ ((stack).list[--(stack).length]) +/* + * Basic queue operations. + */ + #define QUEUE_INIT(self, queue, _capacity) \ (((queue).list = yaml_malloc((_capacity)*sizeof(*(queue).list))) ? \ ((queue).head = (queue).tail = 0, \ @@ -602,6 +659,11 @@ yaml_queue_extend(void **list, size_t size, (queue).list = NULL, \ (queue).head = (queue).tail = (queue).capacity = 0) +#define QUEUE_SET(self, queue, _list, _capacity) \ + ((queue).list = (_list), \ + (queue).head = (queue).tail = 0, \ + (queue).capacity = (_capacity)) + #define QUEUE_EMPTY(self, queue) \ ((queue).head == (queue).tail) @@ -633,9 +695,9 @@ yaml_queue_extend(void **list, size_t size, ((self)->error.type = YAML_MEMORY_ERROR, \ 0)) -/* - * Token initializers. - */ +/***************************************************************************** + * Token Initializers + *****************************************************************************/ #define TOKEN_INIT(token, _type, _start_mark, _end_mark) \ (memset(&(token), 0, sizeof(yaml_token_t)), \ @@ -679,9 +741,9 @@ yaml_queue_extend(void **list, size_t size, (token).data.tag_directive.handle = (_handle), \ (token).data.tag_directive.prefix = (_prefix)) -/* - * Event initializers. - */ +/***************************************************************************** + * Event Initializers + *****************************************************************************/ #define EVENT_INIT(event, _type, _start_mark, _end_mark) \ (memset(&(event), 0, sizeof(yaml_event_t)), \ @@ -715,95 +777,153 @@ yaml_queue_extend(void **list, size_t size, (event).data.alias.anchor = (_anchor)) #define SCALAR_EVENT_INIT(event, _anchor, _tag, _value, _length, \ - _is_plain_implicit, _is_quoted_implicit, _style, _start_mark, _end_mark) \ + _is_plain_nonspecific, _is_quoted_nonspecific, _style, _start_mark, _end_mark) \ (EVENT_INIT((event), YAML_SCALAR_EVENT, (_start_mark), (_end_mark)), \ (event).data.scalar.anchor = (_anchor), \ (event).data.scalar.tag = (_tag), \ (event).data.scalar.value = (_value), \ (event).data.scalar.length = (_length), \ - (event).data.scalar.is_plain_implicit = (_is_plain_implicit), \ - (event).data.scalar.is_quoted_implicit = (_is_quoted_implicit), \ + (event).data.scalar.is_plain_nonspecific = (_is_plain_nonspecific), \ + (event).data.scalar.is_quoted_nonspecific = (_is_quoted_nonspecific), \ (event).data.scalar.style = (_style)) -#define SEQUENCE_START_EVENT_INIT(event, _anchor, _tag, _is_implicit, _style, \ +#define SEQUENCE_START_EVENT_INIT(event, _anchor, _tag, _is_nonspecific, _style, \ _start_mark, _end_mark) \ (EVENT_INIT((event), YAML_SEQUENCE_START_EVENT, (_start_mark), (_end_mark)), \ (event).data.sequence_start.anchor = (_anchor), \ (event).data.sequence_start.tag = (_tag), \ - (event).data.sequence_start.is_implicit = (_is_implicit), \ + (event).data.sequence_start.is_nonspecific = (_is_nonspecific), \ (event).data.sequence_start.style = (_style)) #define SEQUENCE_END_EVENT_INIT(event, _start_mark, _end_mark) \ (EVENT_INIT((event), YAML_SEQUENCE_END_EVENT, (_start_mark), (_end_mark))) -#define MAPPING_START_EVENT_INIT(event, _anchor, _tag, _is_implicit, _style, \ +#define MAPPING_START_EVENT_INIT(event, _anchor, _tag, _is_nonspecific, _style, \ _start_mark, _end_mark) \ (EVENT_INIT((event), YAML_MAPPING_START_EVENT, (_start_mark), (_end_mark)), \ (event).data.mapping_start.anchor = (_anchor), \ (event).data.mapping_start.tag = (_tag), \ - (event).data.mapping_start.is_implicit = (_is_implicit), \ + (event).data.mapping_start.is_nonspecific = (_is_nonspecific), \ (event).data.mapping_start.style = (_style)) #define MAPPING_END_EVENT_INIT(event, _start_mark, _end_mark) \ (EVENT_INIT((event), YAML_MAPPING_END_EVENT, (_start_mark), (_end_mark))) -#if 0 - -/* - * Document initializer. - */ +/***************************************************************************** + * Document, Node and Arc Initializers + *****************************************************************************/ -#define DOCUMENT_INIT(document,document_nodes_start,document_nodes_end, \ - document_version_directive,document_tag_directives_start, \ - document_tag_directives_end,document_start_implicit, \ - document_end_implicit,document_start_mark,document_end_mark) \ +#define DOCUMENT_INIT(document, _nodes_list, _nodes_length, _nodes_capacity, \ + _version_directive, _tag_directives_list, _tag_directives_length, \ + _tag_directives_capacity, _is_start_implicit, _is_end_implicit, \ + _start_mark, _end_mark) \ (memset(&(document), 0, sizeof(yaml_document_t)), \ - (document).nodes.start = (document_nodes_start), \ - (document).nodes.end = (document_nodes_end), \ - (document).nodes.top = (document_nodes_start), \ - (document).version_directive = (document_version_directive), \ - (document).tag_directives.start = (document_tag_directives_start), \ - (document).tag_directives.end = (document_tag_directives_end), \ - (document).start_implicit = (document_start_implicit), \ - (document).end_implicit = (document_end_implicit), \ - (document).start_mark = (document_start_mark), \ - (document).end_mark = (document_end_mark)) - -/* - * Node initializers. - */ - -#define NODE_INIT(node,node_type,node_tag,node_start_mark,node_end_mark) \ + (document).type = YAML_DOCUMENT, \ + (document).nodes.list = (_nodes_list), \ + (document).nodes.length = (_nodes_length), \ + (document).nodes.capacity = (_nodes_capacity), \ + (document).version_directive = (_version_directive), \ + (document).tag_directives.list = (_tag_directives_list), \ + (document).tag_directives.length = (_tag_directives_length), \ + (document).tag_directives.capacity = (_tag_directives_capacity), \ + (document).is_start_implicit = (_is_start_implicit), \ + (document).is_end_implicit = (_is_end_implicit), \ + (document).start_mark = (_start_mark), \ + (document).end_mark = (_end_mark)) + +#define NODE_INIT(node, _type, _anchor, _tag, _start_mark, _end_mark) \ (memset(&(node), 0, sizeof(yaml_node_t)), \ - (node).type = (node_type), \ - (node).tag = (node_tag), \ - (node).start_mark = (node_start_mark), \ - (node).end_mark = (node_end_mark)) - -#define SCALAR_NODE_INIT(node,node_tag,node_value,node_length, \ - node_style,start_mark,end_mark) \ - (NODE_INIT((node),YAML_SCALAR_NODE,(node_tag),(start_mark),(end_mark)), \ - (node).data.scalar.value = (node_value), \ - (node).data.scalar.length = (node_length), \ - (node).data.scalar.style = (node_style)) - -#define SEQUENCE_NODE_INIT(node,node_tag,node_items_start,node_items_end, \ - node_style,start_mark,end_mark) \ - (NODE_INIT((node),YAML_SEQUENCE_NODE,(node_tag),(start_mark),(end_mark)), \ - (node).data.sequence.items.start = (node_items_start), \ - (node).data.sequence.items.end = (node_items_end), \ - (node).data.sequence.items.top = (node_items_start), \ - (node).data.sequence.style = (node_style)) - -#define MAPPING_NODE_INIT(node,node_tag,node_pairs_start,node_pairs_end, \ - node_style,start_mark,end_mark) \ - (NODE_INIT((node),YAML_MAPPING_NODE,(node_tag),(start_mark),(end_mark)), \ - (node).data.mapping.pairs.start = (node_pairs_start), \ - (node).data.mapping.pairs.end = (node_pairs_end), \ - (node).data.mapping.pairs.top = (node_pairs_start), \ - (node).data.mapping.style = (node_style)) + (node).type = (_type), \ + (node).anchor = (_anchor), \ + (node).tag = (_tag), \ + (node).start_mark = (_start_mark), \ + (node).end_mark = (_end_mark)) -#endif +#define SCALAR_NODE_INIT(node, _anchor, _tag, _value, _length, _style, \ + _start_mark, _end_mark) \ + (NODE_INIT((node), YAML_SCALAR_NODE, (_anchor), (_tag), \ + (_start_mark), (_end_mark)), \ + (node).data.scalar.value = (_value), \ + (node).data.scalar.length = (_length), \ + (node).data.scalar.style = (_style)) + +#define SEQUENCE_NODE_INIT(node, _anchor, _tag, _items_list, _items_length, \ + _items_capacity, _style, _start_mark, _end_mark) \ + (NODE_INIT((node), YAML_SEQUENCE_NODE, (_anchor), (_tag), \ + (_start_mark), (_end_mark)), \ + (node).data.sequence.items.list = (_items_list), \ + (node).data.sequence.items.length = (_items_length), \ + (node).data.sequence.items.capacity = (_items_capacity), \ + (node).data.sequence.style = (_style)) + +#define MAPPING_NODE_INIT(node, _anchor, _tag, _pairs_list, _pairs_length, \ + _pairs_capacity, _style, _start_mark, _end_mark) \ + (NODE_INIT((node), YAML_MAPPING_NODE, (_anchor), (_tag), \ + (_start_mark), (_end_mark)), \ + (node).data.mapping.pairs.list = (_pairs_list), \ + (node).data.mapping.pairs.length = (_pairs_length), \ + (node).data.mapping.pairs.capacity = (_pairs_capacity), \ + (node).data.mapping.style = (_style)) + +#define ARC_INIT(arc, _type, _tag) \ + (memset(&(arc), 0, sizeof(yaml_arc_t)), \ + (arc).type = (_type), \ + (arc).tag = (_tag)) + +#define SEQUENCE_ITEM_ARC_INIT(arc, _tag, _index) \ + (ARC_INIT((arc), YAML_SEQUENCE_ITEM_ARC, (_tag)), \ + (arc).data.item.index = (_index)) + +#define MAPPING_KEY_ARC_INIT(arc, _tag) \ + ARC_INIT((arc), YAML_MAPPING_KEY_ARC, (_tag)) + +#define MAPPING_VALUE_ARC_INIT(arc, _tag, _key_type, _key_tag) \ + (ARC_INIT((arc), YAML_MAPPING_VALUE_ARC, (_tag)), \ + (arc).data.value.key.type = (_key_type), \ + (arc).data.value.key.tag = (_key_tag)) + +#define MAPPING_VALUE_FOR_SCALAR_KEY_ARC_INIT(arc, _tag, _key_tag, \ + _key_value, _key_length) \ + (MAPPING_VALUE_ARC_INIT((arc), (_tag), YAML_SCALAR_NODE, (_key_tag)), \ + (arc).data.value.key.data.scalar.value = (_key_value), \ + (arc).data.value.key.data.scalar.length = (_key_length)) + +#define MAPPING_VALUE_FOR_SEQUENCE_KEY_ARC_INIT(arc, _tag, _key_tag) \ + MAPPING_VALUE_ARC_INIT((arc), (_tag), YAML_SEQUENCE_NODE, (_key_tag)) + +#define MAPPING_VALUE_FOR_MAPPING_KEY_INIT(arc, _tag, _key_tag) \ + MAPPING_VALUE_ARC_INIT((arc), (_tag), YAML_MAPPING_NODE, (_key_tag)) + +#define INCOMPLETE_NODE_INIT(node, _type, _path_list, _path_length, \ + _path_capacity, _mark) \ + (memset(&(node), 0, sizeof(yaml_incomplete_node_t)), \ + (node).type = (_type), \ + (node).path.list = (_path_list), \ + (node).path.length = (_path_length), \ + (node).path.capacity = (_path_capacity), \ + (node).mark = (_mark)) + +#define INCOMPLETE_SCALAR_NODE_INIT(node, _path_list, _path_length, \ + _path_capacity, _value, _length, _is_plain, _mark) \ + (INCOMPLETE_NODE_INIT((node), YAML_SCALAR_NODE, (_path_list), \ + (_path_length), (_path_capacity), (_mark)). \ + (node).data.scalar.value = (_value), \ + (node).data.scalar.length = (_length), \ + (node).data.scalar.is_plain = (_is_plain)) + +#define INCOMPLETE_SEQUENCE_NODE_INIT(node, _path_list, _path_length, \ + _path_capacity, _mark) \ + INCOMPLETE_NODE_INIT((node), YAML_SEQUENCE_NODE, (_path_list), \ + (_path_length), (_path_capacity), (_mark)) + +#define INCOMPLETE_MAPPING_NODE_INIT(node, _path_list, _path_length, \ + _path_capacity, _mark) \ + INCOMPLETE_NODE_INIT((node), YAML_MAPPING_NODE, (_path_list), \ + (_path_length), (_path_capacity), (_mark)) + +/***************************************************************************** + * Parser Structures + *****************************************************************************/ /* * This structure holds information about a potential simple key. @@ -1037,51 +1157,73 @@ struct yaml_parser_s { size_t capacity; } aliases; - /* The currently parsed document. */ + /* The document being parsed. */ yaml_document_t *document; }; +/***************************************************************************** + * Internal Parser API + *****************************************************************************/ + +/* + * Reader: Ensure that the buffer contains at least `length` characters. + */ + +YAML_DECLARE(int) +yaml_parser_update_buffer(yaml_parser_t *parser, size_t length); + +/* + * Scanner: Ensure that the token stack contains at least one token ready. + */ + +YAML_DECLARE(int) +yaml_parser_fetch_more_tokens(yaml_parser_t *parser); + +/***************************************************************************** + * Emitter Structures + *****************************************************************************/ + /* * The emitter states. */ typedef enum yaml_emitter_state_e { - /** Expect STREAM-START. */ + /* Expect STREAM-START. */ YAML_EMIT_STREAM_START_STATE, - /** Expect the first DOCUMENT-START or STREAM-END. */ + /* Expect the first DOCUMENT-START or STREAM-END. */ YAML_EMIT_FIRST_DOCUMENT_START_STATE, - /** Expect DOCUMENT-START or STREAM-END. */ + /* Expect DOCUMENT-START or STREAM-END. */ YAML_EMIT_DOCUMENT_START_STATE, - /** Expect the content of a document. */ + /* Expect the content of a document. */ YAML_EMIT_DOCUMENT_CONTENT_STATE, - /** Expect DOCUMENT-END. */ + /* Expect DOCUMENT-END. */ YAML_EMIT_DOCUMENT_END_STATE, - /** Expect the first item of a flow sequence. */ + /* Expect the first item of a flow sequence. */ YAML_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE, - /** Expect an item of a flow sequence. */ + /* Expect an item of a flow sequence. */ YAML_EMIT_FLOW_SEQUENCE_ITEM_STATE, - /** Expect the first key of a flow mapping. */ + /* Expect the first key of a flow mapping. */ YAML_EMIT_FLOW_MAPPING_FIRST_KEY_STATE, - /** Expect a key of a flow mapping. */ + /* Expect a key of a flow mapping. */ YAML_EMIT_FLOW_MAPPING_KEY_STATE, - /** Expect a value for a simple key of a flow mapping. */ + /* Expect a value for a simple key of a flow mapping. */ YAML_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE, - /** Expect a value of a flow mapping. */ + /* Expect a value of a flow mapping. */ YAML_EMIT_FLOW_MAPPING_VALUE_STATE, - /** Expect the first item of a block sequence. */ + /* Expect the first item of a block sequence. */ YAML_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE, - /** Expect an item of a block sequence. */ + /* Expect an item of a block sequence. */ YAML_EMIT_BLOCK_SEQUENCE_ITEM_STATE, - /** Expect the first key of a block mapping. */ + /* Expect the first key of a block mapping. */ YAML_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE, - /** Expect the key of a block mapping. */ + /* Expect the key of a block mapping. */ YAML_EMIT_BLOCK_MAPPING_KEY_STATE, - /** Expect a value for a simple key of a block mapping. */ + /* Expect a value for a simple key of a block mapping. */ YAML_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE, - /** Expect a value of a block mapping. */ + /* Expect a value of a block mapping. */ YAML_EMIT_BLOCK_MAPPING_VALUE_STATE, - /** Expect nothing. */ + /* Expect nothing. */ YAML_EMIT_END_STATE } yaml_emitter_state_t; @@ -1251,6 +1393,12 @@ struct yaml_emitter_s { * Dumper stuff. */ + /* The resolve handler. */ + yaml_resolver_t *resolver; + + /* The application data to be passed to the resolver. */ + void *resolver_data; + /* If the stream was already opened? */ int is_opened; /* If the stream was already closed? */ @@ -1269,22 +1417,8 @@ struct yaml_emitter_s { /* The last assigned anchor id. */ int last_anchor_id; - /* The currently emitted document. */ + /* The document being emitted. */ yaml_document_t *document; }; -/* - * Reader: Ensure that the buffer contains at least `length` characters. - */ - -YAML_DECLARE(int) -yaml_parser_update_buffer(yaml_parser_t *parser, size_t length); - -/* - * Scanner: Ensure that the token stack contains at least one token ready. - */ - -YAML_DECLARE(int) -yaml_parser_fetch_more_tokens(yaml_parser_t *parser); - |