1#include <yaml.h> 2 3#include <stdlib.h> 4#include <stdio.h> 5#include <string.h> 6 7#ifdef NDEBUG 8#undef NDEBUG 9#endif 10#include <assert.h> 11 12#define BUFFER_SIZE 65536 13#define MAX_EVENTS 1024 14 15int copy_event(yaml_event_t *event_to, yaml_event_t *event_from) 16{ 17 switch (event_from->type) 18 { 19 case YAML_STREAM_START_EVENT: 20 return yaml_stream_start_event_initialize(event_to, 21 event_from->data.stream_start.encoding); 22 23 case YAML_STREAM_END_EVENT: 24 return yaml_stream_end_event_initialize(event_to); 25 26 case YAML_DOCUMENT_START_EVENT: 27 return yaml_document_start_event_initialize(event_to, 28 event_from->data.document_start.version_directive, 29 event_from->data.document_start.tag_directives.start, 30 event_from->data.document_start.tag_directives.end, 31 event_from->data.document_start.implicit); 32 33 case YAML_DOCUMENT_END_EVENT: 34 return yaml_document_end_event_initialize(event_to, 35 event_from->data.document_end.implicit); 36 37 case YAML_ALIAS_EVENT: 38 return yaml_alias_event_initialize(event_to, 39 event_from->data.alias.anchor); 40 41 case YAML_SCALAR_EVENT: 42 return yaml_scalar_event_initialize(event_to, 43 event_from->data.scalar.anchor, 44 event_from->data.scalar.tag, 45 event_from->data.scalar.value, 46 event_from->data.scalar.length, 47 event_from->data.scalar.plain_implicit, 48 event_from->data.scalar.quoted_implicit, 49 event_from->data.scalar.style); 50 51 case YAML_SEQUENCE_START_EVENT: 52 return yaml_sequence_start_event_initialize(event_to, 53 event_from->data.sequence_start.anchor, 54 event_from->data.sequence_start.tag, 55 event_from->data.sequence_start.implicit, 56 event_from->data.sequence_start.style); 57 58 case YAML_SEQUENCE_END_EVENT: 59 return yaml_sequence_end_event_initialize(event_to); 60 61 case YAML_MAPPING_START_EVENT: 62 return yaml_mapping_start_event_initialize(event_to, 63 event_from->data.mapping_start.anchor, 64 event_from->data.mapping_start.tag, 65 event_from->data.mapping_start.implicit, 66 event_from->data.mapping_start.style); 67 68 case YAML_MAPPING_END_EVENT: 69 return yaml_mapping_end_event_initialize(event_to); 70 71 default: 72 assert(1); 73 } 74 75 return 0; 76} 77 78int compare_events(yaml_event_t *event1, yaml_event_t *event2) 79{ 80 int k; 81 82 if (event1->type != event2->type) 83 return 0; 84 85 switch (event1->type) 86 { 87 case YAML_STREAM_START_EVENT: 88 return 1; 89 /* return (event1->data.stream_start.encoding == 90 event2->data.stream_start.encoding); */ 91 92 case YAML_DOCUMENT_START_EVENT: 93 if ((event1->data.document_start.version_directive && !event2->data.document_start.version_directive) 94 || (!event1->data.document_start.version_directive && event2->data.document_start.version_directive) 95 || (event1->data.document_start.version_directive && event2->data.document_start.version_directive 96 && (event1->data.document_start.version_directive->major != event2->data.document_start.version_directive->major 97 || event1->data.document_start.version_directive->minor != event2->data.document_start.version_directive->minor))) 98 return 0; 99 if ((event1->data.document_start.tag_directives.end - event1->data.document_start.tag_directives.start) != 100 (event2->data.document_start.tag_directives.end - event2->data.document_start.tag_directives.start)) 101 return 0; 102 for (k = 0; k < (event1->data.document_start.tag_directives.end - event1->data.document_start.tag_directives.start); k ++) { 103 if ((strcmp((char *)event1->data.document_start.tag_directives.start[k].handle, 104 (char *)event2->data.document_start.tag_directives.start[k].handle) != 0) 105 || (strcmp((char *)event1->data.document_start.tag_directives.start[k].prefix, 106 (char *)event2->data.document_start.tag_directives.start[k].prefix) != 0)) 107 return 0; 108 } 109 /* if (event1->data.document_start.implicit != event2->data.document_start.implicit) 110 return 0; */ 111 return 1; 112 113 case YAML_DOCUMENT_END_EVENT: 114 return 1; 115 /* return (event1->data.document_end.implicit == 116 event2->data.document_end.implicit); */ 117 118 case YAML_ALIAS_EVENT: 119 return (strcmp((char *)event1->data.alias.anchor, 120 (char *)event2->data.alias.anchor) == 0); 121 122 case YAML_SCALAR_EVENT: 123 if ((event1->data.scalar.anchor && !event2->data.scalar.anchor) 124 || (!event1->data.scalar.anchor && event2->data.scalar.anchor) 125 || (event1->data.scalar.anchor && event2->data.scalar.anchor 126 && strcmp((char *)event1->data.scalar.anchor, 127 (char *)event2->data.scalar.anchor) != 0)) 128 return 0; 129 if ((event1->data.scalar.tag && !event2->data.scalar.tag 130 && strcmp((char *)event1->data.scalar.tag, "!") != 0) 131 || (!event1->data.scalar.tag && event2->data.scalar.tag 132 && strcmp((char *)event2->data.scalar.tag, "!") != 0) 133 || (event1->data.scalar.tag && event2->data.scalar.tag 134 && strcmp((char *)event1->data.scalar.tag, 135 (char *)event2->data.scalar.tag) != 0)) 136 return 0; 137 if ((event1->data.scalar.length != event2->data.scalar.length) 138 || memcmp(event1->data.scalar.value, event2->data.scalar.value, 139 event1->data.scalar.length) != 0) 140 return 0; 141 if ((event1->data.scalar.plain_implicit != event2->data.scalar.plain_implicit) 142 || (event2->data.scalar.quoted_implicit != event2->data.scalar.quoted_implicit) 143 /* || (event2->data.scalar.style != event2->data.scalar.style) */) 144 return 0; 145 return 1; 146 147 case YAML_SEQUENCE_START_EVENT: 148 if ((event1->data.sequence_start.anchor && !event2->data.sequence_start.anchor) 149 || (!event1->data.sequence_start.anchor && event2->data.sequence_start.anchor) 150 || (event1->data.sequence_start.anchor && event2->data.sequence_start.anchor 151 && strcmp((char *)event1->data.sequence_start.anchor, 152 (char *)event2->data.sequence_start.anchor) != 0)) 153 return 0; 154 if ((event1->data.sequence_start.tag && !event2->data.sequence_start.tag) 155 || (!event1->data.sequence_start.tag && event2->data.sequence_start.tag) 156 || (event1->data.sequence_start.tag && event2->data.sequence_start.tag 157 && strcmp((char *)event1->data.sequence_start.tag, 158 (char *)event2->data.sequence_start.tag) != 0)) 159 return 0; 160 if ((event1->data.sequence_start.implicit != event2->data.sequence_start.implicit) 161 /* || (event2->data.sequence_start.style != event2->data.sequence_start.style) */) 162 return 0; 163 return 1; 164 165 case YAML_MAPPING_START_EVENT: 166 if ((event1->data.mapping_start.anchor && !event2->data.mapping_start.anchor) 167 || (!event1->data.mapping_start.anchor && event2->data.mapping_start.anchor) 168 || (event1->data.mapping_start.anchor && event2->data.mapping_start.anchor 169 && strcmp((char *)event1->data.mapping_start.anchor, 170 (char *)event2->data.mapping_start.anchor) != 0)) 171 return 0; 172 if ((event1->data.mapping_start.tag && !event2->data.mapping_start.tag) 173 || (!event1->data.mapping_start.tag && event2->data.mapping_start.tag) 174 || (event1->data.mapping_start.tag && event2->data.mapping_start.tag 175 && strcmp((char *)event1->data.mapping_start.tag, 176 (char *)event2->data.mapping_start.tag) != 0)) 177 return 0; 178 if ((event1->data.mapping_start.implicit != event2->data.mapping_start.implicit) 179 /* || (event2->data.mapping_start.style != event2->data.mapping_start.style) */) 180 return 0; 181 return 1; 182 183 default: 184 return 1; 185 } 186} 187 188int print_output(char *name, unsigned char *buffer, size_t size, int count) 189{ 190 FILE *file; 191 char data[BUFFER_SIZE]; 192 size_t data_size = 1; 193 size_t total_size = 0; 194 if (count >= 0) { 195 printf("FAILED (at the event #%d)\nSOURCE:\n", count+1); 196 } 197 file = fopen(name, "rb"); 198 assert(file); 199 while (data_size > 0) { 200 data_size = fread(data, 1, BUFFER_SIZE, file); 201 assert(!ferror(file)); 202 if (!data_size) break; 203 assert(fwrite(data, 1, data_size, stdout) == data_size); 204 total_size += data_size; 205 if (feof(file)) break; 206 } 207 fclose(file); 208 printf("#### (length: %d)\n", total_size); 209 printf("OUTPUT:\n%s#### (length: %d)\n", buffer, size); 210 return 0; 211} 212 213int 214main(int argc, char *argv[]) 215{ 216 int number; 217 int canonical = 0; 218 int unicode = 0; 219 220 number = 1; 221 while (number < argc) { 222 if (strcmp(argv[number], "-c") == 0) { 223 canonical = 1; 224 } 225 else if (strcmp(argv[number], "-u") == 0) { 226 unicode = 1; 227 } 228 else if (argv[number][0] == '-') { 229 printf("Unknown option: '%s'\n", argv[number]); 230 return 0; 231 } 232 if (argv[number][0] == '-') { 233 if (number < argc-1) { 234 memmove(argv+number, argv+number+1, (argc-number-1)*sizeof(char *)); 235 } 236 argc --; 237 } 238 else { 239 number ++; 240 } 241 } 242 243 if (argc < 2) { 244 printf("Usage: %s [-c] [-u] file1.yaml ...\n", argv[0]); 245 return 0; 246 } 247 248 for (number = 1; number < argc; number ++) 249 { 250 FILE *file; 251 yaml_parser_t parser; 252 yaml_emitter_t emitter; 253 yaml_event_t event; 254 unsigned char buffer[BUFFER_SIZE]; 255 size_t written = 0; 256 yaml_event_t events[MAX_EVENTS]; 257 size_t event_number = 0; 258 int done = 0; 259 int count = 0; 260 int error = 0; 261 int k; 262 memset(buffer, 0, BUFFER_SIZE); 263 memset(events, 0, MAX_EVENTS*sizeof(yaml_event_t)); 264 265 printf("[%d] Parsing, emitting, and parsing again '%s': ", number, argv[number]); 266 fflush(stdout); 267 268 file = fopen(argv[number], "rb"); 269 assert(file); 270 271 assert(yaml_parser_initialize(&parser)); 272 yaml_parser_set_input_file(&parser, file); 273 assert(yaml_emitter_initialize(&emitter)); 274 if (canonical) { 275 yaml_emitter_set_canonical(&emitter, 1); 276 } 277 if (unicode) { 278 yaml_emitter_set_unicode(&emitter, 1); 279 } 280 yaml_emitter_set_output_string(&emitter, buffer, BUFFER_SIZE, &written); 281 282 while (!done) 283 { 284 if (!yaml_parser_parse(&parser, &event)) { 285 error = 1; 286 break; 287 } 288 289 done = (event.type == YAML_STREAM_END_EVENT); 290 assert(event_number < MAX_EVENTS); 291 assert(copy_event(&(events[event_number++]), &event)); 292 assert(yaml_emitter_emit(&emitter, &event) || 293 (yaml_emitter_flush(&emitter) && print_output(argv[number], buffer, written, count))); 294 count ++; 295 } 296 297 yaml_parser_delete(&parser); 298 assert(!fclose(file)); 299 yaml_emitter_delete(&emitter); 300 301 if (!error) 302 { 303 count = done = 0; 304 assert(yaml_parser_initialize(&parser)); 305 yaml_parser_set_input_string(&parser, buffer, written); 306 307 while (!done) 308 { 309 assert(yaml_parser_parse(&parser, &event) || print_output(argv[number], buffer, written, count)); 310 done = (event.type == YAML_STREAM_END_EVENT); 311 assert(compare_events(events+count, &event) || print_output(argv[number], buffer, written, count)); 312 yaml_event_delete(&event); 313 count ++; 314 } 315 yaml_parser_delete(&parser); 316 } 317 318 for (k = 0; k < event_number; k ++) { 319 yaml_event_delete(events+k); 320 } 321 322 printf("PASSED (length: %d)\n", written); 323 print_output(argv[number], buffer, written, -1); 324 } 325 326 return 0; 327} 328