зеркало из https://github.com/github/ruby.git
172 строки
6.6 KiB
C
172 строки
6.6 KiB
C
/* yamlbyte.h
|
|
*
|
|
* The YAML bytecode "C" interface header file. See the YAML bytecode
|
|
* reference for bytecode sequence rules and for the meaning of each
|
|
* bytecode.
|
|
*/
|
|
|
|
#ifndef YAMLBYTE_H
|
|
#define YAMLBYTE_H
|
|
#include <stddef.h>
|
|
|
|
/* define what a character is */
|
|
typedef unsigned char yamlbyte_utf8_t;
|
|
typedef unsigned short yamlbyte_utf16_t;
|
|
#ifdef YAMLBYTE_UTF8
|
|
#ifdef YAMLBYTE_UTF16
|
|
#error Must only define YAMLBYTE_UTF8 or YAMLBYTE_UTF16
|
|
#endif
|
|
typedef yamlbyte_utf8_t yamlbyte_char_t;
|
|
#else
|
|
#ifdef YAMLBYTE_UTF16
|
|
typedef yamlbyte_utf16_t yamlbyte_char_t;
|
|
#else
|
|
#error Must define YAMLBYTE_UTF8 or YAMLBYTE_UTF16
|
|
#endif
|
|
#endif
|
|
|
|
/* specify list of bytecodes */
|
|
#define YAMLBYTE_FINISH ((yamlbyte_char_t) 0)
|
|
#define YAMLBYTE_DOCUMENT ((yamlbyte_char_t)'D')
|
|
#define YAMLBYTE_DIRECTIVE ((yamlbyte_char_t)'V')
|
|
#define YAMLBYTE_PAUSE ((yamlbyte_char_t)'P')
|
|
#define YAMLBYTE_MAPPING ((yamlbyte_char_t)'M')
|
|
#define YAMLBYTE_SEQUENCE ((yamlbyte_char_t)'Q')
|
|
#define YAMLBYTE_END_BRANCH ((yamlbyte_char_t)'E')
|
|
#define YAMLBYTE_SCALAR ((yamlbyte_char_t)'S')
|
|
#define YAMLBYTE_CONTINUE ((yamlbyte_char_t)'C')
|
|
#define YAMLBYTE_NEWLINE ((yamlbyte_char_t)'N')
|
|
#define YAMLBYTE_NULLCHAR ((yamlbyte_char_t)'Z')
|
|
#define YAMLBYTE_ANCHOR ((yamlbyte_char_t)'A')
|
|
#define YAMLBYTE_ALIAS ((yamlbyte_char_t)'R')
|
|
#define YAMLBYTE_TRANSFER ((yamlbyte_char_t)'T')
|
|
/* formatting bytecodes */
|
|
#define YAMLBYTE_COMMENT ((yamlbyte_char_t)'c')
|
|
#define YAMLBYTE_INDENT ((yamlbyte_char_t)'i')
|
|
#define YAMLBYTE_STYLE ((yamlbyte_char_t)'s')
|
|
/* other bytecodes */
|
|
#define YAMLBYTE_LINE_NUMBER ((yamlbyte_char_t)'#')
|
|
#define YAMLBYTE_WHOLE_SCALAR ((yamlbyte_char_t)'<')
|
|
#define YAMLBYTE_NOTICE ((yamlbyte_char_t)'!')
|
|
#define YAMLBYTE_SPAN ((yamlbyte_char_t)')')
|
|
#define YAMLBYTE_ALLOC ((yamlbyte_char_t)'@')
|
|
|
|
/* second level style bytecodes, ie "s>" */
|
|
#define YAMLBYTE_FLOW ((yamlbyte_char_t)'>')
|
|
#define YAMLBYTE_LITERAL ((yamlbyte_char_t)'|')
|
|
#define YAMLBYTE_BLOCK ((yamlbyte_char_t)'b')
|
|
#define YAMLBYTE_PLAIN ((yamlbyte_char_t)'p')
|
|
#define YAMLBYTE_INLINE_MAPPING ((yamlbyte_char_t)'{')
|
|
#define YAMLBYTE_INLINE_SEQUENCE ((yamlbyte_char_t)'[')
|
|
#define YAMLBYTE_SINGLE_QUOTED ((yamlbyte_char_t)39)
|
|
#define YAMLBYTE_DOUBLE_QUOTED ((yamlbyte_char_t)'"')
|
|
|
|
/*
|
|
* The "C" API has two variants, one based on instructions,
|
|
* with events delivered via pointers; and the other one
|
|
* is character based where one or more instructions are
|
|
* serialized into a buffer.
|
|
*
|
|
* Note: In the instruction based API, WHOLE_SCALAR does
|
|
* not have the '<here' marshalling stuff.
|
|
*/
|
|
|
|
typedef void * yamlbyte_consumer_t;
|
|
typedef void * yamlbyte_producer_t;
|
|
|
|
/* push and pull APIs need a way to communicate results */
|
|
typedef enum {
|
|
YAMLBYTE_OK = 0, /* proceed */
|
|
YAMLBYTE_E_MEMORY = 'M', /* could not allocate memory */
|
|
YAMLBYTE_E_READ = 'R', /* input stream read error */
|
|
YAMLBYTE_E_WRITE = 'W', /* output stream write error */
|
|
YAMLBYTE_E_OTHER = '?', /* some other error condition */
|
|
YAMLBYTE_E_PARSE = 'P', /* parse error, check bytecodes */
|
|
YAMLBYTE_MAX
|
|
} yamlbyte_result_t;
|
|
|
|
typedef const yamlbyte_char_t *yamlbyte_buff_t;
|
|
|
|
/*
|
|
* The "Instruction" API
|
|
*/
|
|
|
|
typedef struct yaml_instruction {
|
|
yamlbyte_char_t bytecode;
|
|
yamlbyte_buff_t start;
|
|
yamlbyte_buff_t finish; /* open range, *finish is _not_ part */
|
|
} *yamlbyte_inst_t;
|
|
|
|
/* producer pushes the instruction with one bytecode event to the
|
|
* consumer; if the consumer's result is not YAMLBYTE_OK, then
|
|
* the producer should stop */
|
|
typedef
|
|
yamlbyte_result_t
|
|
(*yamlbyte_push_t)(
|
|
yamlbyte_consumer_t self,
|
|
yamlbyte_inst_t inst
|
|
);
|
|
|
|
/* consumer pulls a bytecode instruction from the producer; in this
|
|
* case the instruction (and is buffer) are owned by the producer and
|
|
* will remain valid till the pull function is called once again;
|
|
* if the instruction is NULL, then there are no more results; and
|
|
* it is important to call the pull function till it returns NULL so
|
|
* that the producer can clean up its memory allocations */
|
|
typedef
|
|
yamlbyte_result_t
|
|
(*yamlbyte_pull_t)(
|
|
yamlbyte_producer_t self,
|
|
yamlbyte_inst_t *inst /* to be filled in by the producer */
|
|
);
|
|
|
|
/*
|
|
* Buffer based API
|
|
*/
|
|
|
|
/* producer pushes a null terminated buffer filled with one or more
|
|
* bytecode events to the consumer; if the consumer's result is not
|
|
* YAMLBYTE_OK, then the producer should stop */
|
|
typedef
|
|
yamlbyte_result_t
|
|
(*yamlbyte_pushbuff_t)(
|
|
yamlbyte_consumer_t self,
|
|
yamlbyte_buff_t buff
|
|
);
|
|
|
|
/* consumer pulls bytecode events from the producer; in this case
|
|
* the buffer is owned by the producer, and will remain valid till
|
|
* the pull function is called once again; if the buffer pointer
|
|
* is set to NULL, then there are no more results; it is important
|
|
* to call the pull function till it returns NULL so that the
|
|
* producer can clean up its memory allocations */
|
|
typedef
|
|
yamlbyte_result_t
|
|
(*yamlbyte_pullbuff_t)(
|
|
yamlbyte_producer_t self,
|
|
yamlbyte_buff_t *buff /* to be filled in by the producer */
|
|
);
|
|
|
|
/* convert a pull interface to a push interface; the reverse process
|
|
* requires threads and thus is language dependent */
|
|
#define YAMLBYTE_PULL2PUSH(pull,producer,push,consumer,result) \
|
|
do { \
|
|
yamlbyte_pullbuff_t _pull = (pull); \
|
|
yamlbyte_pushbuff_t _push = (push); \
|
|
yamlbyte_result_t _result = YAMLBYTE_OK; \
|
|
yamlbyte_producer_t _producer = (producer); \
|
|
yamlbyte_consumer_t _consumer = (consumer); \
|
|
while(1) { \
|
|
yamlbyte_buff_t buff = NULL; \
|
|
_result = _pull(_producer,&buff); \
|
|
if(YAMLBYTE_OK != result || NULL == buff) \
|
|
break; \
|
|
_result = _push(_consumer,buff); \
|
|
if(YAMLBYTE_OK != result) \
|
|
break; \
|
|
} \
|
|
(result) = _result; \
|
|
} while(0)
|
|
|
|
#endif
|