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_DOCUMENTS 16 |
---|
14 | |
---|
15 | int copy_document(yaml_document_t *document_to, yaml_document_t *document_from) |
---|
16 | { |
---|
17 | yaml_node_t *node; |
---|
18 | yaml_node_item_t *item; |
---|
19 | yaml_node_pair_t *pair; |
---|
20 | |
---|
21 | if (!yaml_document_initialize(document_to, document_from->version_directive, |
---|
22 | document_from->tag_directives.start, |
---|
23 | document_from->tag_directives.end, |
---|
24 | document_from->start_implicit, document_from->end_implicit)) |
---|
25 | return 0; |
---|
26 | |
---|
27 | for (node = document_from->nodes.start; |
---|
28 | node < document_from->nodes.top; node ++) { |
---|
29 | switch (node->type) { |
---|
30 | case YAML_SCALAR_NODE: |
---|
31 | if (!yaml_document_add_scalar(document_to, node->tag, |
---|
32 | node->data.scalar.value, node->data.scalar.length, |
---|
33 | node->data.scalar.style)) goto error; |
---|
34 | break; |
---|
35 | case YAML_SEQUENCE_NODE: |
---|
36 | if (!yaml_document_add_sequence(document_to, node->tag, |
---|
37 | node->data.sequence.style)) goto error; |
---|
38 | break; |
---|
39 | case YAML_MAPPING_NODE: |
---|
40 | if (!yaml_document_add_mapping(document_to, node->tag, |
---|
41 | node->data.mapping.style)) goto error; |
---|
42 | break; |
---|
43 | default: |
---|
44 | assert(0); |
---|
45 | break; |
---|
46 | } |
---|
47 | } |
---|
48 | |
---|
49 | for (node = document_from->nodes.start; |
---|
50 | node < document_from->nodes.top; node ++) { |
---|
51 | switch (node->type) { |
---|
52 | case YAML_SEQUENCE_NODE: |
---|
53 | for (item = node->data.sequence.items.start; |
---|
54 | item < node->data.sequence.items.top; item ++) { |
---|
55 | if (!yaml_document_append_sequence_item(document_to, |
---|
56 | node - document_from->nodes.start + 1, |
---|
57 | *item)) goto error; |
---|
58 | } |
---|
59 | break; |
---|
60 | case YAML_MAPPING_NODE: |
---|
61 | for (pair = node->data.mapping.pairs.start; |
---|
62 | pair < node->data.mapping.pairs.top; pair ++) { |
---|
63 | if (!yaml_document_append_mapping_pair(document_to, |
---|
64 | node - document_from->nodes.start + 1, |
---|
65 | pair->key, pair->value)) goto error; |
---|
66 | } |
---|
67 | break; |
---|
68 | default: |
---|
69 | break; |
---|
70 | } |
---|
71 | } |
---|
72 | return 1; |
---|
73 | |
---|
74 | error: |
---|
75 | yaml_document_delete(document_to); |
---|
76 | return 0; |
---|
77 | } |
---|
78 | |
---|
79 | int compare_nodes(yaml_document_t *document1, int index1, |
---|
80 | yaml_document_t *document2, int index2) |
---|
81 | { |
---|
82 | yaml_node_t *node1 = yaml_document_get_node(document1, index1); |
---|
83 | yaml_node_t *node2 = yaml_document_get_node(document2, index2); |
---|
84 | int k; |
---|
85 | |
---|
86 | assert(node1); |
---|
87 | assert(node2); |
---|
88 | |
---|
89 | if (node1->type != node2->type) |
---|
90 | return 0; |
---|
91 | |
---|
92 | if (strcmp((char *)node1->tag, (char *)node2->tag) != 0) return 0; |
---|
93 | |
---|
94 | switch (node1->type) { |
---|
95 | case YAML_SCALAR_NODE: |
---|
96 | if (node1->data.scalar.length != node2->data.scalar.length) |
---|
97 | return 0; |
---|
98 | if (strncmp((char *)node1->data.scalar.value, (char *)node2->data.scalar.value, |
---|
99 | node1->data.scalar.length) != 0) return 0; |
---|
100 | break; |
---|
101 | case YAML_SEQUENCE_NODE: |
---|
102 | if ((node1->data.sequence.items.top - node1->data.sequence.items.start) != |
---|
103 | (node2->data.sequence.items.top - node2->data.sequence.items.start)) |
---|
104 | return 0; |
---|
105 | for (k = 0; k < (node1->data.sequence.items.top - node1->data.sequence.items.start); k ++) { |
---|
106 | if (!compare_nodes(document1, node1->data.sequence.items.start[k], |
---|
107 | document2, node2->data.sequence.items.start[k])) return 0; |
---|
108 | } |
---|
109 | break; |
---|
110 | case YAML_MAPPING_NODE: |
---|
111 | if ((node1->data.mapping.pairs.top - node1->data.mapping.pairs.start) != |
---|
112 | (node2->data.mapping.pairs.top - node2->data.mapping.pairs.start)) |
---|
113 | return 0; |
---|
114 | for (k = 0; k < (node1->data.mapping.pairs.top - node1->data.mapping.pairs.start); k ++) { |
---|
115 | if (!compare_nodes(document1, node1->data.mapping.pairs.start[k].key, |
---|
116 | document2, node2->data.mapping.pairs.start[k].key)) return 0; |
---|
117 | if (!compare_nodes(document1, node1->data.mapping.pairs.start[k].value, |
---|
118 | document2, node2->data.mapping.pairs.start[k].value)) return 0; |
---|
119 | } |
---|
120 | break; |
---|
121 | default: |
---|
122 | assert(0); |
---|
123 | break; |
---|
124 | } |
---|
125 | return 1; |
---|
126 | } |
---|
127 | |
---|
128 | int compare_documents(yaml_document_t *document1, yaml_document_t *document2) |
---|
129 | { |
---|
130 | int k; |
---|
131 | |
---|
132 | if ((document1->version_directive && !document2->version_directive) |
---|
133 | || (!document1->version_directive && document2->version_directive) |
---|
134 | || (document1->version_directive && document2->version_directive |
---|
135 | && (document1->version_directive->major != document2->version_directive->major |
---|
136 | || document1->version_directive->minor != document2->version_directive->minor))) |
---|
137 | return 0; |
---|
138 | |
---|
139 | if ((document1->tag_directives.end - document1->tag_directives.start) != |
---|
140 | (document2->tag_directives.end - document2->tag_directives.start)) |
---|
141 | return 0; |
---|
142 | for (k = 0; k < (document1->tag_directives.end - document1->tag_directives.start); k ++) { |
---|
143 | if ((strcmp((char *)document1->tag_directives.start[k].handle, |
---|
144 | (char *)document2->tag_directives.start[k].handle) != 0) |
---|
145 | || (strcmp((char *)document1->tag_directives.start[k].prefix, |
---|
146 | (char *)document2->tag_directives.start[k].prefix) != 0)) |
---|
147 | return 0; |
---|
148 | } |
---|
149 | |
---|
150 | if ((document1->nodes.top - document1->nodes.start) != |
---|
151 | (document2->nodes.top - document2->nodes.start)) |
---|
152 | return 0; |
---|
153 | |
---|
154 | if (document1->nodes.top != document1->nodes.start) { |
---|
155 | if (!compare_nodes(document1, 1, document2, 1)) |
---|
156 | return 0; |
---|
157 | } |
---|
158 | |
---|
159 | return 1; |
---|
160 | } |
---|
161 | |
---|
162 | int print_output(char *name, unsigned char *buffer, size_t size, int count) |
---|
163 | { |
---|
164 | FILE *file; |
---|
165 | char data[BUFFER_SIZE]; |
---|
166 | size_t data_size = 1; |
---|
167 | size_t total_size = 0; |
---|
168 | if (count >= 0) { |
---|
169 | printf("FAILED (at the document #%d)\nSOURCE:\n", count+1); |
---|
170 | } |
---|
171 | file = fopen(name, "rb"); |
---|
172 | assert(file); |
---|
173 | while (data_size > 0) { |
---|
174 | data_size = fread(data, 1, BUFFER_SIZE, file); |
---|
175 | assert(!ferror(file)); |
---|
176 | if (!data_size) break; |
---|
177 | assert(fwrite(data, 1, data_size, stdout) == data_size); |
---|
178 | total_size += data_size; |
---|
179 | if (feof(file)) break; |
---|
180 | } |
---|
181 | fclose(file); |
---|
182 | printf("#### (length: %d)\n", total_size); |
---|
183 | printf("OUTPUT:\n%s#### (length: %d)\n", buffer, size); |
---|
184 | return 0; |
---|
185 | } |
---|
186 | |
---|
187 | int |
---|
188 | main(int argc, char *argv[]) |
---|
189 | { |
---|
190 | int number; |
---|
191 | int canonical = 0; |
---|
192 | int unicode = 0; |
---|
193 | |
---|
194 | number = 1; |
---|
195 | while (number < argc) { |
---|
196 | if (strcmp(argv[number], "-c") == 0) { |
---|
197 | canonical = 1; |
---|
198 | } |
---|
199 | else if (strcmp(argv[number], "-u") == 0) { |
---|
200 | unicode = 1; |
---|
201 | } |
---|
202 | else if (argv[number][0] == '-') { |
---|
203 | printf("Unknown option: '%s'\n", argv[number]); |
---|
204 | return 0; |
---|
205 | } |
---|
206 | if (argv[number][0] == '-') { |
---|
207 | if (number < argc-1) { |
---|
208 | memmove(argv+number, argv+number+1, (argc-number-1)*sizeof(char *)); |
---|
209 | } |
---|
210 | argc --; |
---|
211 | } |
---|
212 | else { |
---|
213 | number ++; |
---|
214 | } |
---|
215 | } |
---|
216 | |
---|
217 | if (argc < 2) { |
---|
218 | printf("Usage: %s [-c] [-u] file1.yaml ...\n", argv[0]); |
---|
219 | return 0; |
---|
220 | } |
---|
221 | |
---|
222 | for (number = 1; number < argc; number ++) |
---|
223 | { |
---|
224 | FILE *file; |
---|
225 | yaml_parser_t parser; |
---|
226 | yaml_emitter_t emitter; |
---|
227 | |
---|
228 | yaml_document_t document; |
---|
229 | unsigned char buffer[BUFFER_SIZE]; |
---|
230 | size_t written = 0; |
---|
231 | yaml_document_t documents[MAX_DOCUMENTS]; |
---|
232 | size_t document_number = 0; |
---|
233 | int done = 0; |
---|
234 | int count = 0; |
---|
235 | int error = 0; |
---|
236 | int k; |
---|
237 | memset(buffer, 0, BUFFER_SIZE); |
---|
238 | memset(documents, 0, MAX_DOCUMENTS*sizeof(yaml_document_t)); |
---|
239 | |
---|
240 | printf("[%d] Loading, dumping, and loading again '%s': ", number, argv[number]); |
---|
241 | fflush(stdout); |
---|
242 | |
---|
243 | file = fopen(argv[number], "rb"); |
---|
244 | assert(file); |
---|
245 | |
---|
246 | assert(yaml_parser_initialize(&parser)); |
---|
247 | yaml_parser_set_input_file(&parser, file); |
---|
248 | assert(yaml_emitter_initialize(&emitter)); |
---|
249 | if (canonical) { |
---|
250 | yaml_emitter_set_canonical(&emitter, 1); |
---|
251 | } |
---|
252 | if (unicode) { |
---|
253 | yaml_emitter_set_unicode(&emitter, 1); |
---|
254 | } |
---|
255 | yaml_emitter_set_output_string(&emitter, buffer, BUFFER_SIZE, &written); |
---|
256 | yaml_emitter_open(&emitter); |
---|
257 | |
---|
258 | while (!done) |
---|
259 | { |
---|
260 | if (!yaml_parser_load(&parser, &document)) { |
---|
261 | error = 1; |
---|
262 | break; |
---|
263 | } |
---|
264 | |
---|
265 | done = (!yaml_document_get_root_node(&document)); |
---|
266 | if (!done) { |
---|
267 | assert(document_number < MAX_DOCUMENTS); |
---|
268 | assert(copy_document(&(documents[document_number++]), &document)); |
---|
269 | assert(yaml_emitter_dump(&emitter, &document) || |
---|
270 | (yaml_emitter_flush(&emitter) && print_output(argv[number], buffer, written, count))); |
---|
271 | count ++; |
---|
272 | } |
---|
273 | else { |
---|
274 | yaml_document_delete(&document); |
---|
275 | } |
---|
276 | } |
---|
277 | |
---|
278 | yaml_parser_delete(&parser); |
---|
279 | assert(!fclose(file)); |
---|
280 | yaml_emitter_close(&emitter); |
---|
281 | yaml_emitter_delete(&emitter); |
---|
282 | |
---|
283 | if (!error) |
---|
284 | { |
---|
285 | count = done = 0; |
---|
286 | assert(yaml_parser_initialize(&parser)); |
---|
287 | yaml_parser_set_input_string(&parser, buffer, written); |
---|
288 | |
---|
289 | while (!done) |
---|
290 | { |
---|
291 | assert(yaml_parser_load(&parser, &document) || print_output(argv[number], buffer, written, count)); |
---|
292 | done = (!yaml_document_get_root_node(&document)); |
---|
293 | if (!done) { |
---|
294 | assert(compare_documents(documents+count, &document) || print_output(argv[number], buffer, written, count)); |
---|
295 | count ++; |
---|
296 | } |
---|
297 | yaml_document_delete(&document); |
---|
298 | } |
---|
299 | yaml_parser_delete(&parser); |
---|
300 | } |
---|
301 | |
---|
302 | for (k = 0; k < document_number; k ++) { |
---|
303 | yaml_document_delete(documents+k); |
---|
304 | } |
---|
305 | |
---|
306 | printf("PASSED (length: %d)\n", written); |
---|
307 | print_output(argv[number], buffer, written, -1); |
---|
308 | } |
---|
309 | |
---|
310 | return 0; |
---|
311 | } |
---|