]>
Commit | Line | Data |
---|---|---|
e27a3c88 KS |
1 | #include <yaml.h> |
2 | ||
3 | #include <stdlib.h> | |
4 | #include <stdio.h> | |
e27a3c88 KS |
5 | #include <string.h> |
6 | ||
01224901 KS |
7 | #ifdef NDEBUG |
8 | #undef NDEBUG | |
9 | #endif | |
10 | #include <assert.h> | |
11 | ||
e27a3c88 KS |
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, | |
3b570fc9 | 80 | yaml_document_t *document2, int index2, int level) |
e27a3c88 | 81 | { |
3b570fc9 | 82 | if (level++ > 1000) return 0; |
e27a3c88 KS |
83 | yaml_node_t *node1 = yaml_document_get_node(document1, index1); |
84 | yaml_node_t *node2 = yaml_document_get_node(document2, index2); | |
85 | int k; | |
86 | ||
87 | assert(node1); | |
88 | assert(node2); | |
89 | ||
90 | if (node1->type != node2->type) | |
91 | return 0; | |
92 | ||
93 | if (strcmp((char *)node1->tag, (char *)node2->tag) != 0) return 0; | |
94 | ||
95 | switch (node1->type) { | |
96 | case YAML_SCALAR_NODE: | |
97 | if (node1->data.scalar.length != node2->data.scalar.length) | |
98 | return 0; | |
99 | if (strncmp((char *)node1->data.scalar.value, (char *)node2->data.scalar.value, | |
100 | node1->data.scalar.length) != 0) return 0; | |
101 | break; | |
102 | case YAML_SEQUENCE_NODE: | |
103 | if ((node1->data.sequence.items.top - node1->data.sequence.items.start) != | |
104 | (node2->data.sequence.items.top - node2->data.sequence.items.start)) | |
105 | return 0; | |
106 | for (k = 0; k < (node1->data.sequence.items.top - node1->data.sequence.items.start); k ++) { | |
107 | if (!compare_nodes(document1, node1->data.sequence.items.start[k], | |
3b570fc9 | 108 | document2, node2->data.sequence.items.start[k], level)) return 0; |
e27a3c88 KS |
109 | } |
110 | break; | |
111 | case YAML_MAPPING_NODE: | |
112 | if ((node1->data.mapping.pairs.top - node1->data.mapping.pairs.start) != | |
113 | (node2->data.mapping.pairs.top - node2->data.mapping.pairs.start)) | |
114 | return 0; | |
115 | for (k = 0; k < (node1->data.mapping.pairs.top - node1->data.mapping.pairs.start); k ++) { | |
116 | if (!compare_nodes(document1, node1->data.mapping.pairs.start[k].key, | |
3b570fc9 | 117 | document2, node2->data.mapping.pairs.start[k].key, level)) return 0; |
e27a3c88 | 118 | if (!compare_nodes(document1, node1->data.mapping.pairs.start[k].value, |
3b570fc9 | 119 | document2, node2->data.mapping.pairs.start[k].value, level)) return 0; |
e27a3c88 KS |
120 | } |
121 | break; | |
01224901 KS |
122 | default: |
123 | assert(0); | |
124 | break; | |
e27a3c88 KS |
125 | } |
126 | return 1; | |
127 | } | |
128 | ||
129 | int compare_documents(yaml_document_t *document1, yaml_document_t *document2) | |
130 | { | |
131 | int k; | |
132 | ||
133 | if ((document1->version_directive && !document2->version_directive) | |
134 | || (!document1->version_directive && document2->version_directive) | |
135 | || (document1->version_directive && document2->version_directive | |
136 | && (document1->version_directive->major != document2->version_directive->major | |
137 | || document1->version_directive->minor != document2->version_directive->minor))) | |
138 | return 0; | |
139 | ||
140 | if ((document1->tag_directives.end - document1->tag_directives.start) != | |
141 | (document2->tag_directives.end - document2->tag_directives.start)) | |
142 | return 0; | |
143 | for (k = 0; k < (document1->tag_directives.end - document1->tag_directives.start); k ++) { | |
144 | if ((strcmp((char *)document1->tag_directives.start[k].handle, | |
145 | (char *)document2->tag_directives.start[k].handle) != 0) | |
146 | || (strcmp((char *)document1->tag_directives.start[k].prefix, | |
147 | (char *)document2->tag_directives.start[k].prefix) != 0)) | |
148 | return 0; | |
149 | } | |
150 | ||
151 | if ((document1->nodes.top - document1->nodes.start) != | |
152 | (document2->nodes.top - document2->nodes.start)) | |
153 | return 0; | |
154 | ||
155 | if (document1->nodes.top != document1->nodes.start) { | |
3b570fc9 | 156 | if (!compare_nodes(document1, 1, document2, 1, 0)) |
e27a3c88 KS |
157 | return 0; |
158 | } | |
159 | ||
160 | return 1; | |
161 | } | |
162 | ||
163 | int print_output(char *name, unsigned char *buffer, size_t size, int count) | |
164 | { | |
165 | FILE *file; | |
166 | char data[BUFFER_SIZE]; | |
167 | size_t data_size = 1; | |
168 | size_t total_size = 0; | |
169 | if (count >= 0) { | |
170 | printf("FAILED (at the document #%d)\nSOURCE:\n", count+1); | |
171 | } | |
172 | file = fopen(name, "rb"); | |
173 | assert(file); | |
174 | while (data_size > 0) { | |
175 | data_size = fread(data, 1, BUFFER_SIZE, file); | |
176 | assert(!ferror(file)); | |
177 | if (!data_size) break; | |
178 | assert(fwrite(data, 1, data_size, stdout) == data_size); | |
179 | total_size += data_size; | |
180 | if (feof(file)) break; | |
181 | } | |
182 | fclose(file); | |
fc2dd942 RU |
183 | printf("#### (length: %ld)\n", (long)total_size); |
184 | printf("OUTPUT:\n%s#### (length: %ld)\n", buffer, (long)size); | |
e27a3c88 KS |
185 | return 0; |
186 | } | |
187 | ||
188 | int | |
189 | main(int argc, char *argv[]) | |
190 | { | |
191 | int number; | |
192 | int canonical = 0; | |
193 | int unicode = 0; | |
194 | ||
195 | number = 1; | |
196 | while (number < argc) { | |
197 | if (strcmp(argv[number], "-c") == 0) { | |
198 | canonical = 1; | |
199 | } | |
200 | else if (strcmp(argv[number], "-u") == 0) { | |
201 | unicode = 1; | |
202 | } | |
203 | else if (argv[number][0] == '-') { | |
204 | printf("Unknown option: '%s'\n", argv[number]); | |
205 | return 0; | |
206 | } | |
207 | if (argv[number][0] == '-') { | |
208 | if (number < argc-1) { | |
209 | memmove(argv+number, argv+number+1, (argc-number-1)*sizeof(char *)); | |
210 | } | |
211 | argc --; | |
212 | } | |
213 | else { | |
214 | number ++; | |
215 | } | |
216 | } | |
217 | ||
218 | if (argc < 2) { | |
219 | printf("Usage: %s [-c] [-u] file1.yaml ...\n", argv[0]); | |
220 | return 0; | |
221 | } | |
222 | ||
223 | for (number = 1; number < argc; number ++) | |
224 | { | |
225 | FILE *file; | |
226 | yaml_parser_t parser; | |
227 | yaml_emitter_t emitter; | |
228 | ||
229 | yaml_document_t document; | |
3b570fc9 | 230 | unsigned char buffer[BUFFER_SIZE+1]; |
e27a3c88 KS |
231 | size_t written = 0; |
232 | yaml_document_t documents[MAX_DOCUMENTS]; | |
233 | size_t document_number = 0; | |
234 | int done = 0; | |
235 | int count = 0; | |
236 | int error = 0; | |
237 | int k; | |
3b570fc9 | 238 | memset(buffer, 0, BUFFER_SIZE+1); |
e27a3c88 KS |
239 | memset(documents, 0, MAX_DOCUMENTS*sizeof(yaml_document_t)); |
240 | ||
241 | printf("[%d] Loading, dumping, and loading again '%s': ", number, argv[number]); | |
242 | fflush(stdout); | |
243 | ||
244 | file = fopen(argv[number], "rb"); | |
245 | assert(file); | |
246 | ||
247 | assert(yaml_parser_initialize(&parser)); | |
248 | yaml_parser_set_input_file(&parser, file); | |
249 | assert(yaml_emitter_initialize(&emitter)); | |
250 | if (canonical) { | |
251 | yaml_emitter_set_canonical(&emitter, 1); | |
252 | } | |
253 | if (unicode) { | |
254 | yaml_emitter_set_unicode(&emitter, 1); | |
255 | } | |
256 | yaml_emitter_set_output_string(&emitter, buffer, BUFFER_SIZE, &written); | |
257 | yaml_emitter_open(&emitter); | |
258 | ||
259 | while (!done) | |
260 | { | |
261 | if (!yaml_parser_load(&parser, &document)) { | |
262 | error = 1; | |
263 | break; | |
264 | } | |
265 | ||
266 | done = (!yaml_document_get_root_node(&document)); | |
267 | if (!done) { | |
268 | assert(document_number < MAX_DOCUMENTS); | |
269 | assert(copy_document(&(documents[document_number++]), &document)); | |
270 | assert(yaml_emitter_dump(&emitter, &document) || | |
271 | (yaml_emitter_flush(&emitter) && print_output(argv[number], buffer, written, count))); | |
272 | count ++; | |
273 | } | |
274 | else { | |
275 | yaml_document_delete(&document); | |
276 | } | |
277 | } | |
278 | ||
279 | yaml_parser_delete(&parser); | |
280 | assert(!fclose(file)); | |
281 | yaml_emitter_close(&emitter); | |
282 | yaml_emitter_delete(&emitter); | |
283 | ||
284 | if (!error) | |
285 | { | |
286 | count = done = 0; | |
287 | assert(yaml_parser_initialize(&parser)); | |
288 | yaml_parser_set_input_string(&parser, buffer, written); | |
289 | ||
290 | while (!done) | |
291 | { | |
292 | assert(yaml_parser_load(&parser, &document) || print_output(argv[number], buffer, written, count)); | |
293 | done = (!yaml_document_get_root_node(&document)); | |
294 | if (!done) { | |
295 | assert(compare_documents(documents+count, &document) || print_output(argv[number], buffer, written, count)); | |
296 | count ++; | |
297 | } | |
298 | yaml_document_delete(&document); | |
299 | } | |
300 | yaml_parser_delete(&parser); | |
301 | } | |
302 | ||
303 | for (k = 0; k < document_number; k ++) { | |
304 | yaml_document_delete(documents+k); | |
305 | } | |
306 | ||
fc2dd942 | 307 | printf("PASSED (length: %ld)\n", (long)written); |
e27a3c88 KS |
308 | print_output(argv[number], buffer, written, -1); |
309 | } | |
310 | ||
311 | return 0; | |
312 | } |