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