1 /*
2  * Copyright(C) 1999-2021 National Technology & Engineering Solutions
3  * of Sandia, LLC (NTESS).  Under the terms of Contract DE-NA0003525 with
4  * NTESS, the U.S. Government retains certain rights in this software.
5  *
6  * See packages/seacas/LICENSE for details
7  */
8 
9 #include "exodusII.h"
10 #include "exodusII_int.h"
11 
12 /*! \cond INTERNAL */
ex__get_dimension_value(int exoid,int64_t * var,int default_value,const char * dimension_name,int missing_ok)13 static int ex__get_dimension_value(int exoid, int64_t *var, int default_value,
14                                    const char *dimension_name, int missing_ok)
15 {
16   int    status;
17   char   errmsg[MAX_ERR_LENGTH];
18   size_t idum;
19   int    dimid;
20 
21   if ((status = nc_inq_dimid(exoid, dimension_name, &dimid)) != NC_NOERR) {
22     *var = default_value;
23     if (missing_ok) {
24       return (EX_NOERR);
25     }
26     snprintf(errmsg, MAX_ERR_LENGTH, "ERROR: failed to retrieve dimension %s for file id %d",
27              dimension_name, exoid);
28     ex_err_fn(exoid, __func__, errmsg, status);
29     return (EX_FATAL);
30   }
31   if ((status = nc_inq_dimlen(exoid, dimid, &idum)) != NC_NOERR) {
32     *var = default_value;
33     snprintf(errmsg, MAX_ERR_LENGTH,
34              "ERROR: failed to retrieve value for dimension %s for file id %d", dimension_name,
35              exoid);
36     ex_err_fn(exoid, __func__, errmsg, status);
37     return (EX_FATAL);
38   }
39   *var = idum;
40   return (EX_NOERR);
41 }
42 
ex_get_concat_set_len(int exoid,int64_t * set_length,const char * set_name,const char * set_num_dim,const char * set_stat_var,const char * set_size_root,int missing_ok)43 static int ex_get_concat_set_len(int exoid, int64_t *set_length, const char *set_name,
44                                  const char *set_num_dim, const char *set_stat_var,
45                                  const char *set_size_root, int missing_ok)
46 {
47   int    i;
48   int    status;
49   char   errmsg[MAX_ERR_LENGTH];
50   size_t idum;
51   int    dimid, varid;
52   size_t num_sets;
53   int *  stat_vals = NULL;
54 
55   *set_length = 0; /* default return value */
56 
57   if ((status = nc_inq_dimid(exoid, set_num_dim, &dimid)) == NC_NOERR) {
58     if ((status = nc_inq_dimlen(exoid, dimid, &num_sets)) != NC_NOERR) {
59       snprintf(errmsg, MAX_ERR_LENGTH, "ERROR: failed to get number of %s sets in file id %d",
60                set_name, exoid);
61       ex_err_fn(exoid, __func__, errmsg, status);
62       return (EX_FATAL);
63     }
64 
65     /* Allocate space for stat array */
66     if (!(stat_vals = malloc((int)num_sets * sizeof(int)))) {
67       snprintf(errmsg, MAX_ERR_LENGTH,
68                "ERROR: failed to allocate memory for %s set status "
69                "array for file id %d",
70                set_name, exoid);
71       ex_err_fn(exoid, __func__, errmsg, EX_MEMFAIL);
72       return (EX_FATAL);
73     }
74 
75     /* get variable id of status array */
76     if ((status = nc_inq_varid(exoid, set_stat_var, &varid)) == NC_NOERR) {
77       /* if status array exists, use it, otherwise assume, object exists
78          to be backward compatible */
79       if ((status = nc_get_var_int(exoid, varid, stat_vals)) != NC_NOERR) {
80         free(stat_vals);
81         snprintf(errmsg, MAX_ERR_LENGTH, "ERROR: failed to get %s set status array from file id %d",
82                  set_name, exoid);
83         ex_err_fn(exoid, __func__, errmsg, status);
84         return (EX_FATAL);
85       }
86     }
87     else { /* default: status is true */
88       for (i = 0; i < num_sets; i++) {
89         stat_vals[i] = 1;
90       }
91     }
92 
93     for (i = 0; i < num_sets; i++) {
94       if (stat_vals[i] == 0) { /* is this object null? */
95         continue;
96       }
97 
98       if ((status = nc_inq_dimid(exoid, ex__catstr(set_size_root, i + 1), &dimid)) != NC_NOERR) {
99         if (missing_ok) {
100           idum = 0;
101         }
102         else {
103           *set_length = 0;
104           free(stat_vals);
105           return (EX_FATAL);
106         }
107       }
108       else {
109         if ((status = nc_inq_dimlen(exoid, dimid, &idum)) != NC_NOERR) {
110           *set_length = 0;
111           free(stat_vals);
112           return (EX_FATAL);
113         }
114       }
115 
116       *set_length += idum;
117     }
118 
119     free(stat_vals);
120   }
121   return (EX_NOERR);
122 }
123 
flt_cvt(float * xptr,double x)124 static void flt_cvt(float *xptr, double x) { *xptr = (float)x; }
125 /*! \endcond */
126 
ex_inquire_internal(int exoid,int req_info,int64_t * ret_int,float * ret_float,char * ret_char)127 static int ex_inquire_internal(int exoid, int req_info, int64_t *ret_int, float *ret_float,
128                                char *ret_char)
129 {
130   int       dimid, varid, rootid;
131   void_int *ids = NULL;
132   size_t    i;
133   size_t    ldum = 0;
134   size_t    num_sets, idum;
135   int *     stat_vals;
136   char      errmsg[MAX_ERR_LENGTH];
137   int       status;
138   char      tmp_title[2048];
139   int       num_var;
140 
141   if (ex__check_valid_file_id(exoid, __func__) == EX_FATAL) {
142     return (EX_FATAL);
143   }
144 
145   if (ret_char) {
146     *ret_char = '\0'; /* Only needs to be non-null for TITLE and some GROUP NAME inquiries */
147   }
148   if (!ret_int) {
149     snprintf(errmsg, MAX_ERR_LENGTH, "Warning: integer argument is NULL which is not allowed.");
150     ex_err_fn(exoid, __func__, errmsg, EX_BADPARAM);
151     return (EX_FATAL);
152   }
153 
154   rootid = exoid & EX_FILE_ID_MASK;
155 
156   switch (req_info) {
157   case EX_INQ_FILE_TYPE:
158 
159     /* obsolete call */
160     /*returns "r" for regular EXODUS file or "h" for history EXODUS file*/
161     snprintf(errmsg, MAX_ERR_LENGTH, "Warning: file type inquire is obsolete");
162     ex_err_fn(exoid, __func__, errmsg, EX_BADPARAM);
163     return (EX_WARN);
164 
165   case EX_INQ_API_VERS:
166     /* returns the EXODUS API version number */
167     if (!ret_float) {
168       snprintf(errmsg, MAX_ERR_LENGTH,
169                "Warning: float argument is NULL for EX_INQ_API_VERS "
170                "which is not allowed.");
171       ex_err_fn(exoid, __func__, errmsg, EX_BADPARAM);
172       return (EX_FATAL);
173     }
174 
175     if (nc_get_att_float(rootid, NC_GLOBAL, ATT_API_VERSION, ret_float) !=
176         NC_NOERR) { /* try old (prior to db version 2.02) attribute name */
177       if ((status = nc_get_att_float(rootid, NC_GLOBAL, ATT_API_VERSION_BLANK, ret_float)) !=
178           NC_NOERR) {
179         snprintf(errmsg, MAX_ERR_LENGTH, "ERROR: failed to get EXODUS API version for file id %d",
180                  rootid);
181         ex_err_fn(exoid, __func__, errmsg, status);
182         return (EX_FATAL);
183       }
184     }
185 
186     break;
187 
188   case EX_INQ_DB_VERS:
189     /* returns the EXODUS database version number */
190     if (!ret_float) {
191       snprintf(errmsg, MAX_ERR_LENGTH,
192                "Warning: float argument is NULL for EX_INQ_DB_VERS "
193                "which is not allowed.");
194       ex_err_fn(exoid, __func__, errmsg, EX_BADPARAM);
195       return (EX_FATAL);
196     }
197 
198     if ((status = nc_get_att_float(rootid, NC_GLOBAL, ATT_VERSION, ret_float)) != NC_NOERR) {
199       snprintf(errmsg, MAX_ERR_LENGTH,
200                "ERROR: failed to get EXODUS database version for file id %d", rootid);
201       ex_err_fn(exoid, __func__, errmsg, status);
202       return (EX_FATAL);
203     }
204     break;
205 
206   case EX_INQ_LIB_VERS:
207     /* returns the EXODUS Library version number */
208     if (ret_float) {
209       float version_major = EXODUS_VERSION_MAJOR;
210       float version_minor = EXODUS_VERSION_MINOR;
211       float version       = version_major + version_minor / 100.0;
212       flt_cvt(ret_float, version);
213     }
214 
215     if (ret_int) {
216       *ret_int = EX_API_VERS_NODOT;
217     }
218     break;
219 
220   case EX_INQ_DB_MAX_ALLOWED_NAME_LENGTH:
221     /* Return the MAX_NAME_LENGTH size for this database
222        It will not include the space for the trailing null, so if it
223        is defined as 33 on the database, 32 will be returned.
224     */
225     if ((status = nc_inq_dimid(rootid, DIM_STR_NAME, &dimid)) != NC_NOERR) {
226       /* If not found, then an older database */
227       *ret_int = 32;
228     }
229     else {
230       /* Get the name string length */
231       size_t name_length = 0;
232       if ((status = nc_inq_dimlen(rootid, dimid, &name_length)) != NC_NOERR) {
233         snprintf(errmsg, MAX_ERR_LENGTH, "ERROR: failed to get name string length in file id %d",
234                  exoid);
235         ex_err_fn(exoid, __func__, errmsg, status);
236         return (EX_FATAL);
237       }
238 
239       *ret_int = name_length - 1;
240     }
241     break;
242 
243   case EX_INQ_DB_FLOAT_SIZE: {
244     nc_get_att_longlong(rootid, NC_GLOBAL, ATT_FLT_WORDSIZE, (long long *)ret_int);
245   } break;
246 
247   case EX_INQ_DB_MAX_USED_NAME_LENGTH:
248     /* Return the value of the ATT_MAX_NAME_LENGTH attribute (if it
249        exists) which is the maximum length of any entity, variable,
250        attribute, property name written to this database.  If the
251        attribute does not exist, then '32' is returned.  The length
252        does not include the trailing null.
253     */
254     {
255       nc_type att_type = NC_NAT;
256       size_t  att_len  = 0;
257 
258       *ret_int = 32; /* Default size consistent with older databases */
259 
260       status = nc_inq_att(rootid, NC_GLOBAL, ATT_MAX_NAME_LENGTH, &att_type, &att_len);
261       if (status == NC_NOERR && att_type == NC_INT) {
262         /* The attribute exists, return it... */
263         nc_get_att_longlong(rootid, NC_GLOBAL, ATT_MAX_NAME_LENGTH, (long long *)ret_int);
264       }
265     }
266     break;
267 
268   case EX_INQ_MAX_READ_NAME_LENGTH: {
269     /* Returns the user-specified maximum size of names that will be
270      * returned to the user by any of the ex_get_ routines.  If the
271      * name is longer than this value, it will be truncated. The
272      * default if not set by the client is 32 characters. The value
273      * does not include the trailing null.
274      */
275     struct ex__file_item *file = ex__find_file_item(rootid);
276 
277     if (!file) {
278       snprintf(errmsg, MAX_ERR_LENGTH, "ERROR: unknown file id %d for ex_inquire_int().", rootid);
279       ex_err_fn(exoid, __func__, errmsg, EX_BADFILEID);
280       *ret_int = 0;
281     }
282     else {
283       *ret_int = file->maximum_name_length;
284     }
285   } break;
286 
287   case EX_INQ_TITLE:
288     if (!ret_char) {
289       snprintf(errmsg, MAX_ERR_LENGTH,
290                "ERROR: Requested title, but character pointer was null "
291                "for file id %d",
292                rootid);
293       ex_err_fn(exoid, __func__, errmsg, EX_BADPARAM);
294       return (EX_FATAL);
295     }
296     else {
297       /* returns the title of the database */
298       /* Title is stored at root level... */
299       if ((status = nc_get_att_text(rootid, NC_GLOBAL, ATT_TITLE, tmp_title)) != NC_NOERR) {
300         *ret_char = '\0';
301         snprintf(errmsg, MAX_ERR_LENGTH, "ERROR: failed to get database title for file id %d",
302                  exoid);
303         ex_err_fn(exoid, __func__, errmsg, status);
304         return (EX_FATAL);
305       }
306       ex_copy_string(ret_char, tmp_title, MAX_LINE_LENGTH + 1);
307     }
308     break;
309 
310   case EX_INQ_DIM:
311     /* returns the dimensionality (2 or 3, for 2-d or 3-d) of the database */
312     if (ex__get_dimension(exoid, DIM_NUM_DIM, "database dimensionality", &ldum, &dimid, __func__) !=
313         NC_NOERR) {
314       return (EX_FATAL);
315     }
316     *ret_int = ldum;
317     break;
318 
319   case EX_INQ_ASSEMBLY:
320     /* returns the number of assemblies */
321     {
322       *ret_int                   = 0;
323       struct ex__file_item *file = ex__find_file_item(exoid);
324       if (file) {
325         *ret_int = file->assembly_count;
326       }
327     }
328     break;
329 
330   case EX_INQ_BLOB:
331     /* returns the number of blobs */
332     {
333       *ret_int                   = 0;
334       struct ex__file_item *file = ex__find_file_item(exoid);
335       if (file) {
336         *ret_int = file->blob_count;
337       }
338     }
339     break;
340 
341   case EX_INQ_NODES:
342     /* returns the number of nodes */
343     if (ex__get_dimension(exoid, DIM_NUM_NODES, "nodes", &ldum, &dimid, NULL) != NC_NOERR) {
344       *ret_int = 0;
345     }
346     else {
347       *ret_int = ldum;
348     }
349     break;
350 
351   case EX_INQ_ELEM:
352     /* returns the number of elements */
353     if (ex__get_dimension(exoid, DIM_NUM_ELEM, "elements", &ldum, &dimid, NULL) != NC_NOERR) {
354       *ret_int = 0;
355     }
356     else {
357       *ret_int = ldum;
358     }
359     break;
360 
361   case EX_INQ_ELEM_BLK:
362     /* returns the number of element blocks */
363     if (ex__get_dimension(exoid, DIM_NUM_EL_BLK, "element blocks", &ldum, &dimid, NULL) !=
364         NC_NOERR) {
365       *ret_int = 0;
366     }
367     else {
368       *ret_int = ldum;
369     }
370     break;
371 
372   case EX_INQ_NODE_SETS:
373     /* returns the number of node sets */
374     if (ex__get_dimension(exoid, DIM_NUM_NS, "node sets", &ldum, &dimid, NULL) != NC_NOERR) {
375       *ret_int = 0;
376     }
377     else {
378       *ret_int = ldum;
379     }
380     break;
381 
382   case EX_INQ_NS_NODE_LEN:
383     /* returns the length of the concatenated node sets node list */
384     ex_get_concat_set_len(exoid, ret_int, "node", DIM_NUM_NS, VAR_NS_STAT, "num_nod_ns", 0);
385     break;
386 
387   case EX_INQ_NS_DF_LEN:
388     /*     returns the length of the concatenated node sets dist factor list */
389 
390     /*
391       Determine the concatenated node sets distribution factor length:
392 
393       2. Check see if the dist factor variable for a node set id exists.
394       3. If it exists, goto step 4, else the length is zero.
395       4. Get the dimension of the number of nodes in the node set -0
396       use this value as the length as by definition they are the same.
397       5. Sum the individual lengths for the total list length.
398     */
399 
400     *ret_int = 0; /* default value if no node sets defined */
401 
402     if (nc_inq_dimid(exoid, DIM_NUM_NS, &dimid) == NC_NOERR) {
403       if ((status = nc_inq_dimlen(exoid, dimid, &num_sets)) != NC_NOERR) {
404         snprintf(errmsg, MAX_ERR_LENGTH, "ERROR: failed to get number of node sets in file id %d",
405                  exoid);
406         ex_err_fn(exoid, __func__, errmsg, status);
407         return (EX_FATAL);
408       }
409 
410       for (i = 0; i < num_sets; i++) {
411         if ((status = nc_inq_varid(exoid, VAR_FACT_NS(i + 1), &varid)) != NC_NOERR) {
412           if (status == NC_ENOTVAR) {
413             idum = 0; /* this dist factor doesn't exist */
414           }
415           else {
416             *ret_int = 0;
417             snprintf(
418                 errmsg, MAX_ERR_LENGTH,
419                 "ERROR: failed to locate number of dist fact for %zu'th node set in file id %d", i,
420                 exoid);
421             ex_err_fn(exoid, __func__, errmsg, status);
422             return (EX_FATAL);
423           }
424         }
425         else {
426           if ((status = nc_inq_dimid(exoid, DIM_NUM_NOD_NS(i + 1), &dimid)) != NC_NOERR) {
427             *ret_int = 0;
428             snprintf(errmsg, MAX_ERR_LENGTH,
429                      "ERROR: failed to locate number of nodes in %zu'th node set in file id %d", i,
430                      exoid);
431             ex_err_fn(exoid, __func__, errmsg, status);
432             return (EX_FATAL);
433           }
434           if ((status = nc_inq_dimlen(exoid, dimid, &idum)) != NC_NOERR) {
435             *ret_int = 0;
436             snprintf(errmsg, MAX_ERR_LENGTH,
437                      "ERROR: failed to get number of nodes in %zu'th node set in file id %d", i,
438                      exoid);
439             ex_err_fn(exoid, __func__, errmsg, status);
440             return (EX_FATAL);
441           }
442         }
443         *ret_int += idum;
444       }
445     }
446 
447     break;
448 
449   case EX_INQ_SIDE_SETS:
450     /* returns the number of side sets */
451     if (ex__get_dimension(exoid, DIM_NUM_SS, "side sets", &ldum, &dimid, NULL) != NC_NOERR) {
452       *ret_int = 0;
453     }
454     else {
455       *ret_int = ldum;
456     }
457     break;
458 
459   case EX_INQ_SS_NODE_LEN:
460 
461     /*     returns the length of the concatenated side sets node list */
462 
463     *ret_int = 0; /* default return value */
464 
465     if (nc_inq_dimid(exoid, DIM_NUM_SS, &dimid) == NC_NOERR) {
466       if ((status = nc_inq_dimlen(exoid, dimid, &num_sets)) != NC_NOERR) {
467         snprintf(errmsg, MAX_ERR_LENGTH, "ERROR: failed to get number of side sets in file id %d",
468                  exoid);
469         ex_err_fn(exoid, __func__, errmsg, status);
470         return (EX_FATAL);
471       }
472 
473       if (!(ids = malloc(num_sets * sizeof(int64_t)))) { /* May be getting 2x what is
474                                                             needed, but should be OK */
475         snprintf(errmsg, MAX_ERR_LENGTH,
476                  "ERROR: failed to allocate memory for side set ids for file id %d", exoid);
477         ex_err_fn(exoid, __func__, errmsg, EX_MEMFAIL);
478         return (EX_FATAL);
479       }
480 
481       if (ex_get_ids(exoid, EX_SIDE_SET, ids) == EX_FATAL) {
482         snprintf(errmsg, MAX_ERR_LENGTH, "ERROR: failed to get side set ids in file id %d", exoid);
483         ex_err_fn(exoid, __func__, errmsg, EX_LASTERR);
484         free(ids);
485         return (EX_FATAL);
486       }
487 
488       /* allocate space for stat array */
489       if (!(stat_vals = malloc((int)num_sets * sizeof(int)))) {
490         free(ids);
491         snprintf(errmsg, MAX_ERR_LENGTH,
492                  "ERROR: failed to allocate memory for side set status "
493                  "array for file id %d",
494                  exoid);
495         ex_err_fn(exoid, __func__, errmsg, EX_MEMFAIL);
496         return (EX_FATAL);
497       }
498       /* get variable id of status array */
499       if ((status = nc_inq_varid(exoid, VAR_SS_STAT, &varid)) == NC_NOERR) {
500         /* if status array exists, use it, otherwise assume, object exists
501            to be backward compatible */
502 
503         if ((status = nc_get_var_int(exoid, varid, stat_vals)) != NC_NOERR) {
504           free(ids);
505           free(stat_vals);
506           snprintf(errmsg, MAX_ERR_LENGTH,
507                    "ERROR: failed to get element block status array from file id %d", exoid);
508           ex_err_fn(exoid, __func__, errmsg, status);
509           return (EX_FATAL);
510         }
511       }
512       else { /* default: status is true */
513         for (i = 0; i < num_sets; i++) {
514           stat_vals[i] = 1;
515         }
516       }
517 
518       /* walk id list, get each side set node length and sum for total */
519 
520       for (i = 0; i < num_sets; i++) {
521         ex_entity_id id;
522         if (stat_vals[i] == 0) { /* is this object null? */
523           continue;
524         }
525 
526         if (ex_int64_status(exoid) & EX_IDS_INT64_API) {
527           int64_t tmp_len = 0;
528           id              = ((int64_t *)ids)[i];
529           status          = ex_get_side_set_node_list_len(exoid, id, &tmp_len);
530           if (status != EX_FATAL) {
531             *ret_int += tmp_len;
532           }
533         }
534         else {
535           int tmp_len = 0;
536           id          = ((int *)ids)[i];
537           status      = ex_get_side_set_node_list_len(exoid, id, &tmp_len);
538           if (status != EX_FATAL) {
539             *ret_int += tmp_len;
540           }
541         }
542 
543         if (status == EX_FATAL) {
544           *ret_int = 0;
545           snprintf(errmsg, MAX_ERR_LENGTH,
546                    "ERROR: failed to side set %" PRId64 " node length in file id %d", id, exoid);
547           ex_err_fn(exoid, __func__, errmsg, status);
548           free(stat_vals);
549           free(ids);
550           return (EX_FATAL);
551         }
552       }
553 
554       free(stat_vals);
555       free(ids);
556     }
557 
558     break;
559 
560   case EX_INQ_SS_ELEM_LEN:
561     /*     returns the length of the concatenated side sets element list */
562     ex_get_concat_set_len(exoid, ret_int, "side", DIM_NUM_SS, VAR_SS_STAT, "num_side_ss", 0);
563     break;
564 
565   case EX_INQ_SS_DF_LEN:
566 
567     /*     returns the length of the concatenated side sets dist factor list */
568 
569     /*
570       Determine the concatenated side sets distribution factor length:
571 
572       1. Get the side set ids list.
573       2. Check see if the dist factor dimension for a side set id exists.
574       3. If it exists, goto step 4, else set the individual length to zero.
575       4. Sum the dimension value into the running total length.
576     */
577 
578     *ret_int = 0;
579 
580     /* first check see if any side sets exist */
581 
582     if (nc_inq_dimid(exoid, DIM_NUM_SS, &dimid) == NC_NOERR) {
583       if ((status = nc_inq_dimlen(exoid, dimid, &num_sets)) != NC_NOERR) {
584         snprintf(errmsg, MAX_ERR_LENGTH, "ERROR: failed to get number of side sets in file id %d",
585                  exoid);
586         ex_err_fn(exoid, __func__, errmsg, status);
587         return (EX_FATAL);
588       }
589 
590       for (i = 0; i < num_sets; i++) {
591         if ((status = nc_inq_dimid(exoid, DIM_NUM_DF_SS(i + 1), &dimid)) != NC_NOERR) {
592           if (status == NC_EBADDIM) {
593             ldum = 0; /* this dist factor doesn't exist */
594           }
595           else {
596             *ret_int = 0;
597             snprintf(
598                 errmsg, MAX_ERR_LENGTH,
599                 "ERROR: failed to locate number of dist fact for %zu'th side set in file id %d", i,
600                 exoid);
601             ex_err_fn(exoid, __func__, errmsg, status);
602             return (EX_FATAL);
603           }
604         }
605         else {
606           if ((status = nc_inq_dimlen(exoid, dimid, &ldum)) != NC_NOERR) {
607             *ret_int = 0;
608             snprintf(errmsg, MAX_ERR_LENGTH,
609                      "ERROR: failed to get number of dist factors in %zu'th side set in file id %d",
610                      i, exoid);
611             ex_err_fn(exoid, __func__, errmsg, status);
612             return (EX_FATAL);
613           }
614         }
615         *ret_int += ldum;
616       }
617     }
618 
619     break;
620 
621   case EX_INQ_QA:
622     /* returns the number of QA records */
623     if (ex__get_dimension(rootid, DIM_NUM_QA, "QA records", &ldum, &dimid, NULL) != NC_NOERR) {
624       *ret_int = 0;
625     }
626     else {
627       *ret_int = ldum;
628     }
629     break;
630 
631   case EX_INQ_INFO:
632     /* returns the number of information records */
633     if (ex__get_dimension(rootid, DIM_NUM_INFO, "info records", &ldum, &dimid, NULL) != NC_NOERR) {
634       *ret_int = 0;
635     }
636     else {
637       *ret_int = ldum;
638     }
639     break;
640 
641   case EX_INQ_TIME:
642     /*     returns the number of time steps stored in the database */
643     if (ex__get_dimension(exoid, DIM_TIME, "time dimension", &ldum, &dimid, __func__) != NC_NOERR) {
644       return (EX_FATAL);
645     }
646     *ret_int = ldum;
647     break;
648 
649   case EX_INQ_EB_PROP:
650     /* returns the number of element block properties */
651     *ret_int = ex_get_num_props(exoid, EX_ELEM_BLOCK);
652     break;
653 
654   case EX_INQ_NS_PROP:
655     /* returns the number of node set properties */
656     *ret_int = ex_get_num_props(exoid, EX_NODE_SET);
657     break;
658 
659   case EX_INQ_SS_PROP:
660     /* returns the number of side set properties */
661     *ret_int = ex_get_num_props(exoid, EX_SIDE_SET);
662     break;
663 
664   case EX_INQ_ELEM_MAP:
665     /* returns the number of element maps */
666     if (ex__get_dimension(exoid, DIM_NUM_EM, "element maps", &ldum, &dimid, NULL) != NC_NOERR) {
667       *ret_int = 0;
668     }
669     else {
670       *ret_int = ldum;
671     }
672     break;
673 
674   case EX_INQ_EM_PROP:
675     /* returns the number of element map properties */
676     *ret_int = ex_get_num_props(exoid, EX_ELEM_MAP);
677     break;
678 
679   case EX_INQ_NODE_MAP:
680     /* returns the number of node maps */
681     if (ex__get_dimension(exoid, DIM_NUM_NM, "node maps", &ldum, &dimid, NULL) != NC_NOERR) {
682       *ret_int = 0;
683     }
684     else {
685       *ret_int = ldum;
686     }
687     break;
688 
689   case EX_INQ_NM_PROP:
690     /* returns the number of node map properties */
691     *ret_int = ex_get_num_props(exoid, EX_NODE_MAP);
692     break;
693 
694   case EX_INQ_EDGE:
695     /* returns the number of edges (defined across all edge blocks). */
696     if (ex__get_dimension_value(exoid, ret_int, 0, DIM_NUM_EDGE, 1) != EX_NOERR) {
697       return (EX_FATAL);
698     }
699     break;
700 
701   case EX_INQ_EDGE_BLK:
702     /* returns the number of edge blocks. */
703     if (ex__get_dimension_value(exoid, ret_int, 0, DIM_NUM_ED_BLK, 1) != EX_NOERR) {
704       return (EX_FATAL);
705     }
706     break;
707 
708   case EX_INQ_EDGE_SETS:
709     /* returns the number of edge sets. */
710     if (ex__get_dimension_value(exoid, ret_int, 0, DIM_NUM_ES, 1) != EX_NOERR) {
711       return (EX_FATAL);
712     }
713     break;
714 
715   case EX_INQ_ES_LEN:
716     /* returns the length of the concatenated edge set edge list. */
717     ex_get_concat_set_len(exoid, ret_int, "edge", DIM_NUM_ES, VAR_ES_STAT, "num_edge_es", 0);
718     break;
719 
720   case EX_INQ_ES_DF_LEN:
721     /* returns the length of the concatenated edge set distribution factor list.
722      */
723     ex_get_concat_set_len(exoid, ret_int, "edge", DIM_NUM_ES, VAR_ES_STAT, "num_df_es", 1);
724     break;
725 
726   case EX_INQ_EDGE_PROP:
727     /* returns the number of integer properties stored for each edge block. This
728      * includes the "ID" property. */
729     *ret_int = ex_get_num_props(exoid, EX_EDGE_BLOCK);
730     break;
731 
732   case EX_INQ_ES_PROP:
733     /* returns the number of integer properties stored for each edge set.. This
734      * includes the "ID" property */
735     *ret_int = ex_get_num_props(exoid, EX_EDGE_SET);
736     break;
737 
738   case EX_INQ_FACE:
739     /* returns the number of faces (defined across all face blocks). */
740     if (ex__get_dimension_value(exoid, ret_int, 0, DIM_NUM_FACE, 1) != EX_NOERR) {
741       return (EX_FATAL);
742     }
743     break;
744 
745   case EX_INQ_FACE_BLK:
746     /* returns the number of face blocks. */
747     if (ex__get_dimension_value(exoid, ret_int, 0, DIM_NUM_FA_BLK, 1) != EX_NOERR) {
748       return (EX_FATAL);
749     }
750     break;
751 
752   case EX_INQ_FACE_SETS:
753     /* returns the number of face sets. */
754     if (ex__get_dimension_value(exoid, ret_int, 0, DIM_NUM_FS, 1) != EX_NOERR) {
755       return (EX_FATAL);
756     }
757     break;
758 
759   case EX_INQ_FS_LEN:
760     /* returns the length of the concatenated edge set edge list. */
761     ex_get_concat_set_len(exoid, ret_int, "face", DIM_NUM_FS, VAR_FS_STAT, "num_face_fs", 0);
762     break;
763 
764   case EX_INQ_FS_DF_LEN:
765     /* returns the length of the concatenated edge set distribution factor list.
766      */
767     ex_get_concat_set_len(exoid, ret_int, "face", DIM_NUM_FS, VAR_FS_STAT, "num_df_fs", 1);
768     break;
769 
770   case EX_INQ_FACE_PROP:
771     /* returns the number of integer properties stored for each edge block. This
772      * includes the "ID" property. */
773     *ret_int = ex_get_num_props(exoid, EX_FACE_BLOCK);
774     break;
775 
776   case EX_INQ_FS_PROP:
777     /* returns the number of integer properties stored for each edge set.. This
778      * includes the "ID" property */
779     *ret_int = ex_get_num_props(exoid, EX_FACE_SET);
780     break;
781 
782   case EX_INQ_ELEM_SETS:
783     /* returns the number of element sets. */
784     if (ex__get_dimension_value(exoid, ret_int, 0, DIM_NUM_ELS, 1) != EX_NOERR) {
785       return (EX_FATAL);
786     }
787     break;
788 
789   case EX_INQ_ELS_LEN:
790     /* returns the length of the concatenated element set element list. */
791     ex_get_concat_set_len(exoid, ret_int, "element", DIM_NUM_ELS, VAR_ELS_STAT, "num_ele_els", 0);
792     break;
793 
794   case EX_INQ_ELS_DF_LEN:
795     /* returns the length of the concatenated element set distribution factor
796      * list. */
797     ex_get_concat_set_len(exoid, ret_int, "element", DIM_NUM_ELS, VAR_ELS_STAT, "num_df_els", 1);
798     break;
799 
800   case EX_INQ_ELS_PROP:
801     /* returns the number of integer properties stored for each element set. */
802     *ret_int = ex_get_num_props(exoid, EX_ELEM_SET);
803     break;
804 
805   case EX_INQ_EDGE_MAP:
806     /* returns the number of edge maps. */
807     if (ex__get_dimension_value(exoid, ret_int, 0, DIM_NUM_EDM, 1) != EX_NOERR) {
808       return (EX_FATAL);
809     }
810     break;
811 
812   case EX_INQ_FACE_MAP:
813     /*     returns the number of face maps. */
814     if (ex__get_dimension_value(exoid, ret_int, 0, DIM_NUM_FAM, 1) != EX_NOERR) {
815       return (EX_FATAL);
816     }
817     break;
818 
819   case EX_INQ_NUM_NODE_VAR:
820     if (ex_get_variable_param(exoid, EX_NODAL, &num_var) != EX_NOERR) {
821       return (EX_FATAL);
822     }
823     *ret_int = num_var;
824     break;
825 
826   case EX_INQ_NUM_EDGE_BLOCK_VAR:
827     if (ex_get_variable_param(exoid, EX_EDGE_BLOCK, &num_var) != EX_NOERR) {
828       return (EX_FATAL);
829     }
830     *ret_int = num_var;
831     break;
832 
833   case EX_INQ_NUM_FACE_BLOCK_VAR:
834     if (ex_get_variable_param(exoid, EX_FACE_BLOCK, &num_var) != EX_NOERR) {
835       return (EX_FATAL);
836     }
837     *ret_int = num_var;
838     break;
839 
840   case EX_INQ_NUM_ELEM_BLOCK_VAR:
841     if (ex_get_variable_param(exoid, EX_ELEM_BLOCK, &num_var) != EX_NOERR) {
842       return (EX_FATAL);
843     }
844     *ret_int = num_var;
845     break;
846 
847   case EX_INQ_NUM_NODE_SET_VAR:
848     if (ex_get_variable_param(exoid, EX_NODE_SET, &num_var) != EX_NOERR) {
849       return (EX_FATAL);
850     }
851     *ret_int = num_var;
852     break;
853 
854   case EX_INQ_NUM_EDGE_SET_VAR:
855     if (ex_get_variable_param(exoid, EX_EDGE_SET, &num_var) != EX_NOERR) {
856       return (EX_FATAL);
857     }
858     *ret_int = num_var;
859     break;
860 
861   case EX_INQ_NUM_FACE_SET_VAR:
862     if (ex_get_variable_param(exoid, EX_FACE_SET, &num_var) != EX_NOERR) {
863       return (EX_FATAL);
864     }
865     *ret_int = num_var;
866     break;
867 
868   case EX_INQ_NUM_ELEM_SET_VAR:
869     if (ex_get_variable_param(exoid, EX_ELEM_SET, &num_var) != EX_NOERR) {
870       return (EX_FATAL);
871     }
872     *ret_int = num_var;
873     break;
874 
875   case EX_INQ_NUM_SIDE_SET_VAR:
876     if (ex_get_variable_param(exoid, EX_SIDE_SET, &num_var) != EX_NOERR) {
877       return (EX_FATAL);
878     }
879     *ret_int = num_var;
880     break;
881 
882   case EX_INQ_NUM_GLOBAL_VAR:
883     if (ex_get_variable_param(exoid, EX_GLOBAL, &num_var) != EX_NOERR) {
884       return (EX_FATAL);
885     }
886     *ret_int = num_var;
887     break;
888 
889   case EX_INQ_COORD_FRAMES:
890     /* return the number of coordinate frames */
891     if (ex__get_dimension_value(exoid, ret_int, 0, DIM_NUM_CFRAMES, 1) != EX_NOERR) {
892       return (EX_FATAL);
893     }
894     break;
895 
896   case EX_INQ_NUM_CHILD_GROUPS: {
897     /* return number of groups contained in this (exoid) group */
898     int tmp_num = 0;
899 #if NC_HAS_HDF5
900     nc_inq_grps(exoid, &tmp_num, NULL);
901 #endif
902     *ret_int = tmp_num;
903   } break;
904 
905   case EX_INQ_GROUP_PARENT: {
906 /* return id of parent of this (exoid) group; returns exoid if at root */
907 #if NC_HAS_HDF5
908     int tmp_num = exoid;
909     nc_inq_grp_parent(exoid, &tmp_num);
910     *ret_int = tmp_num;
911 #else
912     *ret_int = exoid;
913 #endif
914   } break;
915 
916   case EX_INQ_GROUP_ROOT:
917     /* return id of root group "/" of this (exoid) group; returns exoid if at
918      * root */
919     *ret_int = (unsigned)exoid & EX_FILE_ID_MASK;
920     break;
921 
922   case EX_INQ_GROUP_NAME_LEN: {
923     size_t len_name = 0;
924 #if NC_HAS_HDF5
925     /* return name length of group exoid */
926     nc_inq_grpname_len(exoid, &len_name);
927 #endif
928     *ret_int = (int)len_name;
929   } break;
930 
931   case EX_INQ_GROUP_NAME:
932     /* return name of group exoid. "/" returned for root group */
933     /* Assumes that ret_char is large enough to hold name. */
934     if (!ret_char) {
935       snprintf(errmsg, MAX_ERR_LENGTH,
936                "ERROR: Requested group name, but character pointer was "
937                "null for file id %d",
938                exoid);
939       ex_err_fn(exoid, __func__, errmsg, EX_BADPARAM);
940       return (EX_FATAL);
941     }
942 #if NC_HAS_HDF5
943     nc_inq_grpname(exoid, ret_char);
944 #endif
945     break;
946 
947   case EX_INQ_FULL_GROUP_NAME_LEN: {
948     size_t len_name = 0;
949 #if NC_HAS_HDF5
950     /* return length of full group name which is the "/" separated path from
951      * root
952      * For example "/group1/subgroup1/subsubgroup1"
953      * length does not include the NULL terminator byte.
954      */
955     nc_inq_grpname_full(exoid, &len_name, NULL);
956 #endif
957     *ret_int = (int)len_name;
958   } break;
959 
960   case EX_INQ_FULL_GROUP_NAME:
961     /* return full path name of group exoid which is the "/" separated path from
962      * root
963      * For example "/group1/subgroup1/subsubgroup1"
964      * Assumes that ret_char is large enough to hold full path name.
965      */
966     if (!ret_char) {
967       snprintf(errmsg, MAX_ERR_LENGTH,
968                "ERROR: Requested group name, but character pointer was "
969                "null for file id %d",
970                exoid);
971       ex_err_fn(exoid, __func__, errmsg, EX_BADPARAM);
972       return (EX_FATAL);
973     }
974 #if NC_HAS_HDF5
975     nc_inq_grpname_full(exoid, NULL, ret_char);
976 #endif
977     break;
978 
979   case EX_INQ_THREADSAFE:
980 /* Return 1 if the library was compiled in thread-safe mode.
981  * Return 0 otherwise
982  */
983 #if defined(EXODUS_THREADSAFE)
984     *ret_int = 1;
985 #else
986     *ret_int = 0;
987 #endif
988     break;
989 
990   default:
991     *ret_int = 0;
992     snprintf(errmsg, MAX_ERR_LENGTH, "ERROR: invalid inquiry %d", req_info);
993     ex_err_fn(exoid, __func__, errmsg, EX_BADPARAM);
994     return (EX_FATAL);
995   }
996   return (EX_NOERR);
997 }
998 
999 /*!
1000   \ingroup Utilities
1001 
1002   A variant of ex_inquire() which queries integer-valued information only. \see
1003 ex_inquire().
1004   \param[in] exoid     exodus file ID returned from a previous call to
1005 ex_create() or ex_open().
1006   \param[in] req_info  A flag of type #ex_inquiry which designates what information is requested.
1007                        (See ex_inquire() documentation)
1008   \return    result of inquiry.
1009 
1010  As an example, the following will return the number of nodes,
1011  elements, and element blocks stored in the exodus file :
1012 
1013 ~~~{.c}
1014 #include "exodusII.h"
1015 int exoid;
1016 int num_nodes = ex_inquire_int(exoid, EX_INQ_NODES);
1017 int num_elems = ex_inquire_int(exoid, EX_INQ_ELEM);
1018 int num_block = ex_inquire_int(exoid, EX_INQ_ELEM_BLK);
1019 ~~~
1020 
1021 */
ex_inquire_int(int exoid,ex_inquiry req_info)1022 int64_t ex_inquire_int(int exoid, ex_inquiry req_info)
1023 {
1024   char *  cdummy  = NULL; /* Needed just for function call, unused. */
1025   float   fdummy  = 0;    /* Needed just for function call, unused. */
1026   int64_t ret_val = 0;
1027   int     error;
1028   EX_FUNC_ENTER();
1029   error = ex_inquire_internal(exoid, req_info, &ret_val, &fdummy, cdummy);
1030   if (error < 0) {
1031     ret_val = error;
1032   }
1033   EX_FUNC_LEAVE(ret_val);
1034 }
1035 
1036 /*!
1037   \ingroup Utilities
1038 
1039 The function ex_inquire() is used to inquire values of certain
1040 data entities in an exodus file. Memory must be allocated for the
1041 returned values before this function is invoked.query database.
1042 
1043 \sa ex_inquire_int(), ex_inquiry.
1044 
1045 \return In case of an error, ex_inquire() returns a negative
1046         number; a warning will return a positive number.
1047         Possible causes of errors include:
1048   -  data file not properly opened with call to ex_create() or ex_open().
1049   -  requested information not stored in the file.
1050   -  invalid request flag.
1051 
1052 \param[in] exoid     exodus file ID returned from a previous call to ex_create()
1053 or ex_open().
1054 \param[in] req_info  A flag of type #ex_inquiry which designates what information is requested. It
1055                      must be one of the following constants in the table below.
1056 
1057 \param[out]  ret_int   Returned integer, if an integer value is requested
1058                        (according to req_info); otherwise, supply a dummy argument.
1059 
1060 \param[out]  ret_float Returned float, if a float value is requested
1061                        (according to req_info); otherwise, supply a dummy
1062                        argument. This argument is always a float even if the
1063                        database IO and/or CPU word size is a double.
1064 
1065 \param[out]  ret_char  Returned character string, if a character value is
1066                        requested (according to req_info);
1067                        otherwise, supply a dummy argument.
1068 
1069 As an example, the following will return the number of element
1070 block properties stored in the exodus file :
1071 
1072 ~~~{.c}
1073 #include "exodusII.h"
1074 int error, exoid, num_props;
1075 float fdum;
1076 char *cdum;
1077 
1078 \comment{determine the number of element block properties}
1079 error = ex_inquire (exoid, EX_INQ_EB_PROP, &num_props,
1080                     &fdum, cdum);
1081 
1082 \comment{...Another way to get the same information}
1083 num_props = ex_inquire_int(exoid, EX_INQ_EB_PROP);
1084 ~~~
1085 
1086 */
1087 
ex_inquire(int exoid,ex_inquiry req_info,void_int * ret_int,float * ret_float,char * ret_char)1088 int ex_inquire(int exoid, ex_inquiry req_info, void_int *ret_int, float *ret_float, char *ret_char)
1089 {
1090   int ierr;
1091   if (ex_int64_status(exoid) & EX_INQ_INT64_API) {
1092     EX_FUNC_ENTER();
1093     ierr = ex_inquire_internal(exoid, req_info, ret_int, ret_float, ret_char);
1094     EX_FUNC_LEAVE(ierr);
1095   }
1096   /* ret_int is a 32-bit int */
1097   int64_t tmp_int;
1098   int *   return_int = ret_int;
1099 
1100   EX_FUNC_ENTER();
1101   ierr        = ex_inquire_internal(exoid, req_info, &tmp_int, ret_float, ret_char);
1102   *return_int = (int)tmp_int;
1103   EX_FUNC_LEAVE(ierr);
1104 }
1105