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