]> andersk Git - libyaml.git/commitdiff
Add Emitter definitions and implement the Writer.
authorKirill Simonov <xi@resolvent.net>
Sun, 23 Jul 2006 11:57:36 +0000 (11:57 +0000)
committerKirill Simonov <xi@resolvent.net>
Sun, 23 Jul 2006 11:57:36 +0000 (11:57 +0000)
include/yaml.h
src/Makefile.am
src/api.c
src/parser.c
src/scanner.c
src/writer.c [new file with mode: 0644]
src/yaml_private.h

index ab1cf6a64e5984bec290ef7d0cc4815813c7f07c..204872ab3b0ba55a601e0167c19cf43f9848bb55 100644 (file)
@@ -101,6 +101,15 @@ typedef enum {
     YAML_UTF16BE_ENCODING
 } yaml_encoding_t;
 
+/** Line break types. */
+
+typedef enum {
+    YAML_ANY_BREAK,
+    YAML_CR_BREAK,
+    YAML_LN_BREAK,
+    YAML_CRLN_BREAK
+} yaml_break_t;
+
 /** Many bad things could happen with the parser and emitter. */
 typedef enum {
     YAML_NO_ERROR,
@@ -435,7 +444,7 @@ yaml_event_delete(yaml_event_t *event);
  *
  * @returns On success, the handler should return @c 1.  If the handler failed,
  * the returned value should be @c 0.  On EOF, the handler should set the
- * @a length to @c 0 and return @c 1.
+ * @a size_read to @c 0 and return @c 1.
  */
 
 typedef int yaml_read_handler_t(void *data, unsigned char *buffer, size_t size,
@@ -554,13 +563,13 @@ typedef struct {
 
     /** The working buffer. */
     struct {
-        /* The beginning of the buffer. */
+        /** The beginning of the buffer. */
         yaml_char_t *start;
-        /* The end of the buffer. */
+        /** The end of the buffer. */
         yaml_char_t *end;
-        /* The current position of the buffer. */
+        /** The current position of the buffer. */
         yaml_char_t *pointer;
-        /* The last filled position of the buffer. */
+        /** The last filled position of the buffer. */
         yaml_char_t *last;
     } buffer;
 
@@ -706,7 +715,7 @@ typedef struct {
  *
  * @param[in]   parser  An empty parser object.
  *
- * @returns #c 1 if the function succeeded, @c 0 on error.
+ * @returns @c 1 if the function succeeded, @c 0 on error.
  */
 
 YAML_DECLARE(int)
@@ -737,7 +746,6 @@ YAML_DECLARE(void)
 yaml_parser_set_input_string(yaml_parser_t *parser,
         unsigned char *input, size_t size);
 
-
 /**
  * Set a file input.
  *
@@ -821,18 +829,545 @@ yaml_parser_parse(yaml_parser_t *parser, yaml_event_t *event);
 
 /** @} */
 
-/*
+/**
+ * @defgroup emitter Emitter Definitions
+ * @{
+ */
+
+/**
+ * The prototype of a write handler.
+ *
+ * The write handler is called when the emitter needs to flush the accumulated
+ * characters to the output.  The handler should write @a size bytes of the
+ * @a buffer to the output.
+ *
+ * @param[in]   data        A pointer to an application data specified by
+ *                          @c yaml_emitter_set_write_handler.
+ * @param[out]  buffer      The buffer with bytes to be written.
+ * @param[in]   size        The size of the buffer.
+ *
+ * @returns On success, the handler should return @c 1.  If the handler failed,
+ * the returned value should be @c 0.
+ */
+
+typedef int yaml_write_handler_t(void *data, unsigned char *buffer, size_t size);
+
+/** The emitter states. */
+typedef enum {
+    YAML_EMIT_STREAM_START_STATE,
+    YAML_EMIT_FIRST_DOCUMENT_START_STATE,
+    YAML_EMIT_DOCUMENT_START_STATE,
+    YAML_EMIT_DOCUMENT_CONTENT_STATE,
+    YAML_EMIT_DOCUMENT_END_STATE,
+    YAML_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE,
+    YAML_EMIT_FLOW_SEQUENCE_ITEM_STATE,
+    YAML_EMIT_FLOW_MAPPING_FIRST_KEY_STATE,
+    YAML_EMIT_FLOW_MAPPING_KEY_STATE,
+    YAML_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE,
+    YAML_EMIT_FLOW_MAPPING_VALUE_STATE,
+    YAML_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE,
+    YAML_EMIT_BLOCK_SEQUENCE_ITEM_STATE,
+    YAML_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE,
+    YAML_EMIT_BLOCK_MAPPING_KEY_STATE,
+    YAML_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE,
+    YAML_EMIT_BLOCK_MAPPING_VALUE_STATE
+} yaml_emitter_state_t;
+
+/**
+ * The emitter structure.
+ *
+ * All members are internal.  Manage the structure using the @c yaml_emitter_
+ * family of functions.
+ */
+
 typedef struct {
+
+    /**
+     * @name Error handling
+     * @{
+     */
+
+    /** Error type. */
+    yaml_error_type_t error;
+    /** Error description. */
+    const char *problem;
+
+    /**
+     * @}
+     */
+
+    /**
+     * @name Writer stuff
+     * @{
+     */
+
+    /** Write handler. */
+    yaml_write_handler_t *write_handler;
+
+    /** A pointer for passing to the white handler. */
+    void *write_handler_data;
+
+    /** Standard (string or file) output data. */
+    union {
+        /** String output data. */
+        struct {
+            /** The buffer pointer. */
+            unsigned char *buffer;
+            /** The buffer size. */
+            size_t size;
+            /** The number of written bytes. */
+            size_t *size_written;
+        } string;
+
+        /** File output data. */
+        FILE *file;
+    } output;
+
+    /** The working buffer. */
+    struct {
+        /** The beginning of the buffer. */
+        yaml_char_t *start;
+        /** The end of the buffer. */
+        yaml_char_t *end;
+        /** The current position of the buffer. */
+        yaml_char_t *pointer;
+        /** The last filled position of the buffer. */
+        yaml_char_t *last;
+    } buffer;
+
+    /** The raw buffer. */
+    struct {
+        /** The beginning of the buffer. */
+        unsigned char *start;
+        /** The end of the buffer. */
+        unsigned char *end;
+        /** The current position of the buffer. */
+        unsigned char *pointer;
+        /** The last filled position of the buffer. */
+        unsigned char *last;
+    } raw_buffer;
+
+    /** The stream encoding. */
+    yaml_encoding_t encoding;
+
+    /**
+     * @}
+     */
+
+    /**
+     * @name Emitter stuff
+     * @{
+     */
+
+    /** If the output is in the canonical style? */
+    int canonical;
+    /** The number of indentation spaces. */
+    int best_indent;
+    /** The preferred width of the output lines. */
+    int best_width;
+    /** Allow unescaped non-ASCII characters? */
+    int unicode;
+    /** The preferred line break. */
+    yaml_break_t line_break;
+
+    /** The stack of states. */
+    struct {
+        /** The beginning of the stack. */
+        yaml_emitter_state_t *start;
+        /** The end of the stack. */
+        yaml_emitter_state_t *end;
+        /** The top of the stack. */
+        yaml_emitter_state_t *top;
+    } states;
+
+    /** The current emitter state. */
+    yaml_emitter_state_t state;
+
+    /** The event queue. */
+    struct {
+        /** The beginning of the event queue. */
+        yaml_event_t *start;
+        /** The end of the event queue. */
+        yaml_event_t *end;
+        /** The head of the event queue. */
+        yaml_event_t *head;
+        /** The tail of the event queue. */
+        yaml_event_t *tail;
+    } events;
+
+    /** The current event. */
+    yaml_event_t event;
+
+    /** The stack of indentation levels. */
+    struct {
+        /** The beginning of the stack. */
+        int *start;
+        /** The end of the stack. */
+        int *end;
+        /** The top of the stack. */
+        int *top;
+    } indents;
+
+    /** The list of tag directives. */
+    struct {
+        /** The beginning of the list. */
+        yaml_tag_directive_t *start;
+        /** The end of the list. */
+        yaml_tag_directive_t *end;
+        /** The top of the list. */
+        yaml_tag_directive_t *top;
+    } tag_directives;
+
+    /** The current indentation level. */
+    int indent;
+
+    /** The current flow level. */
+    int flow_level;
+
+    /** Is it the document root context? */
+    int root_context;
+    /** Is it a sequence context? */
+    int sequence_context;
+    /** Is it a mapping context? */
+    int mapping_context;
+    /** Is it a simple mapping key context? */
+    int simple_key_context;
+
+    /** The current line. */
+    int line;
+    /** The current column. */
+    int column;
+    /** If the last character was a whitespace? */
+    int whitespace;
+    /** If the last character was an indentation character (' ', '-', '?', ':')? */
+    int indention;
+
+    /**
+     * @}
+     */
+
 } yaml_emitter_t;
 
+/**
+ * Initialize an emitter.
+ *
+ * This function creates a new emitter object.  An application is responsible
+ * for destroying the object using the @c yaml_emitter_delete function.
+ *
+ * @param[in]   emitter An empty parser object.
+ *
+ * @returns @c 1 if the function succeeded, @c 0 on error.
+ */
+
+YAML_DECLARE(int)
+yaml_emitter_initialize(yaml_emitter_t *emitter);
+
+/**
+ * Destroy an emitter.
+ *
+ * @param[in]   emitter An emitter object.
+ */
+
+YAML_DECLARE(void)
+yaml_emitter_delete(yaml_emitter_t *emitter);
+
+/**
+ * Set a string output.
+ *
+ * The emitter will write the output characters to the @a output buffer of the
+ * size @a size.  The emitter will set @a size_written to the number of written
+ * bytes.  If the buffer is smaller than required, the emitter produces the
+ * YAML_WRITE_ERROR error.
+ *
+ * @param[in]   emitter         An emitter object.
+ * @param[in]   output          An output buffer.
+ * @param[in]   size            The buffer size.
+ * @param[in]   size_written    The pointer to save the number of written bytes.
+ */
+
+YAML_DECLARE(void)
+yaml_emitter_set_output_string(yaml_emitter_t *emitter,
+        unsigned char *output, size_t size, size_t *size_written);
+
+/**
+ * Set a file output.
+ *
+ * @a file should be a file object open for writing.  The application is
+ * responsible for closing the @a file.
+ *
+ * @param[in]   emitter An emitter object.
+ * @param[in]   file    An open file.
+ */
+
+YAML_DECLARE(void)
+yaml_emitter_set_output_file(yaml_emitter_t *emitter, FILE *file);
+
+/**
+ * Set a generic output handler.
+ *
+ * @param[in]   emitter An emitter object.
+ * @param[in]   handler A write handler.
+ * @param[in]   data    Any application data for passing to the write handler.
+ */
+
+YAML_DECLARE(void)
+yaml_emitter_set_output(yaml_emitter_t *emitter,
+        yaml_write_handler_t *handler, void *data);
+
+/**
+ * Set the output encoding.
+ *
+ * @param[in]   emitter     An emitter object.
+ * @param[in]   encoding    The output encoding.
+ */
+
+YAML_DECLARE(void)
+yaml_emitter_set_encoding(yaml_emitter_t *emitter, yaml_encoding_t encoding);
+
+/**
+ * Set if the output should be in the "canonical" format as in the YAML
+ * specification.
+ *
+ * @param[in]   emitter     An emitter object.
+ * @param[in]   canonical   If the output is canonical.
+ */
+
+YAML_DECLARE(void)
+yaml_emitter_set_canonical(yaml_emitter_t *emitter, int canonical);
+
+/**
+ * Set the intendation increment.
+ *
+ * @param[in]   emitter     An emitter object.
+ * @param[in]   indent      The indentation increment (> 1).
+ */
+
+YAML_DECLARE(void)
+yaml_emitter_set_indent(yaml_emitter_t *emitter, int indent);
+
+/**
+ * Set the preferred line width. @c 0 means unlimited.
+ *
+ * @param[in]   emitter     An emitter object.
+ * @param[in]   width       The preferred line width.
+ */
+
+YAML_DECLARE(void)
+yaml_emitter_set_width(yaml_emitter_t *emitter, int width);
+
+/**
+ * Set if unescaped non-ASCII characters are allowed.
+ *
+ * @param[in]   emitter     An emitter object.
+ * @param[in]   unicode     If unescaped Unicode characters are allowed.
+ */
+
+YAML_DECLARE(void)
+yaml_emitter_set_unicode(yaml_emitter_t *emitter, int unicode);
+
+/**
+ * Set the preferred line break.
+ *
+ * @param[in]   emitter     An emitter object.
+ * @param[in]   line_break  The preferred line break.
+ */
+
+YAML_DECLARE(void)
+yaml_emitter_set_break(yaml_emitter_t *emitter, yaml_break_t line_break);
+
+/**
+ * Emit an event.
+ *
+ * The event object may be generated using the @c yaml_parser_parse function.
+ * The emitter will destroy the event object if the function succeeds.  If the
+ * function fails, the application is responsible for destroing the event
+ * object.
+ *
+ * @param[in]   emitter     An emitter object.
+ * @param[in]   event       An event object.
+ *
+ * @returns @c 1 if the function succeeded, @c 0 on error.
+ */
+
 YAML_DECLARE(int)
 yaml_emitter_emit(yaml_emitter_t *emitter, yaml_event_t *event);
 
+/**
+ * Emit the STREAM-START event.
+ *
+ * @param[in]   emitter     An emitter object.
+ * @param[in]   encoding    The stream encoding.
+ *
+ * @returns @c 1 if the function succeeded, @c 0 on error.
+ */
+
 YAML_DECLARE(int)
 yaml_emitter_emit_stream_start(yaml_emitter_t *emitter,
         yaml_encoding_t encoding);
 
-*/
+/**
+ * Emit the STREAM-END event.
+ *
+ * @param[in]   emitter     An emitter object.
+ *
+ * @returns @c 1 if the function succeeded, @c 0 on error.
+ */
+
+YAML_DECLARE(int)
+yaml_emitter_emit_stream_end(yaml_emitter_t *emitter);
+
+/**
+ * Emit the DOCUMENT-START event.
+ *
+ * The @a implicit argument is considered as a stylistic parameter and may be
+ * ignored by the emitter.
+ *
+ * @param[in]   emitter                 An emitter object.
+ * @param[in]   version_directive       The %YAML directive value or @c NULL.
+ * @param[in]   tag_directives_start    The beginning of the %TAG directives list.
+ * @param[in]   tag_directives_end      The end of the %TAG directives list.
+ * @param[in]   implicit                If the document start indicator is implicit.
+ *
+ * @returns @c 1 if the function succeeded, @c 0 on error.
+ */
+
+YAML_DECLARE(int)
+yaml_emitter_emit_document_start(yaml_emitter_t *emitter,
+        yaml_version_directive_t *version_directive,
+        yaml_tag_directive_t *tag_directives_start,
+        yaml_tag_directive_t *tag_directives_end,
+        int implicit);
+
+/**
+ * Emit the DOCUMENT-END event.
+ *
+ * The @a implicit argument is considered as a stylistic parameter and may be
+ * ignored by the emitter.
+ *
+ * @param[in]   emitter     An emitter object.
+ * @param[in]   implicit    If the document end indicator is implicit.
+ *
+ * @returns @c 1 if the function succeeded, @c 0 on error.
+ */
+
+YAML_DECLARE(int)
+yaml_emitter_emit_document_end(yaml_emitter_t *emitter, int implicit);
+
+/**
+ * Emit an ALIAS event.
+ *
+ * @param[in]   emitter     An emitter object.
+ * @param[in]   anchor      The anchor value.
+ *
+ * @returns @c 1 if the function succeeded, @c 0 on error.
+ */
+
+YAML_DECLARE(int)
+yaml_emitter_emit_alias(yaml_emitter_t *emitter, yaml_char_t *anchor);
+
+/**
+ * Emit a SCALAR event.
+ *
+ * The @a style argument may be ignored by the emitter.
+ *
+ * Either the @a tag attribute or one of the @a plain_implicit and
+ * @a quoted_implicit flags must be set.
+ *
+ * @param[in]   emitter         An emitter object.
+ * @param[in]   anchor          The scalar anchor or @c NULL.
+ * @param[in]   tag             The scalar tag or @c NULL.
+ * @param[in]   value           The scalar value.
+ * @param[in]   length          The length of the scalar value.
+ * @param[in]   plain_implicit  If the tag may be omitted for the plain style.
+ * @param[in]   quoted_implicit If the tag may be omitted for any non-plain style.
+ * @param[in]   style           The scalar style.
+ *
+ * @returns @c 1 if the function succeeded, @c 0 on error.
+ */
+
+YAML_DECLARE(int)
+yaml_emitter_emit_scalar(yaml_emitter_t *emitter,
+        yaml_char_t *anchor, yaml_char_t *tag,
+        yaml_char_t *value, size_t length,
+        int plain_implicit, int quoted_implicit,
+        yaml_scalar_style_t style);
+
+/**
+ * Emit a SEQUENCE-START event.
+ *
+ * The @a style argument may be ignored by the emitter.
+ *
+ * Either the @a tag attribute or the @a implicit flag must be set.
+ *
+ * @param[in]   emitter     An emitter object.
+ * @param[in]   anchor      The sequence anchor or @c NULL.
+ * @param[in]   tag         The sequence tag or @c NULL.
+ * @param[in]   implicit    If the tag may be omitted.
+ * @param[in]   style       The sequence style.
+ *
+ * @returns @c 1 if the function succeeded, @c 0 on error.
+ */
+
+YAML_DECLARE(int)
+yaml_emitter_emit_sequence_start(yaml_emitter_t *emitter,
+        yaml_char_t *anchor, yaml_char_t *tag, int implicit,
+        yaml_sequence_style_t style);
+
+/**
+ * Emit a SEQUENCE-END event.
+ *
+ * @param[in]   emitter     An emitter object.
+ *
+ * @returns @c 1 if the function succeeded, @c 0 on error.
+ */
+
+YAML_DECLARE(int)
+yaml_emitter_emit_sequence_end(yaml_emitter_t *emitter);
+
+/**
+ * Emit a MAPPING-START event.
+ *
+ * The @a style argument may be ignored by the emitter.
+ *
+ * Either the @a tag attribute or the @a implicit flag must be set.
+ *
+ * @param[in]   emitter     An emitter object.
+ * @param[in]   anchor      The mapping anchor or @c NULL.
+ * @param[in]   tag         The mapping tag or @c NULL.
+ * @param[in]   implicit    If the tag may be omitted.
+ * @param[in]   style       The mapping style.
+ *
+ * @returns @c 1 if the function succeeded, @c 0 on error.
+ */
+
+YAML_DECLARE(int)
+yaml_emitter_emit_mapping_start(yaml_emitter_t *emitter,
+        yaml_char_t *anchor, yaml_char_t *tag, int implicit,
+        yaml_mapping_style_t style);
+
+/**
+ * Emit a MAPPING-END event.
+ *
+ * @param[in]   emitter     An emitter object.
+ *
+ * @returns @c 1 if the function succeeded, @c 0 on error.
+ */
+
+YAML_DECLARE(int)
+yaml_emitter_emit_mapping_end(yaml_emitter_t *emitter);
+
+/**
+ * Flush the accumulated characters to the output.
+ *
+ * @param[in]   emitter     An emitter object.
+ *
+ * @returns @c 1 if the function succeeded, @c 0 on error.
+ */
+
+YAML_DECLARE(int)
+yaml_emitter_flush(yaml_emitter_t *emitter);
+
+/** @} */
 
 #ifdef __cplusplus
 }
index c7f6da2ab9cf94bac16c4b6f15a88ae15eda4329..25a5bc82e8d81a1324558820da9419ebdd12f9e9 100644 (file)
@@ -1,4 +1,4 @@
 AM_CPPFLAGS = -I$(top_srcdir)/include
 lib_LTLIBRARIES = libyaml.la
-libyaml_la_SOURCES = api.c reader.c scanner.c parser.c
+libyaml_la_SOURCES = api.c reader.c scanner.c parser.c writer.c
 libyaml_la_LDFLAGS = -release $(YAML_LT_RELEASE) -version-info $(YAML_LT_CURRENT):$(YAML_LT_REVISION):$(YAML_LT_AGE)
index 23f4ff20c4f23eeadf1f8318c109dc712b3433ed..90d86fddee87e11aebce9f5f2f4ea1dde0e6c1cf 100644 (file)
--- a/src/api.c
+++ b/src/api.c
@@ -169,9 +169,9 @@ yaml_parser_initialize(yaml_parser_t *parser)
     assert(parser);     /* Non-NULL parser object expected. */
 
     memset(parser, 0, sizeof(yaml_parser_t));
-    if (!BUFFER_INIT(parser, parser->raw_buffer, RAW_BUFFER_SIZE))
+    if (!BUFFER_INIT(parser, parser->raw_buffer, INPUT_RAW_BUFFER_SIZE))
         goto error;
-    if (!BUFFER_INIT(parser, parser->buffer, BUFFER_SIZE))
+    if (!BUFFER_INIT(parser, parser->buffer, INPUT_BUFFER_SIZE))
         goto error;
     if (!QUEUE_INIT(parser, parser->tokens, INITIAL_QUEUE_SIZE))
         goto error;
@@ -336,6 +336,233 @@ yaml_parser_set_encoding(yaml_parser_t *parser, yaml_encoding_t encoding)
     parser->encoding = encoding;
 }
 
+/*
+ * Create a new emitter object.
+ */
+
+YAML_DECLARE(int)
+yaml_emitter_initialize(yaml_emitter_t *emitter)
+{
+    assert(emitter);    /* Non-NULL emitter object expected. */
+
+    memset(emitter, 0, sizeof(yaml_emitter_t));
+    if (!BUFFER_INIT(emitter, emitter->buffer, OUTPUT_BUFFER_SIZE))
+        goto error;
+    if (!BUFFER_INIT(emitter, emitter->raw_buffer, OUTPUT_RAW_BUFFER_SIZE))
+        goto error;
+    if (!STACK_INIT(emitter, emitter->states, INITIAL_STACK_SIZE))
+        goto error;
+    if (!QUEUE_INIT(emitter, emitter->events, INITIAL_QUEUE_SIZE))
+        goto error;
+    if (!STACK_INIT(emitter, emitter->indents, INITIAL_STACK_SIZE))
+        goto error;
+    if (!STACK_INIT(emitter, emitter->tag_directives, INITIAL_STACK_SIZE))
+        goto error;
+
+    return 1;
+
+error:
+
+    BUFFER_DEL(emitter, emitter->buffer);
+    BUFFER_DEL(emitter, emitter->raw_buffer);
+    STACK_DEL(emitter, emitter->states);
+    QUEUE_DEL(emitter, emitter->events);
+    STACK_DEL(emitter, emitter->indents);
+    STACK_DEL(emitter, emitter->tag_directives);
+
+    return 0;
+}
+
+/*
+ * Destroy an emitter object.
+ */
+
+YAML_DECLARE(void)
+yaml_emitter_delete(yaml_emitter_t *emitter)
+{
+    assert(emitter);    /* Non-NULL emitter object expected. */
+
+    BUFFER_DEL(emitter, emitter->buffer);
+    BUFFER_DEL(emitter, emitter->raw_buffer);
+    STACK_DEL(emitter, emitter->states);
+    while (!QUEUE_EMPTY(emitter, emitter->events)) {
+        yaml_event_delete(&DEQUEUE(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);
+
+    memset(emitter, 0, sizeof(yaml_emitter_t));
+}
+
+/*
+ * String write handler.
+ */
+
+static int
+yaml_string_write_handler(void *data, unsigned char *buffer, size_t size)
+{
+    yaml_emitter_t *emitter = data;
+
+    if (emitter->output.string.size + *emitter->output.string.size_written
+            < size) {
+        memcpy(emitter->output.string.buffer
+                + *emitter->output.string.size_written,
+                buffer,
+                emitter->output.string.size
+                - *emitter->output.string.size_written);
+        *emitter->output.string.size_written = emitter->output.string.size;
+        return 0;
+    }
+
+    memcpy(emitter->output.string.buffer
+            + *emitter->output.string.size_written, buffer, size);
+    *emitter->output.string.size_written += size;
+    return 1;
+}
+
+/*
+ * File write handler.
+ */
+
+static int
+yaml_file_write_handler(void *data, unsigned char *buffer, size_t size)
+{
+    yaml_emitter_t *emitter = data;
+
+    return (fwrite(buffer, 1, size, emitter->output.file) == size);
+}
+/*
+ * Set a string output.
+ */
+
+YAML_DECLARE(void)
+yaml_emitter_set_output_string(yaml_emitter_t *emitter,
+        unsigned char *output, size_t size, size_t *size_written)
+{
+    assert(emitter);    /* Non-NULL emitter object expected. */
+    assert(!emitter->write_handler);    /* You can set the output only once. */
+    assert(output);     /* Non-NULL output string expected. */
+
+    emitter->write_handler = yaml_string_write_handler;
+    emitter->write_handler_data = emitter;
+
+    emitter->output.string.buffer = output;
+    emitter->output.string.size = size;
+    emitter->output.string.size_written = size_written;
+    *size_written = 0;
+}
+
+/*
+ * Set a file output.
+ */
+
+YAML_DECLARE(void)
+yaml_emitter_set_output_file(yaml_emitter_t *emitter, FILE *file)
+{
+    assert(emitter);    /* Non-NULL emitter object expected. */
+    assert(!emitter->write_handler);    /* You can set the output only once. */
+    assert(file);       /* Non-NULL file object expected. */
+
+    emitter->write_handler = yaml_file_write_handler;
+    emitter->write_handler_data = emitter;
+
+    emitter->output.file = file;
+}
+
+/*
+ * Set a generic output handler.
+ */
+
+YAML_DECLARE(void)
+yaml_emitter_set_output(yaml_emitter_t *emitter,
+        yaml_write_handler_t *handler, void *data)
+{
+    assert(emitter);    /* Non-NULL emitter object expected. */
+    assert(!emitter->write_handler);    /* You can set the output only once. */
+    assert(handler);    /* Non-NULL handler object expected. */
+
+    emitter->write_handler = handler;
+    emitter->write_handler_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 canonical)
+{
+    assert(emitter);    /* Non-NULL emitter object expected. */
+
+    emitter->canonical = (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 : 0;
+}
+
+/*
+ * Set if unescaped non-ASCII characters are allowed.
+ */
+
+YAML_DECLARE(void)
+yaml_emitter_set_unicode(yaml_emitter_t *emitter, int unicode)
+{
+    assert(emitter);    /* Non-NULL emitter object expected. */
+
+    emitter->unicode = (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;
+}
+
 /*
  * Destroy a token object.
  */
index 2b81b0c21519cc8ca1e95fb973314813c26c603b..020d5d6898a0af388388f038359702c03c88f47c 100644 (file)
 
 #include "yaml_private.h"
 
-/*
- * Event initializers.
- */
-
-#define EVENT_INIT(event,event_type,event_start_mark,event_end_mark)            \
-    (memset(&(event), 0, sizeof(yaml_event_t)),                                 \
-     (event).type = (event_type),                                               \
-     (event).start_mark = (event_start_mark),                                   \
-     (event).end_mark = (event_end_mark))
-
-#define STREAM_START_EVENT_INIT(event,event_encoding,start_mark,end_mark)       \
-    (EVENT_INIT((event),YAML_STREAM_START_EVENT,(start_mark),(end_mark)),       \
-     (event).data.stream_start.encoding = (event_encoding))
-
-#define STREAM_END_EVENT_INIT(event,start_mark,end_mark)                        \
-    (EVENT_INIT((event),YAML_STREAM_END_EVENT,(start_mark),(end_mark)))
-
-#define DOCUMENT_START_EVENT_INIT(event,event_version_directive,                \
-        event_tag_directives_start,event_tag_directives_end,event_implicit,start_mark,end_mark) \
-    (EVENT_INIT((event),YAML_DOCUMENT_START_EVENT,(start_mark),(end_mark)),     \
-     (event).data.document_start.version_directive = (event_version_directive), \
-     (event).data.document_start.tag_directives.start = (event_tag_directives_start),   \
-     (event).data.document_start.tag_directives.end = (event_tag_directives_end),   \
-     (event).data.document_start.implicit = (event_implicit))
-
-#define DOCUMENT_END_EVENT_INIT(event,event_implicit,start_mark,end_mark)       \
-    (EVENT_INIT((event),YAML_DOCUMENT_END_EVENT,(start_mark),(end_mark)),       \
-     (event).data.document_end.implicit = (event_implicit))
-
-#define ALIAS_EVENT_INIT(event,event_anchor,start_mark,end_mark)                \
-    (EVENT_INIT((event),YAML_ALIAS_EVENT,(start_mark),(end_mark)),              \
-     (event).data.alias.anchor = (event_anchor))
-
-#define SCALAR_EVENT_INIT(event,event_anchor,event_tag,event_value,event_length,    \
-        event_plain_implicit, event_quoted_implicit,event_style,start_mark,end_mark)    \
-    (EVENT_INIT((event),YAML_SCALAR_EVENT,(start_mark),(end_mark)),             \
-     (event).data.scalar.anchor = (event_anchor),                               \
-     (event).data.scalar.tag = (event_tag),                                     \
-     (event).data.scalar.value = (event_value),                                 \
-     (event).data.scalar.length = (event_length),                               \
-     (event).data.scalar.plain_implicit = (event_plain_implicit),               \
-     (event).data.scalar.quoted_implicit = (event_quoted_implicit),             \
-     (event).data.scalar.style = (event_style))
-
-#define SEQUENCE_START_EVENT_INIT(event,event_anchor,event_tag,                 \
-        event_implicit,event_style,start_mark,end_mark)                         \
-    (EVENT_INIT((event),YAML_SEQUENCE_START_EVENT,(start_mark),(end_mark)),     \
-     (event).data.sequence_start.anchor = (event_anchor),                       \
-     (event).data.sequence_start.tag = (event_tag),                             \
-     (event).data.sequence_start.implicit = (event_implicit),                   \
-     (event).data.sequence_start.style = (event_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,event_anchor,event_tag,                  \
-        event_implicit,event_style,start_mark,end_mark)                         \
-    (EVENT_INIT((event),YAML_MAPPING_START_EVENT,(start_mark),(end_mark)),      \
-     (event).data.mapping_start.anchor = (event_anchor),                        \
-     (event).data.mapping_start.tag = (event_tag),                              \
-     (event).data.mapping_start.implicit = (event_implicit),                    \
-     (event).data.mapping_start.style = (event_style))
-
-#define MAPPING_END_EVENT_INIT(event,start_mark,end_mark)                       \
-    (EVENT_INIT((event),YAML_MAPPING_END_EVENT,(start_mark),(end_mark)))
-
 /*
  * Peek the next token in the token queue.
  */
index a9b78ff13393d0a51fe40136bdb8c9273c028fb0..bb811276cdb901a4b7423d9be5037082139b85aa 100644 (file)
       parser->unread --) : 0),                                                  \
     1) : 0)
 
