From: Clark C. E. <cc...@cl...> - 2003-09-26 23:41:24
|
I'm thinking of working a bit on Syck to produce an output interface similar to this. Please comment on both overall view, and also specific details. Best, Clark ... /* yaml.h * * This is a prototype header for a YAML "C" API. In particular, the goal * of this API is to address information contained in the sequential model, * and act as an interface between the parser and various language loaders. * This file defines a data structure, yaml_event_t which denotes a serial * model event, and two function prototypes, yaml_push_t and yaml_pull_t, * which describe a push and pull interface functions respectively. */ #ifndef YAML_H #define YAML_H #include <stddef.h> /* * CHARACTER ENCODING */ typedef unsigned char yaml_utf8_t; typedef unsigned short yaml_utf16_t; #ifdef YAML_UTF8 #ifdef YAML_UTF16 #error Must only define YAML_UTF8 or YAML_UTF16 #endif typedef yaml_utf8_t yaml_char_t; #else #ifdef YAML_UTF16 typedef yaml_utf16_t yaml_char_t; #else #error Must define YAML_UTF8 or YAML_UTF16 #endif #endif /* * BASIC TYPES */ typedef unsigned short yaml_code_t; /* the type of YAML event, as two adjacent ASCII characters, merged via the following macro */ #define YAML_CODE(one, two) (((one) << 8) + (two)) typedef unsigned short yaml_size_t; /* length of the data structure in bytes, the purpose of this item is to enable variable length data structures */ typedef void * yaml_anchor_t; /* an anchor handle to be compared by value for uniqueness; this may actually be a pointer to a string, native object, or any other form of uniqueness (a random number), which should by value and not dereferenced */ typedef const yaml_char_t * yaml_transfer_t; /* a null-terminated fully-qualified transfer URI, possibly including the format fragment */ typedef const yaml_char_t * yaml_bufptr_t; /* this is used for begin/end pointers into a buffer which need not be null terimated; the end pointer will always reference the character following the last character, in this way the length of a scalar is (end-begin) */ typedef const yaml_char_t * yaml_message_t; /* a null-terminated string which represents an error message, the format of the string is error-number ':' error-message */ typedef const yaml_char_t * yaml_position_t; /* a null-terminated string which represents a human readable position where an error or other notification occurred, this can be a line number, or a YPATH for in-memory structures */ typedef void * yaml_producer_t; /* used for the pull API, this is an opaque pointer given to the consumer when the producer is created, it is the first argument to the pull function */ typedef void * yaml_consumer_t; /* used for the push API, this is an opaque pointer given to the producer when the consumer is created, it is the first argument to the push function */ typedef enum { YAML_CONTINUE = 0, /* consumer may continue to call producer */ YAML_STOP = 1 /* consumer should stop calling producer */ } yaml_feedback_t; /* * EVENT DATA STRUCTURE */ typedef struct yaml_event { yaml_code_t code; yaml_size_t size; /* sizeof(args) */ union /* args */ { /* * Events with an anchor and a transfer method */ #define YAML_MAPPING_BEGIN _('M','B') #define YAML_SEQUENCE_BEGIN _('Q','B') #define YAML_SCALAR_BEGIN _('S','B') /* chunked scalar */ struct { yaml_anchor_t anchor; /* optional (possibly zero) anchor */ yaml_transfer_t transfer; /* mandatory (non-NULL) transfer */ } MB, QB, SB; /* * Events with just a character payload */ #define YAML_COMMENT _('c','o') /* single line comment */ #define YAML_SCALAR_CHUNK _('S','C') /* part of a scalar */ struct { yaml_bufptr_t begin; /* start of the buffer */ yaml_bufptr_t end; /* character after the end */ } co, SC; /* * Events with an anchor, transfer, and buffer */ #define YAML_SCALAR_WHOLE _('S',' ') /* single event scalar */ struct { yaml_anchor_t anchor; /* optional (possibly zero) anchor */ yaml_transfer_t transfer; /* mandatory (non-NULL) transfer */ yaml_bufptr_t begin; /* start of the buffer */ yaml_bufptr_t end; /* character after the end */ } S; /* * Events which take a single 'anchor' argument */ #define YAML_ALIAS _('A',' ') struct { yaml_anchor_t anchor; /* mandatory (non-zero) anchor */ } A; /* * Events which take no additional arguments */ #define YAML_STREAM_BEGIN _('T','B') #define YAML_STREAM_PAUSE _('T','P') /* occurance of ... */ #define YAML_STREAM_END _('T','E') #define YAML_DOCUMENT_BEGIN _('D','B') #define YAML_DOCUMENT_END _('D','E') #define YAML_MAPPING_END _('M','E') #define YAML_SEQUENCE_END _('Q','E') #define YAML_SCALAR_END _('S','E') struct { /* no additional arguments, size = 0 */ } TB, TP, TE, DB, DE, ME, QE, SE; /* * NOTIFICATION */ #define YAML_NOTIFY_TRACE _('N','T') #define YAML_NOTIFY_INFORM _('N','I') #define YAML_NOTIFY_WARNING _('N','W') #define YAML_NOTIFY_ERROR _('N','F') #define YAML_NOTIFY_FATAL _('N','E') struct { yaml_message_t message; /* mandatory (non-NULL) messager */ yaml_position_t position; /* optional (possibly NULL) */ } NT, NI, NW, NE, NF; /* * STYLE * * Note: while it may be tempting to add style as an optional * value to most messages; since it is not part of the sequence * model, I think it is best kept as a separate event... no? * especially once you add chomp and other factors... */ #define YAML_STYLE_FLOW _('s','f') /* scalar: flow (>) */ #define YAML_STYLE_LITERAL _('s','l') /* scalar: literal (|) */ #define YAML_STYLE_PLAIN _('s','p') /* scalar: plain */ #define YAML_STYLE_SINGLE _('s','s') /* scalar: single quote */ #define YAML_STYLE_DOUBLE _('s','d') /* scalar: double quote */ #define YAML_STYLE_INLINE _('s','i') /* map/seq: inline */ #define YAML_STYLE_BLOCK _('s','b') /* map/seq: block */ struct { /* no additional arguments, size = 0 */ } sf, sl, sp, ss, sd, si, sb; } args; } yaml_event_t; /* push events -- producer calls this function on the consumer */ typedef yaml_feedback_t (*yaml_push_t)( yaml_consumer_t self, yaml_event_t *event ); /* pull events -- consumer calls this function on the producer The event returned (any any data pointed to) is only valid till the next call to the pull function. If the consumer wishes to shut down the producer, either prematurely or at the end of a stream, it should call the pull function with a stop value of YAML_STOP. In any case, if the event returend is NULL then there are no remaining events and the producer has successfully deallocated memory and should _not_ be called again. */ typedef yaml_event_t * (*yaml_pull_t)( yaml_producer_t self, yaml_feedback_t stop ); /* canonical helper to show how to hook up a parser (as a push * producer) to an emitter (as a push consumer) */ #define YAML_PULL2PUSH(pull, producer, push, consumer) \ do { \ yaml_event_t *event; \ yaml_feedback_t stop = YAML_CONTINUE; \ while(1) { \ event = (pull)((producer), stop); \ if(!event) break; \ stop = (push)((consumer), event); \ }; \ } while(0) #endif |