1 /*
2  * Copyright (c) 2005 Sandia Corporation. Under the terms of Contract
3  * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Governement
4  * retains certain rights in this software.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are
8  * met:
9  *
10  *     * Redistributions of source code must retain the above copyright
11  *       notice, this list of conditions and the following disclaimer.
12  *
13  *     * Redistributions in binary form must reproduce the above
14  *       copyright notice, this list of conditions and the following
15  *       disclaimer in the documentation and/or other materials provided
16  *       with the distribution.
17  *
18  *     * Neither the name of Sandia Corporation nor the names of its
19  *       contributors may be used to endorse or promote products derived
20  *       from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  *
34  */
35 /*****************************************************************************
36 *
37 * exutils - utility routines
38 *
39 *****************************************************************************/
40 
41 #if defined(DEBUG_QSORT)
42 #include <assert.h>
43 #endif
44 
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <ctype.h>
49 #include <unistd.h>
50 
51 #include "exodusII.h"
52 #include "exodusII_int.h"
53 
54 struct obj_stats*  exoII_eb = 0;
55 struct obj_stats*  exoII_ed = 0;
56 struct obj_stats*  exoII_fa = 0;
57 struct obj_stats*  exoII_ns = 0;
58 struct obj_stats*  exoII_es = 0;
59 struct obj_stats*  exoII_fs = 0;
60 struct obj_stats*  exoII_ss = 0;
61 struct obj_stats* exoII_els = 0;
62 struct obj_stats*  exoII_em = 0;
63 struct obj_stats* exoII_edm = 0;
64 struct obj_stats* exoII_fam = 0;
65 struct obj_stats*  exoII_nm = 0;
66 
67 
68 /*****************************************************************************
69 *
70 * utility routines for string conversions
71 * ex_catstr  - concatenate  string/number (where number is converted to ASCII)
72 * ex_catstr2 - concatenate  string1/number1/string2/number2   "
73 *
74 * NOTE: these routines reuse the same storage over and over to build
75 *        concatenated strings, because the strings are just passed to netCDF
76 *        routines as names used to look up variables.  if the strings returned
77 *        by these routines are needed for any other purpose, they should
78 *        immediately be copied into other storage.
79 *****************************************************************************/
80 
81 static char ret_string[10*(MAX_VAR_NAME_LENGTH+1)];
82 static char* cur_string = &ret_string[0];
83 
ex_check_file_type(const char * path,int * type)84 int ex_check_file_type(const char *path, int *type)
85 {
86   /* Based on (stolen from?) NC_check_file_type from netcdf sources.
87 
88      Type is set to:
89      1 if this is a netcdf classic file,
90      2 if this is a netcdf 64-bit offset file,
91      5 if this is an hdf5 file
92   */
93 
94 #define MAGIC_NUMBER_LEN 4
95 
96    char magic[MAGIC_NUMBER_LEN];
97 
98    *type = 0;
99 
100    /* Get the 4-byte magic from the beginning of the file. */
101    {
102       FILE *fp;
103       int i;
104 
105       if (!(fp = fopen(path, "r")))
106 	 return errno;
107       i = fread(magic, MAGIC_NUMBER_LEN, 1, fp);
108       fclose(fp);
109       if(i != 1)
110 	 return errno;
111    }
112 
113    /* Ignore the first byte for HDF */
114    if (magic[1] == 'H' && magic[2] == 'D' && magic[3] == 'F')
115      *type = 5;
116    else if (magic[0] == 'C' && magic[1] == 'D' && magic[2] == 'F')
117    {
118       if (magic[3] == '\001')
119 	*type = 1;
120       else if(magic[3] == '\002')
121 	*type = 2;
122    }
123    return EX_NOERR;
124 }
125 
ex_set_max_name_length(int exoid,int length)126 int ex_set_max_name_length(int exoid, int length)
127 {
128   char errmsg[MAX_ERR_LENGTH];
129   if (length <= 0) {
130     exerrval = NC_EMAXNAME;
131     sprintf(errmsg, "Error: Max name length must be positive.");
132     ex_err("ex_set_max_name_length",errmsg,exerrval);
133     return (EX_FATAL);
134   }
135   else if (length > NC_MAX_NAME) {
136     exerrval = NC_EMAXNAME;
137     sprintf(errmsg, "Error: Max name length (%d) exceeds netcdf max name size (%d).",
138 	    length, NC_MAX_NAME);
139     ex_err("ex_set_max_name_length",errmsg,exerrval);
140     return (EX_FATAL);
141   }
142   else {
143     ex_set_option(exoid, EX_OPT_MAX_NAME_LENGTH, length);
144   }
145   return EX_NOERR;
146 }
147 
ex_update_max_name_length(int exoid,int length)148 void ex_update_max_name_length(int exoid, int length)
149 {
150   int status;
151   int db_length = 0;
152   /* Get current value of the maximum_name_length attribute... */
153   if ((status = nc_get_att_int(exoid, NC_GLOBAL, ATT_MAX_NAME_LENGTH, &db_length)) != NC_NOERR) {
154     char errmsg[MAX_ERR_LENGTH];
155     exerrval = status;
156     sprintf(errmsg,
157 	    "Error: failed to update 'max_name_length' attribute in file id %d",
158 	    exoid);
159 	ex_err("ex_update_max_name_length",errmsg,exerrval);
160   }
161 
162   if (length > db_length) {
163     /* Update with new value... */
164     nc_put_att_int(exoid, NC_GLOBAL, ATT_MAX_NAME_LENGTH, NC_INT, 1, &length);
165   }
166 }
167 
ex_put_names_internal(int exoid,int varid,size_t num_entity,char ** names,ex_entity_type obj_type,const char * subtype,const char * routine)168 int ex_put_names_internal(int exoid, int varid, size_t num_entity, char **names,
169 			  ex_entity_type obj_type, const char *subtype, const char *routine)
170 {
171   size_t i;
172   int status;
173   size_t start[2], count[2];
174   char errmsg[MAX_ERR_LENGTH];
175   int max_name_len = 0;
176   size_t name_length;
177 
178   /* inquire previously defined dimensions  */
179   name_length = ex_inquire_int(exoid, EX_INQ_DB_MAX_ALLOWED_NAME_LENGTH)+1;
180 
181   for (i=0; i<num_entity; i++) {
182     if (names[i] != '\0') {
183       int too_long = 0;
184       start[0] = i;
185       start[1] = 0;
186 
187       count[0] = 1;
188       count[1] = strlen(names[i]) + 1;
189 
190       if (count[1] > name_length) {
191 	fprintf(stderr,
192 		"Warning: The %s %s name '%s' is too long.\n\tIt will be truncated from %d to %d characters\n",
193 		ex_name_of_object(obj_type), subtype, names[i], (int)strlen(names[i]), (int)name_length-1);
194 	count[1] = name_length;
195 	too_long = 1;
196       }
197 
198       if (count[1] > max_name_len)
199 	max_name_len = count[1];
200 
201       if ((status = nc_put_vara_text(exoid, varid, start, count, names[i])) != NC_NOERR) {
202 	exerrval = status;
203 	sprintf(errmsg,
204 		"Error: failed to store %s names in file id %d",
205 		ex_name_of_object(obj_type), exoid);
206 	ex_err(routine,errmsg,exerrval);
207 	return (EX_FATAL);
208       }
209 
210       /* Add the trailing null if the variable name was too long */
211       if (too_long) {
212 	start[1] = name_length-1;
213 	nc_put_var1_text(exoid, varid, start, "\0");
214       }
215     }
216   }
217 
218   /* Update the maximum_name_length attribute on the file. */
219   ex_update_max_name_length(exoid, max_name_len-1);
220 
221   return (EX_NOERR);
222 }
223 
ex_put_name_internal(int exoid,int varid,size_t index,const char * name,ex_entity_type obj_type,const char * subtype,const char * routine)224 int ex_put_name_internal(int exoid, int varid, size_t index, const char *name,
225 			 ex_entity_type obj_type, const char *subtype, const char *routine)
226 {
227   int status;
228   size_t start[2], count[2];
229   char errmsg[MAX_ERR_LENGTH];
230   size_t name_length;
231 
232   /* inquire previously defined dimensions  */
233   name_length = ex_inquire_int(exoid, EX_INQ_DB_MAX_ALLOWED_NAME_LENGTH)+1;
234 
235   if (name != '\0') {
236     int too_long = 0;
237     start[0] = index;
238     start[1] = 0;
239 
240     count[0] = 1;
241     count[1] = strlen(name) + 1;
242 
243     if (count[1] > name_length) {
244       fprintf(stderr,
245 	      "Warning: The %s %s name '%s' is too long.\n\tIt will be truncated from %d to %d characters\n",
246 	      ex_name_of_object(obj_type), subtype, name, (int)strlen(name), (int)name_length-1);
247       count[1] = name_length;
248       too_long = 1;
249     }
250 
251     if ((status = nc_put_vara_text(exoid, varid, start, count, name)) != NC_NOERR) {
252       exerrval = status;
253       sprintf(errmsg,
254 	      "Error: failed to store %s name in file id %d",
255 	      ex_name_of_object(obj_type), exoid);
256       ex_err(routine,errmsg,exerrval);
257       return (EX_FATAL);
258     }
259 
260     /* Add the trailing null if the variable name was too long */
261     if (too_long) {
262       start[1] = name_length-1;
263       nc_put_var1_text(exoid, varid, start, "\0");
264     }
265 
266     /* Update the maximum_name_length attribute on the file. */
267     ex_update_max_name_length(exoid, count[1]-1);
268   }
269 
270   return (EX_NOERR);
271 }
272 
ex_get_names_internal(int exoid,int varid,size_t num_entity,char ** names,ex_entity_type obj_type,const char * routine)273 int ex_get_names_internal(int exoid, int varid, size_t num_entity, char **names,
274 			  ex_entity_type obj_type, const char *routine)
275 {
276   size_t i;
277   int status;
278 
279   /* Query size of names on file
280    * Use the smaller of the size on file or user-specified length
281    */
282   int db_name_size = ex_inquire_int(exoid, EX_INQ_DB_MAX_ALLOWED_NAME_LENGTH);
283   int api_name_size = ex_inquire_int(exoid, EX_INQ_MAX_READ_NAME_LENGTH);
284   int name_size = db_name_size < api_name_size ? db_name_size : api_name_size;
285 
286   for (i=0; i<num_entity; i++) {
287     status = ex_get_name_internal(exoid, varid, i, names[i], name_size, obj_type, routine);
288     if (status != NC_NOERR)
289       return status;
290   }
291   return EX_NOERR;
292 }
293 
ex_get_name_internal(int exoid,int varid,size_t index,char * name,int name_size,ex_entity_type obj_type,const char * routine)294 int ex_get_name_internal(int exoid, int varid, size_t index, char *name, int name_size,
295 			 ex_entity_type obj_type, const char *routine)
296 {
297   size_t start[2], count[2];
298   int status;
299   char errmsg[MAX_ERR_LENGTH];
300   int api_name_size = ex_inquire_int(exoid, EX_INQ_MAX_READ_NAME_LENGTH);
301 
302   /* read the name */
303   start[0] = index;  count[0] = 1;
304   start[1] = 0;      count[1] = name_size+1;
305 
306   status = nc_get_vara_text(exoid, varid, start, count, name);
307   if (status != NC_NOERR) {
308     exerrval = status;
309     sprintf(errmsg, "Error: failed to get %s name at index %d from file id %d",
310 	    ex_name_of_object(obj_type), (int)index, exoid);
311     ex_err(routine,errmsg,exerrval);
312     return (EX_FATAL);
313   }
314 
315   name[api_name_size] = '\0';
316 
317   ex_trim_internal(name);
318   return EX_NOERR;
319 }
320 
ex_trim_internal(char * name)321 void ex_trim_internal(char *name)
322 {
323   /* Trim trailing spaces... */
324   size_t size;
325   char *end;
326 
327   if (name == NULL)
328     return;
329 
330   size = strlen(name);
331   if (size==0)
332     return;
333 
334   end = name + size - 1;
335   while (end >= name && isspace(*end))
336     end--;
337 
338   *(end+1) = '\0';
339 }
340 
341 /** ex_catstr  - concatenate  string/number (where number is converted to ASCII) */
ex_catstr(const char * string,int num)342 char *ex_catstr (const char *string,
343                  int   num)
344 {
345   char* tmp_string = cur_string;
346   cur_string += sprintf (cur_string, "%s%d", string, num) + 1;
347   if ( cur_string - ret_string > 9*(MAX_VAR_NAME_LENGTH+1) )
348     cur_string = ret_string;
349   return (tmp_string);
350 }
351 
352 
353 /** ex_catstr2 - concatenate  string1num1string2num2   */
ex_catstr2(const char * string1,int num1,const char * string2,int num2)354 char *ex_catstr2 (const char *string1,
355                   int   num1,
356                   const char *string2,
357                   int   num2)
358 {
359   char* tmp_string = cur_string;
360   cur_string += sprintf (cur_string, "%s%d%s%d", string1, num1, string2, num2) + 1;
361   if ( cur_string - ret_string > 9*(MAX_VAR_NAME_LENGTH+1) )
362     cur_string = ret_string;
363   return (tmp_string);
364 }
365 
ex_name_of_object(ex_entity_type obj_type)366 char* ex_name_of_object(ex_entity_type obj_type)
367 {
368   switch (obj_type) {
369   case EX_COORDINATE: /* kluge so some wrapper functions work */
370     return "coordinate";
371   case EX_NODAL:
372     return "nodal";
373   case EX_EDGE_BLOCK:
374     return "edge block";
375   case EX_FACE_BLOCK:
376     return "face block";
377   case EX_ELEM_BLOCK:
378     return "element block";
379   case EX_NODE_SET:
380     return "node set";
381   case EX_EDGE_SET:
382     return "edge set";
383   case EX_FACE_SET:
384     return "face set";
385   case EX_SIDE_SET:
386     return "side set";
387   case EX_ELEM_SET:
388     return "element set";
389   case EX_ELEM_MAP:
390     return "element map";
391   case EX_NODE_MAP:
392     return "node map";
393   case EX_EDGE_MAP:
394     return "edge map";
395   case EX_FACE_MAP:
396     return "face map";
397   case EX_GLOBAL:
398     return "global";
399   default:
400     return "invalid type";
401   }
402 }
403 
ex_var_type_to_ex_entity_type(char var_type)404 ex_entity_type ex_var_type_to_ex_entity_type(char var_type)
405 {
406   char var_lower = tolower(var_type);
407   if (var_lower == 'n')
408     return EX_NODAL;
409   else if (var_lower == 'l')
410     return EX_EDGE_BLOCK;
411   else if (var_lower == 'f')
412     return EX_FACE_BLOCK;
413   else if (var_lower == 'e')
414     return EX_ELEM_BLOCK;
415   else if (var_lower == 'm')
416     return EX_NODE_SET;
417   else if (var_lower == 'd')
418     return EX_EDGE_SET;
419   else if (var_lower == 'a')
420     return EX_FACE_SET;
421   else if (var_lower == 's')
422     return EX_SIDE_SET;
423   else if (var_lower == 't')
424     return EX_ELEM_SET;
425   else if (var_lower == 'g')
426     return EX_GLOBAL;
427   else
428     return EX_INVALID;
429 }
430 
ex_dim_num_objects(ex_entity_type obj_type)431 char* ex_dim_num_objects(ex_entity_type obj_type)
432 {
433    exerrval = 0; /* clear error code */
434    switch (obj_type)
435    {
436      case EX_NODAL:
437        return DIM_NUM_NODES;
438      case EX_ELEM_BLOCK:
439        return DIM_NUM_EL_BLK;
440      case EX_EDGE_BLOCK:
441        return DIM_NUM_ED_BLK;
442      case EX_FACE_BLOCK:
443        return DIM_NUM_FA_BLK;
444      case EX_NODE_SET:
445        return DIM_NUM_NS;
446      case EX_EDGE_SET:
447        return DIM_NUM_ES;
448      case EX_FACE_SET:
449        return DIM_NUM_FS;
450      case EX_ELEM_SET:
451        return DIM_NUM_ELS;
452      case EX_SIDE_SET:
453        return DIM_NUM_SS;
454      case EX_ELEM_MAP:
455        return DIM_NUM_EM;
456      case EX_FACE_MAP:
457        return DIM_NUM_FAM;
458      case EX_EDGE_MAP:
459        return DIM_NUM_EDM;
460      case EX_NODE_MAP:
461        return DIM_NUM_NM;
462      default:
463        {
464 	 char errmsg[MAX_ERR_LENGTH];
465 	 exerrval = EX_BADPARAM;
466 	 sprintf(errmsg, "Error: object type %d not supported in call to ex_dim_num_objects",
467 		 obj_type);
468 	 ex_err("ex_dim_num_objects",errmsg,exerrval);
469 	 return (NULL);
470        }
471    }
472 }
473 
ex_dim_num_entries_in_object(ex_entity_type obj_type,int idx)474 char* ex_dim_num_entries_in_object( ex_entity_type obj_type,
475                                     int idx )
476 {
477   switch (obj_type) {
478   case EX_NODAL:
479     return DIM_NUM_NODES;
480   case EX_EDGE_BLOCK:
481     return DIM_NUM_ED_IN_EBLK(idx);
482   case EX_FACE_BLOCK:
483     return DIM_NUM_FA_IN_FBLK(idx);
484   case EX_ELEM_BLOCK:
485     return DIM_NUM_EL_IN_BLK(idx);
486   case EX_NODE_SET:
487     return DIM_NUM_NOD_NS(idx);
488   case EX_EDGE_SET:
489     return DIM_NUM_EDGE_ES(idx);
490   case EX_FACE_SET:
491     return DIM_NUM_FACE_FS(idx);
492   case EX_SIDE_SET:
493     return DIM_NUM_SIDE_SS(idx);
494   case EX_ELEM_SET:
495     return DIM_NUM_ELE_ELS(idx);
496   default:
497     return 0;
498   }
499 }
500 
ex_name_var_of_object(ex_entity_type obj_type,int i,int j)501 char* ex_name_var_of_object(ex_entity_type obj_type,
502 			    int i, int j)
503 {
504   switch (obj_type) {
505   case EX_EDGE_BLOCK:
506     return VAR_EDGE_VAR(i,j);
507   case EX_FACE_BLOCK:
508     return VAR_FACE_VAR(i,j);
509   case EX_ELEM_BLOCK:
510     return VAR_ELEM_VAR(i,j);
511   case EX_NODE_SET:
512     return VAR_NS_VAR(i,j);
513   case EX_EDGE_SET:
514     return VAR_ES_VAR(i,j);
515   case EX_FACE_SET:
516     return VAR_FS_VAR(i,j);
517   case EX_SIDE_SET:
518     return VAR_SS_VAR(i,j);
519   case EX_ELEM_SET:
520     return VAR_ELS_VAR(i,j);
521   default:
522     return 0;
523   }
524 }
525 
ex_name_of_map(ex_entity_type map_type,int map_index)526 char* ex_name_of_map(ex_entity_type map_type, int map_index)
527 {
528   switch (map_type) {
529   case EX_NODE_MAP:
530     return VAR_NODE_MAP(map_index);
531   case EX_EDGE_MAP:
532     return VAR_EDGE_MAP(map_index);
533   case EX_FACE_MAP:
534     return VAR_FACE_MAP(map_index);
535   case EX_ELEM_MAP:
536     return VAR_ELEM_MAP(map_index);
537   default:
538     return 0;
539   }
540 }
541 
542 /*****************************************************************************
543 *
544 * ex_id_lkup - look up id
545 *
546 * entry conditions -
547 *   input parameters:
548 *       int            exoid             exodus file id
549 *       ex_entity_type id_type           id type name:
550 *                                         elem_ss
551 *                                         node_ns
552 *                                         side_ss
553 *       int     num                     id value
554 *
555 * exit conditions -
556 *       int     return                  index into table (1-based)
557 *
558 *****************************************************************************/
559 
ex_id_lkup(int exoid,ex_entity_type id_type,ex_entity_id num)560 int ex_id_lkup( int exoid,
561                 ex_entity_type id_type,
562                 ex_entity_id   num)
563 {
564 
565   char id_table[MAX_VAR_NAME_LENGTH+1];
566   char id_dim[MAX_VAR_NAME_LENGTH+1];
567   char stat_table[MAX_VAR_NAME_LENGTH+1];
568   int varid, dimid;
569   size_t dim_len, i;
570   int64_t *id_vals=NULL;
571   int *stat_vals=NULL;
572 
573   static int filled=FALSE;
574   struct obj_stats *tmp_stats;
575   int status;
576   char errmsg[MAX_ERR_LENGTH];
577 
578   exerrval  = 0; /* clear error code */
579 
580   switch(id_type) {
581   case EX_NODAL:
582     return 0;
583   case EX_GLOBAL:
584     return 0;
585   case EX_ELEM_BLOCK:
586     strcpy(id_table, VAR_ID_EL_BLK);            /* id array name */
587     strcpy(id_dim, DIM_NUM_EL_BLK);             /* id array dimension name*/
588     strcpy(stat_table, VAR_STAT_EL_BLK);        /* id status array name */
589     tmp_stats = ex_get_stat_ptr (exoid, &exoII_eb);
590     break;
591   case EX_NODE_SET:
592     strcpy(id_table, VAR_NS_IDS);
593     strcpy(id_dim, DIM_NUM_NS);
594     strcpy(stat_table, VAR_NS_STAT);
595     tmp_stats = ex_get_stat_ptr (exoid, &exoII_ns);
596     break;
597   case EX_SIDE_SET:
598     strcpy(id_table, VAR_SS_IDS);
599     strcpy(id_dim, DIM_NUM_SS);
600     strcpy(stat_table, VAR_SS_STAT);
601     tmp_stats = ex_get_stat_ptr (exoid, &exoII_ss);
602     break;
603   case EX_ELEM_MAP:
604     strcpy(id_table, VAR_EM_PROP(1));
605     strcpy(id_dim, DIM_NUM_EM);
606     strcpy(stat_table, "");
607     tmp_stats = ex_get_stat_ptr (exoid, &exoII_em);
608     break;
609   case EX_NODE_MAP:
610     strcpy(id_table, VAR_NM_PROP(1));
611     strcpy(id_dim, DIM_NUM_NM);
612     strcpy(stat_table, "");
613     tmp_stats = ex_get_stat_ptr (exoid, &exoII_nm);
614     break;
615   case EX_EDGE_BLOCK:
616     strcpy(id_table, VAR_ID_ED_BLK);
617     strcpy(id_dim, DIM_NUM_ED_BLK);
618     strcpy(stat_table, VAR_STAT_ED_BLK);
619     tmp_stats = ex_get_stat_ptr (exoid, &exoII_ed);
620     break;
621   case EX_FACE_BLOCK:
622     strcpy(id_table, VAR_ID_FA_BLK);
623     strcpy(id_dim, DIM_NUM_FA_BLK);
624     strcpy(stat_table, VAR_STAT_FA_BLK);
625     tmp_stats = ex_get_stat_ptr (exoid, &exoII_fa);
626     break;
627   case EX_EDGE_SET:
628     strcpy(id_table, VAR_ES_IDS);
629     strcpy(id_dim, DIM_NUM_ES);
630     strcpy(stat_table, VAR_ES_STAT);
631     tmp_stats = ex_get_stat_ptr (exoid, &exoII_es);
632     break;
633   case EX_FACE_SET:
634     strcpy(id_table, VAR_FS_IDS);
635     strcpy(id_dim, DIM_NUM_FS);
636     strcpy(stat_table, VAR_FS_STAT);
637     tmp_stats = ex_get_stat_ptr (exoid, &exoII_fs);
638     break;
639   case EX_ELEM_SET:
640     strcpy(id_table, VAR_ELS_IDS);
641     strcpy(id_dim, DIM_NUM_ELS);
642     strcpy(stat_table, VAR_ELS_STAT);
643     tmp_stats = ex_get_stat_ptr (exoid, &exoII_els);
644     break;
645   case EX_EDGE_MAP:
646     strcpy(id_table, VAR_EDM_PROP(1));
647     strcpy(id_dim, DIM_NUM_EDM);
648     strcpy(stat_table, "");
649     tmp_stats = ex_get_stat_ptr (exoid, &exoII_edm);
650     break;
651   case EX_FACE_MAP:
652     strcpy(id_table, VAR_FAM_PROP(1));
653     strcpy(id_dim, DIM_NUM_FAM);
654     strcpy(stat_table, "");
655     tmp_stats = ex_get_stat_ptr (exoid, &exoII_fam);
656     break;
657   default:
658     exerrval = EX_BADPARAM;
659     sprintf(errmsg,
660            "Error: unsupported id array type %d for file id %d",
661             id_type, exoid);
662     ex_err("ex_id_lkup",errmsg,exerrval);
663     return (EX_FATAL);
664   }
665 
666   if ( (tmp_stats->id_vals == NULL) || (!(tmp_stats->valid_ids)) ) {
667 
668     /* first time thru or id arrays haven't been completely filled yet */
669 
670     /* get size of id array */
671 
672     /* First get dimension id of id array */
673     if ((status = nc_inq_dimid(exoid,id_dim,&dimid)) != NC_NOERR) {
674       exerrval = status;
675       sprintf(errmsg,
676            "Error: failed to locate id array dimension in file id %d",
677             exoid);
678       ex_err("ex_id_lkup",errmsg,exerrval);
679       return (EX_FATAL);
680     }
681 
682 
683     /* Next get value of dimension */
684     if ((status = nc_inq_dimlen(exoid,dimid,&dim_len)) != NC_NOERR) {
685       exerrval = status;
686       sprintf(errmsg,
687            "Error: failed to locate %s array length in file id %d",
688             id_table,exoid);
689       ex_err("ex_id_lkup",errmsg,exerrval);
690       return (EX_FATAL);
691     }
692 
693     /* get variable id of id array */
694     if ((status = nc_inq_varid (exoid, id_table, &varid)) != NC_NOERR) {
695       exerrval = status;
696       sprintf(errmsg,
697              "Error: failed to locate %s array in file id %d",
698               id_table, exoid);
699       ex_err("ex_id_lkup",errmsg,exerrval);
700       return (EX_FATAL);
701     }
702 
703     /* allocate space for id array and initialize to zero to ensure
704      that the higher bits don't contain garbage while copy from ints */
705     if (!(id_vals = calloc(dim_len,sizeof(int64_t)))) {
706       exerrval = EX_MEMFAIL;
707       sprintf(errmsg,
708              "Error: failed to allocate memory for %s array for file id %d",
709               id_table,exoid);
710       ex_err("ex_id_lkup",errmsg,exerrval);
711       return (EX_FATAL);
712     }
713 
714     if (ex_int64_status(exoid) & EX_IDS_INT64_API) {
715       status = nc_get_var_longlong (exoid, varid, (long long*)id_vals);
716     }
717     else {
718       int *id_vals_int;
719       if (!(id_vals_int = malloc(dim_len*sizeof(int)))) {
720         exerrval = EX_MEMFAIL;
721         sprintf(errmsg,
722                 "Error: failed to allocate memory for temporary array id_vals_int for file id %d",
723                 exoid);
724         ex_err("ex_id_lkup",errmsg,exerrval);
725         return (EX_FATAL);
726       }
727       status = nc_get_var_int(exoid, varid, (int *)id_vals_int);
728       if (status == NC_NOERR) {
729 	for (i=0;i<dim_len;i++)
730 	  id_vals[i] = (int64_t) id_vals_int[i];
731       }
732       free(id_vals_int);
733     }
734 
735     if (status != NC_NOERR) {
736       exerrval = status;
737       sprintf(errmsg,
738              "Error: failed to get %s array from file id %d",
739               id_table,exoid);
740       ex_err("ex_id_lkup",errmsg,exerrval);
741       free(id_vals);
742       return (EX_FATAL);
743     }
744 
745     /* check if values in stored arrays are filled with non-zeroes */
746     filled = TRUE;
747     for (i=0;i<dim_len;i++) {
748       if (id_vals[i] == EX_INVALID_ID || id_vals[i] == NC_FILL_INT) {
749         filled = FALSE;
750         break; /* id array hasn't been completely filled with valid ids yet */
751       }
752     }
753 
754     if (filled) {
755       tmp_stats->valid_ids = TRUE;
756       tmp_stats->num = dim_len;
757       tmp_stats->id_vals = id_vals;
758     }
759 
760   } else {
761     id_vals = tmp_stats->id_vals;
762     dim_len = tmp_stats->num;
763   }
764 
765   /* Do a linear search through the id array to find the array value
766      corresponding to the passed index number */
767 
768   for (i=0;i<dim_len;i++) {
769     if (id_vals[i] == num)
770       break; /* found the id requested */
771   }
772   if (i >= dim_len) /* failed to find id number */
773   {
774     if ( !(tmp_stats->valid_ids) ) {
775        free (id_vals);
776     }
777     exerrval = EX_LOOKUPFAIL;
778     return(EX_LOOKUPFAIL); /*if we got here, the id array value doesn't exist */
779   }
780 
781   /* Now check status array to see if object is null */
782 
783   /* get variable id of status array */
784   if (nc_inq_varid (exoid, stat_table, &varid) == NC_NOERR) {
785     /* if status array exists, use it, otherwise assume object exists
786        to be backward compatible */
787 
788     if ( (tmp_stats->stat_vals == NULL) || (!(tmp_stats->valid_stat)) ) {
789       /* first time thru or status arrays haven't been filled yet */
790 
791       /* allocate space for new status array */
792 
793       if (!(stat_vals = malloc((int)dim_len*sizeof(int)))) {
794         exerrval = EX_MEMFAIL;
795         sprintf(errmsg,
796                  "Error: failed to allocate memory for %s array for file id %d",
797                   id_table,exoid);
798         ex_err("ex_id_lkup",errmsg,exerrval);
799         return (EX_FATAL);
800       }
801 
802       if ((status = nc_get_var_int (exoid, varid, stat_vals)) != NC_NOERR) {
803         exerrval = status;
804         free(stat_vals);
805         sprintf(errmsg,
806                "Error: failed to get %s array from file id %d",
807                 stat_table,exoid);
808         ex_err("ex_id_lkup",errmsg,exerrval);
809         return (EX_FATAL);
810       }
811 
812       if (tmp_stats->valid_ids) {
813         /* status array is valid only if ids are valid */
814         tmp_stats->valid_stat = TRUE;
815         tmp_stats->stat_vals = stat_vals;
816       }
817 
818     } else {
819       stat_vals = tmp_stats->stat_vals;
820     }
821 
822     if (stat_vals[i] == 0) /* is this object null? */ {
823       exerrval =  EX_NULLENTITY;
824       if ( !(tmp_stats->valid_stat) ) {
825         free (stat_vals);
826       }
827       if ( !(tmp_stats->valid_ids) ) {
828         if (id_vals) free (id_vals);
829       }
830       return(-((int)i+1)); /* return index into id array (1-based) */
831     }
832   }
833   if ( !(tmp_stats->valid_ids) ) {
834     if (id_vals) free (id_vals);
835     if (stat_vals) free (stat_vals);
836   }
837   return(i+1); /* return index into id array (1-based) */
838 }
839 
840 /******************************************************************************
841 *
842 * ex_get_stat_ptr - returns a pointer to a structure of object ids
843 *
844 *****************************************************************************/
845 
846 /*! this routine returns a pointer to a structure containing the ids of
847  * element blocks, node sets, or side sets according to exoid;  if there
848  * is not a structure that matches the exoid, one is created
849  */
850 
ex_get_stat_ptr(int exoid,struct obj_stats ** obj_ptr)851 struct obj_stats *ex_get_stat_ptr (int exoid, struct obj_stats **obj_ptr)
852 
853 {
854   struct obj_stats *tmp_ptr;
855 
856   tmp_ptr = *obj_ptr;
857 
858   while (tmp_ptr) {
859     if ( (tmp_ptr)->exoid == exoid) {
860       break;
861     }
862     tmp_ptr = (tmp_ptr)->next;
863   }
864 
865   if (!tmp_ptr) {    /* exoid not found */
866     tmp_ptr = (struct obj_stats *) calloc (1, sizeof(struct obj_stats));
867     tmp_ptr->exoid = exoid;
868     tmp_ptr->next = *obj_ptr;
869     tmp_ptr->id_vals = 0;
870     tmp_ptr->stat_vals = 0;
871     tmp_ptr->num = 0;
872     tmp_ptr->valid_ids = 0;
873     tmp_ptr->valid_stat = 0;
874     *obj_ptr = tmp_ptr;
875   }
876 
877   return (tmp_ptr);
878 }
879 
880 /******************************************************************************
881 *
882 * ex_rm_stat_ptr - removes a pointer to a structure of object ids
883 *
884 *****************************************************************************/
885 
886 /*! this routine removes a pointer to a structure containing the ids of
887  * element blocks, node sets, or side sets according to exoid;  this
888  * is necessary to clean up because netCDF reuses file ids;  should be
889  * called from ex_close
890  */
891 
ex_rm_stat_ptr(int exoid,struct obj_stats ** obj_ptr)892 void ex_rm_stat_ptr (int exoid, struct obj_stats **obj_ptr)
893 
894 {
895   struct obj_stats *last_head_list_ptr, *tmp_ptr;
896 
897   tmp_ptr = *obj_ptr;
898   last_head_list_ptr = *obj_ptr;        /* save last head pointer */
899 
900   while (tmp_ptr )                      /* Walk linked list of file ids/vals */
901   {
902     if (exoid == tmp_ptr->exoid )       /* linear search for exodus file id */
903     {
904       if (tmp_ptr == *obj_ptr)          /* Are we at the head of the list? */
905         *obj_ptr = (*obj_ptr)->next;    /*   yes, reset ptr to head of list */
906       else                              /*   no, remove this record from chain*/
907         last_head_list_ptr->next=tmp_ptr->next;
908       if (tmp_ptr->id_vals != NULL)
909         free(tmp_ptr->id_vals);           /* free up memory */
910       if (tmp_ptr->stat_vals != NULL)
911         free(tmp_ptr->stat_vals);
912       free(tmp_ptr);
913       break;                            /* Quit if found */
914     }
915     last_head_list_ptr = tmp_ptr;       /* save last head pointer */
916     tmp_ptr = tmp_ptr->next;            /* Loop back if not */
917   }
918 }
919 
920 /* structures to hold number of blocks of that type for each file id */
921 static struct list_item*  ed_ctr_list = 0; /* edge blocks */
922 static struct list_item*  fa_ctr_list = 0; /* face blocks */
923 static struct list_item*  eb_ctr_list = 0; /* element blocks */
924 /* structures to hold number of sets of that type for each file id */
925 static struct list_item*  ns_ctr_list = 0; /* node sets */
926 static struct list_item*  es_ctr_list = 0; /* edge sets */
927 static struct list_item*  fs_ctr_list = 0; /* face sets */
928 static struct list_item*  ss_ctr_list = 0; /* side sets */
929 static struct list_item* els_ctr_list = 0; /* element sets */
930 /* structures to hold number of maps of that type for each file id */
931 static struct list_item*  nm_ctr_list = 0; /* node maps */
932 static struct list_item* edm_ctr_list = 0; /* edge maps */
933 static struct list_item* fam_ctr_list = 0; /* face maps */
934 static struct list_item*  em_ctr_list = 0; /* element maps */
935 
ex_get_counter_list(ex_entity_type obj_type)936 struct list_item** ex_get_counter_list(ex_entity_type obj_type)
937 {
938   switch(obj_type) {
939   case EX_ELEM_BLOCK:
940     return &eb_ctr_list;
941   case EX_NODE_SET:
942     return &ns_ctr_list;
943   case EX_SIDE_SET:
944     return &ss_ctr_list;
945   case EX_ELEM_MAP:
946     return &em_ctr_list;
947   case EX_NODE_MAP:
948     return &nm_ctr_list;
949   case EX_EDGE_BLOCK:
950     return &ed_ctr_list;
951   case EX_FACE_BLOCK:
952     return &fa_ctr_list;
953   case EX_EDGE_SET:
954     return &es_ctr_list;
955   case EX_FACE_SET:
956     return &fs_ctr_list;
957   case EX_ELEM_SET:
958     return &els_ctr_list;
959   case EX_EDGE_MAP:
960     return &edm_ctr_list;
961   case EX_FACE_MAP:
962     return &fam_ctr_list;
963   default:
964     return (NULL);
965   }
966 }
967 
968 /******************************************************************************
969 *
970 * ex_inc_file_item - increment file item
971 *
972 *****************************************************************************/
973 
974 
975 /*! this routine sets up a structure to track and increment a counter for
976  * each open exodus file.  it is designed to be used by the routines
977  * ex_put_elem_block() and ex_put_set_param(),
978  * to keep track of the number of element blocks, and each type of set,
979  * respectively, for each open exodus II file.
980  *
981  * The list structure is used as follows:
982  *
983  *   ptr -----------> list item structure
984  *                    -------------------
985  *                    exodus file id
986  *                    item value (int)
987  *                    ptr to next (NULL if last)
988  *
989  *
990  * NOTE: since netCDF reuses its file ids, and a user may open and close any
991  *       number of files in one application, items must be taken out of the
992  *       linked lists in each of the above routines.  these should be called
993  *       after ncclose().
994  */
995 
ex_inc_file_item(int exoid,struct list_item ** list_ptr)996 int ex_inc_file_item( int exoid,                /* file id */
997                       struct list_item **list_ptr)/* ptr to ptr to list_item */
998 
999 {
1000   struct list_item* tlist_ptr;
1001 
1002 
1003   /* printf("[f] list: %ld, *list: %ld \n", list_ptr, *list_ptr); */
1004   tlist_ptr = *list_ptr;        /* use temp list ptr to walk linked list */
1005 
1006   while (tlist_ptr )                    /* Walk linked list of file ids/vals */
1007   {
1008     if (exoid == tlist_ptr->exo_id )    /* linear search for exodus file id */
1009       break;                            /* Quit if found */
1010     tlist_ptr = tlist_ptr->next;        /* Loop back if not */
1011   }
1012 
1013   if (!tlist_ptr )                      /* ptr NULL? */
1014   {                                     /*  yes, new file id */
1015     /* allocate space for new structure record */
1016     tlist_ptr = (struct list_item*) calloc(1,sizeof(struct list_item));
1017     tlist_ptr->exo_id = exoid;          /* insert file id */
1018     tlist_ptr->next = *list_ptr;        /* insert into head of list */
1019     *list_ptr = tlist_ptr;              /* fix up new head of list  */
1020   }
1021 
1022 /*  printf("[f] tlist: %ld *tlist: %ld **tlist: %ld\n",
1023           tlist_ptr,*tlist_ptr,(*tlist_ptr)->value, (*tlist_ptr)->next); */
1024 
1025 
1026   return(tlist_ptr->value++);
1027 
1028 }
1029 
1030 /*****************************************************************************
1031 *
1032 * ex_get_file_item - increment file item
1033 *
1034 *****************************************************************************/
1035 
1036 
1037 /*! this routine accesses a structure to track and increment a counter for
1038  * each open exodus file.  it is designed to be used by the routines
1039  * ex_put_elem_block(), and ex_put_set_param(),
1040  * to get the number of element blocks, or a type of set,
1041  * respectively, for an open exodus II file.
1042  *
1043  * The list structure is used as follows:
1044  *
1045  *   ptr -----------> list item structure
1046  *                    -------------------
1047  *                    exodus file id
1048  *                    item value (int)
1049  *                    ptr to next (NULL if last)
1050  *
1051  *
1052  * NOTE: since netCDF reuses its file ids, and a user may open and close any
1053  *       number of files in one application, items must be taken out of the
1054  *       linked lists in each of the above routines.  these should be called
1055  *       after ncclose().
1056  */
1057 
ex_get_file_item(int exoid,struct list_item ** list_ptr)1058 int ex_get_file_item( int exoid,                /* file id */
1059                       struct list_item **list_ptr)/* ptr to ptr to list_item */
1060 
1061 {
1062   struct list_item* tlist_ptr;
1063 
1064   /* printf("[f] list: %ld, *list: %ld \n", list_ptr, *list_ptr); */
1065   tlist_ptr = *list_ptr;        /* use temp list ptr to walk linked list */
1066 
1067 
1068   while (tlist_ptr )                    /* Walk linked list of file ids/vals */
1069   {
1070     if (exoid == tlist_ptr->exo_id )    /* linear search for exodus file id */
1071       break;                            /* Quit if found */
1072     tlist_ptr = tlist_ptr->next;        /* Loop back if not */
1073   }
1074 
1075   if (!tlist_ptr )                      /* ptr NULL? */
1076   {                                     /*  yes, Error: file id not found*/
1077     return(-1);
1078   }
1079 
1080 /*  printf("[f] list: %ld *list: %ld **list: %ld\n",
1081           list_ptr,*list_ptr,(*list_ptr)->value, (*list_ptr)->next); */
1082 
1083   return(tlist_ptr->value);
1084 }
1085 
1086 /*****************************************************************************
1087 *
1088 * ex_rm_file_item - remove file item
1089 *
1090 *****************************************************************************/
1091 
1092 
1093 /*! this routine removes a structure to track and increment a counter for
1094  * each open exodus file.
1095  *
1096  * The list structure is used as follows:
1097  *
1098  *   ptr -----------> list item structure
1099  *                    -------------------
1100  *                    exodus file id
1101  *                    item value (int)
1102  *                    ptr to next (NULL if last)
1103  *
1104  *
1105  * NOTE: since netCDF reuses its file ids, and a user may open and close any
1106  *       number of files in one application, items must be taken out of the
1107  *       linked lists in each of the above routines.  these should be called
1108  *       after ncclose().
1109  */
1110 
ex_rm_file_item(int exoid,struct list_item ** list_ptr)1111 void ex_rm_file_item( int exoid,                /* file id */
1112                       struct list_item **list_ptr)/* ptr to ptr to list_item */
1113 
1114 {
1115   struct list_item *last_head_list_ptr, *tlist_ptr;
1116 
1117   /* printf("[f] list: %ld, *list: %ld \n", list_ptr, *list_ptr); */
1118   tlist_ptr = *list_ptr;
1119   last_head_list_ptr = *list_ptr; /* save last head pointer */
1120   /* printf("[f] last head list: %ld\n",last_head_list_ptr); */
1121 
1122   while (tlist_ptr )                    /* Walk linked list of file ids/vals */
1123   {
1124     if (exoid == tlist_ptr->exo_id )    /* linear search for exodus file id */
1125     {
1126       if (tlist_ptr == *list_ptr)       /* Are we at the head of the list? */
1127         *list_ptr = (*list_ptr)->next;  /*   yes, reset ptr to head of list */
1128       else                              /*   no, remove this record from chain*/
1129         last_head_list_ptr->next=tlist_ptr->next;
1130       free(tlist_ptr);                  /* free up memory */
1131       break;                            /* Quit if found */
1132     }
1133     last_head_list_ptr = tlist_ptr;     /* save last head pointer */
1134     tlist_ptr = tlist_ptr->next;        /* Loop back if not */
1135   }
1136 
1137 /*  printf("[f] list: %ld *list: %ld **list: %ld\n",
1138           list_ptr,*list_ptr,(*list_ptr)->value, (*list_ptr)->next); */
1139 
1140 }
1141 
1142 /*****************************************************************************
1143 *
1144 * ex_get_num_props - get number of properties
1145 *
1146 *****************************************************************************/
ex_get_num_props(int exoid,ex_entity_type obj_type)1147 int ex_get_num_props (int exoid, ex_entity_type obj_type)
1148 {
1149   int cntr, varid;
1150   char var_name[MAX_VAR_NAME_LENGTH+1];
1151   char  errmsg[MAX_ERR_LENGTH];
1152 
1153   cntr = 0;
1154 
1155   /* loop until there is not a property variable defined; the name of */
1156   /* the variables begin with an increment of 1 ("xx_prop1") so use cntr+1 */
1157 
1158   while (TRUE)
1159     {
1160       switch (obj_type)
1161 	{
1162 	case EX_ELEM_BLOCK:
1163 	  strcpy (var_name, VAR_EB_PROP(cntr+1));
1164 	  break;
1165 	case EX_EDGE_BLOCK:
1166 	  strcpy (var_name, VAR_ED_PROP(cntr+1));
1167 	  break;
1168 	case EX_FACE_BLOCK:
1169 	  strcpy (var_name, VAR_FA_PROP(cntr+1));
1170 	  break;
1171 	case EX_NODE_SET:
1172 	  strcpy (var_name, VAR_NS_PROP(cntr+1));
1173 	  break;
1174 	case EX_EDGE_SET:
1175 	  strcpy (var_name, VAR_ES_PROP(cntr+1));
1176 	  break;
1177 	case EX_FACE_SET:
1178 	  strcpy (var_name, VAR_FS_PROP(cntr+1));
1179 	  break;
1180 	case EX_SIDE_SET:
1181 	  strcpy (var_name, VAR_SS_PROP(cntr+1));
1182 	  break;
1183 	case EX_ELEM_SET:
1184 	  strcpy (var_name, VAR_ELS_PROP(cntr+1));
1185 	  break;
1186 	case EX_ELEM_MAP:
1187 	  strcpy (var_name, VAR_EM_PROP(cntr+1));
1188 	  break;
1189 	case EX_FACE_MAP:
1190 	  strcpy (var_name, VAR_FAM_PROP(cntr+1));
1191 	  break;
1192 	case EX_EDGE_MAP:
1193 	  strcpy (var_name, VAR_EDM_PROP(cntr+1));
1194 	  break;
1195 	case EX_NODE_MAP:
1196 	  strcpy (var_name, VAR_NM_PROP(cntr+1));
1197 	  break;
1198 	default:
1199 	  exerrval = EX_BADPARAM;
1200 	  sprintf(errmsg, "Error: object type %d not supported; file id %d",
1201 		  obj_type, exoid);
1202 	  ex_err("ex_get_prop_names",errmsg,exerrval);
1203 	  return(EX_FATAL);
1204 	}
1205 
1206       if (nc_inq_varid (exoid, var_name, &varid) != NC_NOERR) {
1207 	/*   no variable with this name; return cntr which is now the number of */
1208 	/*   properties for this type of entity */
1209 	return (cntr);
1210       }
1211       cntr++;
1212     }
1213 }
1214 
ex_get_cpu_ws(void)1215 int ex_get_cpu_ws(void)
1216 {
1217   return(sizeof(float));
1218 }
1219 
1220 
1221 /* swap - interchange v[i] and v[j] */
ex_swap(int v[],int i,int j)1222 static void ex_swap (int v[], int i, int j)
1223 {
1224   int temp;
1225 
1226   temp = v[i];
1227   v[i] = v[j];
1228   v[j] = temp;
1229 }
1230 
ex_swap64(int64_t v[],int64_t i,int64_t j)1231 static void ex_swap64 (int64_t v[], int64_t i, int64_t j)
1232 {
1233   int64_t temp;
1234 
1235   temp = v[i];
1236   v[i] = v[j];
1237   v[j] = temp;
1238 }
1239 
1240 /*!
1241  * The following 'indexed qsort' routine is modified from Sedgewicks
1242  * algorithm It selects the pivot based on the median of the left,
1243  * right, and center values to try to avoid degenerate cases ocurring
1244  * when a single value is chosen.  It performs a quicksort on
1245  * intervals down to the EX_QSORT_CUTOFF size and then performs a final
1246  * insertion sort on the almost sorted final array.  Based on data in
1247  * Sedgewick, the EX_QSORT_CUTOFF value should be between 5 and 20.
1248  *
1249  * See Sedgewick for further details
1250  * Define DEBUG_QSORT at the top of this file and recompile to compile
1251  * in code that verifies that the array is sorted.
1252  */
1253 
1254 #define EX_QSORT_CUTOFF 12
1255 
ex_int_median3(int v[],int iv[],int left,int right)1256 static int ex_int_median3(int v[], int iv[], int left, int right)
1257 {
1258   ssize_t center;
1259   center = ((ssize_t)left + (ssize_t)right) / 2;
1260 
1261   if (v[iv[left]] > v[iv[center]])
1262     ex_swap(iv, left, center);
1263   if (v[iv[left]] > v[iv[right]])
1264     ex_swap(iv, left, right);
1265   if (v[iv[center]] > v[iv[right]])
1266     ex_swap(iv, center, right);
1267 
1268   ex_swap(iv, center, right-1);
1269   return iv[right-1];
1270 }
1271 
ex_int_median3_64(int64_t v[],int64_t iv[],int64_t left,int64_t right)1272 static int64_t ex_int_median3_64(int64_t v[], int64_t iv[], int64_t left, int64_t right)
1273 {
1274   int64_t center;
1275   center = (left + right) / 2;
1276 
1277   if (v[iv[left]] > v[iv[center]])
1278     ex_swap64(iv, left, center);
1279   if (v[iv[left]] > v[iv[right]])
1280     ex_swap64(iv, left, right);
1281   if (v[iv[center]] > v[iv[right]])
1282     ex_swap64(iv, center, right);
1283 
1284   ex_swap64(iv, center, right-1);
1285   return iv[right-1];
1286 }
1287 
ex_int_iqsort(int v[],int iv[],int left,int right)1288 static void ex_int_iqsort(int v[], int iv[], int left, int right)
1289 {
1290   int pivot;
1291   int i, j;
1292 
1293   if (left + EX_QSORT_CUTOFF <= right) {
1294     pivot = ex_int_median3(v, iv, left, right);
1295     i = left;
1296     j = right - 1;
1297 
1298     for ( ; ; ) {
1299       while (v[iv[++i]] < v[pivot]);
1300       while (v[iv[--j]] > v[pivot]);
1301       if (i < j) {
1302         ex_swap(iv, i, j);
1303       } else {
1304         break;
1305       }
1306     }
1307 
1308     ex_swap(iv, i, right-1);
1309     ex_int_iqsort(v, iv, left, i-1);
1310     ex_int_iqsort(v, iv, i+1, right);
1311   }
1312 }
1313 
ex_int_iqsort64(int64_t v[],int64_t iv[],int64_t left,int64_t right)1314 static void ex_int_iqsort64(int64_t v[], int64_t iv[], int64_t left, int64_t right)
1315 {
1316   int64_t pivot;
1317   int64_t i, j;
1318 
1319   if (left + EX_QSORT_CUTOFF <= right) {
1320     pivot = ex_int_median3_64(v, iv, left, right);
1321     i = left;
1322     j = right - 1;
1323 
1324     for ( ; ; ) {
1325       while (v[iv[++i]] < v[pivot]);
1326       while (v[iv[--j]] > v[pivot]);
1327       if (i < j) {
1328         ex_swap64(iv, i, j);
1329       } else {
1330         break;
1331       }
1332     }
1333 
1334     ex_swap64(iv, i, right-1);
1335     ex_int_iqsort64(v, iv, left, i-1);
1336     ex_int_iqsort64(v, iv, i+1, right);
1337   }
1338 }
1339 
ex_int_iisort(int v[],int iv[],int N)1340 static void ex_int_iisort(int v[], int iv[], int N)
1341 {
1342   int i,j;
1343   int ndx = 0;
1344   int small;
1345   int tmp;
1346 
1347   small = v[iv[0]];
1348   for (i = 1; i < N; i++) {
1349     if (v[iv[i]] < small) {
1350       small = v[iv[i]];
1351       ndx = i;
1352     }
1353   }
1354   /* Put smallest value in slot 0 */
1355   ex_swap(iv, 0, ndx);
1356 
1357   for (i=1; i <N; i++) {
1358     tmp = iv[i];
1359     for (j=i; v[tmp] < v[iv[j-1]]; j--) {
1360       iv[j] = iv[j-1];
1361     }
1362     iv[j] = tmp;
1363   }
1364 }
1365 
ex_int_iisort64(int64_t v[],int64_t iv[],int64_t N)1366 static void ex_int_iisort64(int64_t v[], int64_t iv[], int64_t N)
1367 {
1368   int64_t i,j;
1369   int64_t ndx = 0;
1370   int64_t small;
1371   int64_t tmp;
1372 
1373   small = v[iv[0]];
1374   for (i = 1; i < N; i++) {
1375     if (v[iv[i]] < small) {
1376       small = v[iv[i]];
1377       ndx = i;
1378     }
1379   }
1380   /* Put smallest value in slot 0 */
1381   ex_swap64(iv, 0, ndx);
1382 
1383   for (i=1; i <N; i++) {
1384     tmp = iv[i];
1385     for (j=i; v[tmp] < v[iv[j-1]]; j--) {
1386       iv[j] = iv[j-1];
1387     }
1388     iv[j] = tmp;
1389   }
1390 }
1391 
ex_iqsort(int v[],int iv[],int N)1392 void ex_iqsort(int v[], int iv[], int N)
1393 {
1394   ex_int_iqsort(v, iv, 0, N-1);
1395   ex_int_iisort(v, iv, N);
1396 
1397 #if defined(DEBUG_QSORT)
1398   fprintf(stderr, "Checking sort of %d values\n", N+1);
1399   int i;
1400   for (i=1; i < N; i++) {
1401     assert(v[iv[i-1]] <= v[iv[i]]);
1402   }
1403 #endif
1404 }
1405 
ex_iqsort64(int64_t v[],int64_t iv[],int64_t N)1406 void ex_iqsort64(int64_t v[], int64_t iv[], int64_t N)
1407 {
1408   ex_int_iqsort64(v, iv, 0, N-1);
1409   ex_int_iisort64(v, iv, N);
1410 
1411 #if defined(DEBUG_QSORT)
1412   fprintf(stderr, "Checking sort of %d values\n", N+1);
1413   int i;
1414   for (i=1; i < N; i++) {
1415     assert(v[iv[i-1]] <= v[iv[i]]);
1416   }
1417 #endif
1418 }
1419 
1420 /*!
1421  * Determine whether the new large model storage is being used in this
1422  * file, or old method. Basically, the difference is whether the
1423  * coordinates and nodal variables are stored in a blob (xyz
1424  * components together) or as a variable per component per
1425  * nodal_variable.
1426  */
ex_large_model(int exoid)1427 int ex_large_model(int exoid)
1428 {
1429   static int message_output = FALSE;
1430   if (exoid < 0) {
1431     /* If exoid not specified, then query is to see if user specified
1432      * the large model via an environment variable
1433      */
1434     char *option = getenv("EXODUS_LARGE_MODEL");
1435     if (option != NULL) {
1436       if (option[0] == 'n' || option[0] == 'N') {
1437 	if (!message_output) {
1438 	  fprintf(stderr,
1439 		  "EXODUSII: Small model size selected via EXODUS_LARGE_MODEL environment variable\n");
1440 	  message_output = TRUE;
1441 	}
1442         return 0;
1443       } else {
1444 	if (!message_output) {
1445 	  fprintf(stderr,
1446 		  "EXODUSII: Large model size selected via EXODUS_LARGE_MODEL environment variable\n");
1447 	  message_output = TRUE;
1448 	}
1449         return 1;
1450       }
1451     } else {
1452       return EXODUS_DEFAULT_SIZE; /* Specified in exodusII_int.h */
1453     }
1454 
1455   } else {
1456     /* See if the ATT_FILESIZE attribute is defined in the file */
1457     int file_size = 0;
1458     if (nc_get_att_int(exoid, NC_GLOBAL, ATT_FILESIZE, &file_size) != NC_NOERR) {
1459       /* Variable not found; default is 0 */
1460       file_size = 0;
1461     }
1462     return file_size;
1463   }
1464 }
1465 
ex_get_dimension(int exoid,const char * DIMENSION,const char * label,size_t * count,int * dimid,const char * routine)1466 int ex_get_dimension(int exoid, const char* DIMENSION, const char *label,
1467                      size_t *count, int *dimid, const char *routine)
1468 {
1469   char errmsg[MAX_ERR_LENGTH];
1470   int status;
1471 
1472   *count = 0;
1473   *dimid = -1;
1474 
1475   if ((status = nc_inq_dimid(exoid, DIMENSION, dimid)) != NC_NOERR) {
1476     exerrval = status;
1477     if (routine != NULL) {
1478       if (status == NC_EBADDIM) {
1479         sprintf(errmsg,
1480                 "Warning: no %s defined in file id %d",
1481                 label, exoid);
1482         ex_err(routine, errmsg,exerrval);
1483 
1484       } else {
1485         sprintf(errmsg,
1486                 "Error: failed to locate number of %s in file id %d",
1487                 label, exoid);
1488         ex_err(routine,errmsg,exerrval);
1489       }
1490     }
1491     return status;
1492   }
1493 
1494   if ((status = nc_inq_dimlen (exoid, *dimid, count)) != NC_NOERR) {
1495     exerrval = status;
1496     if (routine != NULL) {
1497       sprintf(errmsg,
1498               "Error: failed to get number of %s in file id %d",
1499               label, exoid);
1500       ex_err(routine,errmsg,exerrval);
1501       return -1;
1502     }
1503   }
1504   return status;
1505 }
1506 
1507 /* Deprecated. do not use */
ex_header_size(int exoid)1508 size_t ex_header_size(int exoid)
1509 {
1510   return 0;
1511 }
1512 
1513 /* type = 1 for integer, 2 for real, 3 for character */
ex_compress_variable(int exoid,int varid,int type)1514 void ex_compress_variable(int exoid, int varid, int type)
1515 {
1516 #if !defined(NOT_NETCDF4)
1517 
1518   struct file_item* file = ex_find_file_item(exoid);
1519 
1520   if (!file ) {
1521     char errmsg[MAX_ERR_LENGTH];
1522     exerrval = EX_BADFILEID;
1523     sprintf(errmsg,"Error: unknown file id %d for ex_compress_variable().",exoid);
1524     ex_err("ex_compress_variable",errmsg,exerrval);
1525   }
1526   else {
1527     int deflate_level = file->compression_level;
1528     int compress = 1;
1529     int shuffle = file->shuffle;
1530 #if 0
1531     if (type == 2)
1532       shuffle = 0;
1533 #endif
1534     if (deflate_level > 0 && (file->file_type == 2 || file->file_type == 3)) {
1535       nc_def_var_deflate(exoid, varid, shuffle, compress, deflate_level);
1536     }
1537   }
1538 #endif
1539 }
1540