NetCDF  4.6.1
 All Data Structures Files Functions Variables Typedefs Macros Modules Pages
nc4internal.c
Go to the documentation of this file.
1 /* Copyright 2003-2018, University Corporation for Atmospheric
2  * Research. See the COPYRIGHT file for copying and redistribution
3  * conditions.
4  */
18 #include "config.h"
19 #include "nc4internal.h"
20 #include "nc.h" /* from libsrc */
21 #include "ncdispatch.h" /* from libdispatch */
22 #include "ncutf8.h"
23 #include "H5DSpublic.h"
24 
25 #undef DEBUGH5
26 
27 #ifdef DEBUGH5
28 
35 static herr_t
36 h5catch(void* ignored)
37 {
38  H5Eprint(NULL);
39  return 0;
40 }
41 #endif
42 
43 /* These are the default chunk cache sizes for HDF5 files created or
44  * opened with netCDF-4. */
45 extern size_t nc4_chunk_cache_size;
46 extern size_t nc4_chunk_cache_nelems;
47 extern float nc4_chunk_cache_preemption;
48 
49 #ifdef LOGGING
50 /* This is the severity level of messages which will be logged. Use
51  severity 0 for errors, 1 for important log messages, 2 for less
52  important, etc. */
53 int nc_log_level = NC_TURN_OFF_LOGGING;
54 
55 #endif /* LOGGING */
56 
66 static herr_t
67 set_auto(void* func, void *client_data)
68 {
69 #ifdef DEBUGH5
70  return H5Eset_auto2(H5E_DEFAULT,(H5E_auto2_t)h5catch,client_data);
71 #else
72  return H5Eset_auto2(H5E_DEFAULT,(H5E_auto2_t)func,client_data);
73 #endif
74 }
75 
80 void
81 nc4_hdf5_initialize(void)
82 {
83  if (set_auto(NULL, NULL) < 0)
84  LOG((0, "Couldn't turn off HDF5 error messages!"));
85  LOG((1, "HDF5 error messages have been turned off."));
87 }
88 
100 int
101 nc4_check_name(const char *name, char *norm_name)
102 {
103  char *temp;
104  int retval;
105 
106  /* Check for NULL. */
107  if (!name)
108  return NC_EINVAL;
109 
110  assert(norm_name);
111 
112  /* Check for NULL. */
113  if (!name)
114  return NC_EINVAL;
115 
116  /* Check the length. */
117  if (strlen(name) > NC_MAX_NAME)
118  return NC_EMAXNAME;
119 
120  /* Make sure this is a valid netcdf name. This should be done
121  * before the name is normalized, because it gives better error
122  * codes for bad utf8 strings. */
123  if ((retval = NC_check_name(name)))
124  return retval;
125 
126  /* Normalize the name. */
127  retval = nc_utf8_normalize((const unsigned char *)name,(unsigned char**)&temp);
128  if(retval != NC_NOERR)
129  return retval;
130 
131  if(strlen(temp) > NC_MAX_NAME) {
132  free(temp);
133  return NC_EMAXNAME;
134  }
135 
136  strcpy(norm_name, temp);
137  free(temp);
138 
139  return NC_NOERR;
140 }
141 
154 static int
155 find_var_dim_max_length(NC_GRP_INFO_T *grp, int varid, int dimid, size_t *maxlen)
156 {
157  hid_t datasetid = 0, spaceid = 0;
158  NC_VAR_INFO_T *var;
159  hsize_t *h5dimlen = NULL, *h5dimlenmax = NULL;
160  int d, dataset_ndims = 0;
161  int retval = NC_NOERR;
162 
163  *maxlen = 0;
164 
165  /* Find this var. */
166  if (varid < 0 || varid >= grp->vars.nelems)
167  return NC_ENOTVAR;
168  var = grp->vars.value[varid];
169  if (!var) return NC_ENOTVAR;
170  assert(var->varid == varid);
171 
172  /* If the var hasn't been created yet, its size is 0. */
173  if (!var->created)
174  {
175  *maxlen = 0;
176  }
177  else
178  {
179  /* Get the number of records in the dataset. */
180  if ((retval = nc4_open_var_grp2(grp, var->varid, &datasetid)))
181  BAIL(retval);
182  if ((spaceid = H5Dget_space(datasetid)) < 0)
183  BAIL(NC_EHDFERR);
184 
185  /* If it's a scalar dataset, it has length one. */
186  if (H5Sget_simple_extent_type(spaceid) == H5S_SCALAR)
187  {
188  *maxlen = (var->dimids && var->dimids[0] == dimid) ? 1 : 0;
189  }
190  else
191  {
192  /* Check to make sure ndims is right, then get the len of each
193  dim in the space. */
194  if ((dataset_ndims = H5Sget_simple_extent_ndims(spaceid)) < 0)
195  BAIL(NC_EHDFERR);
196  if (dataset_ndims != var->ndims)
197  BAIL(NC_EHDFERR);
198  if (!(h5dimlen = malloc(dataset_ndims * sizeof(hsize_t))))
199  BAIL(NC_ENOMEM);
200  if (!(h5dimlenmax = malloc(dataset_ndims * sizeof(hsize_t))))
201  BAIL(NC_ENOMEM);
202  if ((dataset_ndims = H5Sget_simple_extent_dims(spaceid,
203  h5dimlen, h5dimlenmax)) < 0)
204  BAIL(NC_EHDFERR);
205  LOG((5, "find_var_dim_max_length: varid %d len %d max: %d",
206  varid, (int)h5dimlen[0], (int)h5dimlenmax[0]));
207  for (d=0; d<dataset_ndims; d++) {
208  if (var->dimids[d] == dimid) {
209  *maxlen = *maxlen > h5dimlen[d] ? *maxlen : h5dimlen[d];
210  }
211  }
212  }
213  }
214 
215 exit:
216  if (spaceid > 0 && H5Sclose(spaceid) < 0)
217  BAIL2(NC_EHDFERR);
218  if (h5dimlen) free(h5dimlen);
219  if (h5dimlenmax) free(h5dimlenmax);
220  return retval;
221 }
222 
234 int
235 nc4_nc4f_list_add(NC *nc, const char *path, int mode)
236 {
237  NC_HDF5_FILE_INFO_T *h5;
238 
239  assert(nc && !NC4_DATA(nc) && path);
240 
241  /* We need to malloc and
242  initialize the substructure NC_HDF_FILE_INFO_T. */
243  if (!(h5 = calloc(1, sizeof(NC_HDF5_FILE_INFO_T))))
244  return NC_ENOMEM;
245  NC4_DATA_SET(nc,h5);
246  h5->controller = nc;
247 
248  /* Hang on to cmode, and note that we're in define mode. */
249  h5->cmode = mode | NC_INDEF;
250 
251  /* The next_typeid needs to be set beyond the end of our atomic
252  * types. */
253  h5->next_typeid = NC_FIRSTUSERTYPEID;
254 
255  /* There's always at least one open group - the root
256  * group. Allocate space for one group's worth of information. Set
257  * its hdf id, name, and a pointer to it's file structure. */
258  return nc4_grp_list_add(&(h5->root_grp), h5->next_nc_grpid++,
259  NULL, nc, NC_GROUP_NAME, NULL);
260 }
261 
275 int
276 nc4_find_nc4_grp(int ncid, NC_GRP_INFO_T **grp)
277 {
278  NC_HDF5_FILE_INFO_T* h5;
279  NC *f = nc4_find_nc_file(ncid,&h5);
280  if(f == NULL) return NC_EBADID;
281 
282  /* No netcdf-3 files allowed! */
283  if (!h5) return NC_ENOTNC4;
284  assert(h5->root_grp);
285 
286  /* This function demands netcdf-4 files without strict nc3
287  * rules.*/
288  if (h5->cmode & NC_CLASSIC_MODEL) return NC_ESTRICTNC3;
289 
290  /* If we can't find it, the grp id part of ncid is bad. */
291  if (!(*grp = nc4_rec_find_grp(h5->root_grp, (ncid & GRP_ID_MASK))))
292  return NC_EBADID;
293  return NC_NOERR;
294 }
295 
309 int
310 nc4_find_grp_h5(int ncid, NC_GRP_INFO_T **grpp, NC_HDF5_FILE_INFO_T **h5p)
311 {
312  NC_HDF5_FILE_INFO_T *h5;
313  NC_GRP_INFO_T *grp;
314  NC *f = nc4_find_nc_file(ncid,&h5);
315  if(f == NULL) return NC_EBADID;
316  if (h5) {
317  assert(h5->root_grp);
318  /* If we can't find it, the grp id part of ncid is bad. */
319  if (!(grp = nc4_rec_find_grp(h5->root_grp, (ncid & GRP_ID_MASK))))
320  return NC_EBADID;
321  h5 = (grp)->nc4_info;
322  assert(h5);
323  } else {
324  h5 = NULL;
325  grp = NULL;
326  }
327  if(h5p) *h5p = h5;
328  if(grpp) *grpp = grp;
329  return NC_NOERR;
330 }
331 
344 int
345 nc4_find_nc_grp_h5(int ncid, NC **nc, NC_GRP_INFO_T **grpp,
346  NC_HDF5_FILE_INFO_T **h5p)
347 {
348  NC_GRP_INFO_T *grp;
349  NC_HDF5_FILE_INFO_T* h5;
350  NC *f = nc4_find_nc_file(ncid,&h5);
351 
352  if(f == NULL) return NC_EBADID;
353  *nc = f;
354 
355  if (h5) {
356  assert(h5->root_grp);
357  /* If we can't find it, the grp id part of ncid is bad. */
358  if (!(grp = nc4_rec_find_grp(h5->root_grp, (ncid & GRP_ID_MASK))))
359  return NC_EBADID;
360 
361  h5 = (grp)->nc4_info;
362  assert(h5);
363  } else {
364  h5 = NULL;
365  grp = NULL;
366  }
367  if(h5p) *h5p = h5;
368  if(grpp) *grpp = grp;
369  return NC_NOERR;
370 }
371 
381 NC_GRP_INFO_T *
382 nc4_rec_find_grp(NC_GRP_INFO_T *start_grp, int target_nc_grpid)
383 {
384  NC_GRP_INFO_T *g, *res;
385 
386  assert(start_grp);
387 
388  /* Is this the group we are searching for? */
389  if (start_grp->nc_grpid == target_nc_grpid)
390  return start_grp;
391 
392  /* Shake down the kids. */
393  if (start_grp->children)
394  for (g = start_grp->children; g; g = g->l.next)
395  if ((res = nc4_rec_find_grp(g, target_nc_grpid)))
396  return res;
397 
398  /* Can't find it. Fate, why do you mock me? */
399  return NULL;
400 }
401 
414 int
415 nc4_find_g_var_nc(NC *nc, int ncid, int varid,
416  NC_GRP_INFO_T **grp, NC_VAR_INFO_T **var)
417 {
418  NC_HDF5_FILE_INFO_T* h5 = NC4_DATA(nc);
419 
420  /* Find the group info. */
421  assert(grp && var && h5 && h5->root_grp);
422  *grp = nc4_rec_find_grp(h5->root_grp, (ncid & GRP_ID_MASK));
423 
424  /* It is possible for *grp to be NULL. If it is,
425  return an error. */
426  if(*grp == NULL)
427  return NC_EBADID;
428 
429  /* Find the var info. */
430  if (varid < 0 || varid >= (*grp)->vars.nelems)
431  return NC_ENOTVAR;
432  (*var) = (*grp)->vars.value[varid];
433 
434  return NC_NOERR;
435 }
436 
449 int
450 nc4_find_dim(NC_GRP_INFO_T *grp, int dimid, NC_DIM_INFO_T **dim,
451  NC_GRP_INFO_T **dim_grp)
452 {
453  NC_GRP_INFO_T *g, *dg = NULL;
454  int finished = 0;
455 
456  assert(grp && dim);
457 
458  /* Find the dim info. */
459  for (g = grp; g && !finished; g = g->parent)
460  for ((*dim) = g->dim; (*dim); (*dim) = (*dim)->l.next)
461  if ((*dim)->dimid == dimid)
462  {
463  dg = g;
464  finished++;
465  break;
466  }
467 
468  /* If we didn't find it, return an error. */
469  if (!(*dim))
470  return NC_EBADDIM;
471 
472  /* Give the caller the group the dimension is in. */
473  if (dim_grp)
474  *dim_grp = dg;
475 
476  return NC_NOERR;
477 }
478 
489 int
490 nc4_find_var(NC_GRP_INFO_T *grp, const char *name, NC_VAR_INFO_T **var)
491 {
492  int i;
493  assert(grp && var && name);
494 
495  /* Find the var info. */
496  *var = NULL;
497  for (i=0; i < grp->vars.nelems; i++)
498  {
499  if (0 == strcmp(name, grp->vars.value[i]->name))
500  {
501  *var = grp->vars.value[i];
502  break;
503  }
504  }
505  return NC_NOERR;
506 }
507 
517 NC_TYPE_INFO_T *
518 nc4_rec_find_hdf_type(NC_GRP_INFO_T *start_grp, hid_t target_hdf_typeid)
519 {
520  NC_GRP_INFO_T *g;
521  NC_TYPE_INFO_T *type, *res;
522  htri_t equal;
523 
524  assert(start_grp);
525 
526  /* Does this group have the type we are searching for? */
527  for (type = start_grp->type; type; type = type->l.next)
528  {
529  if ((equal = H5Tequal(type->native_hdf_typeid ? type->native_hdf_typeid : type->hdf_typeid, target_hdf_typeid)) < 0)
530  return NULL;
531  if (equal)
532  return type;
533  }
534 
535  /* Shake down the kids. */
536  if (start_grp->children)
537  for (g = start_grp->children; g; g = g->l.next)
538  if ((res = nc4_rec_find_hdf_type(g, target_hdf_typeid)))
539  return res;
540 
541  /* Can't find it. Fate, why do you mock me? */
542  return NULL;
543 }
544 
554 NC_TYPE_INFO_T *
555 nc4_rec_find_named_type(NC_GRP_INFO_T *start_grp, char *name)
556 {
557  NC_GRP_INFO_T *g;
558  NC_TYPE_INFO_T *type, *res;
559 
560  assert(start_grp);
561 
562  /* Does this group have the type we are searching for? */
563  for (type = start_grp->type; type; type = type->l.next)
564  if (!strcmp(type->name, name))
565  return type;
566 
567  /* Search subgroups. */
568  if (start_grp->children)
569  for (g = start_grp->children; g; g = g->l.next)
570  if ((res = nc4_rec_find_named_type(g, name)))
571  return res;
572 
573  /* Can't find it. Oh, woe is me! */
574  return NULL;
575 }
576 
586 NC_TYPE_INFO_T *
587 nc4_rec_find_nc_type(const NC_GRP_INFO_T *start_grp, nc_type target_nc_typeid)
588 {
589  NC_TYPE_INFO_T *type;
590 
591  assert(start_grp);
592 
593  /* Does this group have the type we are searching for? */
594  for (type = start_grp->type; type; type = type->l.next)
595  if (type->nc_typeid == target_nc_typeid)
596  return type;
597 
598  /* Shake down the kids. */
599  if (start_grp->children)
600  {
601  NC_GRP_INFO_T *g;
602 
603  for (g = start_grp->children; g; g = g->l.next)
604  {
605  NC_TYPE_INFO_T *res;
606 
607  if ((res = nc4_rec_find_nc_type(g, target_nc_typeid)))
608  return res;
609  }
610  }
611 
612  /* Can't find it. Fate, why do you mock me? */
613  return NULL;
614 }
615 
627 int
628 nc4_find_type(const NC_HDF5_FILE_INFO_T *h5, nc_type typeid, NC_TYPE_INFO_T **type)
629 {
630  if (typeid < 0 || !type)
631  return NC_EINVAL;
632  *type = NULL;
633 
634  /* Atomic types don't have associated NC_TYPE_INFO_T struct, just
635  * return NOERR. */
636  if (typeid <= NC_STRING)
637  return NC_NOERR;
638 
639  /* Find the type. */
640  if(!(*type = nc4_rec_find_nc_type(h5->root_grp, typeid)))
641  return NC_EBADTYPID;
642 
643  return NC_NOERR;
644 }
645 
658 int
659 nc4_find_dim_len(NC_GRP_INFO_T *grp, int dimid, size_t **len)
660 {
661  NC_GRP_INFO_T *g;
662  NC_VAR_INFO_T *var;
663  int retval;
664  int i;
665 
666  assert(grp && len);
667  LOG((3, "nc4_find_dim_len: grp->name %s dimid %d", grp->name, dimid));
668 
669  /* If there are any groups, call this function recursively on
670  * them. */
671  for (g = grp->children; g; g = g->l.next)
672  if ((retval = nc4_find_dim_len(g, dimid, len)))
673  return retval;
674 
675  /* For all variables in this group, find the ones that use this
676  * dimension, and remember the max length. */
677  for (i=0; i < grp->vars.nelems; i++)
678  {
679  size_t mylen;
680  var = grp->vars.value[i];
681  if (!var) continue;
682 
683  /* Find max length of dim in this variable... */
684  if ((retval = find_var_dim_max_length(grp, var->varid, dimid, &mylen)))
685  return retval;
686 
687  **len = **len > mylen ? **len : mylen;
688  }
689 
690  return NC_NOERR;
691 }
692 
707 int
708 nc4_find_grp_att(NC_GRP_INFO_T *grp, int varid, const char *name, int attnum,
709  NC_ATT_INFO_T **att)
710 {
711  NC_VAR_INFO_T *var;
712  NC_ATT_INFO_T *attlist = NULL;
713 
714  assert(grp && grp->name);
715  LOG((4, "nc4_find_grp_att: grp->name %s varid %d name %s attnum %d",
716  grp->name, varid, name, attnum));
717 
718  /* Get either the global or a variable attribute list. */
719  if (varid == NC_GLOBAL)
720  attlist = grp->att;
721  else
722  {
723  if (varid < 0 || varid >= grp->vars.nelems)
724  return NC_ENOTVAR;
725  var = grp->vars.value[varid];
726  if (!var) return NC_ENOTVAR;
727  attlist = var->att;
728  assert(var->varid == varid);
729  }
730 
731  /* Now find the attribute by name or number. If a name is provided,
732  * ignore the attnum. */
733  if(attlist)
734  for (*att = attlist; *att; *att = (*att)->l.next) {
735  if (name && (*att)->name && !strcmp((*att)->name, name))
736  return NC_NOERR;
737  if (!name && (*att)->attnum == attnum)
738  return NC_NOERR;
739  }
740 
741  /* If we get here, we couldn't find the attribute. */
742  return NC_ENOTATT;
743 }
744 
760 int
761 nc4_find_nc_att(int ncid, int varid, const char *name, int attnum,
762  NC_ATT_INFO_T **att)
763 {
764  NC_GRP_INFO_T *grp;
765  NC_HDF5_FILE_INFO_T *h5;
766  NC_VAR_INFO_T *var;
767  NC_ATT_INFO_T *attlist = NULL;
768  int retval;
769 
770  LOG((4, "nc4_find_nc_att: ncid 0x%x varid %d name %s attnum %d",
771  ncid, varid, name, attnum));
772 
773  /* Find info for this file and group, and set pointer to each. */
774  if ((retval = nc4_find_grp_h5(ncid, &grp, &h5)))
775  return retval;
776  assert(grp && h5);
777 
778  /* Get either the global or a variable attribute list. */
779  if (varid == NC_GLOBAL)
780  attlist = grp->att;
781  else
782  {
783  if (varid < 0 || varid >= grp->vars.nelems)
784  return NC_ENOTVAR;
785  var = grp->vars.value[varid];
786  if (!var) return NC_ENOTVAR;
787  attlist = var->att;
788  assert(var->varid == varid);
789  }
790 
791  /* Now find the attribute by name or number. If a name is provided, ignore the attnum. */
792  for (*att = attlist; *att; *att = (*att)->l.next)
793  if ((name && !strcmp((*att)->name, name)) ||
794  (!name && (*att)->attnum == attnum))
795  return NC_NOERR;
796 
797  /* If we get here, we couldn't find the attribute. */
798  return NC_ENOTATT;
799 }
800 
801 
811 NC*
812 nc4_find_nc_file(int ext_ncid, NC_HDF5_FILE_INFO_T** h5p)
813 {
814  NC* nc;
815  int stat;
816 
817  stat = NC_check_id(ext_ncid,&nc);
818  if(stat != NC_NOERR)
819  nc = NULL;
820 
821  if(nc)
822  if(h5p) *h5p = (NC_HDF5_FILE_INFO_T*)nc->dispatchdata;
823 
824  return nc;
825 }
826 
836 static void
837 obj_list_add(NC_LIST_NODE_T **list, NC_LIST_NODE_T *obj)
838 {
839  /* Go to the end of the list and set the last one to point at object,
840  * or, if the list is empty, our new object becomes the list. */
841  if(*list)
842  {
843  NC_LIST_NODE_T *o;
844 
845  for (o = *list; o; o = o->next)
846  if (!o->next)
847  break;
848  o->next = obj;
849  obj->prev = o;
850  }
851  else
852  *list = obj;
853 }
854 
864 static void
865 obj_list_del(NC_LIST_NODE_T **list, NC_LIST_NODE_T *obj)
866 {
867  /* Remove the var from the linked list. */
868  if(*list == obj)
869  *list = obj->next;
870  else
871  ((NC_LIST_NODE_T *)obj->prev)->next = obj->next;
872 
873  if(obj->next)
874  ((NC_LIST_NODE_T *)obj->next)->prev = obj->prev;
875 }
876 
886 int
887 nc4_var_add(NC_VAR_INFO_T **var)
888 {
889  NC_VAR_INFO_T *new_var;
890 
891  /* Allocate storage for new variable. */
892  if (!(new_var = calloc(1, sizeof(NC_VAR_INFO_T))))
893  return NC_ENOMEM;
894 
895  /* These are the HDF5-1.8.4 defaults. */
896  new_var->chunk_cache_size = nc4_chunk_cache_size;
897  new_var->chunk_cache_nelems = nc4_chunk_cache_nelems;
898  new_var->chunk_cache_preemption = nc4_chunk_cache_preemption;
899 
900  /* Set the var pointer, if one was given */
901  if (var)
902  *var = new_var;
903  else
904  free(new_var);
905 
906  return NC_NOERR;
907 }
908 
918 int
919 nc4_dim_list_add(NC_DIM_INFO_T **list, NC_DIM_INFO_T **dim)
920 {
921  NC_DIM_INFO_T *new_dim;
922 
923  if (!(new_dim = calloc(1, sizeof(NC_DIM_INFO_T))))
924  return NC_ENOMEM;
925 
926  /* Add object to list */
927  obj_list_add((NC_LIST_NODE_T **)list, (NC_LIST_NODE_T *)new_dim);
928 
929  /* Set the dim pointer, if one was given */
930  if (dim)
931  *dim = new_dim;
932 
933  return NC_NOERR;
934 }
935 
945 int
946 nc4_att_list_add(NC_ATT_INFO_T **list, NC_ATT_INFO_T **att)
947 {
948  NC_ATT_INFO_T *new_att;
949 
950  if (!(new_att = calloc(1, sizeof(NC_ATT_INFO_T))))
951  return NC_ENOMEM;
952 
953  /* Add object to list */
954  obj_list_add((NC_LIST_NODE_T **)list, (NC_LIST_NODE_T *)new_att);
955 
956  /* Set the attribute pointer, if one was given */
957  if (att)
958  *att = new_att;
959 
960  return NC_NOERR;
961 }
962 
977 int
978 nc4_grp_list_add(NC_GRP_INFO_T **list, int new_nc_grpid,
979  NC_GRP_INFO_T *parent_grp, NC *nc,
980  char *name, NC_GRP_INFO_T **grp)
981 {
982  NC_GRP_INFO_T *new_grp;
983 
984  LOG((3, "%s: new_nc_grpid %d name %s ", __func__, new_nc_grpid, name));
985 
986  /* Get the memory to store this groups info. */
987  if (!(new_grp = calloc(1, sizeof(NC_GRP_INFO_T))))
988  return NC_ENOMEM;
989 
990  /* Fill in this group's information. */
991  new_grp->nc_grpid = new_nc_grpid;
992  new_grp->parent = parent_grp;
993  if (!(new_grp->name = strdup(name)))
994  {
995  free(new_grp);
996  return NC_ENOMEM;
997  }
998  new_grp->nc4_info = NC4_DATA(nc);
999 
1000  /* Add object to list */
1001  obj_list_add((NC_LIST_NODE_T **)list, (NC_LIST_NODE_T *)new_grp);
1002 
1003  /* Set the group pointer, if one was given */
1004  if (grp)
1005  *grp = new_grp;
1006 
1007  return NC_NOERR;
1008 }
1009 
1023 int
1024 nc4_check_dup_name(NC_GRP_INFO_T *grp, char *name)
1025 {
1026  NC_TYPE_INFO_T *type;
1027  NC_GRP_INFO_T *g;
1028  NC_VAR_INFO_T *var;
1029  uint32_t hash;
1030  int i;
1031 
1032  /* Any types of this name? */
1033  for (type = grp->type; type; type = type->l.next)
1034  if (!strcmp(type->name, name))
1035  return NC_ENAMEINUSE;
1036 
1037  /* Any child groups of this name? */
1038  for (g = grp->children; g; g = g->l.next)
1039  if (!strcmp(g->name, name))
1040  return NC_ENAMEINUSE;
1041 
1042  /* Any variables of this name? */
1043  hash = hash_fast(name, strlen(name));
1044  for (i=0; i < grp->vars.nelems; i++)
1045  {
1046  var = grp->vars.value[i];
1047  if (!var) continue;
1048  if (var->hash == hash && !strcmp(var->name, name))
1049  return NC_ENAMEINUSE;
1050  }
1051  return NC_NOERR;
1052 }
1053 
1067 int
1068 nc4_type_list_add(NC_GRP_INFO_T *grp, size_t size, const char *name,
1069  NC_TYPE_INFO_T **type)
1070 {
1071  NC_TYPE_INFO_T *new_type;
1072 
1073  /* Allocate memory for the type */
1074  if (!(new_type = calloc(1, sizeof(NC_TYPE_INFO_T))))
1075  return NC_ENOMEM;
1076 
1077  /* Add object to list */
1078  obj_list_add((NC_LIST_NODE_T **)(&grp->type), (NC_LIST_NODE_T *)new_type);
1079 
1080  /* Remember info about this type. */
1081  new_type->nc_typeid = grp->nc4_info->next_typeid++;
1082  new_type->size = size;
1083  if (!(new_type->name = strdup(name)))
1084  return NC_ENOMEM;
1085 
1086  /* Increment the ref. count on the type */
1087  new_type->rc++;
1088 
1089  /* Return a pointer to the new type, if requested */
1090  if (type)
1091  *type = new_type;
1092 
1093  return NC_NOERR;
1094 }
1095 
1112 int
1113 nc4_field_list_add(NC_FIELD_INFO_T **list, int fieldid, const char *name,
1114  size_t offset, hid_t field_hdf_typeid, hid_t native_typeid,
1115  nc_type xtype, int ndims, const int *dim_sizesp)
1116 {
1117  NC_FIELD_INFO_T *field;
1118 
1119  /* Name has already been checked and UTF8 normalized. */
1120  if (!name)
1121  return NC_EINVAL;
1122 
1123  /* Allocate storage for this field information. */
1124  if (!(field = calloc(1, sizeof(NC_FIELD_INFO_T))))
1125  return NC_ENOMEM;
1126 
1127  /* Store the information about this field. */
1128  field->fieldid = fieldid;
1129  if (!(field->name = strdup(name)))
1130  {
1131  free(field);
1132  return NC_ENOMEM;
1133  }
1134  field->hdf_typeid = field_hdf_typeid;
1135  field->native_hdf_typeid = native_typeid;
1136  field->nc_typeid = xtype;
1137  field->offset = offset;
1138  field->ndims = ndims;
1139  if (ndims)
1140  {
1141  int i;
1142 
1143  if (!(field->dim_size = malloc(ndims * sizeof(int))))
1144  {
1145  free(field->name);
1146  free(field);
1147  return NC_ENOMEM;
1148  }
1149  for (i = 0; i < ndims; i++)
1150  field->dim_size[i] = dim_sizesp[i];
1151  }
1152 
1153  /* Add object to list */
1154  obj_list_add((NC_LIST_NODE_T **)list, (NC_LIST_NODE_T *)field);
1155 
1156  return NC_NOERR;
1157 }
1158 
1171 int
1172 nc4_enum_member_add(NC_ENUM_MEMBER_INFO_T **list, size_t size,
1173  const char *name, const void *value)
1174 {
1175  NC_ENUM_MEMBER_INFO_T *member;
1176 
1177  /* Name has already been checked. */
1178  assert(name && size > 0 && value);
1179  LOG((4, "%s: size %d name %s", __func__, size, name));
1180 
1181  /* Allocate storage for this field information. */
1182  if (!(member = calloc(1, sizeof(NC_ENUM_MEMBER_INFO_T))))
1183  return NC_ENOMEM;
1184  if (!(member->value = malloc(size))) {
1185  free(member);
1186  return NC_ENOMEM;
1187  }
1188  if (!(member->name = strdup(name))) {
1189  free(member->value);
1190  free(member);
1191  return NC_ENOMEM;
1192  }
1193 
1194  /* Store the value for this member. */
1195  memcpy(member->value, value, size);
1196 
1197  /* Add object to list */
1198  obj_list_add((NC_LIST_NODE_T **)list, (NC_LIST_NODE_T *)member);
1199 
1200  return NC_NOERR;
1201 }
1202 
1212 static void
1213 field_list_del(NC_FIELD_INFO_T **list, NC_FIELD_INFO_T *field)
1214 {
1215  /* Take this field out of the list. */
1216  obj_list_del((NC_LIST_NODE_T **)list, (NC_LIST_NODE_T *)field);
1217 
1218  /* Free some stuff. */
1219  if (field->name)
1220  free(field->name);
1221  if (field->dim_size)
1222  free(field->dim_size);
1223 
1224  /* Nc_Free the memory. */
1225  free(field);
1226 }
1227 
1236 int
1237 nc4_type_free(NC_TYPE_INFO_T *type)
1238 {
1239  /* Decrement the ref. count on the type */
1240  assert(type->rc);
1241  type->rc--;
1242 
1243  /* Release the type, if the ref. count drops to zero */
1244  if (0 == type->rc)
1245  {
1246  /* Close any open user-defined HDF5 typeids. */
1247  if (type->hdf_typeid && H5Tclose(type->hdf_typeid) < 0)
1248  return NC_EHDFERR;
1249  if (type->native_hdf_typeid && H5Tclose(type->native_hdf_typeid) < 0)
1250  return NC_EHDFERR;
1251 
1252  /* Free the name. */
1253  if (type->name)
1254  free(type->name);
1255 
1256  /* Class-specific cleanup */
1257  switch (type->nc_type_class)
1258  {
1259  case NC_COMPOUND:
1260  {
1261  NC_FIELD_INFO_T *field;
1262 
1263  /* Delete all the fields in this type (there will be some if its a
1264  * compound). */
1265  field = type->u.c.field;
1266  while (field)
1267  {
1268  NC_FIELD_INFO_T *f = field->l.next;
1269 
1270  field_list_del(&type->u.c.field, field);
1271  field = f;
1272  }
1273  }
1274  break;
1275 
1276  case NC_ENUM:
1277  {
1278  NC_ENUM_MEMBER_INFO_T *enum_member;
1279 
1280  /* Delete all the enum_members, if any. */
1281  enum_member = type->u.e.enum_member;
1282  while (enum_member)
1283  {
1284  NC_ENUM_MEMBER_INFO_T *em = enum_member->l.next;
1285 
1286  free(enum_member->value);
1287  free(enum_member->name);
1288  free(enum_member);
1289  enum_member = em;
1290  }
1291 
1292  if (H5Tclose(type->u.e.base_hdf_typeid) < 0)
1293  return NC_EHDFERR;
1294  }
1295  break;
1296 
1297  case NC_VLEN:
1298  if (H5Tclose(type->u.v.base_hdf_typeid) < 0)
1299  return NC_EHDFERR;
1300 
1301  default:
1302  break;
1303  }
1304 
1305  /* Release the memory. */
1306  free(type);
1307  }
1308 
1309  return NC_NOERR;
1310 }
1311 
1320 int
1321 nc4_var_del(NC_VAR_INFO_T *var)
1322 {
1323  NC_ATT_INFO_T *a, *att;
1324  int ret;
1325 
1326  if(var == NULL)
1327  return NC_NOERR;
1328 
1329  /* First delete all the attributes attached to this var. */
1330  att = var->att;
1331  while (att)
1332  {
1333  a = att->l.next;
1334  if ((ret = nc4_att_list_del(&var->att, att)))
1335  return ret;
1336  att = a;
1337  }
1338 
1339  /* Free some things that may be allocated. */
1340  if (var->chunksizes)
1341  {free(var->chunksizes);var->chunksizes = NULL;}
1342 
1343  if (var->hdf5_name)
1344  {free(var->hdf5_name); var->hdf5_name = NULL;}
1345 
1346  if (var->name)
1347  {free(var->name); var->name = NULL;}
1348 
1349  if (var->dimids)
1350  {free(var->dimids); var->dimids = NULL;}
1351 
1352  if (var->dim)
1353  {free(var->dim); var->dim = NULL;}
1354 
1355  /* Delete any fill value allocation. This must be done before the
1356  * type_info is freed. */
1357  if (var->fill_value)
1358  {
1359  if (var->hdf_datasetid)
1360  {
1361  if (var->type_info)
1362  {
1363  if (var->type_info->nc_type_class == NC_VLEN)
1364  nc_free_vlen((nc_vlen_t *)var->fill_value);
1365  else if (var->type_info->nc_type_class == NC_STRING && *(char **)var->fill_value)
1366  free(*(char **)var->fill_value);
1367  }
1368  }
1369  free(var->fill_value);
1370  var->fill_value = NULL;
1371  }
1372 
1373  /* Release type information */
1374  if (var->type_info)
1375  {
1376  int retval;
1377 
1378  if ((retval = nc4_type_free(var->type_info)))
1379  return retval;
1380  var->type_info = NULL;
1381  }
1382 
1383  /* Delete any HDF5 dimscale objid information. */
1384  if (var->dimscale_hdf5_objids)
1385  free(var->dimscale_hdf5_objids);
1386 
1387  /* Delete information about the attachment status of dimscales. */
1388  if (var->dimscale_attached)
1389  free(var->dimscale_attached);
1390 
1391  /* Release parameter information. */
1392  if (var->params)
1393  free(var->params);
1394 
1395  /* Delete the var. */
1396  free(var);
1397 
1398  return NC_NOERR;
1399 }
1400 
1410 static int
1411 type_list_del(NC_TYPE_INFO_T **list, NC_TYPE_INFO_T *type)
1412 {
1413  /* Take this type out of the list. */
1414  obj_list_del((NC_LIST_NODE_T **)list, (NC_LIST_NODE_T *)type);
1415 
1416  /* Free the type, and its components */
1417  return nc4_type_free(type);
1418 }
1419 
1429 int
1430 nc4_dim_list_del(NC_DIM_INFO_T **list, NC_DIM_INFO_T *dim)
1431 {
1432  /* Take this dimension out of the list. */
1433  obj_list_del((NC_LIST_NODE_T **)list, (NC_LIST_NODE_T *)dim);
1434 
1435  /* Free memory allocated for names. */
1436  if (dim->name)
1437  free(dim->name);
1438 
1439  free(dim);
1440  return NC_NOERR;
1441 }
1442 
1453 static void
1454 grp_list_del(NC_GRP_INFO_T **list, NC_GRP_INFO_T *grp)
1455 {
1456  /* Take this group out of the list. */
1457  obj_list_del((NC_LIST_NODE_T **)list, (NC_LIST_NODE_T *)grp);
1458 
1459  free(grp);
1460 }
1461 
1472 int
1473 nc4_rec_grp_del(NC_GRP_INFO_T **list, NC_GRP_INFO_T *grp)
1474 {
1475  NC_GRP_INFO_T *g, *c;
1476  NC_VAR_INFO_T *var;
1477  NC_ATT_INFO_T *a, *att;
1478  NC_DIM_INFO_T *d, *dim;
1479  NC_TYPE_INFO_T *type, *t;
1480  int retval;
1481  int i;
1482 
1483  assert(grp);
1484  LOG((3, "%s: grp->name %s", __func__, grp->name));
1485 
1486  /* Recursively call this function for each child, if any, stopping
1487  * if there is an error. */
1488  g = grp->children;
1489  while(g)
1490  {
1491  c = g->l.next;
1492  if ((retval = nc4_rec_grp_del(&(grp->children), g)))
1493  return retval;
1494  g = c;
1495  }
1496 
1497  /* Delete all the list contents for vars, dims, and atts, in each
1498  * group. */
1499  att = grp->att;
1500  while (att)
1501  {
1502  LOG((4, "%s: deleting att %s", __func__, att->name));
1503  a = att->l.next;
1504  if ((retval = nc4_att_list_del(&grp->att, att)))
1505  return retval;
1506  att = a;
1507  }
1508 
1509  /* Delete all vars. */
1510  for (i=0; i < grp->vars.nelems; i++)
1511  {
1512  var = grp->vars.value[i];
1513  if (!var) continue;
1514 
1515  LOG((4, "%s: deleting var %s", __func__, var->name));
1516  /* Close HDF5 dataset associated with this var, unless it's a
1517  * scale. */
1518  if (var->hdf_datasetid && H5Dclose(var->hdf_datasetid) < 0)
1519  return NC_EHDFERR;
1520  if ((retval = nc4_var_del(var)))
1521  return retval;
1522  grp->vars.value[i] = NULL;
1523  }
1524 
1525  /* Vars are all freed above. When eliminate linked-list,
1526  then need to iterate value and free vars from it.
1527  */
1528  if (grp->vars.nalloc != 0) {
1529  assert(grp->vars.value != NULL);
1530  free(grp->vars.value);
1531  grp->vars.value = NULL;
1532  grp->vars.nalloc = 0;
1533  }
1534 
1535  /* Delete all dims. */
1536  dim = grp->dim;
1537  while (dim)
1538  {
1539  LOG((4, "%s: deleting dim %s", __func__, dim->name));
1540  /* If this is a dim without a coordinate variable, then close
1541  * the HDF5 DIM_WITHOUT_VARIABLE dataset associated with this
1542  * dim. */
1543  if (dim->hdf_dimscaleid && H5Dclose(dim->hdf_dimscaleid) < 0)
1544  return NC_EHDFERR;
1545  d = dim->l.next;
1546  if ((retval = nc4_dim_list_del(&grp->dim, dim)))
1547  return retval;
1548  dim = d;
1549  }
1550 
1551  /* Delete all types. */
1552  type = grp->type;
1553  while (type)
1554  {
1555  LOG((4, "%s: deleting type %s", __func__, type->name));
1556  t = type->l.next;
1557  if ((retval = type_list_del(&grp->type, type)))
1558  return retval;
1559  type = t;
1560  }
1561 
1562  /* Tell HDF5 we're closing this group. */
1563  LOG((4, "%s: closing group %s", __func__, grp->name));
1564  if (grp->hdf_grpid && H5Gclose(grp->hdf_grpid) < 0)
1565  return NC_EHDFERR;
1566 
1567  /* Free the name. */
1568  free(grp->name);
1569 
1570  /* Finally, redirect pointers around this entry in the list, and
1571  * nc_free its memory. */
1572  grp_list_del(list, grp);
1573 
1574  return NC_NOERR;
1575 }
1576 
1587 int
1588 nc4_att_list_del(NC_ATT_INFO_T **list, NC_ATT_INFO_T *att)
1589 {
1590  int i;
1591 
1592  /* Take this att out of the list. */
1593  obj_list_del((NC_LIST_NODE_T **)list, (NC_LIST_NODE_T *)att);
1594 
1595  /* Free memory that was malloced to hold data for this
1596  * attribute. */
1597  if (att->data)
1598  free(att->data);
1599 
1600  /* Free the name. */
1601  if (att->name)
1602  free(att->name);
1603 
1604  /* Close the HDF5 typeid. */
1605  if (att->native_hdf_typeid && H5Tclose(att->native_hdf_typeid) < 0)
1606  return NC_EHDFERR;
1607 
1608  /* If this is a string array attribute, delete all members of the
1609  * string array, then delete the array of pointers to strings. (The
1610  * array was filled with pointers by HDF5 when the att was read,
1611  * and memory for each string was allocated by HDF5. That's why I
1612  * use free and not nc_free, because the netCDF library didn't
1613  * allocate the memory that is being freed.) */
1614  if (att->stdata)
1615  {
1616  for (i = 0; i < att->len; i++)
1617  if(att->stdata[i])
1618  free(att->stdata[i]);
1619  free(att->stdata);
1620  }
1621 
1622  /* If this att has vlen data, release it. */
1623  if (att->vldata)
1624  {
1625  for (i = 0; i < att->len; i++)
1626  nc_free_vlen(&att->vldata[i]);
1627  free(att->vldata);
1628  }
1629 
1630  free(att);
1631  return NC_NOERR;
1632 }
1633 
1651 int
1652 nc4_break_coord_var(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *coord_var, NC_DIM_INFO_T *dim)
1653 {
1654  int retval = NC_NOERR;
1655 
1656  /* Sanity checks */
1657  assert(grp && coord_var && dim && dim->coord_var == coord_var &&
1658  coord_var->dim[0] == dim && coord_var->dimids[0] == dim->dimid &&
1659  !dim->hdf_dimscaleid);
1660  LOG((3, "%s dim %s was associated with var %s, but now has different name",
1661  __func__, dim->name, coord_var->name));
1662 
1663  /* If we're replacing an existing dimscale dataset, go to
1664  * every var in the file and detach this dimension scale. */
1665  if ((retval = rec_detach_scales(grp->nc4_info->root_grp,
1666  dim->dimid, coord_var->hdf_datasetid)))
1667  return retval;
1668 
1669  /* Allow attached dimscales to be tracked on the [former]
1670  * coordinate variable */
1671  if (coord_var->ndims)
1672  {
1673  /* Coordinate variables shouldn't have dimscales attached. */
1674  assert(!coord_var->dimscale_attached);
1675 
1676  /* Allocate space for tracking them */
1677  if (!(coord_var->dimscale_attached = calloc(coord_var->ndims,
1678  sizeof(nc_bool_t))))
1679  return NC_ENOMEM;
1680  }
1681 
1682  /* Remove the atts that go with being a coordinate var. */
1683  /* if ((retval = remove_coord_atts(coord_var->hdf_datasetid))) */
1684  /* return retval; */
1685 
1686  /* Detach dimension from variable */
1687  coord_var->dimscale = NC_FALSE;
1688  dim->coord_var = NULL;
1689 
1690  /* Set state transition indicators */
1691  coord_var->was_coord_var = NC_TRUE;
1692  coord_var->became_coord_var = NC_FALSE;
1693 
1694  return NC_NOERR;
1695 }
1696 
1717 int
1718 delete_existing_dimscale_dataset(NC_GRP_INFO_T *grp, int dimid, NC_DIM_INFO_T *dim)
1719 {
1720  int retval;
1721 
1722  assert(grp && dim);
1723  LOG((2, "%s: deleting dimscale dataset %s dimid %d", __func__, dim->name,
1724  dimid));
1725 
1726  /* Detach dimscale from any variables using it */
1727  if ((retval = rec_detach_scales(grp, dimid, dim->hdf_dimscaleid)) < 0)
1728  return retval;
1729 
1730  /* Close the HDF5 dataset */
1731  if (H5Dclose(dim->hdf_dimscaleid) < 0)
1732  return NC_EHDFERR;
1733  dim->hdf_dimscaleid = 0;
1734 
1735  /* Now delete the dataset. */
1736  if (H5Gunlink(grp->hdf_grpid, dim->name) < 0)
1737  return NC_EHDFERR;
1738 
1739  return NC_NOERR;
1740 }
1741 
1753 int
1754 nc4_reform_coord_var(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var, NC_DIM_INFO_T *dim)
1755 {
1756  int need_to_reattach_scales = 0;
1757  int retval = NC_NOERR;
1758 
1759  assert(grp && var && dim);
1760  LOG((3, "%s: dim->name %s var->name %s", __func__, dim->name, var->name));
1761 
1762  /* Detach dimscales from the [new] coordinate variable */
1763  if(var->dimscale_attached)
1764  {
1765  int dims_detached = 0;
1766  int finished = 0;
1767  int d;
1768 
1769  /* Loop over all dimensions for variable */
1770  for (d = 0; d < var->ndims && !finished; d++)
1771  {
1772  /* Is there a dimscale attached to this axis? */
1773  if(var->dimscale_attached[d])
1774  {
1775  NC_GRP_INFO_T *g;
1776 
1777  for (g = grp; g && !finished; g = g->parent)
1778  {
1779  NC_DIM_INFO_T *dim1;
1780 
1781  for (dim1 = g->dim; dim1 && !finished; dim1 = dim1->l.next)
1782  {
1783  if (var->dimids[d] == dim1->dimid)
1784  {
1785  hid_t dim_datasetid; /* Dataset ID for dimension */
1786 
1787  /* Find dataset ID for dimension */
1788  if (dim1->coord_var)
1789  dim_datasetid = dim1->coord_var->hdf_datasetid;
1790  else
1791  dim_datasetid = dim1->hdf_dimscaleid;
1792 
1793  /* dim_datasetid may be 0 in some cases when
1794  * renames of dims and vars are happening. In
1795  * this case, the scale has already been
1796  * detached. */
1797  if (dim_datasetid > 0)
1798  {
1799  LOG((3, "detaching scale from %s", var->name));
1800  if (H5DSdetach_scale(var->hdf_datasetid, dim_datasetid, d) < 0)
1801  BAIL(NC_EHDFERR);
1802  }
1803  var->dimscale_attached[d] = NC_FALSE;
1804  if (dims_detached++ == var->ndims)
1805  finished++;
1806  }
1807  }
1808  }
1809  }
1810  } /* next variable dimension */
1811 
1812  /* Release & reset the array tracking attached dimscales */
1813  free(var->dimscale_attached);
1814  var->dimscale_attached = NULL;
1815  need_to_reattach_scales++;
1816  }
1817 
1818  /* Use variable's dataset ID for the dimscale ID. */
1819  if (dim->hdf_dimscaleid && grp != NULL)
1820  {
1821  LOG((3, "closing and unlinking dimscale dataset %s", dim->name));
1822  if (H5Dclose(dim->hdf_dimscaleid) < 0)
1823  BAIL(NC_EHDFERR);
1824  dim->hdf_dimscaleid = 0;
1825 
1826  /* Now delete the dimscale's dataset
1827  (it will be recreated later, if necessary) */
1828  if (H5Gunlink(grp->hdf_grpid, dim->name) < 0)
1829  return NC_EDIMMETA;
1830  }
1831 
1832  /* Attach variable to dimension */
1833  var->dimscale = NC_TRUE;
1834  dim->coord_var = var;
1835 
1836  /* Check if this variable used to be a coord. var */
1837  if (need_to_reattach_scales || (var->was_coord_var && grp != NULL))
1838  {
1839  /* Reattach the scale everywhere it is used. */
1840  /* (Recall that netCDF dimscales are always 1-D) */
1841  if ((retval = rec_reattach_scales(grp->nc4_info->root_grp,
1842  var->dimids[0], var->hdf_datasetid)))
1843  return retval;
1844 
1845  /* Set state transition indicator (cancels earlier transition) */
1846  var->was_coord_var = NC_FALSE;
1847  }
1848  else
1849  /* Set state transition indicator */
1850  var->became_coord_var = NC_TRUE;
1851 
1852 exit:
1853  return retval;
1854 }
1855 
1869 int
1870 nc4_normalize_name(const char *name, char *norm_name)
1871 {
1872  char *temp_name;
1873  int stat = nc_utf8_normalize((const unsigned char *)name,(unsigned char **)&temp_name);
1874  if(stat != NC_NOERR)
1875  return stat;
1876  if (strlen(temp_name) > NC_MAX_NAME)
1877  {
1878  free(temp_name);
1879  return NC_EMAXNAME;
1880  }
1881  strcpy(norm_name, temp_name);
1882  free(temp_name);
1883  return NC_NOERR;
1884 }
1885 
1886 /* Print out a bunch of info to stderr about the metadata for
1887  debugging purposes. */
1888 #ifdef LOGGING
1889 
1899 int
1900 nc_set_log_level(int new_level)
1901 {
1903  nc4_hdf5_initialize();
1904 
1905  /* If the user wants to completely turn off logging, turn off HDF5
1906  logging too. Now I truely can't think of what to do if this
1907  fails, so just ignore the return code. */
1908  if (new_level == NC_TURN_OFF_LOGGING)
1909  {
1910  set_auto(NULL,NULL);
1911  LOG((1, "HDF5 error messages turned off!"));
1912  }
1913 
1914  /* Do we need to turn HDF5 logging back on? */
1915  if (new_level > NC_TURN_OFF_LOGGING &&
1916  nc_log_level <= NC_TURN_OFF_LOGGING)
1917  {
1918  if (set_auto((H5E_auto_t)&H5Eprint, stderr) < 0)
1919  LOG((0, "H5Eset_auto failed!"));
1920  LOG((1, "HDF5 error messages turned on."));
1921  }
1922 
1923  /* Now remember the new level. */
1924  nc_log_level = new_level;
1925  LOG((4, "log_level changed to %d", nc_log_level));
1926  return 0;
1927 }
1928 
1929 #define MAX_NESTS 10
1930 
1939 static int
1940 rec_print_metadata(NC_GRP_INFO_T *grp, int tab_count)
1941 {
1942  NC_GRP_INFO_T *g;
1943  NC_ATT_INFO_T *att;
1944  NC_VAR_INFO_T *var;
1945  NC_DIM_INFO_T *dim;
1946  NC_TYPE_INFO_T *type;
1947  NC_FIELD_INFO_T *field;
1948  char tabs[MAX_NESTS+1] = "";
1949  char *dims_string = NULL;
1950  char temp_string[10];
1951  int t, retval, d, i;
1952 
1953  /* Come up with a number of tabs relative to the group. */
1954  for (t = 0; t < tab_count && t < MAX_NESTS; t++)
1955  tabs[t] = '\t';
1956  tabs[t] = '\0';
1957 
1958  LOG((2, "%s GROUP - %s nc_grpid: %d nvars: %d natts: %d",
1959  tabs, grp->name, grp->nc_grpid, grp->nvars, grp->natts));
1960 
1961  for(att = grp->att; att; att = att->l.next)
1962  LOG((2, "%s GROUP ATTRIBUTE - attnum: %d name: %s type: %d len: %d",
1963  tabs, att->attnum, att->name, att->nc_typeid, att->len));
1964 
1965  for(dim = grp->dim; dim; dim = dim->l.next)
1966  LOG((2, "%s DIMENSION - dimid: %d name: %s len: %d unlimited: %d",
1967  tabs, dim->dimid, dim->name, dim->len, dim->unlimited));
1968 
1969  for (i=0; i < grp->vars.nelems; i++)
1970  {
1971  var = grp->vars.value[i];
1972  if (!var) continue;
1973  if(var->ndims > 0)
1974  {
1975  dims_string = (char*)malloc(sizeof(char)*(var->ndims*4));
1976  strcpy(dims_string, "");
1977  for (d = 0; d < var->ndims; d++)
1978  {
1979  sprintf(temp_string, " %d", var->dimids[d]);
1980  strcat(dims_string, temp_string);
1981  }
1982  }
1983  LOG((2, "%s VARIABLE - varid: %d name: %s type: %d ndims: %d dimscale: %d dimids:%s endianness: %d, hdf_typeid: %d",
1984  tabs, var->varid, var->name, var->type_info->nc_typeid, var->ndims, (int)var->dimscale,
1985  (dims_string ? dims_string : " -"),var->type_info->endianness, var->type_info->native_hdf_typeid));
1986  for(att = var->att; att; att = att->l.next)
1987  LOG((2, "%s VAR ATTRIBUTE - attnum: %d name: %s type: %d len: %d",
1988  tabs, att->attnum, att->name, att->nc_typeid, att->len));
1989  if(dims_string)
1990  {
1991  free(dims_string);
1992  dims_string = NULL;
1993  }
1994  }
1995 
1996  for (type = grp->type; type; type = type->l.next)
1997  {
1998  LOG((2, "%s TYPE - nc_typeid: %d hdf_typeid: 0x%x size: %d committed: %d "
1999  "name: %s num_fields: %d", tabs, type->nc_typeid,
2000  type->hdf_typeid, type->size, (int)type->committed, type->name,
2001  type->u.c.num_fields));
2002  /* Is this a compound type? */
2003  if (type->nc_type_class == NC_COMPOUND)
2004  {
2005  LOG((3, "compound type"));
2006  for (field = type->u.c.field; field; field = field->l.next)
2007  LOG((4, "field %s offset %d nctype %d ndims %d", field->name,
2008  field->offset, field->nc_typeid, field->ndims));
2009  }
2010  else if (type->nc_type_class == NC_VLEN)
2011  {
2012  LOG((3, "VLEN type"));
2013  LOG((4, "base_nc_type: %d", type->u.v.base_nc_typeid));
2014  }
2015  else if (type->nc_type_class == NC_OPAQUE)
2016  LOG((3, "Opaque type"));
2017  else if (type->nc_type_class == NC_ENUM)
2018  {
2019  LOG((3, "Enum type"));
2020  LOG((4, "base_nc_type: %d", type->u.e.base_nc_typeid));
2021  }
2022  else
2023  {
2024  LOG((0, "Unknown class: %d", type->nc_type_class));
2025  return NC_EBADTYPE;
2026  }
2027  }
2028 
2029  /* Call self for each child of this group. */
2030  if (grp->children)
2031  {
2032  for (g = grp->children; g; g = g->l.next)
2033  if ((retval = rec_print_metadata(g, tab_count + 1)))
2034  return retval;
2035  }
2036 
2037  return NC_NOERR;
2038 }
2039 
2048 int
2049 log_metadata_nc(NC *nc)
2050 {
2051  NC_HDF5_FILE_INFO_T *h5 = NC4_DATA(nc);
2052 
2053  LOG((2, "*** NetCDF-4 Internal Metadata: int_ncid 0x%x ext_ncid 0x%x",
2054  nc->int_ncid, nc->ext_ncid));
2055  if (!h5)
2056  {
2057  LOG((2, "This is a netCDF-3 file."));
2058  return NC_NOERR;
2059  }
2060  LOG((2, "FILE - hdfid: 0x%x path: %s cmode: 0x%x parallel: %d redef: %d "
2061  "fill_mode: %d no_write: %d next_nc_grpid: %d", h5->hdfid, nc->path,
2062  h5->cmode, (int)h5->parallel, (int)h5->redef, h5->fill_mode, (int)h5->no_write,
2063  h5->next_nc_grpid));
2064  return rec_print_metadata(h5->root_grp, 0);
2065 }
2066 
2067 #endif /*LOGGING */
2068 
2077 int
2078 NC4_show_metadata(int ncid)
2079 {
2080  int retval = NC_NOERR;
2081 #ifdef LOGGING
2082  NC *nc;
2083  int old_log_level = nc_log_level;
2084 
2085  /* Find file metadata. */
2086  if (!(nc = nc4_find_nc_file(ncid,NULL)))
2087  return NC_EBADID;
2088 
2089  /* Log level must be 2 to see metadata. */
2090  nc_log_level = 2;
2091  retval = log_metadata_nc(nc);
2092  nc_log_level = old_log_level;
2093 #endif /*LOGGING*/
2094  return retval;
2095 }
#define NC_ENOMEM
Memory allocation (malloc) failure.
Definition: netcdf.h:395
#define NC_ENOTNC4
Attempting netcdf-4 operation on netcdf-3 file.
Definition: netcdf.h:437
#define NC_CLASSIC_MODEL
Enforce classic model on netCDF-4.
Definition: netcdf.h:135
#define NC_EHDFERR
Error at HDF5 layer.
Definition: netcdf.h:427
#define NC_OPAQUE
opaque types
Definition: netcdf.h:53
#define nc_set_log_level(e)
Get rid of these calls.
Definition: netcdf.h:1741
#define NC_STRING
string
Definition: netcdf.h:46
size_t nc4_chunk_cache_nelems
Default chunk cache number of elements.
Definition: nc4file.c:671
int nc_type
The nc_type type is just an int.
Definition: netcdf.h:24
#define NC_EBADDIM
Invalid dimension id or name.
Definition: netcdf.h:358
#define NC_ENAMEINUSE
String match to name in use.
Definition: netcdf.h:354
#define NC_VLEN
vlen (variable-length) types
Definition: netcdf.h:52
int nc4_hdf5_initialized
True if initialization has happened.
Definition: nc4internal.c:57
#define NC_EBADTYPE
Not a netcdf data type.
Definition: netcdf.h:357
#define NC_EDIMMETA
Problem with dimension metadata.
Definition: netcdf.h:432
#define NC_EINVAL
Invalid Argument.
Definition: netcdf.h:325
#define NC_ESTRICTNC3
Attempting netcdf-4 operation on strict nc3 netcdf-4 file.
Definition: netcdf.h:438
#define NC_MAX_NAME
Maximum for classic library.
Definition: netcdf.h:265
#define NC_EBADTYPID
Bad type ID.
Definition: netcdf.h:443
EXTERNL int nc_free_vlen(nc_vlen_t *vl)
Free memory in a VLEN object.
Definition: dvlen.c:31
#define NC_EBADID
Not a netcdf id.
Definition: netcdf.h:322
size_t nc4_chunk_cache_size
Default chunk cache size.
Definition: nc4file.c:670
This is the type of arrays of vlens.
Definition: netcdf.h:667
#define NC_ENOTVAR
Variable not found.
Definition: netcdf.h:369
#define NC_EMAXNAME
NC_MAX_NAME exceeded.
Definition: netcdf.h:373
#define NC_NOERR
No Error.
Definition: netcdf.h:315
#define NC_ENUM
enum types
Definition: netcdf.h:54
float nc4_chunk_cache_preemption
Default chunk cache preemption.
Definition: nc4file.c:672
#define NC_COMPOUND
compound types
Definition: netcdf.h:55
#define NC_GLOBAL
Attribute id to put/get a global attribute.
Definition: netcdf.h:238
#define NC_ENOTATT
Attribute not found.
Definition: netcdf.h:355

Return to the Main Unidata NetCDF page.
Generated on Fri May 11 2018 21:22:25 for NetCDF. NetCDF is a Unidata library.