-/*
- * Token initializers.
- */
-
-#define TOKEN_INIT(token,token_type,token_start_mark,token_end_mark)            \
-    (memset(&(token), 0, sizeof(yaml_token_t)),                                 \
-     (token).type = (token_type),                                               \
-     (token).start_mark = (token_start_mark),                                   \
-     (token).end_mark = (token_end_mark))
-
-#define STREAM_START_TOKEN_INIT(token,token_encoding,start_mark,end_mark)       \
-    (TOKEN_INIT((token),YAML_STREAM_START_TOKEN,(start_mark),(end_mark)),       \
-     (token).data.stream_start.encoding = (token_encoding))
-
-#define STREAM_END_TOKEN_INIT(token,start_mark,end_mark)                        \
-    (TOKEN_INIT((token),YAML_STREAM_END_TOKEN,(start_mark),(end_mark)))
-
-#define ALIAS_TOKEN_INIT(token,token_value,start_mark,end_mark)                 \
-    (TOKEN_INIT((token),YAML_ALIAS_TOKEN,(start_mark),(end_mark)),              \
-     (token).data.alias.value = (token_value))
-
-#define ANCHOR_TOKEN_INIT(token,token_value,start_mark,end_mark)                \
-    (TOKEN_INIT((token),YAML_ANCHOR_TOKEN,(start_mark),(end_mark)),             \
-     (token).data.anchor.value = (token_value))
-
-#define TAG_TOKEN_INIT(token,token_handle,token_suffix,start_mark,end_mark)     \
-    (TOKEN_INIT((token),YAML_TAG_TOKEN,(start_mark),(end_mark)),                \
-     (token).data.tag.handle = (token_handle),                                  \
-     (token).data.tag.suffix = (token_suffix))
-
-#define SCALAR_TOKEN_INIT(token,token_value,token_length,token_style,start_mark,end_mark)   \
-    (TOKEN_INIT((token),YAML_SCALAR_TOKEN,(start_mark),(end_mark)),             \
-     (token).data.scalar.value = (token_value),                                 \
-     (token).data.scalar.length = (token_length),                               \
-     (token).data.scalar.style = (token_style))
-
-#define VERSION_DIRECTIVE_TOKEN_INIT(token,token_major,token_minor,start_mark,end_mark)     \
-    (TOKEN_INIT((token),YAML_VERSION_DIRECTIVE_TOKEN,(start_mark),(end_mark)),  \
-     (token).data.version_directive.major = (token_major),                      \
-     (token).data.version_directive.minor = (token_minor))
-
-#define TAG_DIRECTIVE_TOKEN_INIT(token,token_handle,token_prefix,start_mark,end_mark)       \
-    (TOKEN_INIT((token),YAML_TAG_DIRECTIVE_TOKEN,(start_mark),(end_mark)),      \
-     (token).data.tag_directive.handle = (token_handle),                        \
-     (token).data.tag_directive.prefix = (token_prefix))
-
 /*
  * Public API declarations.
  */
