1 #include <stdio.h>
2 #include <ctype.h>
3 #include <string.h>
4 #include <stdlib.h>
5 #include <math.h>
6
7 #include "cgns_io.h"
8 #include "getargs.h"
9
10 #ifndef CGNSTYPES_H
11 # define cgsize_t int
12 #endif
13
14 static int nocase = 0;
15 static int nospace = 0;
16 static int quiet = 0;
17 static int follow_links = 0;
18 static int recurse = 0;
19 static int node_data = 0;
20 static double tol = 0.0;
21
22 static int cgio1, cgio2;
23
24 static char options[] = "ciqrfdt:";
25 static char *usgmsg[] = {
26 "usage : cgnsdiff [options] CGNSfile1 [dataset1] CGNSfile2 [dataset2]",
27 "options:",
28 " -c : case insensitive names",
29 " -i : ignore white space in names",
30 " -q : print only if they differ",
31 " -f : follow links",
32 " -r : recurse (used only when dataset given)",
33 " -d : compare node data also",
34 " -t<tol> : tolerance for comparing floats/doubles (default 0)",
35 NULL
36 };
37
err_exit(char * msg,char * name)38 static void err_exit (char *msg, char *name)
39 {
40 char errmsg[128];
41
42 fflush (stdout);
43 if (cgio_error_message (errmsg)) {
44 if (msg != NULL)
45 fprintf (stderr, "%s:", msg);
46 if (name != NULL)
47 fprintf (stderr, "%s:", name);
48 fprintf (stderr, "%s\n", errmsg);
49 }
50 else {
51 if (msg != NULL)
52 fprintf (stderr, "%s", msg);
53 if (name != NULL) {
54 if (msg != NULL) putc (':', stderr);
55 fprintf (stderr, "%s", name);
56 }
57 putc ('\n', stderr);
58 }
59 cgio_cleanup ();
60 exit (1);
61 }
62
data_size(char * type,int ndim,cgsize_t * dims,int * size)63 static size_t data_size (char *type, int ndim, cgsize_t *dims, int *size)
64 {
65 int n;
66 size_t bytes;
67
68 *size = 0;
69 if (ndim < 1) return 0;
70 if (0 == strcmp (type, "C1") ||
71 0 == strcmp (type, "B1"))
72 bytes = sizeof(char);
73 else if (0 == strcmp (type, "I4") ||
74 0 == strcmp (type, "U4"))
75 bytes = sizeof(int);
76 else if (0 == strcmp (type, "I8") ||
77 0 == strcmp (type, "U8"))
78 bytes = sizeof(cglong_t);
79 else if (0 == strcmp (type, "R4")) {
80 *size = 4;
81 bytes = sizeof(float);
82 }
83 else if (0 == strcmp (type, "R8")) {
84 *size = 8;
85 bytes = sizeof(double);
86 }
87 else if (0 == strcmp (type, "X4")) {
88 *size = 4;
89 bytes = 2 * sizeof(float);
90 }
91 else if (0 == strcmp (type, "X8")) {
92 *size = 8;
93 bytes = 2 * sizeof(double);
94 }
95 else
96 return 0;
97
98 for (n = 0; n < ndim; n++)
99 bytes *= (size_t)dims[n];
100 return bytes;
101 }
102
compare_bytes(size_t cnt,unsigned char * d1,unsigned char * d2)103 static int compare_bytes (size_t cnt, unsigned char *d1, unsigned char *d2)
104 {
105 size_t n;
106
107 for (n = 0; n < cnt; n++) {
108 if (d1[n] != d2[n]) return 1;
109 }
110 return 0;
111 }
112
compare_floats(size_t cnt,float * d1,float * d2)113 static int compare_floats (size_t cnt, float *d1, float *d2)
114 {
115 size_t n;
116
117 for (n = 0; n < cnt; n++) {
118 if (fabs(d1[n] - d2[n]) > tol) return 1;
119 }
120 return 0;
121 }
122
compare_doubles(size_t cnt,double * d1,double * d2)123 static int compare_doubles (size_t cnt, double *d1, double *d2)
124 {
125 size_t n;
126
127 for (n = 0; n < cnt; n++) {
128 if (fabs(d1[n] - d2[n]) > tol) return 1;
129 }
130 return 0;
131 }
132
compare_data(char * name1,double id1,char * name2,double id2)133 static void compare_data (char *name1, double id1, char *name2, double id2)
134 {
135 int n, err;
136 size_t bytes;
137 char label1[CGIO_MAX_NAME_LENGTH+1];
138 char type1[CGIO_MAX_NAME_LENGTH+1];
139 int ndim1, ndim2;
140 cgsize_t dims1[CGIO_MAX_DIMENSIONS];
141 cgsize_t dims2[CGIO_MAX_DIMENSIONS];
142 char label2[CGIO_MAX_NAME_LENGTH+1];
143 char type2[CGIO_MAX_NAME_LENGTH+1];
144 void *data1, *data2;
145
146 /* compare labels */
147
148 if (cgio_get_label (cgio1, id1, label1))
149 err_exit (name1, "cgio_get_label");
150 if (cgio_get_label (cgio2, id2, label2))
151 err_exit (name2, "cgio_get_label");
152 if (strcmp (label1, label2)) {
153 printf ("%s <> %s : labels differ\n", name1, name2);
154 return;
155 }
156
157 /* compare data types */
158
159 if (cgio_get_data_type (cgio1, id1, type1))
160 err_exit (name1, "cgio_get_data_type");
161 if (cgio_get_data_type (cgio2, id2, type2))
162 err_exit (name2, "cgio_get_data_type");
163 if (strcmp (type1, type2)) {
164 printf ("%s <> %s : data types differ\n", name1, name2);
165 return;
166 }
167
168 /* compare number of dimensions */
169
170 if (cgio_get_dimensions (cgio1, id1, &ndim1, dims1))
171 err_exit (name1, "cgio_get_dimensions");
172 if (cgio_get_dimensions (cgio2, id2, &ndim2, dims2))
173 err_exit (name2, "cgio_get_dimensions");
174 if (ndim1 != ndim2) {
175 printf ("%s <> %s : number of dimensions differ\n", name1, name2);
176 return;
177 }
178
179 /* compare dimensions */
180
181 if (ndim1 > 0) {
182 for (n = 0; n < ndim1; n++) {
183 if (dims1[n] != dims2[n]) {
184 printf ("%s <> %s : dimensions differ\n", name1, name2);
185 return;
186 }
187 }
188 }
189
190 if (!node_data || ndim1 <= 0) return;
191
192 /* compare data */
193
194 bytes = data_size (type1, ndim1, dims1, &n);
195 if (bytes > 0) {
196 data1 = malloc (bytes);
197 if (data1 == NULL) {
198 fprintf (stderr, "%s:malloc failed for node data\n", name1);
199 exit (1);
200 }
201 data2 = malloc (bytes);
202 if (data2 == NULL) {
203 fprintf (stderr, "%s:malloc failed for node data\n", name2);
204 exit (1);
205 }
206 if (cgio_read_all_data_type (cgio1, id1, type1, data1))
207 err_exit (name1, "cgio_read_all_data_type");
208 if (cgio_read_all_data_type (cgio2, id2, type2, data2))
209 err_exit (name2, "cgio_read_all_data_type");
210 if (tol > 0.0 && n) {
211 if (n == 4)
212 err = compare_floats (bytes >> 2, data1, data2);
213 else
214 err = compare_doubles (bytes >> 3, data1, data2);
215 }
216 else {
217 err = compare_bytes (bytes, (unsigned char *)data1,
218 (unsigned char *)data2);
219 }
220 free (data1);
221 free (data2);
222 if (err)
223 printf ("%s <> %s : data values differ\n", name1, name2);
224 }
225 }
226
copy_name(char * name,char * newname)227 static void copy_name (char *name, char *newname)
228 {
229 int n1, n2;
230
231 if (nospace) {
232 if (nocase) {
233 for (n1 = 0, n2 = 0; name[n1]; n1++) {
234 if (!isspace (name[n1]))
235 newname[n2++] = tolower (name[n1]);
236 }
237 }
238 else {
239 for (n1 = 0, n2 = 0; name[n1]; n1++) {
240 if (!isspace (name[n1]))
241 newname[n2++] = name[n1];
242 }
243 }
244 newname[n2] = 0;
245 }
246 else if (nocase) {
247 for (n1 = 0; name[n1]; n1++)
248 newname[n1] = tolower (name[n1]);
249 newname[n1] = 0;
250 }
251 else
252 strcpy (newname, name);
253 }
254
sort_children(const void * v1,const void * v2)255 static int sort_children (const void *v1, const void *v2)
256 {
257 char p1[33], p2[33];
258
259 copy_name ((char *)v1, p1);
260 copy_name ((char *)v2, p2);
261 return strcmp (p1, p2);
262 }
263
find_name(char * name,int nlist,char * namelist)264 static int find_name (char *name, int nlist, char *namelist)
265 {
266 int cmp, mid, lo = 0, hi = nlist - 1;
267 char p1[33], p2[33];
268
269 copy_name (name, p1);
270 copy_name (namelist, p2);
271 if (0 == strcmp (p1, p2)) return 0;
272 copy_name (&namelist[33*hi], p2);
273 if (0 == strcmp (p1, p2)) return hi;
274
275 while (lo <= hi) {
276 mid = (lo + hi) >> 1;
277 copy_name (&namelist[33*mid], p2);
278 cmp = strcmp (p1, p2);
279 if (0 == cmp) return mid;
280 if (cmp > 0)
281 lo = mid + 1;
282 else
283 hi = mid - 1;
284 }
285 return -1;
286 }
287
compare_nodes(char * name1,double id1,char * name2,double id2)288 static void compare_nodes (char *name1, double id1, char *name2, double id2)
289 {
290 int n1, n2, nc1, nc2, nret;
291 char *p, *children1 = NULL, *children2 = NULL;
292 char path1[1024], path2[1024];
293 double cid1, cid2;
294
295 compare_data (name1, id1, name2, id2);
296 if (!recurse) return;
297 if (!follow_links) {
298 if (cgio_is_link (cgio1, id1, &nret))
299 err_exit (name1, "cgio_is_link");
300 if (nret > 0) return;
301 if (cgio_is_link (cgio2, id2, &nret))
302 err_exit (name2, "cgio_is_link");
303 if (nret > 0) return;
304 }
305
306 if (cgio_number_children (cgio1, id1, &nc1))
307 err_exit (name1, "cgio_number_children");
308 if (nc1) {
309 children1 = (char *) malloc (33 * nc1);
310 if (children1 == NULL) {
311 fprintf (stderr, "%s:malloc failed for children names\n", name1);
312 exit (1);
313 }
314 if (cgio_children_names (cgio1, id1, 1, nc1, 33,
315 &nret, children1))
316 err_exit (name1, "cgio_children_names");
317 if (nc1 > 1)
318 qsort (children1, nc1, 33, sort_children);
319 }
320
321 if (cgio_number_children (cgio2, id2, &nc2))
322 err_exit (name2, "cgio_number_children");
323 if (nc2) {
324 children2 = (char *) malloc (33 * nc2);
325 if (children2 == NULL) {
326 fprintf (stderr, "%s:malloc failed for children names\n", name2);
327 exit (1);
328 }
329 if (cgio_children_names (cgio2, id2, 1, nc2, 33,
330 &nret, children2))
331 err_exit (name2, "cgio_children_names");
332 if (nc2 > 1)
333 qsort (children2, nc2, 33, sort_children);
334 }
335
336 if (0 == strcmp (name1, "/")) name1 = "";
337 if (0 == strcmp (name2, "/")) name2 = "";
338 if (nc1 == 0) {
339 if (nc2 == 0) return;
340 for (n2 = 0; n2 < nc2; n2++)
341 printf ("> %s/%s\n", name2, &children2[33*n2]);
342 free (children2);
343 return;
344 }
345 if (nc2 == 0) {
346 for (n1 = 0; n1 < nc1; n1++)
347 printf ("< %s/%s\n", name1, &children1[33*n1]);
348 free (children1);
349 return;
350 }
351
352 for (n1 = 0, n2 = 0; n1 < nc1; n1++) {
353 p = &children1[33*n1];
354 nret = find_name (p, nc2, children2);
355 if (nret < 0) {
356 printf ("< %s/%s\n", name1, p);
357 continue;
358 }
359 while (n2 < nret) {
360 printf ("> %s/%s\n", name2, &children2[33*n2]);
361 n2++;
362 }
363 if (cgio_get_node_id (cgio1, id1, p, &cid1))
364 err_exit (name1, "cgio_get_node_id");
365 sprintf (path1, "%s/%s", name1, p);
366 p = &children2[33*n2];
367 if (cgio_get_node_id (cgio2, id2, p, &cid2))
368 err_exit (name2, "cgio_get_node_id");
369 sprintf (path2, "%s/%s", name2, p);
370 compare_nodes (path1, cid1, path2, cid2);
371 n2++;
372 }
373 while (n2 < nc2) {
374 printf ("> %s/%s\n", name2, &children2[33*n2]);
375 n2++;
376 }
377 free (children1);
378 free (children2);
379 }
380
main(int argc,char * argv[])381 int main (int argc, char *argv[])
382 {
383 double root1, root2;
384 double node1, node2;
385 int n;
386 char *file1, *file2;
387 char *ds1 = NULL;
388 char *ds2 = NULL;
389
390 if (argc < 3)
391 print_usage (usgmsg, NULL);
392 while ((n = getargs (argc, argv, options)) > 0) {
393 switch (n) {
394 case 'c':
395 nocase = 1;
396 break;
397 case 'i':
398 nospace = 1;
399 break;
400 case 'q':
401 quiet = 1;
402 break;
403 case 'f':
404 follow_links = 1;
405 break;
406 case 'r':
407 recurse = 1;
408 break;
409 case 'd':
410 node_data = 1;
411 break;
412 case 't':
413 tol = atof (argarg);
414 break;
415 }
416 }
417
418 if (argind > argc - 2)
419 print_usage (usgmsg, "CGNSfile1 and/or CGNSfile2 not given");
420
421 file1 = argv[argind++];
422 if (cgio_open_file (file1, 'r', CGIO_FILE_NONE, &cgio1))
423 err_exit (file1, "cgio_open_file");
424 if (cgio_get_root_id (cgio1, &root1))
425 err_exit (file1, "cgio_get_root_id");
426 if (argind < argc - 1)
427 ds1 = argv[argind++];
428
429 file2 = argv[argind++];
430 if (cgio_open_file (file2, 'r', CGIO_FILE_NONE, &cgio2))
431 err_exit (file2, "cgio_open_file");
432 if (cgio_get_root_id (cgio2, &root2))
433 err_exit (file2, "cgio_get_root_id");
434 if (argind < argc)
435 ds2 = argv[argind++];
436
437 if (ds1 == NULL) {
438 recurse = 1;
439 compare_nodes ("/", root1, "/", root2);
440 }
441 else {
442 if (cgio_get_node_id (cgio1, root1, ds1, &node1))
443 err_exit (ds1, "cgio_get_node_id");
444 if (ds2 == NULL) ds2 = ds1;
445 if (cgio_get_node_id (cgio2, root2, ds2, &node2))
446 err_exit (ds2, "cgio_get_node_id");
447 compare_nodes (ds1, node1, ds2, node2);
448 }
449
450 cgio_close_file (cgio1);
451 cgio_close_file (cgio2);
452 return 0;
453 }
454
455