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 
copy_event(yaml_event_t * event_to,yaml_event_t * event_from)15 int 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 
compare_events(yaml_event_t * event1,yaml_event_t * event2)78 int 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 
print_output(char * name,unsigned char * buffer,size_t size,int count)188 int 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: %zd)\n", total_size);
209     printf("OUTPUT:\n%s#### (length: %zd)\n", buffer, size);
210     return 0;
211 }
212 
213 int
main(int argc,char * argv[])214 main(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+1];
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+1);
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                     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: %zd)\n", written);
323         print_output(argv[number], buffer, written, -1);
324     }
325 
326     return 0;
327 }
328