diff --git a/src/writer.c b/src/writer.c
new file mode 100644 (file)
index 0000000..2131372
--- /dev/null
@@ -0,0 +1,138 @@
+
+#include "yaml_private.h"
+
+/*
+ * Declarations.
+ */
+
+static int
+yaml_emitter_set_writer_error(yaml_emitter_t *emitter, const char *problem);
+
+YAML_DECLARE(int)
+yaml_emitter_flush(yaml_emitter_t *emitter);
+
+/*
+ * Set the writer error and return 0.
+ */
+
+static int
+yaml_emitter_set_writer_error(yaml_emitter_t *emitter, const char *problem)
+{
+    emitter->error = YAML_WRITER_ERROR;
+    emitter->problem = problem;
+
+    return 0;
+}
+
+/*
+ * Flush the output buffer.
+ */
+
+YAML_DECLARE(int)
+yaml_emitter_flush(yaml_emitter_t *emitter)
+{
+    int low, high;
+
+    assert(emitter);    /* Non-NULL emitter object is expected. */
+    assert(emitter->write_handler); /* Write handler must be set. */
+    assert(emitter->encoding);  /* Output encoding must be set. */
+
+    /* Check if the buffer is empty. */
+
+    if (emitter->buffer.start == emitter->buffer.last) {
+        return 1;
+    }
+
+    /* If the output encoding is UTF-8, we don't need to recode the buffer. */
+
+    if (emitter->encoding == YAML_UTF8_ENCODING)
+    {
+        if (emitter->write_handler(emitter->write_handler_data,
+                    emitter->buffer.start,
+                    emitter->buffer.last - emitter->buffer.start)) {
+            emitter->buffer.last = emitter->buffer.start;
+            emitter->buffer.pointer = emitter->buffer.start;
+            return 1;
+        }
+        else {
+            return yaml_emitter_set_writer_error(emitter, "Write error");
+        }
+    }
+
+    /* Recode the buffer into the raw buffer. */
+
+    low = (emitter->encoding == YAML_UTF16LE_ENCODING ? 0 : 1);
+    high = (emitter->encoding == YAML_UTF16LE_ENCODING ? 1 : 0);
+
+    while (emitter->buffer.pointer != emitter->buffer.last)
+    {
+        unsigned char octet;
+        unsigned int width;
+        unsigned int value;
+        int k;
+
+        /* 
+         * See the "reader.c" code for more details on UTF-8 encoding.  Note
+         * that we assume that the buffer contains a valid UTF-8 sequence.
+         */
+
+        /* Read the next UTF-8 character. */
+
+        octet = emitter->buffer.pointer[0];
+
+        width = (octet & 0x80) == 0x00 ? 1 :
+                (octet & 0xE0) == 0xC0 ? 2 :
+                (octet & 0xF0) == 0xE0 ? 3 :
+                (octet & 0xF8) == 0xF0 ? 4 : 0;
+
+        value = (octet & 0x80) == 0x00 ? octet & 0x7F :
+                (octet & 0xE0) == 0xC0 ? octet & 0x1F :
+                (octet & 0xF0) == 0xE0 ? octet & 0x0F :
+                (octet & 0xF8) == 0xF0 ? octet & 0x07 : 0;
+
+        for (k = 1; k < width; k ++) {
+            octet = emitter->buffer.pointer[k];
+            value = (value << 6) + (octet & 0x3F);
+        }
+
+        emitter->buffer.pointer += width;
+
+        /* Write the character. */
+
+        if (value < 0x10000)
+        {
+            emitter->raw_buffer.last[high] = value >> 8;
+            emitter->raw_buffer.last[low] = value & 0xFF;
+
+            emitter->raw_buffer.last += 2;
+        }
+        else
+        {
+            /* Write the character using a surrogate pair (check "reader.c"). */
+
+            value -= 0x10000;
+            emitter->raw_buffer.last[high] = 0xD8 + (value >> 18);
+            emitter->raw_buffer.last[low] = (value >> 10) & 0xFF;
+            emitter->raw_buffer.last[high+2] = 0xDC + ((value >> 8) & 0xFF);
+            emitter->raw_buffer.last[low+2] = value & 0xFF;
+
+            emitter->raw_buffer.last += 4;
+        }
+    }
+
+    /* Write the raw buffer. */
+
+    if (emitter->write_handler(emitter->write_handler_data,
+                emitter->raw_buffer.start,
+                emitter->raw_buffer.last - emitter->raw_buffer.start)) {
+        emitter->buffer.last = emitter->buffer.start;
+        emitter->buffer.pointer = emitter->buffer.start;
+        emitter->raw_buffer.last = emitter->raw_buffer.start;
+        emitter->raw_buffer.pointer = emitter->raw_buffer.start;
+        return 1;
+    }
+    else {
+        return yaml_emitter_set_writer_error(emitter, "Write error");
+    }
+}
+
index d7ac644da8d72ccceb7a837e2730c4bd0025bdc1..7304d8d3376f2b6cff568ef0410660483b295a58 100644 (file)
@@ -38,18 +38,32 @@ YAML_DECLARE(int)
 yaml_parser_fetch_more_tokens(yaml_parser_t *parser);
 
 /*
- * The size of the raw buffer.
+ * The size of the input raw buffer.
  */
 
