NetCDF  4.7.1
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 
105 int
106 nc4_file_list_add(int ncid, const char *path, int mode, void **dispatchdata)
107 {
108  NC *nc;
109  int ret;
110 
111  /* Find NC pointer for this file. */
112  if ((ret = NC_check_id(ncid, &nc)))
113  return ret;
114 
115  /* Add necessary structs to hold netcdf-4 file data. This is where
116  * the NC_FILE_INFO_T struct is allocated for the file. */
117  if ((ret = nc4_nc4f_list_add(nc, path, mode)))
118  return ret;
119 
120  /* If the user wants a pointer to the NC_FILE_INFO_T, then provide
121  * it. */
122  if (dispatchdata)
123  *dispatchdata = nc->dispatchdata;
124 
125  return NC_NOERR;
126 }
127 
128 /* /\** */
129 /* * @internal Change the ncid of an open file. This is needed for PIO */
130 /* * integration. */
131 /* * */
132 /* * @param ncid The ncid of the file (aka ext_ncid). */
133 /* * @param new_ncid The new ncid to use. */
134 /* * */
135 /* * @return ::NC_NOERR No error. */
136 /* * @return ::NC_EBADID No NC struct with this ext_ncid. */
137 /* * @return ::NC_ENOMEM Out of memory. */
138 /* * @author Ed Hartnett */
139 /* *\/ */
140 /* int */
141 /* nc4_file_change_ncid(int ncid, int new_ncid) */
142 /* { */
143 /* NC *nc; */
144 /* int ret; */
145 
146 /* /\* Find NC pointer for this file. *\/ */
147 /* if ((ret = NC_check_id(ncid, &nc))) */
148 /* return ret; */
149 
150 /* return NC_NOERR; */
151 /* } */
152 
172 int
173 nc4_file_list_get(int ncid, char **path, int *mode, void **dispatchdata)
174 {
175  NC *nc;
176  int ret;
177 
178  /* Find NC pointer for this file. */
179  if ((ret = NC_check_id(ncid, &nc)))
180  return ret;
181 
182  /* If the user wants path, give it. */
183  if (path)
184  strncpy(*path, nc->path, NC_MAX_NAME);
185 
186  /* If the user wants mode, give it. */
187  if (mode)
188  *mode = nc->mode;
189 
190  /* If the user wants dispatchdata, give it. */
191  if (dispatchdata)
192  *dispatchdata = nc->dispatchdata;
193 
194  return NC_NOERR;
195 }
196 
211 int
212 nc4_nc4f_list_add(NC *nc, const char *path, int mode)
213 {
214  NC_FILE_INFO_T *h5;
215  int retval;
216 
217  assert(nc && !NC4_DATA(nc) && path);
218 
219  /* We need to malloc and initialize the substructure
220  NC_FILE_INFO_T. */
221  if (!(h5 = calloc(1, sizeof(NC_FILE_INFO_T))))
222  return NC_ENOMEM;
223  nc->dispatchdata = h5;
224  h5->controller = nc;
225 
226  /* Hang on to cmode, and note that we're in define mode. */
227  h5->cmode = mode | NC_INDEF;
228 
229  /* The next_typeid needs to be set beyond the end of our atomic
230  * types. */
231  h5->next_typeid = NC_FIRSTUSERTYPEID;
232 
233  /* Initialize lists for dimensions, types, and groups. */
234  h5->alldims = nclistnew();
235  h5->alltypes = nclistnew();
236  h5->allgroups = nclistnew();
237 
238  /* There's always at least one open group - the root
239  * group. Allocate space for one group's worth of information. Set
240  * its grp id, name, and allocate associated empty lists. */
241  if ((retval = nc4_grp_list_add(h5, NULL, NC_GROUP_NAME, &h5->root_grp)))
242  return retval;
243 
244  return NC_NOERR;
245 }
246 
259 int
260 nc4_find_nc4_grp(int ncid, NC_GRP_INFO_T **grp)
261 {
262  return nc4_find_nc_grp_h5(ncid, NULL, grp, NULL);
263 }
264 
280 int
281 nc4_find_grp_h5(int ncid, NC_GRP_INFO_T **grp, NC_FILE_INFO_T **h5)
282 {
283  return nc4_find_nc_grp_h5(ncid, NULL, grp, h5);
284 }
285 
300 int
301 nc4_find_nc_grp_h5(int ncid, NC **nc, NC_GRP_INFO_T **grp, NC_FILE_INFO_T **h5)
302 {
303  NC_GRP_INFO_T *my_grp = NULL;
304  NC_FILE_INFO_T *my_h5 = NULL;
305  NC *my_nc;
306  int retval;
307 
308  /* Look up file metadata. */
309  if ((retval = NC_check_id(ncid, &my_nc)))
310  return retval;
311  my_h5 = my_nc->dispatchdata;
312  assert(my_h5 && my_h5->root_grp);
313 
314  /* If we can't find it, the grp id part of ncid is bad. */
315  if (!(my_grp = nclistget(my_h5->allgroups, (ncid & GRP_ID_MASK))))
316  return NC_EBADID;
317 
318  /* Return pointers to caller, if desired. */
319  if (nc)
320  *nc = my_nc;
321  if (h5)
322  *h5 = my_h5;
323  if (grp)
324  *grp = my_grp;
325 
326  return NC_NOERR;
327 }
328 
344 int
345 nc4_find_grp_h5_var(int ncid, int varid, NC_FILE_INFO_T **h5, NC_GRP_INFO_T **grp,
346  NC_VAR_INFO_T **var)
347 {
348  NC_FILE_INFO_T *my_h5;
349  NC_GRP_INFO_T *my_grp;
350  NC_VAR_INFO_T *my_var;
351  int retval;
352 
353  /* Look up file and group metadata. */
354  if ((retval = nc4_find_grp_h5(ncid, &my_grp, &my_h5)))
355  return retval;
356  assert(my_grp && my_h5);
357 
358  /* Find the var. */
359  if (!(my_var = (NC_VAR_INFO_T *)ncindexith(my_grp->vars, varid)))
360  return NC_ENOTVAR;
361  assert(my_var && my_var->hdr.id == varid);
362 
363  /* Return pointers that caller wants. */
364  if (h5)
365  *h5 = my_h5;
366  if (grp)
367  *grp = my_grp;
368  if (var)
369  *var = my_var;
370 
371  return NC_NOERR;
372 }
373 
387 int
388 nc4_find_dim(NC_GRP_INFO_T *grp, int dimid, NC_DIM_INFO_T **dim,
389  NC_GRP_INFO_T **dim_grp)
390 {
391  assert(grp && grp->nc4_info && dim);
392  LOG((4, "%s: dimid %d", __func__, dimid));
393 
394  /* Find the dim info. */
395  if (!((*dim) = nclistget(grp->nc4_info->alldims, dimid)))
396  return NC_EBADDIM;
397 
398  /* Give the caller the group the dimension is in. */
399  if (dim_grp)
400  *dim_grp = (*dim)->container;
401 
402  return NC_NOERR;
403 }
404 
415 int
416 nc4_find_var(NC_GRP_INFO_T *grp, const char *name, NC_VAR_INFO_T **var)
417 {
418  assert(grp && var && name);
419 
420  /* Find the var info. */
421  *var = (NC_VAR_INFO_T*)ncindexlookup(grp->vars,name);
422  return NC_NOERR;
423 }
424 
434 NC_TYPE_INFO_T *
435 nc4_rec_find_named_type(NC_GRP_INFO_T *start_grp, char *name)
436 {
437  NC_GRP_INFO_T *g;
438  NC_TYPE_INFO_T *type, *res;
439  int i;
440 
441  assert(start_grp);
442 
443  /* Does this group have the type we are searching for? */
444  type = (NC_TYPE_INFO_T*)ncindexlookup(start_grp->type,name);
445  if(type != NULL)
446  return type;
447 
448  /* Search subgroups. */
449  for(i=0;i<ncindexsize(start_grp->children);i++) {
450  g = (NC_GRP_INFO_T*)ncindexith(start_grp->children,i);
451  if(g == NULL) continue;
452  if ((res = nc4_rec_find_named_type(g, name)))
453  return res;
454  }
455  /* Can't find it. Oh, woe is me! */
456  return NULL;
457 }
458 
470 int
471 nc4_find_type(const NC_FILE_INFO_T *h5, nc_type typeid, NC_TYPE_INFO_T **type)
472 {
473  /* Check inputs. */
474  assert(h5);
475  if (typeid < 0 || !type)
476  return NC_EINVAL;
477  *type = NULL;
478 
479  /* Atomic types don't have associated NC_TYPE_INFO_T struct, just
480  * return NOERR. */
481  if (typeid <= NC_STRING)
482  return NC_NOERR;
483 
484  /* Find the type. */
485  if (!(*type = nclistget(h5->alltypes,typeid)))
486  return NC_EBADTYPID;
487 
488  return NC_NOERR;
489 }
490 
506 int
507 nc4_find_grp_att(NC_GRP_INFO_T *grp, int varid, const char *name, int attnum,
508  NC_ATT_INFO_T **att)
509 {
510  NC_VAR_INFO_T *var;
511  NC_ATT_INFO_T *my_att;
512  NCindex *attlist = NULL;
513 
514  assert(grp && grp->hdr.name && att);
515 
516  LOG((4, "%s: grp->name %s varid %d attnum %d", __func__, grp->hdr.name,
517  varid, attnum));
518 
519  /* Get either the global or a variable attribute list. */
520  if (varid == NC_GLOBAL)
521  {
522  attlist = grp->att;
523  }
524  else
525  {
526  var = (NC_VAR_INFO_T*)ncindexith(grp->vars,varid);
527  if (!var) return NC_ENOTVAR;
528 
529  attlist = var->att;
530  }
531  assert(attlist);
532 
533  /* Now find the attribute by name or number. If a name is provided,
534  * ignore the attnum. */
535  if (name)
536  my_att = (NC_ATT_INFO_T *)ncindexlookup(attlist, name);
537  else
538  my_att = (NC_ATT_INFO_T *)ncindexith(attlist, attnum);
539 
540  if (!my_att)
541  return NC_ENOTATT;
542 
543  *att = my_att;
544  return NC_NOERR;
545 }
546 
563 int
564 nc4_find_nc_att(int ncid, int varid, const char *name, int attnum,
565  NC_ATT_INFO_T **att)
566 {
567  NC_GRP_INFO_T *grp;
568  int retval;
569 
570  LOG((4, "nc4_find_nc_att: ncid 0x%x varid %d name %s attnum %d",
571  ncid, varid, name, attnum));
572 
573  /* Find info for this file and group, and set pointer to each. */
574  if ((retval = nc4_find_grp_h5(ncid, &grp, NULL)))
575  return retval;
576  assert(grp);
577 
578  return nc4_find_grp_att(grp, varid, name, attnum, att);
579 }
580 
589 static void
590 obj_track(NC_FILE_INFO_T* file, NC_OBJ* obj)
591 {
592  NClist* list = NULL;
593  /* record the object in the file */
594  switch (obj->sort) {
595  case NCDIM: list = file->alldims; break;
596  case NCTYP: list = file->alltypes; break;
597  case NCGRP: list = file->allgroups; break;
598  default:
599  assert(NC_FALSE);
600  }
601  /* Insert at the appropriate point in the list */
602  nclistset(list,obj->id,obj);
603 }
604 
619 int
620 nc4_var_list_add2(NC_GRP_INFO_T *grp, const char *name, NC_VAR_INFO_T **var)
621 {
622  NC_VAR_INFO_T *new_var;
623 
624  /* Allocate storage for new variable. */
625  if (!(new_var = calloc(1, sizeof(NC_VAR_INFO_T))))
626  return NC_ENOMEM;
627  new_var->hdr.sort = NCVAR;
628  new_var->container = grp;
629 
630  /* These are the HDF5-1.8.4 defaults. */
631  new_var->chunk_cache_size = nc4_chunk_cache_size;
632  new_var->chunk_cache_nelems = nc4_chunk_cache_nelems;
633  new_var->chunk_cache_preemption = nc4_chunk_cache_preemption;
634 
635  /* Now fill in the values in the var info structure. */
636  new_var->hdr.id = ncindexsize(grp->vars);
637  if (!(new_var->hdr.name = strdup(name)))
638  return NC_ENOMEM;
639  new_var->hdr.hashkey = NC_hashmapkey(new_var->hdr.name,
640  strlen(new_var->hdr.name));
641 
642  /* Create an indexed list for the attributes. */
643  new_var->att = ncindexnew(0);
644 
645  /* Officially track it */
646  ncindexadd(grp->vars, (NC_OBJ *)new_var);
647 
648  /* Set the var pointer, if one was given */
649  if (var)
650  *var = new_var;
651 
652  return NC_NOERR;
653 }
654 
667 int
668 nc4_var_set_ndims(NC_VAR_INFO_T *var, int ndims)
669 {
670  assert(var);
671 
672  /* Remember the number of dimensions. */
673  var->ndims = ndims;
674 
675  /* Allocate space for dimension information. */
676  if (ndims)
677  {
678  if (!(var->dim = calloc(ndims, sizeof(NC_DIM_INFO_T *))))
679  return NC_ENOMEM;
680  if (!(var->dimids = calloc(ndims, sizeof(int))))
681  return NC_ENOMEM;
682 
683  /* Initialize dimids to illegal values (-1). See the comment
684  in nc4_rec_match_dimscales(). */
685  memset(var->dimids, -1, ndims * sizeof(int));
686  }
687 
688  return NC_NOERR;
689 }
690 
705 int
706 nc4_var_list_add(NC_GRP_INFO_T* grp, const char* name, int ndims,
707  NC_VAR_INFO_T **var)
708 {
709  int retval;
710 
711  if ((retval = nc4_var_list_add2(grp, name, var)))
712  return retval;
713  if ((retval = nc4_var_set_ndims(*var, ndims)))
714  return retval;
715 
716  return NC_NOERR;
717 }
718 
732 int
733 nc4_dim_list_add(NC_GRP_INFO_T *grp, const char *name, size_t len,
734  int assignedid, NC_DIM_INFO_T **dim)
735 {
736  NC_DIM_INFO_T *new_dim;
737 
738  assert(grp && name);
739 
740  /* Allocate memory for dim metadata. */
741  if (!(new_dim = calloc(1, sizeof(NC_DIM_INFO_T))))
742  return NC_ENOMEM;
743 
744  new_dim->hdr.sort = NCDIM;
745 
746  /* Assign the dimension ID. */
747  if (assignedid >= 0)
748  new_dim->hdr.id = assignedid;
749  else
750  new_dim->hdr.id = grp->nc4_info->next_dimid++;
751 
752  /* Remember the name and create a hash. */
753  if (!(new_dim->hdr.name = strdup(name)))
754  return NC_ENOMEM;
755  new_dim->hdr.hashkey = NC_hashmapkey(new_dim->hdr.name,
756  strlen(new_dim->hdr.name));
757 
758  /* Is dimension unlimited? */
759  new_dim->len = len;
760  if (len == NC_UNLIMITED)
761  new_dim->unlimited = NC_TRUE;
762 
763  /* Remember the containing group. */
764  new_dim->container = grp;
765 
766  /* Add object to dimension list for this group. */
767  ncindexadd(grp->dim, (NC_OBJ *)new_dim);
768  obj_track(grp->nc4_info, (NC_OBJ *)new_dim);
769 
770  /* Set the dim pointer, if one was given */
771  if (dim)
772  *dim = new_dim;
773 
774  return NC_NOERR;
775 }
776 
789 int
790 nc4_att_list_add(NCindex *list, const char *name, NC_ATT_INFO_T **att)
791 {
792  NC_ATT_INFO_T *new_att;
793 
794  LOG((3, "%s: name %s ", __func__, name));
795 
796  if (!(new_att = calloc(1, sizeof(NC_ATT_INFO_T))))
797  return NC_ENOMEM;
798  new_att->hdr.sort = NCATT;
799 
800  /* Fill in the information we know. */
801  new_att->hdr.id = ncindexsize(list);
802  if (!(new_att->hdr.name = strdup(name)))
803  return NC_ENOMEM;
804 
805  /* Create a hash of the name. */
806  new_att->hdr.hashkey = NC_hashmapkey(name, strlen(name));
807 
808  /* Add object to list as specified by its number */
809  ncindexadd(list, (NC_OBJ *)new_att);
810 
811  /* Set the attribute pointer, if one was given */
812  if (att)
813  *att = new_att;
814 
815  return NC_NOERR;
816 }
817 
832 int
833 nc4_grp_list_add(NC_FILE_INFO_T *h5, NC_GRP_INFO_T *parent, char *name,
834  NC_GRP_INFO_T **grp)
835 {
836  NC_GRP_INFO_T *new_grp;
837 
838  /* Check inputs. */
839  assert(h5 && name);
840  LOG((3, "%s: name %s ", __func__, name));
841 
842  /* Get the memory to store this groups info. */
843  if (!(new_grp = calloc(1, sizeof(NC_GRP_INFO_T))))
844  return NC_ENOMEM;
845 
846  /* Fill in this group's information. */
847  new_grp->hdr.sort = NCGRP;
848  new_grp->nc4_info = h5;
849  new_grp->parent = parent;
850 
851  /* Assign the group ID. The root group will get id 0. */
852  new_grp->hdr.id = h5->next_nc_grpid++;
853  assert(parent || !new_grp->hdr.id);
854 
855  /* Handle the group name. */
856  if (!(new_grp->hdr.name = strdup(name)))
857  {
858  free(new_grp);
859  return NC_ENOMEM;
860  }
861  new_grp->hdr.hashkey = NC_hashmapkey(new_grp->hdr.name,
862  strlen(new_grp->hdr.name));
863 
864  /* Set up new indexed lists for stuff this group can contain. */
865  new_grp->children = ncindexnew(0);
866  new_grp->dim = ncindexnew(0);
867  new_grp->att = ncindexnew(0);
868  new_grp->type = ncindexnew(0);
869  new_grp->vars = ncindexnew(0);
870 
871  /* Add object to lists */
872  if (parent)
873  ncindexadd(parent->children, (NC_OBJ *)new_grp);
874  obj_track(h5, (NC_OBJ *)new_grp);
875 
876  /* Set the group pointer, if one was given */
877  if (grp)
878  *grp = new_grp;
879 
880  return NC_NOERR;
881 }
882 
896 int
897 nc4_check_dup_name(NC_GRP_INFO_T *grp, char *name)
898 {
899  NC_TYPE_INFO_T *type;
900  NC_GRP_INFO_T *g;
901  NC_VAR_INFO_T *var;
902 
903  /* Any types of this name? */
904  type = (NC_TYPE_INFO_T*)ncindexlookup(grp->type,name);
905  if(type != NULL)
906  return NC_ENAMEINUSE;
907 
908  /* Any child groups of this name? */
909  g = (NC_GRP_INFO_T*)ncindexlookup(grp->children,name);
910  if(g != NULL)
911  return NC_ENAMEINUSE;
912 
913  /* Any variables of this name? */
914  var = (NC_VAR_INFO_T*)ncindexlookup(grp->vars,name);
915  if(var != NULL)
916  return NC_ENAMEINUSE;
917 
918  return NC_NOERR;
919 }
920 
934 int
935 nc4_type_new(size_t size, const char *name, int assignedid,
936  NC_TYPE_INFO_T **type)
937 {
938  NC_TYPE_INFO_T *new_type;
939 
940  LOG((4, "%s: size %d name %s assignedid %d", __func__, size, name, assignedid));
941 
942  /* Check inputs. */
943  assert(type);
944 
945  /* Allocate memory for the type */
946  if (!(new_type = calloc(1, sizeof(NC_TYPE_INFO_T))))
947  return NC_ENOMEM;
948  new_type->hdr.sort = NCTYP;
949 
950  /* Remember info about this type. */
951  new_type->hdr.id = assignedid;
952  new_type->size = size;
953  if (!(new_type->hdr.name = strdup(name))) {
954  free(new_type);
955  return NC_ENOMEM;
956  }
957 
958  new_type->hdr.hashkey = NC_hashmapkey(name, strlen(name));
959 
960  /* Return a pointer to the new type. */
961  *type = new_type;
962 
963  return NC_NOERR;
964 }
965 
979 int
980 nc4_type_list_add(NC_GRP_INFO_T *grp, size_t size, const char *name,
981  NC_TYPE_INFO_T **type)
982 {
983  NC_TYPE_INFO_T *new_type;
984  int retval;
985 
986  /* Check inputs. */
987  assert(grp && name && type);
988  LOG((4, "%s: size %d name %s", __func__, size, name));
989 
990  /* Create the new TYPE_INFO struct. */
991  if ((retval = nc4_type_new(size, name, grp->nc4_info->next_typeid,
992  &new_type)))
993  return retval;
994  grp->nc4_info->next_typeid++;
995 
996  /* Increment the ref. count on the type */
997  new_type->rc++;
998 
999  /* Add object to lists */
1000  ncindexadd(grp->type, (NC_OBJ *)new_type);
1001  obj_track(grp->nc4_info,(NC_OBJ*)new_type);
1002 
1003  /* Return a pointer to the new type. */
1004  *type = new_type;
1005 
1006  return NC_NOERR;
1007 }
1008 
1022 int
1023 nc4_field_list_add(NC_TYPE_INFO_T *parent, const char *name,
1024  size_t offset, nc_type xtype, int ndims,
1025  const int *dim_sizesp)
1026 {
1027  NC_FIELD_INFO_T *field;
1028 
1029  /* Name has already been checked and UTF8 normalized. */
1030  if (!name)
1031  return NC_EINVAL;
1032 
1033  /* Allocate storage for this field information. */
1034  if (!(field = calloc(1, sizeof(NC_FIELD_INFO_T))))
1035  return NC_ENOMEM;
1036  field->hdr.sort = NCFLD;
1037 
1038  /* Store the information about this field. */
1039  if (!(field->hdr.name = strdup(name)))
1040  {
1041  free(field);
1042  return NC_ENOMEM;
1043  }
1044  field->hdr.hashkey = NC_hashmapkey(field->hdr.name,strlen(field->hdr.name));
1045  field->nc_typeid = xtype;
1046  field->offset = offset;
1047  field->ndims = ndims;
1048  if (ndims)
1049  {
1050  int i;
1051  if (!(field->dim_size = malloc(ndims * sizeof(int))))
1052  {
1053  free(field->hdr.name);
1054  free(field);
1055  return NC_ENOMEM;
1056  }
1057  for (i = 0; i < ndims; i++)
1058  field->dim_size[i] = dim_sizesp[i];
1059  }
1060 
1061  /* Add object to lists */
1062  field->hdr.id = nclistlength(parent->u.c.field);
1063  nclistpush(parent->u.c.field,field);
1064 
1065  return NC_NOERR;
1066 }
1067 
1080 int
1081 nc4_enum_member_add(NC_TYPE_INFO_T *parent, size_t size,
1082  const char *name, const void *value)
1083 {
1084  NC_ENUM_MEMBER_INFO_T *member;
1085 
1086  /* Name has already been checked. */
1087  assert(name && size > 0 && value);
1088  LOG((4, "%s: size %d name %s", __func__, size, name));
1089 
1090  /* Allocate storage for this field information. */
1091  if (!(member = calloc(1, sizeof(NC_ENUM_MEMBER_INFO_T))))
1092  return NC_ENOMEM;
1093  if (!(member->value = malloc(size))) {
1094  free(member);
1095  return NC_ENOMEM;
1096  }
1097  if (!(member->name = strdup(name))) {
1098  free(member->value);
1099  free(member);
1100  return NC_ENOMEM;
1101  }
1102 
1103  /* Store the value for this member. */
1104  memcpy(member->value, value, size);
1105 
1106  /* Add object to list */
1107  nclistpush(parent->u.e.enum_member,member);
1108 
1109  return NC_NOERR;
1110 }
1111 
1120 static void
1121 field_free(NC_FIELD_INFO_T *field)
1122 {
1123  /* Free some stuff. */
1124  if (field->hdr.name)
1125  free(field->hdr.name);
1126  if (field->dim_size)
1127  free(field->dim_size);
1128 
1129  /* Nc_Free the memory. */
1130  free(field);
1131 }
1132 
1142 int
1143 nc4_type_free(NC_TYPE_INFO_T *type)
1144 {
1145  int i;
1146 
1147  assert(type && type->rc && type->hdr.name);
1148 
1149  /* Decrement the ref. count on the type */
1150  type->rc--;
1151 
1152  /* Release the type, if the ref. count drops to zero */
1153  if (type->rc == 0)
1154  {
1155  LOG((4, "%s: deleting type %s", __func__, type->hdr.name));
1156 
1157  /* Free the name. */
1158  free(type->hdr.name);
1159 
1160  /* Enums and compound types have lists of fields to clean up. */
1161  switch (type->nc_type_class)
1162  {
1163  case NC_COMPOUND:
1164  {
1165  NC_FIELD_INFO_T *field;
1166 
1167  /* Delete all the fields in this type (there will be some if its a
1168  * compound). */
1169  for(i=0;i<nclistlength(type->u.c.field);i++) {
1170  field = nclistget(type->u.c.field,i);
1171  field_free(field);
1172  }
1173  nclistfree(type->u.c.field);
1174  }
1175  break;
1176 
1177  case NC_ENUM:
1178  {
1179  NC_ENUM_MEMBER_INFO_T *enum_member;
1180 
1181  /* Delete all the enum_members, if any. */
1182  for(i=0;i<nclistlength(type->u.e.enum_member);i++) {
1183  enum_member = nclistget(type->u.e.enum_member,i);
1184  free(enum_member->value);
1185  free(enum_member->name);
1186  free(enum_member);
1187  }
1188  nclistfree(type->u.e.enum_member);
1189  }
1190  break;
1191 
1192  default:
1193  break;
1194  }
1195 
1196  /* Release any HDF5-specific type info. */
1197  if (type->format_type_info)
1198  free(type->format_type_info);
1199 
1200  /* Release the memory. */
1201  free(type);
1202  }
1203 
1204  return NC_NOERR;
1205 }
1206 
1215 static int
1216 att_free(NC_ATT_INFO_T *att)
1217 {
1218  int i;
1219 
1220  assert(att);
1221  LOG((3, "%s: name %s ", __func__, att->hdr.name));
1222 
1223  /* Free memory that was malloced to hold data for this
1224  * attribute. */
1225  if (att->data)
1226  free(att->data);
1227 
1228  /* Free the name. */
1229  if (att->hdr.name)
1230  free(att->hdr.name);
1231 
1232  /* If this is a string array attribute, delete all members of the
1233  * string array, then delete the array of pointers to strings. (The
1234  * array was filled with pointers by HDF5 when the att was read,
1235  * and memory for each string was allocated by HDF5. That's why I
1236  * use free and not nc_free, because the netCDF library didn't
1237  * allocate the memory that is being freed.) */
1238  if (att->stdata)
1239  {
1240  for (i = 0; i < att->len; i++)
1241  if(att->stdata[i])
1242  free(att->stdata[i]);
1243  free(att->stdata);
1244  }
1245 
1246  /* If this att has vlen data, release it. */
1247  if (att->vldata)
1248  {
1249  for (i = 0; i < att->len; i++)
1250  nc_free_vlen(&att->vldata[i]);
1251  free(att->vldata);
1252  }
1253 
1254  /* Free any format-sepecific info. Some formats use this (ex. HDF5)
1255  * and some don't (ex. HDF4). So it may be NULL. */
1256  if (att->format_att_info)
1257  free(att->format_att_info);
1258 
1259  free(att);
1260  return NC_NOERR;
1261 }
1262 
1272 static int
1273 var_free(NC_VAR_INFO_T *var)
1274 {
1275  int i;
1276  int retval;
1277 
1278  assert(var);
1279  LOG((4, "%s: deleting var %s", __func__, var->hdr.name));
1280 
1281  /* First delete all the attributes attached to this var. */
1282  for (i = 0; i < ncindexsize(var->att); i++)
1283  if ((retval = att_free((NC_ATT_INFO_T *)ncindexith(var->att, i))))
1284  return retval;
1285  ncindexfree(var->att);
1286 
1287  /* Free some things that may be allocated. */
1288  if (var->chunksizes)
1289  free(var->chunksizes);
1290 
1291  if (var->hdf5_name)
1292  free(var->hdf5_name);
1293 
1294  if (var->hdr.name)
1295  free(var->hdr.name);
1296 
1297  if (var->dimids)
1298  free(var->dimids);
1299 
1300  if (var->dim)
1301  free(var->dim);
1302 
1303  /* Delete any fill value allocation. */
1304  if (var->fill_value)
1305  free(var->fill_value);
1306 
1307  /* Release type information */
1308  if (var->type_info)
1309  if ((retval = nc4_type_free(var->type_info)))
1310  return retval;
1311 
1312  /* Delete information about the attachment status of dimscales. */
1313  if (var->dimscale_attached)
1314  free(var->dimscale_attached);
1315 
1316  /* Release parameter information. */
1317  if (var->params)
1318  free(var->params);
1319 
1320  /* Delete any format-specific info. */
1321  if (var->format_var_info)
1322  free(var->format_var_info);
1323 
1324  /* Delete the var. */
1325  free(var);
1326 
1327  return NC_NOERR;
1328 }
1329 
1339 int
1340 nc4_var_list_del(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var)
1341 {
1342  int i;
1343 
1344  assert(var && grp);
1345 
1346  /* Remove from lists */
1347  i = ncindexfind(grp->vars, (NC_OBJ *)var);
1348  if (i >= 0)
1349  ncindexidel(grp->vars, i);
1350 
1351  return var_free(var);
1352 }
1353 
1362 static int
1363 dim_free(NC_DIM_INFO_T *dim)
1364 {
1365  assert(dim);
1366  LOG((4, "%s: deleting dim %s", __func__, dim->hdr.name));
1367 
1368  /* Free memory allocated for names. */
1369  if (dim->hdr.name)
1370  free(dim->hdr.name);
1371 
1372  /* Release any format-specific information. */
1373  if (dim->format_dim_info)
1374  free(dim->format_dim_info);
1375 
1376  free(dim);
1377  return NC_NOERR;
1378 }
1379 
1389 int
1390 nc4_dim_list_del(NC_GRP_INFO_T *grp, NC_DIM_INFO_T *dim)
1391 {
1392  if (grp && dim)
1393  {
1394  int pos = ncindexfind(grp->dim, (NC_OBJ *)dim);
1395  if(pos >= 0)
1396  ncindexidel(grp->dim, pos);
1397  }
1398 
1399  return dim_free(dim);
1400 }
1401 
1411 int
1412 nc4_rec_grp_del(NC_GRP_INFO_T *grp)
1413 {
1414  int i;
1415  int retval;
1416 
1417  assert(grp);
1418  LOG((3, "%s: grp->name %s", __func__, grp->hdr.name));
1419 
1420  /* Recursively call this function for each child, if any, stopping
1421  * if there is an error. */
1422  for (i = 0; i < ncindexsize(grp->children); i++)
1423  if ((retval = nc4_rec_grp_del((NC_GRP_INFO_T *)ncindexith(grp->children,
1424  i))))
1425  return retval;
1426  ncindexfree(grp->children);
1427 
1428  /* Free attributes, but leave in parent list */
1429  for (i = 0; i < ncindexsize(grp->att); i++)
1430  if ((retval = att_free((NC_ATT_INFO_T *)ncindexith(grp->att, i))))
1431  return retval;
1432  ncindexfree(grp->att);
1433 
1434  /* Delete all vars. */
1435  for (i = 0; i < ncindexsize(grp->vars); i++)
1436  if ((retval = var_free((NC_VAR_INFO_T *)ncindexith(grp->vars, i))))
1437  return retval;
1438  ncindexfree(grp->vars);
1439 
1440  /* Delete all dims, and free the list of dims. */
1441  for (i = 0; i < ncindexsize(grp->dim); i++)
1442  if ((retval = dim_free((NC_DIM_INFO_T *)ncindexith(grp->dim, i))))
1443  return retval;
1444  ncindexfree(grp->dim);
1445 
1446  /* Delete all types. */
1447  for (i = 0; i < ncindexsize(grp->type); i++)
1448  if ((retval = nc4_type_free((NC_TYPE_INFO_T *)ncindexith(grp->type, i))))
1449  return retval;
1450  ncindexfree(grp->type);
1451 
1452  /* Free the name. */
1453  free(grp->hdr.name);
1454 
1455  /* Release any format-specific information about this group. */
1456  if (grp->format_grp_info)
1457  free(grp->format_grp_info);
1458 
1459  /* Free up this group */
1460  free(grp);
1461 
1462  return NC_NOERR;
1463 }
1464 
1475 int
1476 nc4_att_list_del(NCindex *list, NC_ATT_INFO_T *att)
1477 {
1478  assert(att && list);
1479  ncindexidel(list, ((NC_OBJ *)att)->id);
1480  return att_free(att);
1481 }
1482 
1496 int
1497 nc4_file_list_del(int ncid)
1498 {
1499  NC_FILE_INFO_T *h5;
1500  int retval;
1501 
1502  /* Find our metadata for this file. */
1503  if ((retval = nc4_find_grp_h5(ncid, NULL, &h5)))
1504  return retval;
1505  assert(h5);
1506 
1507  /* Delete the file resources. */
1508  if ((retval = nc4_nc4f_list_del(h5)))
1509  return retval;
1510 
1511  return NC_NOERR;
1512 }
1513 
1523 int
1524 nc4_nc4f_list_del(NC_FILE_INFO_T *h5)
1525 {
1526  int retval;
1527 
1528  assert(h5);
1529 
1530  /* Delete all the list contents for vars, dims, and atts, in each
1531  * group. */
1532  if ((retval = nc4_rec_grp_del(h5->root_grp)))
1533  return retval;
1534 
1535  /* Cleanup these (extra) lists of all dims, groups, and types. */
1536  nclistfree(h5->alldims);
1537  nclistfree(h5->allgroups);
1538  nclistfree(h5->alltypes);
1539 
1540  /* Free the NC_FILE_INFO_T struct. */
1541  free(h5);
1542 
1543  return NC_NOERR;
1544 }
1545 
1559 int
1560 nc4_normalize_name(const char *name, char *norm_name)
1561 {
1562  char *temp_name;
1563  int stat = nc_utf8_normalize((const unsigned char *)name,(unsigned char **)&temp_name);
1564  if(stat != NC_NOERR)
1565  return stat;
1566  if (strlen(temp_name) > NC_MAX_NAME)
1567  {
1568  free(temp_name);
1569  return NC_EMAXNAME;
1570  }
1571  strcpy(norm_name, temp_name);
1572  free(temp_name);
1573  return NC_NOERR;
1574 }
1575 
1576 #ifdef ENABLE_SET_LOG_LEVEL
1577 
1592 int
1593 nc_set_log_level(int new_level)
1594 {
1595 #ifdef LOGGING
1596  /* Remember the new level. */
1597  nc_log_level = new_level;
1598  LOG((4, "log_level changed to %d", nc_log_level));
1599 #endif /*LOGGING */
1600  return 0;
1601 }
1602 #endif /* ENABLE_SET_LOG_LEVEL */
1603 
1604 #ifdef LOGGING
1605 #define MAX_NESTS 10
1606 
1615 static int
1616 rec_print_metadata(NC_GRP_INFO_T *grp, int tab_count)
1617 {
1618  NC_ATT_INFO_T *att;
1619  NC_VAR_INFO_T *var;
1620  NC_DIM_INFO_T *dim;
1621  NC_TYPE_INFO_T *type;
1622  NC_FIELD_INFO_T *field;
1623  char tabs[MAX_NESTS+1] = "";
1624  char *dims_string = NULL;
1625  char temp_string[10];
1626  int t, retval, d, i;
1627 
1628  /* Come up with a number of tabs relative to the group. */
1629  for (t = 0; t < tab_count && t < MAX_NESTS; t++)
1630  tabs[t] = '\t';
1631  tabs[t] = '\0';
1632 
1633  LOG((2, "%s GROUP - %s nc_grpid: %d nvars: %d natts: %d",
1634  tabs, grp->hdr.name, grp->hdr.id, ncindexsize(grp->vars), ncindexsize(grp->att)));
1635 
1636  for (i = 0; i < ncindexsize(grp->att); i++)
1637  {
1638  att = (NC_ATT_INFO_T *)ncindexith(grp->att, i);
1639  assert(att);
1640  LOG((2, "%s GROUP ATTRIBUTE - attnum: %d name: %s type: %d len: %d",
1641  tabs, att->hdr.id, att->hdr.name, att->nc_typeid, att->len));
1642  }
1643 
1644  for (i = 0; i < ncindexsize(grp->dim); i++)
1645  {
1646  dim = (NC_DIM_INFO_T *)ncindexith(grp->dim, i);
1647  assert(dim);
1648  LOG((2, "%s DIMENSION - dimid: %d name: %s len: %d unlimited: %d",
1649  tabs, dim->hdr.id, dim->hdr.name, dim->len, dim->unlimited));
1650  }
1651 
1652  for (i = 0; i < ncindexsize(grp->vars); i++)
1653  {
1654  int j;
1655  var = (NC_VAR_INFO_T*)ncindexith(grp->vars,i);
1656  assert(var);
1657  if (var->ndims > 0)
1658  {
1659  if (!(dims_string = malloc(sizeof(char) * var->ndims * 4)))
1660  return NC_ENOMEM;
1661  strcpy(dims_string, "");
1662  for (d = 0; d < var->ndims; d++)
1663  {
1664  sprintf(temp_string, " %d", var->dimids[d]);
1665  strcat(dims_string, temp_string);
1666  }
1667  }
1668  LOG((2, "%s VARIABLE - varid: %d name: %s ndims: %d dimscale: %d dimids:%s",
1669  tabs, var->hdr.id, var->hdr.name, var->ndims, (int)var->dimscale,
1670  (dims_string ? dims_string : " -")));
1671  for (j = 0; j < ncindexsize(var->att); j++)
1672  {
1673  att = (NC_ATT_INFO_T *)ncindexith(var->att, j);
1674  assert(att);
1675  LOG((2, "%s VAR ATTRIBUTE - attnum: %d name: %s type: %d len: %d",
1676  tabs, att->hdr.id, att->hdr.name, att->nc_typeid, att->len));
1677  }
1678  if (dims_string)
1679  free(dims_string);
1680  }
1681 
1682  for (i = 0; i < ncindexsize(grp->type); i++)
1683  {
1684  type = (NC_TYPE_INFO_T*)ncindexith(grp->type, i);
1685  assert(type);
1686  LOG((2, "%s TYPE - nc_typeid: %d size: %d committed: %d name: %s",
1687  tabs, type->hdr.id, type->size, (int)type->committed, type->hdr.name));
1688  /* Is this a compound type? */
1689  if (type->nc_type_class == NC_COMPOUND)
1690  {
1691  int j;
1692  LOG((3, "compound type"));
1693  for (j = 0; j < nclistlength(type->u.c.field); j++)
1694  {
1695  field = (NC_FIELD_INFO_T *)nclistget(type->u.c.field, j);
1696  LOG((4, "field %s offset %d nctype %d ndims %d", field->hdr.name,
1697  field->offset, field->nc_typeid, field->ndims));
1698  }
1699  }
1700  else if (type->nc_type_class == NC_VLEN)
1701  {
1702  LOG((3, "VLEN type"));
1703  LOG((4, "base_nc_type: %d", type->u.v.base_nc_typeid));
1704  }
1705  else if (type->nc_type_class == NC_OPAQUE)
1706  LOG((3, "Opaque type"));
1707  else if (type->nc_type_class == NC_ENUM)
1708  {
1709  LOG((3, "Enum type"));
1710  LOG((4, "base_nc_type: %d", type->u.e.base_nc_typeid));
1711  }
1712  else
1713  {
1714  LOG((0, "Unknown class: %d", type->nc_type_class));
1715  return NC_EBADTYPE;
1716  }
1717  }
1718 
1719  /* Call self for each child of this group. */
1720  for (i = 0; i < ncindexsize(grp->children); i++)
1721  if ((retval = rec_print_metadata((NC_GRP_INFO_T *)ncindexith(grp->children, i),
1722  tab_count + 1)))
1723  return retval;
1724 
1725  return NC_NOERR;
1726 }
1727 
1738 int
1739 log_metadata_nc(NC_FILE_INFO_T *h5)
1740 {
1741  LOG((2, "*** NetCDF-4 Internal Metadata: int_ncid 0x%x ext_ncid 0x%x",
1742  h5->root_grp->nc4_info->controller->int_ncid,
1743  h5->root_grp->nc4_info->controller->ext_ncid));
1744  if (!h5)
1745  {
1746  LOG((2, "This is a netCDF-3 file."));
1747  return NC_NOERR;
1748  }
1749  LOG((2, "FILE - path: %s cmode: 0x%x parallel: %d redef: %d "
1750  "fill_mode: %d no_write: %d next_nc_grpid: %d", h5->root_grp->nc4_info->controller->path,
1751  h5->cmode, (int)h5->parallel, (int)h5->redef, h5->fill_mode, (int)h5->no_write,
1752  h5->next_nc_grpid));
1753  if(nc_log_level >= 2)
1754  return rec_print_metadata(h5->root_grp, 0);
1755  return NC_NOERR;
1756 }
1757 
1758 #endif /*LOGGING */
1759 
1771 int
1772 NC4_show_metadata(int ncid)
1773 {
1774  int retval = NC_NOERR;
1775 #ifdef LOGGING
1776  NC_FILE_INFO_T *h5;
1777  int old_log_level = nc_log_level;
1778 
1779  /* Find file metadata. */
1780  if ((retval = nc4_find_grp_h5(ncid, NULL, &h5)))
1781  return retval;
1782 
1783  /* Log level must be 2 to see metadata. */
1784  nc_log_level = 2;
1785  retval = log_metadata_nc(h5);
1786  nc_log_level = old_log_level;
1787 #endif /*LOGGING*/
1788  return retval;
1789 }
#define NC_ENOMEM
Memory allocation (malloc) failure.
Definition: netcdf.h:405
#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:368
#define NC_ENAMEINUSE
String match to name in use.
Definition: netcdf.h:364
#define NC_VLEN
vlen (variable-length) types
Definition: netcdf.h:53
#define NC_EBADTYPE
Not a netcdf data type.
Definition: netcdf.h:367
#define NC_EINVAL
Invalid Argument.
Definition: netcdf.h:335
#define NC_MAX_NAME
Maximum for classic library.
Definition: netcdf.h:275
#define NC_EBADTYPID
Bad type ID.
Definition: netcdf.h:454
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:332
#define NC_UNLIMITED
Size argument to nc_def_dim() for an unlimited dimension.
Definition: netcdf.h:245
size_t nc4_chunk_cache_size
Default chunk cache size.
Definition: nc4internal.c:25
#define NC_ENOTVAR
Variable not found.
Definition: netcdf.h:379
#define NC_EMAXNAME
NC_MAX_NAME exceeded.
Definition: netcdf.h:383
#define NC_NOERR
No Error.
Definition: netcdf.h:325
#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:248
#define NC_ENOTATT
Attribute not found.
Definition: netcdf.h:365

Return to the Main Unidata NetCDF page.
Generated on Fri Aug 30 2019 08:26:47 for NetCDF. NetCDF is a Unidata library.