1 /*  yamlbyte.h
2  *
3  *  The YAML bytecode "C" interface header file.   See the YAML bytecode
4  *  reference for bytecode sequence rules and for the meaning of each
5  *  bytecode.
6  */
7 
8 #ifndef YAMLBYTE_H
9 #define YAMLBYTE_H
10 #include <stddef.h>
11 
12 /* define what a character is */
13 typedef unsigned char yamlbyte_utf8_t;
14 typedef unsigned short yamlbyte_utf16_t;
15 #ifdef YAMLBYTE_UTF8
16   #ifdef YAMLBYTE_UTF16
17     #error Must only define YAMLBYTE_UTF8 or YAMLBYTE_UTF16
18   #endif
19   typedef yamlbyte_utf8_t yamlbyte_char_t;
20 #else
21   #ifdef YAMLBYTE_UTF16
22     typedef yamlbyte_utf16_t yamlbyte_char_t;
23   #else
24     #error Must define YAMLBYTE_UTF8 or YAMLBYTE_UTF16
25   #endif
26 #endif
27 
28 /* specify list of bytecodes */
29 #define YAMLBYTE_FINISH          ((yamlbyte_char_t) 0)
30 #define YAMLBYTE_DOCUMENT        ((yamlbyte_char_t)'D')
31 #define YAMLBYTE_DIRECTIVE       ((yamlbyte_char_t)'V')
32 #define YAMLBYTE_PAUSE           ((yamlbyte_char_t)'P')
33 #define YAMLBYTE_MAPPING         ((yamlbyte_char_t)'M')
34 #define YAMLBYTE_SEQUENCE        ((yamlbyte_char_t)'S')
35 #define YAMLBYTE_END_BRANCH      ((yamlbyte_char_t)'E')
36 #define YAMLBYTE_SCALAR          ((yamlbyte_char_t)'S')
37 #define YAMLBYTE_CONTINUE        ((yamlbyte_char_t)'C')
38 #define YAMLBYTE_NEWLINE         ((yamlbyte_char_t)'N')
39 #define YAMLBYTE_NULLCHAR        ((yamlbyte_char_t)'Z')
40 #define YAMLBYTE_ANCHOR          ((yamlbyte_char_t)'A')
41 #define YAMLBYTE_ALIAS           ((yamlbyte_char_t)'R')
42 #define YAMLBYTE_TRANSFER        ((yamlbyte_char_t)'T')
43 /* formatting bytecodes */
44 #define YAMLBYTE_COMMENT         ((yamlbyte_char_t)'c')
45 #define YAMLBYTE_INDENT          ((yamlbyte_char_t)'i')
46 #define YAMLBYTE_STYLE           ((yamlbyte_char_t)'s')
47 /* other bytecodes */
48 #define YAMLBYTE_LINE_NUMBER     ((yamlbyte_char_t)'#')
49 #define YAMLBYTE_WHOLE_SCALAR    ((yamlbyte_char_t)'<')
50 #define YAMLBYTE_NOTICE          ((yamlbyte_char_t)'!')
51 #define YAMLBYTE_SPAN            ((yamlbyte_char_t)')')
52 #define YAMLBYTE_ALLOC           ((yamlbyte_char_t)'@')
53 
54 /* second level style bytecodes, ie "s>" */
55 #define YAMLBYTE_FLOW            ((yamlbyte_char_t)'>')
56 #define YAMLBYTE_LITERAL         ((yamlbyte_char_t)'|')
57 #define YAMLBYTE_BLOCK           ((yamlbyte_char_t)'b')
58 #define YAMLBYTE_PLAIN           ((yamlbyte_char_t)'p')
59 #define YAMLBYTE_INLINE_MAPPING  ((yamlbyte_char_t)'{')
60 #define YAMLBYTE_INLINE_SEQUENCE ((yamlbyte_char_t)'[')
61 #define YAMLBYTE_SINGLE_QUOTED   ((yamlbyte_char_t)39)
62 #define YAMLBYTE_DOUBLE_QUOTED   ((yamlbyte_char_t)'"')
63 
64 /*
65  * The "C" API has two variants, one based on instructions,
66  * with events delivered via pointers; and the other one
67  * is character based where one or more instructions are
68  * serialized into a buffer.
69  *
70  * Note: In the instruction based API, WHOLE_SCALAR does
71  *       not have the '<here' marshalling stuff.
72  */
73 
74 typedef void * yamlbyte_consumer_t;
75 typedef void * yamlbyte_producer_t;
76 
77 /* push and pull APIs need a way to communicate results */
78 typedef enum {
79     YAMLBYTE_OK          = 0,     /* proceed                        */
80     YAMLBYTE_E_MEMORY    = 'M',   /* could not allocate memory      */
81     YAMLBYTE_E_READ      = 'R',   /* input stream read error        */
82     YAMLBYTE_E_WRITE     = 'W',   /* output stream write error      */
83     YAMLBYTE_E_OTHER     = '?',   /* some other error condition     */
84     YAMLBYTE_E_PARSE     = 'P',   /* parse error, check bytecodes   */
85 } yamlbyte_result_t;
86 
87 typedef const yamlbyte_char_t *yamlbyte_buff_t;
88 
89 /*
90  *  The "Instruction" API
91  */
92 
93 typedef struct yaml_instruction {
94     yamlbyte_char_t bytecode;
95     yamlbyte_buff_t start;
96     yamlbyte_buff_t finish;  /* open range, *finish is _not_ part */
97 } *yamlbyte_inst_t;
98 
99 /* producer pushes the instruction with one bytecode event to the
100  * consumer; if the consumer's result is not YAMLBYTE_OK, then
101  * the producer should stop */
102 typedef
103   yamlbyte_result_t
104    (*yamlbyte_push_t)(
105      yamlbyte_consumer_t self,
106      yamlbyte_inst_t  inst
107    );
108 
109 /* consumer pulls a bytecode instruction from the producer; in this
110  * case the instruction (and is buffer) are owned by the producer and
111  * will remain valid till the pull function is called once again;
112  * if the instruction is NULL, then there are no more results; and
113  * it is important to call the pull function till it returns NULL so
114  * that the producer can clean up its memory allocations */
115 typedef
116    yamlbyte_result_t
117     (*yamlbyte_pull_t)(
118       yamlbyte_producer_t self,
119       yamlbyte_inst_t *inst   /* to be filled in by the producer */
120     );
121 
122 /*
123  *  Buffer based API
124  */
125 
126 /* producer pushes a null terminated buffer filled with one or more
127  * bytecode events to the consumer; if the consumer's result is not
128  * YAMLBYTE_OK, then the producer should stop */
129 typedef
130   yamlbyte_result_t
131    (*yamlbyte_pushbuff_t)(
132      yamlbyte_consumer_t self,
133      yamlbyte_buff_t  buff
134    );
135 
136 /* consumer pulls bytecode events from the producer; in this case
137  * the buffer is owned by the producer, and will remain valid till
138  * the pull function is called once again; if the buffer pointer
139  * is set to NULL, then there are no more results; it is important
140  * to call the pull function till it returns NULL so that the
141  * producer can clean up its memory allocations */
142 typedef
143    yamlbyte_result_t
144     (*yamlbyte_pullbuff_t)(
145       yamlbyte_producer_t self,
146       yamlbyte_buff_t *buff   /* to be filled in by the producer */
147     );
148 
149 /* convert a pull interface to a push interface; the reverse process
150  * requires threads and thus is language dependent */
151 #define YAMLBYTE_PULL2PUSH(pull,producer,push,consumer,result)       \
152     do {                                                         \
153         yamlbyte_pullbuff_t _pull = (pull);                              \
154         yamlbyte_pushbuff_t _push = (push);                              \
155         yamlbyte_result_t _result = YAMLBYTE_OK;                         \
156         yamlbyte_producer_t _producer = (producer);                  \
157         yamlbyte_consumer_t _consumer = (consumer);                  \
158         while(1) {                                               \
159             yamlbyte_buff_t buff = NULL;                           \
160             _result = _pull(_producer,&buff);                    \
161             if(YAMLBYTE_OK != result || NULL == buff)                \
162                 break;                                           \
163             _result = _push(_consumer,buff);                     \
164             if(YAMLBYTE_OK != result)                                \
165                 break;                                           \
166         }                                                        \
167         (result) = _result;                                      \
168     } while(0)
169 
170 #endif
171