-#define RAW_BUFFER_SIZE 16384
+#define INPUT_RAW_BUFFER_SIZE   16384
 
 /*
- * The size of the buffer.
+ * The size of the input buffer.
  *
  * It should be possible to decode the whole raw buffer.
  */
 
-#define BUFFER_SIZE     (RAW_BUFFER_SIZE*3)
+#define INPUT_BUFFER_SIZE       (INPUT_RAW_BUFFER_SIZE*3)
+
+/*
+ * The size of the output buffer.
+ */
+
+#define OUTPUT_BUFFER_SIZE      16384
+
+/*
+ * The size of the output raw buffer.
+ *
+ * It should be possible to encode the whole output buffer.
+ */
+
+#define OUTPUT_RAW_BUFFER_SIZE  (OUTPUT_BUFFER_SIZE*2+2)
 
 /*
  * The size of other stacks and queues.
@@ -203,3 +217,115 @@ yaml_queue_extend(void **start, void **head, void **tail, void **end);
         ((context)->error = YAML_MEMORY_ERROR,                                  \
          0))
 
+/*
+ * Token initializers.
+ */
+
+#define TOKEN_INIT(token,token_type,token_start_mark,token_end_mark)            \
+    (memset(&(token), 0, sizeof(yaml_token_t)),                                 \
+     (token).type = (token_type),                                               \
+     (token).start_mark = (token_start_mark),                                   \
+     (token).end_mark = (token_end_mark))
+
+#define STREAM_START_TOKEN_INIT(token,token_encoding,start_mark,end_mark)       \
+    (TOKEN_INIT((token),YAML_STREAM_START_TOKEN,(start_mark),(end_mark)),       \
+     (token).data.stream_start.encoding = (token_encoding))
+
+#define STREAM_END_TOKEN_INIT(token,start_mark,end_mark)                        \
+    (TOKEN_INIT((token),YAML_STREAM_END_TOKEN,(start_mark),(end_mark)))
+
+#define ALIAS_TOKEN_INIT(token,token_value,start_mark,end_mark)                 \
+    (TOKEN_INIT((token),YAML_ALIAS_TOKEN,(start_mark),(end_mark)),              \
+     (token).data.alias.value = (token_value))
+
+#define ANCHOR_TOKEN_INIT(token,token_value,start_mark,end_mark)                \
+    (TOKEN_INIT((token),YAML_ANCHOR_TOKEN,(start_mark),(end_mark)),             \
+     (token).data.anchor.value = (token_value))
+
+#define TAG_TOKEN_INIT(token,token_handle,token_suffix,start_mark,end_mark)     \
+    (TOKEN_INIT((token),YAML_TAG_TOKEN,(start_mark),(end_mark)),                \
+     (token).data.tag.handle = (token_handle),                                  \
+     (token).data.tag.suffix = (token_suffix))
+
+#define SCALAR_TOKEN_INIT(token,token_value,token_length,token_style,start_mark,end_mark)   \
+    (TOKEN_INIT((token),YAML_SCALAR_TOKEN,(start_mark),(end_mark)),             \
+     (token).data.scalar.value = (token_value),                                 \
+     (token).data.scalar.length = (token_length),                               \
+     (token).data.scalar.style = (token_style))
+
+#define VERSION_DIRECTIVE_TOKEN_INIT(token,token_major,token_minor,start_mark,end_mark)     \
+    (TOKEN_INIT((token),YAML_VERSION_DIRECTIVE_TOKEN,(start_mark),(end_mark)),  \
+     (token).data.version_directive.major = (token_major),                      \
+     (token).data.version_directive.minor = (token_minor))
+
+#define TAG_DIRECTIVE_TOKEN_INIT(token,token_handle,token_prefix,start_mark,end_mark)       \
+    (TOKEN_INIT((token),YAML_TAG_DIRECTIVE_TOKEN,(start_mark),(end_mark)),      \
+     (token).data.tag_directive.handle = (token_handle),                        \
+     (token).data.tag_directive.prefix = (token_prefix))
+
+/*
+ * Event initializers.
+ */
+
+#define EVENT_INIT(event,event_type,event_start_mark,event_end_mark)            \
+    (memset(&(event), 0, sizeof(yaml_event_t)),                                 \
+     (event).type = (event_type),                                               \
+     (event).start_mark = (event_start_mark),                                   \
+     (event).end_mark = (event_end_mark))
+
+#define STREAM_START_EVENT_INIT(event,event_encoding,start_mark,end_mark)       \
+    (EVENT_INIT((event),YAML_STREAM_START_EVENT,(start_mark),(end_mark)),       \
+     (event).data.stream_start.encoding = (event_encoding))
+
+#define STREAM_END_EVENT_INIT(event,start_mark,end_mark)                        \
+    (EVENT_INIT((event),YAML_STREAM_END_EVENT,(start_mark),(end_mark)))
+
+#define DOCUMENT_START_EVENT_INIT(event,event_version_directive,                \
+        event_tag_directives_start,event_tag_directives_end,event_implicit,start_mark,end_mark) \
+    (EVENT_INIT((event),YAML_DOCUMENT_START_EVENT,(start_mark),(end_mark)),     \
+     (event).data.document_start.version_directive = (event_version_directive), \
+     (event).data.document_start.tag_directives.start = (event_tag_directives_start),   \
+     (event).data.document_start.tag_directives.end = (event_tag_directives_end),   \
+     (event).data.document_start.implicit = (event_implicit))
+
+#define DOCUMENT_END_EVENT_INIT(event,event_implicit,start_mark,end_mark)       \
+    (EVENT_INIT((event),YAML_DOCUMENT_END_EVENT,(start_mark),(end_mark)),       \
+     (event).data.document_end.implicit = (event_implicit))
+
+#define ALIAS_EVENT_INIT(event,event_anchor,start_mark,end_mark)                \
+    (EVENT_INIT((event),YAML_ALIAS_EVENT,(start_mark),(end_mark)),              \
+     (event).data.alias.anchor = (event_anchor))
+
+#define SCALAR_EVENT_INIT(event,event_anchor,event_tag,event_value,event_length,    \
+        event_plain_implicit, event_quoted_implicit,event_style,start_mark,end_mark)    \
+    (EVENT_INIT((event),YAML_SCALAR_EVENT,(start_mark),(end_mark)),             \
+     (event).data.scalar.anchor = (event_anchor),                               \
+     (event).data.scalar.tag = (event_tag),                                     \
+     (event).data.scalar.value = (event_value),                                 \
+     (event).data.scalar.length = (event_length),                               \
+     (event).data.scalar.plain_implicit = (event_plain_implicit),               \
+     (event).data.scalar.quoted_implicit = (event_quoted_implicit),             \
+     (event).data.scalar.style = (event_style))
+
+#define SEQUENCE_START_EVENT_INIT(event,event_anchor,event_tag,                 \
+        event_implicit,event_style,start_mark,end_mark)                         \
+    (EVENT_INIT((event),YAML_SEQUENCE_START_EVENT,(start_mark),(end_mark)),     \
+     (event).data.sequence_start.anchor = (event_anchor),                       \
+     (event).data.sequence_start.tag = (event_tag),                             \
+     (event).data.sequence_start.implicit = (event_implicit),                   \
+     (event).data.sequence_start.style = (event_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,event_anchor,event_tag,                  \
+        event_implicit,event_style,start_mark,end_mark)                         \
+    (EVENT_INIT((event),YAML_MAPPING_START_EVENT,(start_mark),(end_mark)),      \
+     (event).data.mapping_start.anchor = (event_anchor),                        \
+     (event).data.mapping_start.tag = (event_tag),                              \
+     (event).data.mapping_start.implicit = (event_implicit),                    \
+     (event).data.mapping_start.style = (event_style))
+
+#define MAPPING_END_EVENT_INIT(event,start_mark,end_mark)                       \
+    (EVENT_INIT((event),YAML_MAPPING_END_EVENT,(start_mark),(end_mark)))
+
This page took 0.291039 seconds and 5 git commands to generate.