NetCDF  4.6.3
 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 
24 /* These hold the file caching settings for the library. */
25 size_t nc4_chunk_cache_size = CHUNK_CACHE_SIZE;
26 size_t nc4_chunk_cache_nelems = CHUNK_CACHE_NELEMS;
27 float nc4_chunk_cache_preemption = CHUNK_CACHE_PREEMPTION;
29 #ifdef LOGGING
30 /* This is the severity level of messages which will be logged. Use
31  severity 0 for errors, 1 for important log messages, 2 for less
32  important, etc. */
33 int nc_log_level = NC_TURN_OFF_LOGGING;
34 #endif /* LOGGING */
35 
48 int
49 nc4_check_name(const char *name, char *norm_name)
50 {
51  char *temp;
52  int retval;
53 
54  assert(norm_name);
55 
56  /* Check for NULL. */
57  if (!name)
58  return NC_EINVAL;
59 
60  /* Make sure this is a valid netcdf name. This should be done
61  * before the name is normalized, because it gives better error
62  * codes for bad utf8 strings. */
63  if ((retval = NC_check_name(name)))
64  return retval;
65 
66  /* Normalize the name. */
67  if ((retval = nc_utf8_normalize((const unsigned char *)name,
68  (unsigned char **)&temp)))
69  return retval;
70 
71  /* Check length of normalized name. */
72  if (strlen(temp) > NC_MAX_NAME)
73  {
74  free(temp);
75  return NC_EMAXNAME;
76  }
77 
78  /* Copy the normalized name. */
79  strcpy(norm_name, temp);
80  free(temp);
81 
82  return NC_NOERR;
83 }
84 
97 int
98 nc4_nc4f_list_add(NC *nc, const char *path, int mode)
99 {
100  NC_FILE_INFO_T *h5;
101  int retval;
102 
103  assert(nc && !NC4_DATA(nc) && path);
104 
105  /* We need to malloc and initialize the substructure
106  NC_HDF_FILE_INFO_T. */
107  if (!(h5 = calloc(1, sizeof(NC_FILE_INFO_T))))
108  return NC_ENOMEM;
109  nc->dispatchdata = h5;
110  h5->controller = nc;
111 
112  /* Hang on to cmode, and note that we're in define mode. */
113  h5->cmode = mode | NC_INDEF;
114 
115  /* The next_typeid needs to be set beyond the end of our atomic
116  * types. */
117  h5->next_typeid = NC_FIRSTUSERTYPEID;
118 
119  /* Initialize lists for dimensions, types, and groups. */
120  h5->alldims = nclistnew();
121  h5->alltypes = nclistnew();
122  h5->allgroups = nclistnew();
123 
124  /* There's always at least one open group - the root
125  * group. Allocate space for one group's worth of information. Set
126  * its hdf id, name, and a pointer to it's file structure. */
127  if ((retval = nc4_grp_list_add(h5, NULL, NC_GROUP_NAME, &h5->root_grp)))
128  return retval;
129 
130  return NC_NOERR;
131 }
132 
145 int
146 nc4_find_nc4_grp(int ncid, NC_GRP_INFO_T **grp)
147 {
148  return nc4_find_nc_grp_h5(ncid, NULL, grp, NULL);
149 }
150 
166 int
167 nc4_find_grp_h5(int ncid, NC_GRP_INFO_T **grp, NC_FILE_INFO_T **h5)
168 {
169  return nc4_find_nc_grp_h5(ncid, NULL, grp, h5);
170 }
171 
186 int
187 nc4_find_nc_grp_h5(int ncid, NC **nc, NC_GRP_INFO_T **grp, NC_FILE_INFO_T **h5)
188 {
189  NC_GRP_INFO_T *my_grp = NULL;
190  NC_FILE_INFO_T *my_h5 = NULL;
191  NC *my_nc;
192  int retval;
193 
194  /* Look up file metadata. */
195  if ((retval = NC_check_id(ncid, &my_nc)))
196  return retval;
197  my_h5 = my_nc->dispatchdata;
198  assert(my_h5 && my_h5->root_grp);
199 
200  /* If we can't find it, the grp id part of ncid is bad. */
201  if (!(my_grp = nclistget(my_h5->allgroups, (ncid & GRP_ID_MASK))))
202  return NC_EBADID;
203 
204  /* Return pointers to caller, if desired. */
205  if (nc)
206  *nc = my_nc;
207  if (h5)
208  *h5 = my_h5;
209  if (grp)
210  *grp = my_grp;
211 
212  return NC_NOERR;
213 }
214 
230 int
231 nc4_find_grp_h5_var(int ncid, int varid, NC_FILE_INFO_T **h5, NC_GRP_INFO_T **grp,
232  NC_VAR_INFO_T **var)
233 {
234  NC_FILE_INFO_T *my_h5;
235  NC_GRP_INFO_T *my_grp;
236  NC_VAR_INFO_T *my_var;
237  int retval;
238 
239  /* Look up file and group metadata. */
240  if ((retval = nc4_find_grp_h5(ncid, &my_grp, &my_h5)))
241  return retval;
242  assert(my_grp && my_h5);
243 
244  /* Find the var. */
245  if (!(my_var = (NC_VAR_INFO_T *)ncindexith(my_grp->vars, varid)))
246  return NC_ENOTVAR;
247  assert(my_var && my_var->hdr.id == varid);
248 
249  /* Return pointers that caller wants. */
250  if (h5)
251  *h5 = my_h5;
252  if (grp)
253  *grp = my_grp;
254  if (var)
255  *var = my_var;
256 
257  return NC_NOERR;
258 }
259 
273 int
274 nc4_find_dim(NC_GRP_INFO_T *grp, int dimid, NC_DIM_INFO_T **dim,
275  NC_GRP_INFO_T **dim_grp)
276 {
277  assert(grp && grp->nc4_info && dim);
278  LOG((4, "%s: dimid %d", __func__, dimid));
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  NC_ATT_INFO_T *my_att;
398  NCindex *attlist = NULL;
399 
400  assert(grp && grp->hdr.name && att);
401 
402  LOG((4, "%s: grp->name %s varid %d attnum %d", __func__, grp->hdr.name,
403  varid, attnum));
404 
405  /* Get either the global or a variable attribute list. */
406  if (varid == NC_GLOBAL)
407  {
408  attlist = grp->att;
409  }
410  else
411  {
412  var = (NC_VAR_INFO_T*)ncindexith(grp->vars,varid);
413  if (!var) return NC_ENOTVAR;
414 
415  attlist = var->att;
416  }
417  assert(attlist);
418 
419  /* Now find the attribute by name or number. If a name is provided,
420  * ignore the attnum. */
421  if (name)
422  my_att = (NC_ATT_INFO_T *)ncindexlookup(attlist, name);
423  else
424  my_att = (NC_ATT_INFO_T *)ncindexith(attlist, attnum);
425 
426  if (!my_att)
427  return NC_ENOTATT;
428 
429  *att = my_att;
430  return NC_NOERR;
431 }
432 
449 int
450 nc4_find_nc_att(int ncid, int varid, const char *name, int attnum,
451  NC_ATT_INFO_T **att)
452 {
453  NC_GRP_INFO_T *grp;
454  int retval;
455 
456  LOG((4, "nc4_find_nc_att: ncid 0x%x varid %d name %s attnum %d",
457  ncid, varid, name, attnum));
458 
459  /* Find info for this file and group, and set pointer to each. */
460  if ((retval = nc4_find_grp_h5(ncid, &grp, NULL)))
461  return retval;
462  assert(grp);
463 
464  return nc4_find_grp_att(grp, varid, name, attnum, att);
465 }
466 
475 static void
476 obj_track(NC_FILE_INFO_T* file, NC_OBJ* obj)
477 {
478  NClist* list = NULL;
479  /* record the object in the file */
480  switch (obj->sort) {
481  case NCDIM: list = file->alldims; break;
482  case NCTYP: list = file->alltypes; break;
483  case NCGRP: list = file->allgroups; break;
484  default:
485  assert(NC_FALSE);
486  }
487  /* Insert at the appropriate point in the list */
488  nclistset(list,obj->id,obj);
489 }
490 
505 int
506 nc4_var_list_add2(NC_GRP_INFO_T *grp, const char *name, NC_VAR_INFO_T **var)
507 {
508  NC_VAR_INFO_T *new_var;
509 
510  /* Allocate storage for new variable. */
511  if (!(new_var = calloc(1, sizeof(NC_VAR_INFO_T))))
512  return NC_ENOMEM;
513  new_var->hdr.sort = NCVAR;
514  new_var->container = grp;
515 
516  /* These are the HDF5-1.8.4 defaults. */
517  new_var->chunk_cache_size = nc4_chunk_cache_size;
518  new_var->chunk_cache_nelems = nc4_chunk_cache_nelems;
519  new_var->chunk_cache_preemption = nc4_chunk_cache_preemption;
520 
521  /* Now fill in the values in the var info structure. */
522  new_var->hdr.id = ncindexsize(grp->vars);
523  if (!(new_var->hdr.name = strdup(name)))
524  return NC_ENOMEM;
525  new_var->hdr.hashkey = NC_hashmapkey(new_var->hdr.name,
526  strlen(new_var->hdr.name));
527 
528  /* Create an indexed list for the attributes. */
529  new_var->att = ncindexnew(0);
530 
531  /* Officially track it */
532  ncindexadd(grp->vars, (NC_OBJ *)new_var);
533 
534  /* Set the var pointer, if one was given */
535  if (var)
536  *var = new_var;
537 
538  return NC_NOERR;
539 }
540 
553 int
554 nc4_var_set_ndims(NC_VAR_INFO_T *var, int ndims)
555 {
556  assert(var);
557 
558  /* Remember the number of dimensions. */
559  var->ndims = ndims;
560 
561  /* Allocate space for dimension information. */
562  if (ndims)
563  {
564  if (!(var->dim = calloc(ndims, sizeof(NC_DIM_INFO_T *))))
565  return NC_ENOMEM;
566  if (!(var->dimids = calloc(ndims, sizeof(int))))
567  return NC_ENOMEM;
568 
569  /* Initialize dimids to illegal values (-1). See the comment
570  in nc4_rec_match_dimscales(). */
571  memset(var->dimids, -1, ndims * sizeof(int));
572  }
573 
574  return NC_NOERR;
575 }
576 
591 int
592 nc4_var_list_add(NC_GRP_INFO_T* grp, const char* name, int ndims,
593  NC_VAR_INFO_T **var)
594 {
595  int retval;
596 
597  if ((retval = nc4_var_list_add2(grp, name, var)))
598  return retval;
599  if ((retval = nc4_var_set_ndims(*var, ndims)))
600  return retval;
601 
602  return NC_NOERR;
603 }
604 
618 int
619 nc4_dim_list_add(NC_GRP_INFO_T *grp, const char *name, size_t len,
620  int assignedid, NC_DIM_INFO_T **dim)
621 {
622  NC_DIM_INFO_T *new_dim;
623 
624  assert(grp && name);
625 
626  /* Allocate memory for dim metadata. */
627  if (!(new_dim = calloc(1, sizeof(NC_DIM_INFO_T))))
628  return NC_ENOMEM;
629 
630  new_dim->hdr.sort = NCDIM;
631 
632  /* Assign the dimension ID. */
633  if (assignedid >= 0)
634  new_dim->hdr.id = assignedid;
635  else
636  new_dim->hdr.id = grp->nc4_info->next_dimid++;
637 
638  /* Remember the name and create a hash. */
639  if (!(new_dim->hdr.name = strdup(name)))
640  return NC_ENOMEM;
641  new_dim->hdr.hashkey = NC_hashmapkey(new_dim->hdr.name,
642  strlen(new_dim->hdr.name));
643 
644  /* Is dimension unlimited? */
645  new_dim->len = len;
646  if (len == NC_UNLIMITED)
647  new_dim->unlimited = NC_TRUE;
648 
649  /* Remember the containing group. */
650  new_dim->container = grp;
651 
652  /* Add object to dimension list for this group. */
653  ncindexadd(grp->dim, (NC_OBJ *)new_dim);
654  obj_track(grp->nc4_info, (NC_OBJ *)new_dim);
655 
656  /* Set the dim pointer, if one was given */
657  if (dim)
658  *dim = new_dim;
659 
660  return NC_NOERR;
661 }
662 
675 int
676 nc4_att_list_add(NCindex *list, const char *name, NC_ATT_INFO_T **att)
677 {
678  NC_ATT_INFO_T *new_att;
679 
680  LOG((3, "%s: name %s ", __func__, name));
681 
682  if (!(new_att = calloc(1, sizeof(NC_ATT_INFO_T))))
683  return NC_ENOMEM;
684  new_att->hdr.sort = NCATT;
685 
686  /* Fill in the information we know. */
687  new_att->hdr.id = ncindexsize(list);
688  if (!(new_att->hdr.name = strdup(name)))
689  return NC_ENOMEM;
690 
691  /* Create a hash of the name. */
692  new_att->hdr.hashkey = NC_hashmapkey(name, strlen(name));
693 
694  /* Add object to list as specified by its number */
695  ncindexadd(list, (NC_OBJ *)new_att);
696 
697  /* Set the attribute pointer, if one was given */
698  if (att)
699  *att = new_att;
700 
701  return NC_NOERR;
702 }
703 
718 int
719 nc4_grp_list_add(NC_FILE_INFO_T *h5, NC_GRP_INFO_T *parent, char *name,
720  NC_GRP_INFO_T **grp)
721 {
722  NC_GRP_INFO_T *new_grp;
723 
724  /* Check inputs. */
725  assert(h5 && name);
726  LOG((3, "%s: name %s ", __func__, name));
727 
728  /* Get the memory to store this groups info. */
729  if (!(new_grp = calloc(1, sizeof(NC_GRP_INFO_T))))
730  return NC_ENOMEM;
731 
732  /* Fill in this group's information. */
733  new_grp->hdr.sort = NCGRP;
734  new_grp->nc4_info = h5;
735  new_grp->parent = parent;
736 
737  /* Assign the group ID. The root group will get id 0. */
738  new_grp->hdr.id = h5->next_nc_grpid++;
739  assert(parent || !new_grp->hdr.id);
740 
741  /* Handle the group name. */
742  if (!(new_grp->hdr.name = strdup(name)))
743  {
744  free(new_grp);
745  return NC_ENOMEM;
746  }
747  new_grp->hdr.hashkey = NC_hashmapkey(new_grp->hdr.name,
748  strlen(new_grp->hdr.name));
749 
750  /* Set up new indexed lists for stuff this group can contain. */
751  new_grp->children = ncindexnew(0);
752  new_grp->dim = ncindexnew(0);
753  new_grp->att = ncindexnew(0);
754  new_grp->type = ncindexnew(0);
755  new_grp->vars = ncindexnew(0);
756 
757  /* Add object to lists */
758  if (parent)
759  ncindexadd(parent->children, (NC_OBJ *)new_grp);
760  obj_track(h5, (NC_OBJ *)new_grp);
761 
762  /* Set the group pointer, if one was given */
763  if (grp)
764  *grp = new_grp;
765 
766  return NC_NOERR;
767 }
768 
782 int
783 nc4_check_dup_name(NC_GRP_INFO_T *grp, char *name)
784 {
785  NC_TYPE_INFO_T *type;
786  NC_GRP_INFO_T *g;
787  NC_VAR_INFO_T *var;
788 
789  /* Any types of this name? */
790  type = (NC_TYPE_INFO_T*)ncindexlookup(grp->type,name);
791  if(type != NULL)
792  return NC_ENAMEINUSE;
793 
794  /* Any child groups of this name? */
795  g = (NC_GRP_INFO_T*)ncindexlookup(grp->children,name);
796  if(g != NULL)
797  return NC_ENAMEINUSE;
798 
799  /* Any variables of this name? */
800  var = (NC_VAR_INFO_T*)ncindexlookup(grp->vars,name);
801  if(var != NULL)
802  return NC_ENAMEINUSE;
803 
804  return NC_NOERR;
805 }
806 
820 int
821 nc4_type_new(size_t size, const char *name, int assignedid,
822  NC_TYPE_INFO_T **type)
823 {
824  NC_TYPE_INFO_T *new_type;
825 
826  LOG((4, "%s: size %d name %s assignedid %d", __func__, size, name, assignedid));
827 
828  /* Check inputs. */
829  assert(type);
830 
831  /* Allocate memory for the type */
832  if (!(new_type = calloc(1, sizeof(NC_TYPE_INFO_T))))
833  return NC_ENOMEM;
834  new_type->hdr.sort = NCTYP;
835 
836  /* Remember info about this type. */
837  new_type->hdr.id = assignedid;
838  new_type->size = size;
839  if (!(new_type->hdr.name = strdup(name))) {
840  free(new_type);
841  return NC_ENOMEM;
842  }
843 
844  new_type->hdr.hashkey = NC_hashmapkey(name, strlen(name));
845 
846  /* Return a pointer to the new type. */
847  *type = new_type;
848 
849  return NC_NOERR;
850 }
851 
865 int
866 nc4_type_list_add(NC_GRP_INFO_T *grp, size_t size, const char *name,
867  NC_TYPE_INFO_T **type)
868 {
869  NC_TYPE_INFO_T *new_type;
870  int retval;
871 
872  /* Check inputs. */
873  assert(grp && name && type);
874  LOG((4, "%s: size %d name %s", __func__, size, name));
875 
876  /* Create the new TYPE_INFO struct. */
877  if ((retval = nc4_type_new(size, name, grp->nc4_info->next_typeid,
878  &new_type)))
879  return retval;
880  grp->nc4_info->next_typeid++;
881 
882  /* Increment the ref. count on the type */
883  new_type->rc++;
884 
885  /* Add object to lists */
886  ncindexadd(grp->type, (NC_OBJ *)new_type);
887  obj_track(grp->nc4_info,(NC_OBJ*)new_type);
888 
889  /* Return a pointer to the new type. */
890  *type = new_type;
891 
892  return NC_NOERR;
893 }
894 
908 int
909 nc4_field_list_add(NC_TYPE_INFO_T *parent, const char *name,
910  size_t offset, nc_type xtype, int ndims,
911  const int *dim_sizesp)
912 {
913  NC_FIELD_INFO_T *field;
914 
915  /* Name has already been checked and UTF8 normalized. */
916  if (!name)
917  return NC_EINVAL;
918 
919  /* Allocate storage for this field information. */
920  if (!(field = calloc(1, sizeof(NC_FIELD_INFO_T))))
921  return NC_ENOMEM;
922  field->hdr.sort = NCFLD;
923 
924  /* Store the information about this field. */
925  if (!(field->hdr.name = strdup(name)))
926  {
927  free(field);
928  return NC_ENOMEM;
929  }
930  field->hdr.hashkey = NC_hashmapkey(field->hdr.name,strlen(field->hdr.name));
931  field->nc_typeid = xtype;
932  field->offset = offset;
933  field->ndims = ndims;
934  if (ndims)
935  {
936  int i;
937  if (!(field->dim_size = malloc(ndims * sizeof(int))))
938  {
939  free(field->hdr.name);
940  free(field);
941  return NC_ENOMEM;
942  }
943  for (i = 0; i < ndims; i++)
944  field->dim_size[i] = dim_sizesp[i];
945  }
946 
947  /* Add object to lists */
948  field->hdr.id = nclistlength(parent->u.c.field);
949  nclistpush(parent->u.c.field,field);
950 
951  return NC_NOERR;
952 }
953 
966 int
967 nc4_enum_member_add(NC_TYPE_INFO_T *parent, size_t size,
968  const char *name, const void *value)
969 {
970  NC_ENUM_MEMBER_INFO_T *member;
971 
972  /* Name has already been checked. */
973  assert(name && size > 0 && value);
974  LOG((4, "%s: size %d name %s", __func__, size, name));
975 
976  /* Allocate storage for this field information. */
977  if (!(member = calloc(1, sizeof(NC_ENUM_MEMBER_INFO_T))))
978  return NC_ENOMEM;
979  if (!(member->value = malloc(size))) {
980  free(member);
981  return NC_ENOMEM;
982  }
983  if (!(member->name = strdup(name))) {
984  free(member->value);
985  free(member);
986  return NC_ENOMEM;
987  }
988 
989  /* Store the value for this member. */
990  memcpy(member->value, value, size);
991 
992  /* Add object to list */
993  nclistpush(parent->u.e.enum_member,member);
994 
995  return NC_NOERR;
996 }
997 
1006 static void
1007 field_free(NC_FIELD_INFO_T *field)
1008 {
1009  /* Free some stuff. */
1010  if (field->hdr.name)
1011  free(field->hdr.name);
1012  if (field->dim_size)
1013  free(field->dim_size);
1014 
1015  /* Nc_Free the memory. */
1016  free(field);
1017 }
1018 
1028 int
1029 nc4_type_free(NC_TYPE_INFO_T *type)
1030 {
1031  int i;
1032 
1033  assert(type && type->rc && type->hdr.name);
1034 
1035  /* Decrement the ref. count on the type */
1036  type->rc--;
1037 
1038  /* Release the type, if the ref. count drops to zero */
1039  if (type->rc == 0)
1040  {
1041  LOG((4, "%s: deleting type %s", __func__, type->hdr.name));
1042 
1043  /* Free the name. */
1044  free(type->hdr.name);
1045 
1046  /* Enums and compound types have lists of fields to clean up. */
1047  switch (type->nc_type_class)
1048  {
1049  case NC_COMPOUND:
1050  {
1051  NC_FIELD_INFO_T *field;
1052 
1053  /* Delete all the fields in this type (there will be some if its a
1054  * compound). */
1055  for(i=0;i<nclistlength(type->u.c.field);i++) {
1056  field = nclistget(type->u.c.field,i);
1057  field_free(field);
1058  }
1059  nclistfree(type->u.c.field);
1060  }
1061  break;
1062 
1063  case NC_ENUM:
1064  {
1065  NC_ENUM_MEMBER_INFO_T *enum_member;
1066 
1067  /* Delete all the enum_members, if any. */
1068  for(i=0;i<nclistlength(type->u.e.enum_member);i++) {
1069  enum_member = nclistget(type->u.e.enum_member,i);
1070  free(enum_member->value);
1071  free(enum_member->name);
1072  free(enum_member);
1073  }
1074  nclistfree(type->u.e.enum_member);
1075  }
1076  break;
1077 
1078  default:
1079  break;
1080  }
1081 
1082  /* Release any HDF5-specific type info. */
1083  if (type->format_type_info)
1084  free(type->format_type_info);
1085 
1086  /* Release the memory. */
1087  free(type);
1088  }
1089 
1090  return NC_NOERR;
1091 }
1092 
1101 static int
1102 att_free(NC_ATT_INFO_T *att)
1103 {
1104  int i;
1105 
1106  assert(att);
1107  LOG((3, "%s: name %s ", __func__, att->hdr.name));
1108 
1109  /* Free memory that was malloced to hold data for this
1110  * attribute. */
1111  if (att->data)
1112  free(att->data);
1113 
1114  /* Free the name. */
1115  if (att->hdr.name)
1116  free(att->hdr.name);
1117 
1118  /* If this is a string array attribute, delete all members of the
1119  * string array, then delete the array of pointers to strings. (The
1120  * array was filled with pointers by HDF5 when the att was read,
1121  * and memory for each string was allocated by HDF5. That's why I
1122  * use free and not nc_free, because the netCDF library didn't
1123  * allocate the memory that is being freed.) */
1124  if (att->stdata)
1125  {
1126  for (i = 0; i < att->len; i++)
1127  if(att->stdata[i])
1128  free(att->stdata[i]);
1129  free(att->stdata);
1130  }
1131 
1132  /* If this att has vlen data, release it. */
1133  if (att->vldata)
1134  {
1135  for (i = 0; i < att->len; i++)
1136  nc_free_vlen(&att->vldata[i]);
1137  free(att->vldata);
1138  }
1139 
1140  /* Free any format-sepecific info. Some formats use this (ex. HDF5)
1141  * and some don't (ex. HDF4). So it may be NULL. */
1142  if (att->format_att_info)
1143  free(att->format_att_info);
1144 
1145  free(att);
1146  return NC_NOERR;
1147 }
1148 
1158 static int
1159 var_free(NC_VAR_INFO_T *var)
1160 {
1161  int i;
1162  int retval;
1163 
1164  assert(var);
1165  LOG((4, "%s: deleting var %s", __func__, var->hdr.name));
1166 
1167  /* First delete all the attributes attached to this var. */
1168  for (i = 0; i < ncindexsize(var->att); i++)
1169  if ((retval = att_free((NC_ATT_INFO_T *)ncindexith(var->att, i))))
1170  return retval;
1171  ncindexfree(var->att);
1172 
1173  /* Free some things that may be allocated. */
1174  if (var->chunksizes)
1175  free(var->chunksizes);
1176 
1177  if (var->hdf5_name)
1178  free(var->hdf5_name);
1179 
1180  if (var->hdr.name)
1181  free(var->hdr.name);
1182 
1183  if (var->dimids)
1184  free(var->dimids);
1185 
1186  if (var->dim)
1187  free(var->dim);
1188 
1189  /* Delete any fill value allocation. */
1190  if (var->fill_value)
1191  free(var->fill_value);
1192 
1193  /* Release type information */
1194  if (var->type_info)
1195  if ((retval = nc4_type_free(var->type_info)))
1196  return retval;
1197 
1198  /* Delete information about the attachment status of dimscales. */
1199  if (var->dimscale_attached)
1200  free(var->dimscale_attached);
1201 
1202  /* Release parameter information. */
1203  if (var->params)
1204  free(var->params);
1205 
1206  /* Delete any format-specific info. */
1207  if (var->format_var_info)
1208  free(var->format_var_info);
1209 
1210  /* Delete the var. */
1211  free(var);
1212 
1213  return NC_NOERR;
1214 }
1215 
1225 int
1226 nc4_var_list_del(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var)
1227 {
1228  int i;
1229 
1230  assert(var && grp);
1231 
1232  /* Remove from lists */
1233  i = ncindexfind(grp->vars, (NC_OBJ *)var);
1234  if (i >= 0)
1235  ncindexidel(grp->vars, i);
1236 
1237  return var_free(var);
1238 }
1239 
1248 static int
1249 dim_free(NC_DIM_INFO_T *dim)
1250 {
1251  assert(dim);
1252  LOG((4, "%s: deleting dim %s", __func__, dim->hdr.name));
1253 
1254  /* Free memory allocated for names. */
1255  if (dim->hdr.name)
1256  free(dim->hdr.name);
1257 
1258  /* Release any format-specific information. */
1259  if (dim->format_dim_info)
1260  free(dim->format_dim_info);
1261 
1262  free(dim);
1263  return NC_NOERR;
1264 }
1265 
1275 int
1276 nc4_dim_list_del(NC_GRP_INFO_T* grp, NC_DIM_INFO_T *dim)
1277 {
1278  if(grp && dim) {
1279  int pos = ncindexfind(grp->dim,(NC_OBJ*)dim);
1280  if(pos >= 0)
1281  ncindexidel(grp->dim,pos);
1282  }
1283  return dim_free(dim);
1284 }
1285 
1295 int
1296 nc4_rec_grp_del(NC_GRP_INFO_T *grp)
1297 {
1298  int i;
1299  int retval;
1300 
1301  assert(grp);
1302  LOG((3, "%s: grp->name %s", __func__, grp->hdr.name));
1303 
1304  /* Recursively call this function for each child, if any, stopping
1305  * if there is an error. */
1306  for (i = 0; i < ncindexsize(grp->children); i++)
1307  if ((retval = nc4_rec_grp_del((NC_GRP_INFO_T *)ncindexith(grp->children,
1308  i))))
1309  return retval;
1310  ncindexfree(grp->children);
1311 
1312  /* Free attributes, but leave in parent list */
1313  for (i = 0; i < ncindexsize(grp->att); i++)
1314  if ((retval = att_free((NC_ATT_INFO_T *)ncindexith(grp->att, i))))
1315  return retval;
1316  ncindexfree(grp->att);
1317 
1318  /* Delete all vars. */
1319  for (i = 0; i < ncindexsize(grp->vars); i++)
1320  if ((retval = var_free((NC_VAR_INFO_T *)ncindexith(grp->vars, i))))
1321  return retval;
1322  ncindexfree(grp->vars);
1323 
1324  /* Delete all dims, and free the list of dims. */
1325  for (i = 0; i < ncindexsize(grp->dim); i++)
1326  if ((retval = dim_free((NC_DIM_INFO_T *)ncindexith(grp->dim, i))))
1327  return retval;
1328  ncindexfree(grp->dim);
1329 
1330  /* Delete all types. */
1331  for (i = 0; i < ncindexsize(grp->type); i++)
1332  if ((retval = nc4_type_free((NC_TYPE_INFO_T *)ncindexith(grp->type, i))))
1333  return retval;
1334  ncindexfree(grp->type);
1335 
1336  /* Free the name. */
1337  free(grp->hdr.name);
1338 
1339  /* Release any format-specific information about this group. */
1340  if (grp->format_grp_info)
1341  free(grp->format_grp_info);
1342 
1343  /* Free up this group */
1344  free(grp);
1345 
1346  return NC_NOERR;
1347 }
1348 
1359 int
1360 nc4_att_list_del(NCindex *list, NC_ATT_INFO_T *att)
1361 {
1362  assert(att && list);
1363  ncindexidel(list, ((NC_OBJ *)att)->id);
1364  return att_free(att);
1365 }
1366 
1380 int
1381 nc4_normalize_name(const char *name, char *norm_name)
1382 {
1383  char *temp_name;
1384  int stat = nc_utf8_normalize((const unsigned char *)name,(unsigned char **)&temp_name);
1385  if(stat != NC_NOERR)
1386  return stat;
1387  if (strlen(temp_name) > NC_MAX_NAME)
1388  {
1389  free(temp_name);
1390  return NC_EMAXNAME;
1391  }
1392  strcpy(norm_name, temp_name);
1393  free(temp_name);
1394  return NC_NOERR;
1395 }
1396 
1397 #ifdef ENABLE_SET_LOG_LEVEL
1398 
1413 int
1414 nc_set_log_level(int new_level)
1415 {
1416 #ifdef LOGGING
1417  /* Remember the new level. */
1418  nc_log_level = new_level;
1419  LOG((4, "log_level changed to %d", nc_log_level));
1420 #endif /*LOGGING */
1421  return 0;
1422 }
1423 #endif /* ENABLE_SET_LOG_LEVEL */
1424 
1425 #ifdef LOGGING
1426 #define MAX_NESTS 10
1427 
1436 static int
1437 rec_print_metadata(NC_GRP_INFO_T *grp, int tab_count)
1438 {
1439  NC_ATT_INFO_T *att;
1440  NC_VAR_INFO_T *var;
1441  NC_DIM_INFO_T *dim;
1442  NC_TYPE_INFO_T *type;
1443  NC_FIELD_INFO_T *field;
1444  char tabs[MAX_NESTS+1] = "";
1445  char *dims_string = NULL;
1446  char temp_string[10];
1447  int t, retval, d, i;
1448 
1449  /* Come up with a number of tabs relative to the group. */
1450  for (t = 0; t < tab_count && t < MAX_NESTS; t++)
1451  tabs[t] = '\t';
1452  tabs[t] = '\0';
1453 
1454  LOG((2, "%s GROUP - %s nc_grpid: %d nvars: %d natts: %d",
1455  tabs, grp->hdr.name, grp->hdr.id, ncindexsize(grp->vars), ncindexsize(grp->att)));
1456 
1457  for (i = 0; i < ncindexsize(grp->att); i++)
1458  {
1459  att = (NC_ATT_INFO_T *)ncindexith(grp->att, i);
1460  assert(att);
1461  LOG((2, "%s GROUP ATTRIBUTE - attnum: %d name: %s type: %d len: %d",
1462  tabs, att->hdr.id, att->hdr.name, att->nc_typeid, att->len));
1463  }
1464 
1465  for (i = 0; i < ncindexsize(grp->dim); i++)
1466  {
1467  dim = (NC_DIM_INFO_T *)ncindexith(grp->dim, i);
1468  assert(dim);
1469  LOG((2, "%s DIMENSION - dimid: %d name: %s len: %d unlimited: %d",
1470  tabs, dim->hdr.id, dim->hdr.name, dim->len, dim->unlimited));
1471  }
1472 
1473  for (i = 0; i < ncindexsize(grp->vars); i++)
1474  {
1475  int j;
1476  var = (NC_VAR_INFO_T*)ncindexith(grp->vars,i);
1477  assert(var);
1478  if (var->ndims > 0)
1479  {
1480  if (!(dims_string = malloc(sizeof(char) * var->ndims * 4)))
1481  return NC_ENOMEM;
1482  strcpy(dims_string, "");
1483  for (d = 0; d < var->ndims; d++)
1484  {
1485  sprintf(temp_string, " %d", var->dimids[d]);
1486  strcat(dims_string, temp_string);
1487  }
1488  }
1489  LOG((2, "%s VARIABLE - varid: %d name: %s ndims: %d dimscale: %d dimids:%s",
1490  tabs, var->hdr.id, var->hdr.name, var->ndims, (int)var->dimscale,
1491  (dims_string ? dims_string : " -")));
1492  for (j = 0; j < ncindexsize(var->att); j++)
1493  {
1494  att = (NC_ATT_INFO_T *)ncindexith(var->att, j);
1495  assert(att);
1496  LOG((2, "%s VAR ATTRIBUTE - attnum: %d name: %s type: %d len: %d",
1497  tabs, att->hdr.id, att->hdr.name, att->nc_typeid, att->len));
1498  }
1499  if (dims_string)
1500  free(dims_string);
1501  }
1502 
1503  for (i = 0; i < ncindexsize(grp->type); i++)
1504  {
1505  type = (NC_TYPE_INFO_T*)ncindexith(grp->type, i);
1506  assert(type);
1507  LOG((2, "%s TYPE - nc_typeid: %d size: %d committed: %d name: %s",
1508  tabs, type->hdr.id, type->size, (int)type->committed, type->hdr.name));
1509  /* Is this a compound type? */
1510  if (type->nc_type_class == NC_COMPOUND)
1511  {
1512  int j;
1513  LOG((3, "compound type"));
1514  for (j = 0; j < nclistlength(type->u.c.field); j++)
1515  {
1516  field = (NC_FIELD_INFO_T *)nclistget(type->u.c.field, j);
1517  LOG((4, "field %s offset %d nctype %d ndims %d", field->hdr.name,
1518  field->offset, field->nc_typeid, field->ndims));
1519  }
1520  }
1521  else if (type->nc_type_class == NC_VLEN)
1522  {
1523  LOG((3, "VLEN type"));
1524  LOG((4, "base_nc_type: %d", type->u.v.base_nc_typeid));
1525  }
1526  else if (type->nc_type_class == NC_OPAQUE)
1527  LOG((3, "Opaque type"));
1528  else if (type->nc_type_class == NC_ENUM)
1529  {
1530  LOG((3, "Enum type"));
1531  LOG((4, "base_nc_type: %d", type->u.e.base_nc_typeid));
1532  }
1533  else
1534  {
1535  LOG((0, "Unknown class: %d", type->nc_type_class));
1536  return NC_EBADTYPE;
1537  }
1538  }
1539 
1540  /* Call self for each child of this group. */
1541  for (i = 0; i < ncindexsize(grp->children); i++)
1542  if ((retval = rec_print_metadata((NC_GRP_INFO_T *)ncindexith(grp->children, i),
1543  tab_count + 1)))
1544  return retval;
1545 
1546  return NC_NOERR;
1547 }
1548 
1559 int
1560 log_metadata_nc(NC_FILE_INFO_T *h5)
1561 {
1562  LOG((2, "*** NetCDF-4 Internal Metadata: int_ncid 0x%x ext_ncid 0x%x",
1563  h5->root_grp->nc4_info->controller->int_ncid,
1564  h5->root_grp->nc4_info->controller->ext_ncid));
1565  if (!h5)
1566  {
1567  LOG((2, "This is a netCDF-3 file."));
1568  return NC_NOERR;
1569  }
1570  LOG((2, "FILE - path: %s cmode: 0x%x parallel: %d redef: %d "
1571  "fill_mode: %d no_write: %d next_nc_grpid: %d", h5->root_grp->nc4_info->controller->path,
1572  h5->cmode, (int)h5->parallel, (int)h5->redef, h5->fill_mode, (int)h5->no_write,
1573  h5->next_nc_grpid));
1574  if(nc_log_level >= 2)
1575  return rec_print_metadata(h5->root_grp, 0);
1576  return NC_NOERR;
1577 }
1578 
1579 #endif /*LOGGING */
1580 
1592 int
1593 NC4_show_metadata(int ncid)
1594 {
1595  int retval = NC_NOERR;
1596 #ifdef LOGGING
1597  NC_FILE_INFO_T *h5;
1598  int old_log_level = nc_log_level;
1599 
1600  /* Find file metadata. */
1601  if ((retval = nc4_find_grp_h5(ncid, NULL, &h5)))
1602  return retval;
1603 
1604  /* Log level must be 2 to see metadata. */
1605  nc_log_level = 2;
1606  retval = log_metadata_nc(h5);
1607  nc_log_level = old_log_level;
1608 #endif /*LOGGING*/
1609  return retval;
1610 }
#define NC_ENOMEM
Memory allocation (malloc) failure.
Definition: netcdf.h:403
#define NC_OPAQUE
opaque types
Definition: netcdf.h:54
#define NC_STRING
string
Definition: netcdf.h:47
size_t nc4_chunk_cache_nelems
Default chunk cache number of elements.
Definition: nc4internal.c:26
int nc_type
The nc_type type is just an int.
Definition: netcdf.h:25
#define NC_EBADDIM
Invalid dimension id or name.
Definition: netcdf.h:366
#define NC_ENAMEINUSE
String match to name in use.
Definition: netcdf.h:362
#define NC_VLEN
vlen (variable-length) types
Definition: netcdf.h:53
#define NC_EBADTYPE
Not a netcdf data type.
Definition: netcdf.h:365
#define NC_EINVAL
Invalid Argument.
Definition: netcdf.h:333
#define NC_MAX_NAME
Maximum for classic library.
Definition: netcdf.h:273
#define NC_EBADTYPID
Bad type ID.
Definition: netcdf.h:452
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:330
#define NC_UNLIMITED
Size argument to nc_def_dim() for an unlimited dimension.
Definition: netcdf.h:243
size_t nc4_chunk_cache_size
Default chunk cache size.
Definition: nc4internal.c:25
#define NC_ENOTVAR
Variable not found.
Definition: netcdf.h:377
#define NC_EMAXNAME
NC_MAX_NAME exceeded.
Definition: netcdf.h:381
#define NC_NOERR
No Error.
Definition: netcdf.h:323
#define NC_ENUM
enum types
Definition: netcdf.h:55
float nc4_chunk_cache_preemption
Default chunk cache preemption.
Definition: nc4internal.c:27
#define NC_COMPOUND
compound types
Definition: netcdf.h:56
#define NC_GLOBAL
Attribute id to put/get a global attribute.
Definition: netcdf.h:246
#define NC_ENOTATT
Attribute not found.
Definition: netcdf.h:363

Return to the Main Unidata NetCDF page.
Generated on Sat Apr 6 2019 08:19:00 for NetCDF. NetCDF is a Unidata library.