| 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 |
|---|