NetCDF  4.6.2
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 
24 /* These are the default chunk cache sizes for HDF5 files created or
25  * opened with netCDF-4. */
26 extern size_t nc4_chunk_cache_size;
27 extern size_t nc4_chunk_cache_nelems;
28 extern float nc4_chunk_cache_preemption;
29 
30 #ifdef LOGGING
31 /* This is the severity level of messages which will be logged. Use
32  severity 0 for errors, 1 for important log messages, 2 for less
33  important, etc. */
34 int nc_log_level = NC_TURN_OFF_LOGGING;
35 #endif /* LOGGING */
36 
49 int
50 nc4_check_name(const char *name, char *norm_name)
51 {
52  char *temp;
53  int retval;
54 
55  assert(norm_name);
56 
57  /* Check for NULL. */
58  if (!name)
59  return NC_EINVAL;
60 
61  /* Make sure this is a valid netcdf name. This should be done
62  * before the name is normalized, because it gives better error
63  * codes for bad utf8 strings. */
64  if ((retval = NC_check_name(name)))
65  return retval;
66 
67  /* Normalize the name. */
68  if ((retval = nc_utf8_normalize((const unsigned char *)name,
69  (unsigned char **)&temp)))
70  return retval;
71 
72  /* Check length of normalized name. */
73  if (strlen(temp) > NC_MAX_NAME)
74  {
75  free(temp);
76  return NC_EMAXNAME;
77  }
78 
79  /* Copy the normalized name. */
80  strcpy(norm_name, temp);
81  free(temp);
82 
83  return NC_NOERR;
84 }
85 
98 int
99 nc4_nc4f_list_add(NC *nc, const char *path, int mode)
100 {
101  NC_FILE_INFO_T *h5;
102  int retval;
103 
104  assert(nc && !NC4_DATA(nc) && path);
105 
106  /* We need to malloc and initialize the substructure
107  NC_HDF_FILE_INFO_T. */
108  if (!(h5 = calloc(1, sizeof(NC_FILE_INFO_T))))
109  return NC_ENOMEM;
110  nc->dispatchdata = h5;
111  h5->controller = nc;
112 
113  /* Hang on to cmode, and note that we're in define mode. */
114  h5->cmode = mode | NC_INDEF;
115 
116  /* The next_typeid needs to be set beyond the end of our atomic
117  * types. */
118  h5->next_typeid = NC_FIRSTUSERTYPEID;
119 
120  /* Initialize lists for dimensions, types, and groups. */
121  h5->alldims = nclistnew();
122  h5->alltypes = nclistnew();
123  h5->allgroups = nclistnew();
124 
125  /* There's always at least one open group - the root
126  * group. Allocate space for one group's worth of information. Set
127  * its hdf id, name, and a pointer to it's file structure. */
128  if ((retval = nc4_grp_list_add(h5, NULL, NC_GROUP_NAME, &h5->root_grp)))
129  return retval;
130 
131  return NC_NOERR;
132 }
133 
146 int
147 nc4_find_nc4_grp(int ncid, NC_GRP_INFO_T **grp)
148 {
149  return nc4_find_nc_grp_h5(ncid, NULL, grp, NULL);
150 }
151 
167 int
168 nc4_find_grp_h5(int ncid, NC_GRP_INFO_T **grp, NC_FILE_INFO_T **h5)
169 {
170  return nc4_find_nc_grp_h5(ncid, NULL, grp, h5);
171 }
172 
187 int
188 nc4_find_nc_grp_h5(int ncid, NC **nc, NC_GRP_INFO_T **grp, NC_FILE_INFO_T **h5)
189 {
190  NC_GRP_INFO_T *my_grp = NULL;
191  NC_FILE_INFO_T *my_h5 = NULL;
192  NC *my_nc;
193  int retval;
194 
195  /* Look up file metadata. */
196  if ((retval = NC_check_id(ncid, &my_nc)))
197  return retval;
198  my_h5 = my_nc->dispatchdata;
199  assert(my_h5 && my_h5->root_grp);
200 
201  /* If we can't find it, the grp id part of ncid is bad. */
202  if (!(my_grp = nclistget(my_h5->allgroups, (ncid & GRP_ID_MASK))))
203  return NC_EBADID;
204 
205  /* Return pointers to caller, if desired. */
206  if (nc)
207  *nc = my_nc;
208  if (h5)
209  *h5 = my_h5;
210  if (grp)
211  *grp = my_grp;
212 
213  return NC_NOERR;
214 }
215 
231 int
232 nc4_find_grp_h5_var(int ncid, int varid, NC_FILE_INFO_T **h5, NC_GRP_INFO_T **grp,
233  NC_VAR_INFO_T **var)
234 {
235  NC_FILE_INFO_T *my_h5;
236  NC_GRP_INFO_T *my_grp;
237  NC_VAR_INFO_T *my_var;
238  int retval;
239 
240  /* Look up file and group metadata. */
241  if ((retval = nc4_find_grp_h5(ncid, &my_grp, &my_h5)))
242  return retval;
243  assert(my_grp && my_h5);
244 
245  /* Find the var. */
246  if (!(my_var = (NC_VAR_INFO_T *)ncindexith(my_grp->vars, varid)))
247  return NC_ENOTVAR;
248  assert(my_var && my_var->hdr.id == varid);
249 
250  /* Return pointers that caller wants. */
251  if (h5)
252  *h5 = my_h5;
253  if (grp)
254  *grp = my_grp;
255  if (var)
256  *var = my_var;
257 
258  return NC_NOERR;
259 }
260 
274 int
275 nc4_find_dim(NC_GRP_INFO_T *grp, int dimid, NC_DIM_INFO_T **dim,
276  NC_GRP_INFO_T **dim_grp)
277 {
278  assert(grp && grp->nc4_info && dim);
279 
280  /* Find the dim info. */
281  if (!((*dim) = nclistget(grp->nc4_info->alldims, dimid)))
282  return NC_EBADDIM;
283 
284  /* Give the caller the group the dimension is in. */
285  if (dim_grp)
286  *dim_grp = (*dim)->container;
287 
288  return NC_NOERR;
289 }
290 
301 int
302 nc4_find_var(NC_GRP_INFO_T *grp, const char *name, NC_VAR_INFO_T **var)
303 {
304  assert(grp && var && name);
305 
306  /* Find the var info. */
307  *var = (NC_VAR_INFO_T*)ncindexlookup(grp->vars,name);
308  return NC_NOERR;
309 }
310 
320 NC_TYPE_INFO_T *
321 nc4_rec_find_named_type(NC_GRP_INFO_T *start_grp, char *name)
322 {
323  NC_GRP_INFO_T *g;
324  NC_TYPE_INFO_T *type, *res;
325  int i;
326 
327  assert(start_grp);
328 
329  /* Does this group have the type we are searching for? */
330  type = (NC_TYPE_INFO_T*)ncindexlookup(start_grp->type,name);
331  if(type != NULL)
332  return type;
333 
334  /* Search subgroups. */
335  for(i=0;i<ncindexsize(start_grp->children);i++) {
336  g = (NC_GRP_INFO_T*)ncindexith(start_grp->children,i);
337  if(g == NULL) continue;
338  if ((res = nc4_rec_find_named_type(g, name)))
339  return res;
340  }
341  /* Can't find it. Oh, woe is me! */
342  return NULL;
343 }
344 
356 int
357 nc4_find_type(const NC_FILE_INFO_T *h5, nc_type typeid, NC_TYPE_INFO_T **type)
358 {
359  /* Check inputs. */
360  assert(h5);
361  if (typeid < 0 || !type)
362  return NC_EINVAL;
363  *type = NULL;
364 
365  /* Atomic types don't have associated NC_TYPE_INFO_T struct, just
366  * return NOERR. */
367  if (typeid <= NC_STRING)
368  return NC_NOERR;
369 
370  /* Find the type. */
371  if (!(*type = nclistget(h5->alltypes,typeid)))
372  return NC_EBADTYPID;
373 
374  return NC_NOERR;
375 }
376 
392 int
393 nc4_find_grp_att(NC_GRP_INFO_T *grp, int varid, const char *name, int attnum,
394  NC_ATT_INFO_T **att)
395 {
396  NC_VAR_INFO_T *var;
397  NCindex* attlist = NULL;
398  int retval;
399 
400  assert(grp && grp->hdr.name);
401  LOG((4, "nc4_find_grp_att: grp->name %s varid %d name %s attnum %d",
402  grp->hdr.name, varid, name, attnum));
403 
404  /* Get either the global or a variable attribute list. */
405  if (varid == NC_GLOBAL)
406  {
407  attlist = grp->att;
408 
409  /* Do we need to read the atts? */
410  if (grp->atts_not_read)
411  if ((retval = nc4_read_atts(grp, NULL)))
412  return retval;
413  }
414  else
415  {
416  var = (NC_VAR_INFO_T*)ncindexith(grp->vars,varid);
417  if (!var) return NC_ENOTVAR;
418 
419  /* Do we need to read the var attributes? */
420  if (var->atts_not_read)
421  if ((retval = nc4_read_atts(grp, var)))
422  return retval;
423 
424  attlist = var->att;
425  assert(var->hdr.id == varid);
426  }
427 
428  /* Now find the attribute by name or number. If a name is provided,
429  * ignore the attnum. */
430  if (attlist)
431  {
432  NC_ATT_INFO_T *my_att;
433  if (name)
434  my_att = (NC_ATT_INFO_T *)ncindexlookup(attlist, name);
435  else
436  my_att = (NC_ATT_INFO_T *)ncindexith(attlist, attnum);
437  if (my_att)
438  {
439  *att = my_att;
440  return NC_NOERR;
441  }
442  }
443 
444  /* If we get here, we couldn't find the attribute. */
445  return NC_ENOTATT;
446 }
447 
464 int
465 nc4_find_nc_att(int ncid, int varid, const char *name, int attnum,
466  NC_ATT_INFO_T **att)
467 {
468  NC_GRP_INFO_T *grp;
469  int retval;
470 
471  LOG((4, "nc4_find_nc_att: ncid 0x%x varid %d name %s attnum %d",
472  ncid, varid, name, attnum));
473 
474  /* Find info for this file and group, and set pointer to each. */
475  if ((retval = nc4_find_grp_h5(ncid, &grp, NULL)))
476  return retval;
477  assert(grp);
478 
479  return nc4_find_grp_att(grp, varid, name, attnum, att);
480 }
481 
490 static void
491 obj_track(NC_FILE_INFO_T* file, NC_OBJ* obj)
492 {
493  NClist* list = NULL;
494  /* record the object in the file */
495  switch (obj->sort) {
496  case NCDIM: list = file->alldims; break;
497  case NCTYP: list = file->alltypes; break;
498  case NCGRP: list = file->allgroups; break;
499  default:
500  assert(NC_FALSE);
501  }
502  /* Insert at the appropriate point in the list */
503  nclistset(list,obj->id,obj);
504 }
505 
520 int
521 nc4_var_list_add2(NC_GRP_INFO_T *grp, const char *name, NC_VAR_INFO_T **var)
522 {
523  NC_VAR_INFO_T *new_var;
524 
525  /* Allocate storage for new variable. */
526  if (!(new_var = calloc(1, sizeof(NC_VAR_INFO_T))))
527  return NC_ENOMEM;
528  new_var->hdr.sort = NCVAR;
529 
530  /* These are the HDF5-1.8.4 defaults. */
531  new_var->chunk_cache_size = nc4_chunk_cache_size;
532  new_var->chunk_cache_nelems = nc4_chunk_cache_nelems;
533  new_var->chunk_cache_preemption = nc4_chunk_cache_preemption;
534 
535  /* Now fill in the values in the var info structure. */
536  new_var->hdr.id = ncindexsize(grp->vars);
537  if (!(new_var->hdr.name = strdup(name)))
538  return NC_ENOMEM;
539  new_var->hdr.hashkey = NC_hashmapkey(new_var->hdr.name,
540  strlen(new_var->hdr.name));
541 
542  /* Create an indexed list for the attributes. */
543  new_var->att = ncindexnew(0);
544 
545  /* Officially track it */
546  ncindexadd(grp->vars, (NC_OBJ *)new_var);
547 
548  /* Set the var pointer, if one was given */
549  if (var)
550  *var = new_var;
551 
552  return NC_NOERR;
553 }
554 
567 int
568 nc4_var_set_ndims(NC_VAR_INFO_T *var, int ndims)
569 {
570 
571  /* Remember the number of dimensions. */
572  var->ndims = ndims;
573 
574  /* Allocate space for dimension information. */
575  if (ndims)
576  {
577  if (!(var->dim = calloc(ndims, sizeof(NC_DIM_INFO_T *))))
578  return NC_ENOMEM;
579  if (!(var->dimids = calloc(ndims, sizeof(int))))
580  return NC_ENOMEM;
581 
582  /* Initialize dimids to illegal values (-1). See the comment
583  in nc4hdf.c#nc4_rec_match_dimscales. */
584  memset(var->dimids, -1, ndims * sizeof(int));
585  }
586 
587  return NC_NOERR;
588 }
589 
604 int
605 nc4_var_list_add(NC_GRP_INFO_T* grp, const char* name, int ndims,
606  NC_VAR_INFO_T **var)
607 {
608  int retval;
609 
610  if ((retval = nc4_var_list_add2(grp, name, var)))
611  return retval;
612  if ((retval = nc4_var_set_ndims(*var, ndims)))
613  return retval;
614 
615  return NC_NOERR;
616 }
617 
631 int
632 nc4_dim_list_add(NC_GRP_INFO_T *grp, const char *name, size_t len,
633  int assignedid, NC_DIM_INFO_T **dim)
634 {
635  NC_DIM_INFO_T *new_dim;
636 
637  assert(grp && name);
638 
639  /* Allocate memory for dim metadata. */
640  if (!(new_dim = calloc(1, sizeof(NC_DIM_INFO_T))))
641  return NC_ENOMEM;
642 
643  new_dim->hdr.sort = NCDIM;
644 
645  /* Assign the dimension ID. */
646  if (assignedid >= 0)
647  new_dim->hdr.id = assignedid;
648  else
649  new_dim->hdr.id = grp->nc4_info->next_dimid++;
650 
651  /* Remember the name and create a hash. */
652  if (!(new_dim->hdr.name = strdup(name)))
653  return NC_ENOMEM;
654  new_dim->hdr.hashkey = NC_hashmapkey(new_dim->hdr.name,
655  strlen(new_dim->hdr.name));
656 
657  /* Is dimension unlimited? */
658  new_dim->len = len;
659  if (len == NC_UNLIMITED)
660  new_dim->unlimited = NC_TRUE;
661 
662  /* Remember the containing group. */
663  new_dim->container = grp;
664 
665  /* Add object to dimension list for this group. */
666  ncindexadd(grp->dim, (NC_OBJ *)new_dim);
667  obj_track(grp->nc4_info, (NC_OBJ *)new_dim);
668 
669  /* Set the dim pointer, if one was given */
670  if (dim)
671  *dim = new_dim;
672 
673  return NC_NOERR;
674 }
675 
688 int
689 nc4_att_list_add(NCindex *list, const char *name, NC_ATT_INFO_T **att)
690 {
691  NC_ATT_INFO_T *new_att;
692 
693  LOG((3, "%s: name %s ", __func__, name));
694 
695  if (!(new_att = calloc(1, sizeof(NC_ATT_INFO_T))))
696  return NC_ENOMEM;
697  new_att->hdr.sort = NCATT;
698 
699  /* Fill in the information we know. */
700  new_att->hdr.id = ncindexsize(list);
701  if (!(new_att->hdr.name = strdup(name)))
702  return NC_ENOMEM;
703 
704  /* Create a hash of the name. */
705  new_att->hdr.hashkey = NC_hashmapkey(name, strlen(name));
706 
707  /* Add object to list as specified by its number */
708  ncindexadd(list, (NC_OBJ *)new_att);
709 
710  /* Set the attribute pointer, if one was given */
711  if (att)
712  *att = new_att;
713 
714  return NC_NOERR;
715 }
716 
731 int
732 nc4_grp_list_add(NC_FILE_INFO_T *h5, NC_GRP_INFO_T *parent, char *name,
733  NC_GRP_INFO_T **grp)
734 {
735  NC_GRP_INFO_T *new_grp;
736 
737  /* Check inputs. */
738  assert(h5 && name);
739  LOG((3, "%s: name %s ", __func__, name));
740 
741  /* Get the memory to store this groups info. */
742  if (!(new_grp = calloc(1, sizeof(NC_GRP_INFO_T))))
743  return NC_ENOMEM;
744 
745  /* Fill in this group's information. */
746  new_grp->hdr.sort = NCGRP;
747  new_grp->nc4_info = h5;
748  new_grp->parent = parent;
749 
750  /* Assign the group ID. The root group will get id 0. */
751  new_grp->hdr.id = h5->next_nc_grpid++;
752  assert(parent || !new_grp->hdr.id);
753 
754  /* Handle the group name. */
755  if (!(new_grp->hdr.name = strdup(name)))
756  {
757  free(new_grp);
758  return NC_ENOMEM;
759  }
760  new_grp->hdr.hashkey = NC_hashmapkey(new_grp->hdr.name,
761  strlen(new_grp->hdr.name));
762 
763  /* Set up new indexed lists for stuff this group can contain. */
764  new_grp->children = ncindexnew(0);
765  new_grp->dim = ncindexnew(0);
766  new_grp->att = ncindexnew(0);
767  new_grp->type = ncindexnew(0);
768  new_grp->vars = ncindexnew(0);
769 
770  /* Add object to lists */
771  if (parent)
772  ncindexadd(parent->children, (NC_OBJ *)new_grp);
773  obj_track(h5, (NC_OBJ *)new_grp);
774 
775  /* Set the group pointer, if one was given */
776  if (grp)
777  *grp = new_grp;
778 
779  return NC_NOERR;
780 }
781 
795 int
796 nc4_check_dup_name(NC_GRP_INFO_T *grp, char *name)
797 {
798  NC_TYPE_INFO_T *type;
799  NC_GRP_INFO_T *g;
800  NC_VAR_INFO_T *var;
801 
802  /* Any types of this name? */
803  type = (NC_TYPE_INFO_T*)ncindexlookup(grp->type,name);
804  if(type != NULL)
805  return NC_ENAMEINUSE;
806 
807  /* Any child groups of this name? */
808  g = (NC_GRP_INFO_T*)ncindexlookup(grp->children,name);
809  if(g != NULL)
810  return NC_ENAMEINUSE;
811 
812  /* Any variables of this name? */
813  var = (NC_VAR_INFO_T*)ncindexlookup(grp->vars,name);
814  if(var != NULL)
815  return NC_ENAMEINUSE;
816 
817  return NC_NOERR;
818 }
819 
834 int
835 nc4_type_new(NC_GRP_INFO_T *grp, size_t size, const char *name, int assignedid,
836  NC_TYPE_INFO_T **type)
837 {
838  NC_TYPE_INFO_T *new_type;
839 
840  /* Check inputs. */
841  assert(type);
842 
843  /* Allocate memory for the type */
844  if (!(new_type = calloc(1, sizeof(NC_TYPE_INFO_T))))
845  return NC_ENOMEM;
846  new_type->hdr.sort = NCTYP;
847 
848  /* Remember info about this type. */
849  new_type->hdr.id = assignedid;
850  new_type->size = size;
851  if (!(new_type->hdr.name = strdup(name))) {
852  free(new_type);
853  return NC_ENOMEM;
854  }
855 
856  new_type->hdr.hashkey = NC_hashmapkey(name, strlen(name));
857 
858  /* Return a pointer to the new type. */
859  *type = new_type;
860 
861  return NC_NOERR;
862 }
863 
877 int
878 nc4_type_list_add(NC_GRP_INFO_T *grp, size_t size, const char *name,
879  NC_TYPE_INFO_T **type)
880 {
881  NC_TYPE_INFO_T *new_type;
882  int retval;
883 
884  /* Check inputs. */
885  assert(type);
886 
887  /* Create the new TYPE_INFO struct. */
888  if ((retval = nc4_type_new(grp, size, name, grp->nc4_info->next_typeid,
889  &new_type)))
890  return retval;
891  grp->nc4_info->next_typeid++;
892 
893  /* Increment the ref. count on the type */
894  new_type->rc++;
895 
896  /* Add object to lists */
897  ncindexadd(grp->type, (NC_OBJ *)new_type);
898  obj_track(grp->nc4_info,(NC_OBJ*)new_type);
899 
900  /* Return a pointer to the new type. */
901  *type = new_type;
902 
903  return NC_NOERR;
904 }
905 
921 int
922 nc4_field_list_add(NC_TYPE_INFO_T *parent, const char *name,
923  size_t offset, hid_t field_hdf_typeid, hid_t native_typeid,
924  nc_type xtype, int ndims, const int *dim_sizesp)
925 {
926  NC_FIELD_INFO_T *field;
927 
928  /* Name has already been checked and UTF8 normalized. */
929  if (!name)
930  return NC_EINVAL;
931 
932  /* Allocate storage for this field information. */
933  if (!(field = calloc(1, sizeof(NC_FIELD_INFO_T))))
934  return NC_ENOMEM;
935  field->hdr.sort = NCFLD;
936 
937  /* Store the information about this field. */
938  if (!(field->hdr.name = strdup(name)))
939  {
940  free(field);
941  return NC_ENOMEM;
942  }
943  field->hdr.hashkey = NC_hashmapkey(field->hdr.name,strlen(field->hdr.name));
944  field->hdf_typeid = field_hdf_typeid;
945  field->native_hdf_typeid = native_typeid;
946  field->nc_typeid = xtype;
947  field->offset = offset;
948  field->ndims = ndims;
949  if (ndims)
950  {
951  int i;
952  if (!(field->dim_size = malloc(ndims * sizeof(int))))
953  {
954  free(field->hdr.name);
955  free(field);
956  return NC_ENOMEM;
957  }
958  for (i = 0; i < ndims; i++)
959  field->dim_size[i] = dim_sizesp[i];
960  }
961 
962  /* Add object to lists */
963  field->hdr.id = nclistlength(parent->u.c.field);
964  nclistpush(parent->u.c.field,field);
965 
966  return NC_NOERR;
967 }
968 
981 int
982 nc4_enum_member_add(NC_TYPE_INFO_T *parent, size_t size,
983  const char *name, const void *value)
984 {
985  NC_ENUM_MEMBER_INFO_T *member;
986 
987  /* Name has already been checked. */
988  assert(name && size > 0 && value);
989  LOG((4, "%s: size %d name %s", __func__, size, name));
990 
991  /* Allocate storage for this field information. */
992  if (!(member = calloc(1, sizeof(NC_ENUM_MEMBER_INFO_T))))
993  return NC_ENOMEM;
994  if (!(member->value = malloc(size))) {
995  free(member);
996  return NC_ENOMEM;
997  }
998  if (!(member->name = strdup(name))) {
999  free(member->value);
1000  free(member);
1001  return NC_ENOMEM;
1002  }
1003 
1004  /* Store the value for this member. */
1005  memcpy(member->value, value, size);
1006 
1007  /* Add object to list */
1008  nclistpush(parent->u.e.enum_member,member);
1009 
1010  return NC_NOERR;
1011 }
1012 
1021 static void
1022 field_free(NC_FIELD_INFO_T *field)
1023 {
1024  /* Free some stuff. */
1025  if (field->hdr.name)
1026  free(field->hdr.name);
1027  if (field->dim_size)
1028  free(field->dim_size);
1029 
1030  /* Nc_Free the memory. */
1031  free(field);
1032 }
1033 
1043 int
1044 nc4_type_free(NC_TYPE_INFO_T *type)
1045 {
1046  int i;
1047 
1048  assert(type && type->rc && type->hdr.name);
1049 
1050  /* Decrement the ref. count on the type */
1051  type->rc--;
1052 
1053  /* Release the type, if the ref. count drops to zero */
1054  if (type->rc == 0)
1055  {
1056  LOG((4, "%s: deleting type %s", __func__, type->hdr.name));
1057 
1058  /* Free the name. */
1059  free(type->hdr.name);
1060 
1061  /* Enums and compound types have lists of fields to clean up. */
1062  switch (type->nc_type_class)
1063  {
1064  case NC_COMPOUND:
1065  {
1066  NC_FIELD_INFO_T *field;
1067 
1068  /* Delete all the fields in this type (there will be some if its a
1069  * compound). */
1070  for(i=0;i<nclistlength(type->u.c.field);i++) {
1071  field = nclistget(type->u.c.field,i);
1072  field_free(field);
1073  }
1074  nclistfree(type->u.c.field);
1075  }
1076  break;
1077 
1078  case NC_ENUM:
1079  {
1080  NC_ENUM_MEMBER_INFO_T *enum_member;
1081 
1082  /* Delete all the enum_members, if any. */
1083  for(i=0;i<nclistlength(type->u.e.enum_member);i++) {
1084  enum_member = nclistget(type->u.e.enum_member,i);
1085  free(enum_member->value);
1086  free(enum_member->name);
1087  free(enum_member);
1088  }
1089  nclistfree(type->u.e.enum_member);
1090  }
1091  break;
1092 
1093  default:
1094  break;
1095  }
1096 
1097  /* Release the memory. */
1098  free(type);
1099  }
1100 
1101  return NC_NOERR;
1102 }
1103 
1112 static int
1113 att_free(NC_ATT_INFO_T *att)
1114 {
1115  int i;
1116 
1117  assert(att);
1118  LOG((3, "%s: name %s ", __func__, att->hdr.name));
1119 
1120  /* Free memory that was malloced to hold data for this
1121  * attribute. */
1122  if (att->data)
1123  free(att->data);
1124 
1125  /* Free the name. */
1126  if (att->hdr.name)
1127  free(att->hdr.name);
1128 
1129  /* If this is a string array attribute, delete all members of the
1130  * string array, then delete the array of pointers to strings. (The
1131  * array was filled with pointers by HDF5 when the att was read,
1132  * and memory for each string was allocated by HDF5. That's why I
1133  * use free and not nc_free, because the netCDF library didn't
1134  * allocate the memory that is being freed.) */
1135  if (att->stdata)
1136  {
1137  for (i = 0; i < att->len; i++)
1138  if(att->stdata[i])
1139  free(att->stdata[i]);
1140  free(att->stdata);
1141  }
1142 
1143  /* If this att has vlen data, release it. */
1144  if (att->vldata)
1145  {
1146  for (i = 0; i < att->len; i++)
1147  nc_free_vlen(&att->vldata[i]);
1148  free(att->vldata);
1149  }
1150 
1151  /* Free any format-sepecific info. Some formats use this (ex. HDF5)
1152  * and some don't (ex. HDF4). So it may be NULL. */
1153  if (att->format_att_info)
1154  free(att->format_att_info);
1155 
1156  free(att);
1157  return NC_NOERR;
1158 }
1159 
1169 static int
1170 var_free(NC_VAR_INFO_T *var)
1171 {
1172  int i;
1173  int retval;
1174 
1175  assert(var);
1176  LOG((4, "%s: deleting var %s", __func__, var->hdr.name));
1177 
1178  /* First delete all the attributes attached to this var. */
1179  for (i = 0; i < ncindexsize(var->att); i++)
1180  if ((retval = att_free((NC_ATT_INFO_T *)ncindexith(var->att, i))))
1181  return retval;
1182  ncindexfree(var->att);
1183 
1184  /* Free some things that may be allocated. */
1185  /* Free some things that may be allocated. */
1186  if (var->chunksizes)
1187  free(var->chunksizes);
1188 
1189  if (var->hdf5_name)
1190  free(var->hdf5_name);
1191 
1192  if (var->hdr.name)
1193  free(var->hdr.name);
1194 
1195  if (var->dimids)
1196  free(var->dimids);
1197 
1198  if (var->dim)
1199  free(var->dim);
1200 
1201  /* Delete any fill value allocation. This must be done before the
1202  * type_info is freed. */
1203  if (var->fill_value)
1204  {
1205  if (var->hdf_datasetid)
1206  {
1207  if (var->type_info)
1208  {
1209  if (var->type_info->nc_type_class == NC_VLEN)
1210  nc_free_vlen((nc_vlen_t *)var->fill_value);
1211  else if (var->type_info->nc_type_class == NC_STRING && *(char **)var->fill_value)
1212  free(*(char **)var->fill_value);
1213  }
1214  }
1215  free(var->fill_value);
1216  }
1217 
1218  /* Release type information */
1219  if (var->type_info)
1220  if ((retval = nc4_type_free(var->type_info)))
1221  return retval;
1222 
1223  /* Delete any HDF5 dimscale objid information. */
1224  if (var->dimscale_hdf5_objids)
1225  free(var->dimscale_hdf5_objids);
1226 
1227  /* Delete information about the attachment status of dimscales. */
1228  if (var->dimscale_attached)
1229  free(var->dimscale_attached);
1230 
1231  /* Release parameter information. */
1232  if (var->params)
1233  free(var->params);
1234 
1235  /* Delete the var. */
1236  free(var);
1237 
1238  return NC_NOERR;
1239 }
1240 
1250 int
1251 nc4_var_list_del(NC_GRP_INFO_T* grp, NC_VAR_INFO_T *var)
1252 {
1253  int i;
1254 
1255  if(var == NULL)
1256  return NC_NOERR;
1257 
1258  /* Remove from lists */
1259  if(grp) {
1260  i = ncindexfind(grp->vars,(NC_OBJ*)var);
1261  if(i >= 0)
1262  ncindexidel(grp->vars, i);
1263  }
1264  return var_free(var);
1265 }
1266 
1275 static int
1276 dim_free(NC_DIM_INFO_T *dim)
1277 {
1278  assert(dim);
1279  LOG((4, "%s: deleting dim %s", __func__, dim->hdr.name));
1280 
1281  /* Free memory allocated for names. */
1282  if (dim->hdr.name)
1283  free(dim->hdr.name);
1284 
1285  /* Release any format-specific information. */
1286  if (dim->format_dim_info)
1287  free(dim->format_dim_info);
1288 
1289  free(dim);
1290  return NC_NOERR;
1291 }
1292 
1302 int
1303 nc4_dim_list_del(NC_GRP_INFO_T* grp, NC_DIM_INFO_T *dim)
1304 {
1305  if(grp && dim) {
1306  int pos = ncindexfind(grp->dim,(NC_OBJ*)dim);
1307  if(pos >= 0)
1308  ncindexidel(grp->dim,pos);
1309  }
1310  return dim_free(dim);
1311 }
1312 
1322 int
1323 nc4_rec_grp_del(NC_GRP_INFO_T *grp)
1324 {
1325  int i;
1326  int retval;
1327 
1328  assert(grp);
1329  LOG((3, "%s: grp->name %s", __func__, grp->hdr.name));
1330 
1331  /* Recursively call this function for each child, if any, stopping
1332  * if there is an error. */
1333  for (i = 0; i < ncindexsize(grp->children); i++)
1334  if ((retval = nc4_rec_grp_del((NC_GRP_INFO_T *)ncindexith(grp->children,
1335  i))))
1336  return retval;
1337  ncindexfree(grp->children);
1338 
1339  /* Free attributes, but leave in parent list */
1340  for (i = 0; i < ncindexsize(grp->att); i++)
1341  if ((retval = att_free((NC_ATT_INFO_T *)ncindexith(grp->att, i))))
1342  return retval;
1343  ncindexfree(grp->att);
1344 
1345  /* Delete all vars. */
1346  for (i = 0; i < ncindexsize(grp->vars); i++)
1347  if ((retval = var_free((NC_VAR_INFO_T *)ncindexith(grp->vars, i))))
1348  return retval;
1349  ncindexfree(grp->vars);
1350 
1351  /* Delete all dims, and free the list of dims. */
1352  for (i = 0; i < ncindexsize(grp->dim); i++)
1353  if ((retval = dim_free((NC_DIM_INFO_T *)ncindexith(grp->dim, i))))
1354  return retval;
1355  ncindexfree(grp->dim);
1356 
1357  /* Delete all types. */
1358  for (i = 0; i < ncindexsize(grp->type); i++)
1359  if ((retval = nc4_type_free((NC_TYPE_INFO_T *)ncindexith(grp->type, i))))
1360  return retval;
1361  ncindexfree(grp->type);
1362 
1363  /* Free the name. */
1364  free(grp->hdr.name);
1365 
1366  /* Release any format-specific information about this group. */
1367  if (grp->format_grp_info)
1368  free(grp->format_grp_info);
1369 
1370  /* Free up this group */
1371  free(grp);
1372 
1373  return NC_NOERR;
1374 }
1375 
1386 int
1387 nc4_att_list_del(NCindex *list, NC_ATT_INFO_T *att)
1388 {
1389  assert(att && list);
1390  ncindexidel(list, ((NC_OBJ *)att)->id);
1391  return att_free(att);
1392 }
1393 
1407 int
1408 nc4_normalize_name(const char *name, char *norm_name)
1409 {
1410  char *temp_name;
1411  int stat = nc_utf8_normalize((const unsigned char *)name,(unsigned char **)&temp_name);
1412  if(stat != NC_NOERR)
1413  return stat;
1414  if (strlen(temp_name) > NC_MAX_NAME)
1415  {
1416  free(temp_name);
1417  return NC_EMAXNAME;
1418  }
1419  strcpy(norm_name, temp_name);
1420  free(temp_name);
1421  return NC_NOERR;
1422 }
1423 
1424 #ifdef ENABLE_SET_LOG_LEVEL
1425 
1440 int
1441 nc_set_log_level(int new_level)
1442 {
1443 #ifdef LOGGING
1444  if(!nc4_hdf5_initialized)
1445  nc4_hdf5_initialize();
1446 
1447  /* Now remember the new level. */
1448  nc_log_level = new_level;
1449  LOG((4, "log_level changed to %d", nc_log_level));
1450 #endif /*LOGGING */
1451  return 0;
1452 }
1453 #endif /* ENABLE_SET_LOG_LEVEL */
1454 
1455 #ifdef LOGGING
1456 #define MAX_NESTS 10
1457 
1466 static int
1467 rec_print_metadata(NC_GRP_INFO_T *grp, int tab_count)
1468 {
1469  NC_GRP_INFO_T *g;
1470  NC_ATT_INFO_T *att;
1471  NC_VAR_INFO_T *var;
1472  NC_DIM_INFO_T *dim;
1473  NC_TYPE_INFO_T *type;
1474  NC_FIELD_INFO_T *field;
1475  char tabs[MAX_NESTS+1] = "";
1476  char *dims_string = NULL;
1477  char temp_string[10];
1478  int t, retval, d, i;
1479 
1480  /* Come up with a number of tabs relative to the group. */
1481  for (t = 0; t < tab_count && t < MAX_NESTS; t++)
1482  tabs[t] = '\t';
1483  tabs[t] = '\0';
1484 
1485  LOG((2, "%s GROUP - %s nc_grpid: %d nvars: %d natts: %d",
1486  tabs, grp->hdr.name, grp->hdr.id, ncindexsize(grp->vars), ncindexsize(grp->att)));
1487 
1488  for(i=0;i<ncindexsize(grp->att);i++) {
1489  att = (NC_ATT_INFO_T*)ncindexith(grp->att,i);
1490  if(att == NULL) continue;
1491  LOG((2, "%s GROUP ATTRIBUTE - attnum: %d name: %s type: %d len: %d",
1492  tabs, att->hdr.id, att->hdr.name, att->nc_typeid, att->len));
1493  }
1494 
1495  for(i=0;i<ncindexsize(grp->dim);i++) {
1496  dim = (NC_DIM_INFO_T*)ncindexith(grp->dim,i);
1497  if(dim == NULL) continue;
1498  LOG((2, "%s DIMENSION - dimid: %d name: %s len: %d unlimited: %d",
1499  tabs, dim->hdr.id, dim->hdr.name, dim->len, dim->unlimited));
1500  }
1501 
1502  for(i=0;i<ncindexsize(grp->vars);i++)
1503  {
1504  int j;
1505  var = (NC_VAR_INFO_T*)ncindexith(grp->vars,i);
1506  if (var == NULL) continue;
1507  if(var->ndims > 0)
1508  {
1509  dims_string = (char*)malloc(sizeof(char)*(var->ndims*4));
1510  strcpy(dims_string, "");
1511  for (d = 0; d < var->ndims; d++)
1512  {
1513  sprintf(temp_string, " %d", var->dimids[d]);
1514  strcat(dims_string, temp_string);
1515  }
1516  }
1517  LOG((2, "%s VARIABLE - varid: %d name: %s ndims: %d dimscale: %d dimids:%s",
1518  tabs, var->hdr.id, var->hdr.name, var->ndims, (int)var->dimscale,
1519  (dims_string ? dims_string : " -")));
1520  for(j=0;j<ncindexsize(var->att);j++) {
1521  att = (NC_ATT_INFO_T*)ncindexith(var->att,j);
1522  if(att == NULL) continue;
1523  LOG((2, "%s VAR ATTRIBUTE - attnum: %d name: %s type: %d len: %d",
1524  tabs, att->hdr.id, att->hdr.name, att->nc_typeid, att->len));
1525  }
1526  if(dims_string)
1527  {
1528  free(dims_string);
1529  dims_string = NULL;
1530  }
1531  }
1532 
1533  for(i=0;i<ncindexsize(grp->type);i++)
1534  {
1535  if((type = (NC_TYPE_INFO_T*)ncindexith(grp->type,i)) == NULL) continue;
1536  LOG((2, "%s TYPE - nc_typeid: %d hdf_typeid: 0x%x committed: %d "
1537  "name: %s num_fields: %d", tabs, type->hdr.id,
1538  type->hdf_typeid, type->size, (int)type->committed, type->hdr.name));
1539  /* Is this a compound type? */
1540  if (type->nc_type_class == NC_COMPOUND)
1541  {
1542  int j;
1543  LOG((3, "compound type"));
1544  for(j=0;j<nclistlength(type->u.c.field);j++) {
1545  field = (NC_FIELD_INFO_T*)nclistget(type->u.c.field,j);
1546  LOG((4, "field %s offset %d nctype %d ndims %d", field->hdr.name,
1547  field->offset, field->nc_typeid, field->ndims));
1548  }
1549  }
1550  else if (type->nc_type_class == NC_VLEN)
1551  {
1552  LOG((3, "VLEN type"));
1553  LOG((4, "base_nc_type: %d", type->u.v.base_nc_typeid));
1554  }
1555  else if (type->nc_type_class == NC_OPAQUE)
1556  LOG((3, "Opaque type"));
1557  else if (type->nc_type_class == NC_ENUM)
1558  {
1559  LOG((3, "Enum type"));
1560  LOG((4, "base_nc_type: %d", type->u.e.base_nc_typeid));
1561  }
1562  else
1563  {
1564  LOG((0, "Unknown class: %d", type->nc_type_class));
1565  return NC_EBADTYPE;
1566  }
1567  }
1568 
1569  /* Call self for each child of this group. */
1570  for(i=0;i<ncindexsize(grp->children);i++)
1571  {
1572  if((g = (NC_GRP_INFO_T*)ncindexith(grp->children,i)) == NULL) continue;
1573  if ((retval = rec_print_metadata(g, tab_count + 1)))
1574  return retval;
1575  }
1576  return NC_NOERR;
1577 }
1578 
1589 int
1590 log_metadata_nc(NC_FILE_INFO_T *h5)
1591 {
1592  LOG((2, "*** NetCDF-4 Internal Metadata: int_ncid 0x%x ext_ncid 0x%x",
1593  h5->root_grp->nc4_info->controller->int_ncid,
1594  h5->root_grp->nc4_info->controller->ext_ncid));
1595  if (!h5)
1596  {
1597  LOG((2, "This is a netCDF-3 file."));
1598  return NC_NOERR;
1599  }
1600  LOG((2, "FILE - path: %s cmode: 0x%x parallel: %d redef: %d "
1601  "fill_mode: %d no_write: %d next_nc_grpid: %d", h5->root_grp->nc4_info->controller->path,
1602  h5->cmode, (int)h5->parallel, (int)h5->redef, h5->fill_mode, (int)h5->no_write,
1603  h5->next_nc_grpid));
1604  if(nc_log_level >= 2)
1605  return rec_print_metadata(h5->root_grp, 0);
1606  return NC_NOERR;
1607 }
1608 
1609 #endif /*LOGGING */
1610 
1622 int
1623 NC4_show_metadata(int ncid)
1624 {
1625  int retval = NC_NOERR;
1626 #ifdef LOGGING
1627  NC_FILE_INFO_T *h5;
1628  int old_log_level = nc_log_level;
1629 
1630  /* Find file metadata. */
1631  if ((retval = nc4_find_grp_h5(ncid, NULL, &h5)))
1632  return retval;
1633 
1634  /* Log level must be 2 to see metadata. */
1635  nc_log_level = 2;
1636  retval = log_metadata_nc(h5);
1637  nc_log_level = old_log_level;
1638 #endif /*LOGGING*/
1639  return retval;
1640 }
#define NC_ENOMEM
Memory allocation (malloc) failure.
Definition: netcdf.h:402
#define NC_OPAQUE
opaque types
Definition: netcdf.h:53
#define NC_STRING
string
Definition: netcdf.h:46
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:365
#define NC_ENAMEINUSE
String match to name in use.
Definition: netcdf.h:361
#define NC_VLEN
vlen (variable-length) types
Definition: netcdf.h:52
#define NC_EBADTYPE
Not a netcdf data type.
Definition: netcdf.h:364
#define NC_EINVAL
Invalid Argument.
Definition: netcdf.h:332
#define NC_MAX_NAME
Maximum for classic library.
Definition: netcdf.h:272
#define NC_EBADTYPID
Bad type ID.
Definition: netcdf.h:451
EXTERNL int nc_free_vlen(nc_vlen_t *vl)
Free memory in a VLEN object.
Definition: dvlen.c:41
#define NC_EBADID
Not a netcdf id.
Definition: netcdf.h:329
#define NC_UNLIMITED
Size argument to nc_def_dim() for an unlimited dimension.
Definition: netcdf.h:242
This is the type of arrays of vlens.
Definition: netcdf.h:684
#define NC_ENOTVAR
Variable not found.
Definition: netcdf.h:376
#define NC_EMAXNAME
NC_MAX_NAME exceeded.
Definition: netcdf.h:380
#define NC_NOERR
No Error.
Definition: netcdf.h:322
#define NC_ENUM
enum types
Definition: netcdf.h:54
#define NC_COMPOUND
compound types
Definition: netcdf.h:55
#define NC_GLOBAL
Attribute id to put/get a global attribute.
Definition: netcdf.h:245
#define NC_ENOTATT
Attribute not found.
Definition: netcdf.h:362

Return to the Main Unidata NetCDF page.
Generated on Tue Nov 20 2018 06:04:35 for NetCDF. NetCDF is a Unidata library.