NetCDF  4.7.3
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 
141 int
142 nc4_file_change_ncid(int ncid, unsigned short new_ncid_index)
143 {
144  NC *nc;
145  int ret;
146 
147  LOG((2, "%s: ncid %d new_ncid_index %d", __func__, ncid, new_ncid_index));
148 
149  /* Find NC pointer for this file. */
150  if ((ret = NC_check_id(ncid, &nc)))
151  return ret;
152 
153  /* Move it in the list. It will faile if list spot is already
154  * occupied. */
155  LOG((3, "moving nc->ext_ncid %d nc->ext_ncid >> ID_SHIFT %d",
156  nc->ext_ncid, nc->ext_ncid >> ID_SHIFT));
157  if (move_in_NCList(nc, new_ncid_index))
158  return NC_EIO;
159  LOG((3, "moved to new_ncid_index %d new nc->ext_ncid %d", new_ncid_index,
160  nc->ext_ncid));
161 
162  return NC_NOERR;
163 }
164 
184 int
185 nc4_file_list_get(int ncid, char **path, int *mode, void **dispatchdata)
186 {
187  NC *nc;
188  int ret;
189 
190  /* Find NC pointer for this file. */
191  if ((ret = NC_check_id(ncid, &nc)))
192  return ret;
193 
194  /* If the user wants path, give it. */
195  if (path)
196  strncpy(*path, nc->path, NC_MAX_NAME);
197 
198  /* If the user wants mode, give it. */
199  if (mode)
200  *mode = nc->mode;
201 
202  /* If the user wants dispatchdata, give it. */
203  if (dispatchdata)
204  *dispatchdata = nc->dispatchdata;
205 
206  return NC_NOERR;
207 }
208 
223 int
224 nc4_nc4f_list_add(NC *nc, const char *path, int mode)
225 {
226  NC_FILE_INFO_T *h5;
227  int retval;
228 
229  assert(nc && !NC4_DATA(nc) && path);
230 
231  /* We need to malloc and initialize the substructure
232  NC_FILE_INFO_T. */
233  if (!(h5 = calloc(1, sizeof(NC_FILE_INFO_T))))
234  return NC_ENOMEM;
235  nc->dispatchdata = h5;
236  h5->controller = nc;
237 
238  /* Hang on to cmode, and note that we're in define mode. */
239  h5->cmode = mode | NC_INDEF;
240 
241  /* The next_typeid needs to be set beyond the end of our atomic
242  * types. */
243  h5->next_typeid = NC_FIRSTUSERTYPEID;
244 
245  /* Initialize lists for dimensions, types, and groups. */
246  h5->alldims = nclistnew();
247  h5->alltypes = nclistnew();
248  h5->allgroups = nclistnew();
249 
250  /* There's always at least one open group - the root
251  * group. Allocate space for one group's worth of information. Set
252  * its grp id, name, and allocate associated empty lists. */
253  if ((retval = nc4_grp_list_add(h5, NULL, NC_GROUP_NAME, &h5->root_grp)))
254  return retval;
255 
256  return NC_NOERR;
257 }
258 
271 int
272 nc4_find_nc4_grp(int ncid, NC_GRP_INFO_T **grp)
273 {
274  return nc4_find_nc_grp_h5(ncid, NULL, grp, NULL);
275 }
276 
292 int
293 nc4_find_grp_h5(int ncid, NC_GRP_INFO_T **grp, NC_FILE_INFO_T **h5)
294 {
295  return nc4_find_nc_grp_h5(ncid, NULL, grp, h5);
296 }
297 
312 int
313 nc4_find_nc_grp_h5(int ncid, NC **nc, NC_GRP_INFO_T **grp, NC_FILE_INFO_T **h5)
314 {
315  NC_GRP_INFO_T *my_grp = NULL;
316  NC_FILE_INFO_T *my_h5 = NULL;
317  NC *my_nc;
318  int retval;
319 
320  /* Look up file metadata. */
321  if ((retval = NC_check_id(ncid, &my_nc)))
322  return retval;
323  my_h5 = my_nc->dispatchdata;
324  assert(my_h5 && my_h5->root_grp);
325 
326  /* If we can't find it, the grp id part of ncid is bad. */
327  if (!(my_grp = nclistget(my_h5->allgroups, (ncid & GRP_ID_MASK))))
328  return NC_EBADID;
329 
330  /* Return pointers to caller, if desired. */
331  if (nc)
332  *nc = my_nc;
333  if (h5)
334  *h5 = my_h5;
335  if (grp)
336  *grp = my_grp;
337 
338  return NC_NOERR;
339 }
340 
356 int
357 nc4_find_grp_h5_var(int ncid, int varid, NC_FILE_INFO_T **h5, NC_GRP_INFO_T **grp,
358  NC_VAR_INFO_T **var)
359 {
360  NC_FILE_INFO_T *my_h5;
361  NC_GRP_INFO_T *my_grp;
362  NC_VAR_INFO_T *my_var;
363  int retval;
364 
365  /* Look up file and group metadata. */
366  if ((retval = nc4_find_grp_h5(ncid, &my_grp, &my_h5)))
367  return retval;
368  assert(my_grp && my_h5);
369 
370  /* Find the var. */
371  if (!(my_var = (NC_VAR_INFO_T *)ncindexith(my_grp->vars, varid)))
372  return NC_ENOTVAR;
373  assert(my_var && my_var->hdr.id == varid);
374 
375  /* Return pointers that caller wants. */
376  if (h5)
377  *h5 = my_h5;
378  if (grp)
379  *grp = my_grp;
380  if (var)
381  *var = my_var;
382 
383  return NC_NOERR;
384 }
385 
399 int
400 nc4_find_dim(NC_GRP_INFO_T *grp, int dimid, NC_DIM_INFO_T **dim,
401  NC_GRP_INFO_T **dim_grp)
402 {
403  assert(grp && grp->nc4_info && dim);
404  LOG((4, "%s: dimid %d", __func__, dimid));
405 
406  /* Find the dim info. */
407  if (!((*dim) = nclistget(grp->nc4_info->alldims, dimid)))
408  return NC_EBADDIM;
409 
410  /* Give the caller the group the dimension is in. */
411  if (dim_grp)
412  *dim_grp = (*dim)->container;
413 
414  return NC_NOERR;
415 }
416 
427 int
428 nc4_find_var(NC_GRP_INFO_T *grp, const char *name, NC_VAR_INFO_T **var)
429 {
430  assert(grp && var && name);
431 
432  /* Find the var info. */
433  *var = (NC_VAR_INFO_T*)ncindexlookup(grp->vars,name);
434  return NC_NOERR;
435 }
436 
446 NC_TYPE_INFO_T *
447 nc4_rec_find_named_type(NC_GRP_INFO_T *start_grp, char *name)
448 {
449  NC_GRP_INFO_T *g;
450  NC_TYPE_INFO_T *type, *res;
451  int i;
452 
453  assert(start_grp);
454 
455  /* Does this group have the type we are searching for? */
456  type = (NC_TYPE_INFO_T*)ncindexlookup(start_grp->type,name);
457  if(type != NULL)
458  return type;
459 
460  /* Search subgroups. */
461  for(i=0;i<ncindexsize(start_grp->children);i++) {
462  g = (NC_GRP_INFO_T*)ncindexith(start_grp->children,i);
463  if(g == NULL) continue;
464  if ((res = nc4_rec_find_named_type(g, name)))
465  return res;
466  }
467  /* Can't find it. Oh, woe is me! */
468  return NULL;
469 }
470 
482 int
483 nc4_find_type(const NC_FILE_INFO_T *h5, nc_type typeid, NC_TYPE_INFO_T **type)
484 {
485  /* Check inputs. */
486  assert(h5);
487  if (typeid < 0 || !type)
488  return NC_EINVAL;
489  *type = NULL;
490 
491  /* Atomic types don't have associated NC_TYPE_INFO_T struct, just
492  * return NOERR. */
493  if (typeid <= NC_STRING)
494  return NC_NOERR;
495 
496  /* Find the type. */
497  if (!(*type = nclistget(h5->alltypes,typeid)))
498  return NC_EBADTYPID;
499 
500  return NC_NOERR;
501 }
502 
518 int
519 nc4_find_grp_att(NC_GRP_INFO_T *grp, int varid, const char *name, int attnum,
520  NC_ATT_INFO_T **att)
521 {
522  NC_VAR_INFO_T *var;
523  NC_ATT_INFO_T *my_att;
524  NCindex *attlist = NULL;
525 
526  assert(grp && grp->hdr.name && att);
527 
528  LOG((4, "%s: grp->name %s varid %d attnum %d", __func__, grp->hdr.name,
529  varid, attnum));
530 
531  /* Get either the global or a variable attribute list. */
532  if (varid == NC_GLOBAL)
533  {
534  attlist = grp->att;
535  }
536  else
537  {
538  var = (NC_VAR_INFO_T*)ncindexith(grp->vars,varid);
539  if (!var) return NC_ENOTVAR;
540 
541  attlist = var->att;
542  }
543  assert(attlist);
544 
545  /* Now find the attribute by name or number. If a name is provided,
546  * ignore the attnum. */
547  if (name)
548  my_att = (NC_ATT_INFO_T *)ncindexlookup(attlist, name);
549  else
550  my_att = (NC_ATT_INFO_T *)ncindexith(attlist, attnum);
551 
552  if (!my_att)
553  return NC_ENOTATT;
554 
555  *att = my_att;
556  return NC_NOERR;
557 }
558 
575 int
576 nc4_find_nc_att(int ncid, int varid, const char *name, int attnum,
577  NC_ATT_INFO_T **att)
578 {
579  NC_GRP_INFO_T *grp;
580  int retval;
581 
582  LOG((4, "nc4_find_nc_att: ncid 0x%x varid %d name %s attnum %d",
583  ncid, varid, name, attnum));
584 
585  /* Find info for this file and group, and set pointer to each. */
586  if ((retval = nc4_find_grp_h5(ncid, &grp, NULL)))
587  return retval;
588  assert(grp);
589 
590  return nc4_find_grp_att(grp, varid, name, attnum, att);
591 }
592 
601 static void
602 obj_track(NC_FILE_INFO_T* file, NC_OBJ* obj)
603 {
604  NClist* list = NULL;
605  /* record the object in the file */
606  switch (obj->sort) {
607  case NCDIM: list = file->alldims; break;
608  case NCTYP: list = file->alltypes; break;
609  case NCGRP: list = file->allgroups; break;
610  default:
611  assert(NC_FALSE);
612  }
613  /* Insert at the appropriate point in the list */
614  nclistset(list,obj->id,obj);
615 }
616 
631 int
632 nc4_var_list_add2(NC_GRP_INFO_T *grp, const char *name, NC_VAR_INFO_T **var)
633 {
634  NC_VAR_INFO_T *new_var = NULL;
635 
636  /* Allocate storage for new variable. */
637  if (!(new_var = calloc(1, sizeof(NC_VAR_INFO_T))))
638  return NC_ENOMEM;
639  new_var->hdr.sort = NCVAR;
640  new_var->container = grp;
641 
642  /* These are the HDF5-1.8.4 defaults. */
643  new_var->chunk_cache_size = nc4_chunk_cache_size;
644  new_var->chunk_cache_nelems = nc4_chunk_cache_nelems;
645  new_var->chunk_cache_preemption = nc4_chunk_cache_preemption;
646 
647  /* Now fill in the values in the var info structure. */
648  new_var->hdr.id = ncindexsize(grp->vars);
649  if (!(new_var->hdr.name = strdup(name))) {
650  if(new_var)
651  free(new_var);
652  return NC_ENOMEM;
653  }
654 
655  new_var->hdr.hashkey = NC_hashmapkey(new_var->hdr.name,
656  strlen(new_var->hdr.name));
657 
658  /* Create an indexed list for the attributes. */
659  new_var->att = ncindexnew(0);
660 
661  /* Officially track it */
662  ncindexadd(grp->vars, (NC_OBJ *)new_var);
663 
664  /* Set the var pointer, if one was given */
665  if (var)
666  *var = new_var;
667 
668  return NC_NOERR;
669 }
670 
683 int
684 nc4_var_set_ndims(NC_VAR_INFO_T *var, int ndims)
685 {
686  assert(var);
687 
688  /* Remember the number of dimensions. */
689  var->ndims = ndims;
690 
691  /* Allocate space for dimension information. */
692  if (ndims)
693  {
694  if (!(var->dim = calloc(ndims, sizeof(NC_DIM_INFO_T *))))
695  return NC_ENOMEM;
696  if (!(var->dimids = calloc(ndims, sizeof(int))))
697  return NC_ENOMEM;
698 
699  /* Initialize dimids to illegal values (-1). See the comment
700  in nc4_rec_match_dimscales(). */
701  memset(var->dimids, -1, ndims * sizeof(int));
702  }
703 
704  return NC_NOERR;
705 }
706 
721 int
722 nc4_var_list_add(NC_GRP_INFO_T* grp, const char* name, int ndims,
723  NC_VAR_INFO_T **var)
724 {
725  int retval;
726 
727  if ((retval = nc4_var_list_add2(grp, name, var)))
728  return retval;
729  if ((retval = nc4_var_set_ndims(*var, ndims)))
730  return retval;
731 
732  return NC_NOERR;
733 }
734 
748 int
749 nc4_dim_list_add(NC_GRP_INFO_T *grp, const char *name, size_t len,
750  int assignedid, NC_DIM_INFO_T **dim)
751 {
752  NC_DIM_INFO_T *new_dim = NULL;
753 
754  assert(grp && name);
755 
756  /* Allocate memory for dim metadata. */
757  if (!(new_dim = calloc(1, sizeof(NC_DIM_INFO_T))))
758  return NC_ENOMEM;
759 
760  new_dim->hdr.sort = NCDIM;
761 
762  /* Assign the dimension ID. */
763  if (assignedid >= 0)
764  new_dim->hdr.id = assignedid;
765  else
766  new_dim->hdr.id = grp->nc4_info->next_dimid++;
767 
768  /* Remember the name and create a hash. */
769  if (!(new_dim->hdr.name = strdup(name))) {
770  if(new_dim)
771  free(new_dim);
772 
773  return NC_ENOMEM;
774  }
775  new_dim->hdr.hashkey = NC_hashmapkey(new_dim->hdr.name,
776  strlen(new_dim->hdr.name));
777 
778  /* Is dimension unlimited? */
779  new_dim->len = len;
780  if (len == NC_UNLIMITED)
781  new_dim->unlimited = NC_TRUE;
782 
783  /* Remember the containing group. */
784  new_dim->container = grp;
785 
786  /* Add object to dimension list for this group. */
787  ncindexadd(grp->dim, (NC_OBJ *)new_dim);
788  obj_track(grp->nc4_info, (NC_OBJ *)new_dim);
789 
790  /* Set the dim pointer, if one was given */
791  if (dim)
792  *dim = new_dim;
793 
794  return NC_NOERR;
795 }
796 
809 int
810 nc4_att_list_add(NCindex *list, const char *name, NC_ATT_INFO_T **att)
811 {
812  NC_ATT_INFO_T *new_att = NULL;
813 
814  LOG((3, "%s: name %s ", __func__, name));
815 
816  if (!(new_att = calloc(1, sizeof(NC_ATT_INFO_T))))
817  return NC_ENOMEM;
818  new_att->hdr.sort = NCATT;
819 
820  /* Fill in the information we know. */
821  new_att->hdr.id = ncindexsize(list);
822  if (!(new_att->hdr.name = strdup(name))) {
823  if(new_att)
824  free(new_att);
825  return NC_ENOMEM;
826  }
827  /* Create a hash of the name. */
828  new_att->hdr.hashkey = NC_hashmapkey(name, strlen(name));
829 
830  /* Add object to list as specified by its number */
831  ncindexadd(list, (NC_OBJ *)new_att);
832 
833  /* Set the attribute pointer, if one was given */
834  if (att)
835  *att = new_att;
836 
837  return NC_NOERR;
838 }
839 
854 int
855 nc4_grp_list_add(NC_FILE_INFO_T *h5, NC_GRP_INFO_T *parent, char *name,
856  NC_GRP_INFO_T **grp)
857 {
858  NC_GRP_INFO_T *new_grp;
859 
860  /* Check inputs. */
861  assert(h5 && name);
862  LOG((3, "%s: name %s ", __func__, name));
863 
864  /* Get the memory to store this groups info. */
865  if (!(new_grp = calloc(1, sizeof(NC_GRP_INFO_T))))
866  return NC_ENOMEM;
867 
868  /* Fill in this group's information. */
869  new_grp->hdr.sort = NCGRP;
870  new_grp->nc4_info = h5;
871  new_grp->parent = parent;
872 
873  /* Assign the group ID. The root group will get id 0. */
874  new_grp->hdr.id = h5->next_nc_grpid++;
875  assert(parent || !new_grp->hdr.id);
876 
877  /* Handle the group name. */
878  if (!(new_grp->hdr.name = strdup(name)))
879  {
880  free(new_grp);
881  return NC_ENOMEM;
882  }
883  new_grp->hdr.hashkey = NC_hashmapkey(new_grp->hdr.name,
884  strlen(new_grp->hdr.name));
885 
886  /* Set up new indexed lists for stuff this group can contain. */
887  new_grp->children = ncindexnew(0);
888  new_grp->dim = ncindexnew(0);
889  new_grp->att = ncindexnew(0);
890  new_grp->type = ncindexnew(0);
891  new_grp->vars = ncindexnew(0);
892 
893  /* Add object to lists */
894  if (parent)
895  ncindexadd(parent->children, (NC_OBJ *)new_grp);
896  obj_track(h5, (NC_OBJ *)new_grp);
897 
898  /* Set the group pointer, if one was given */
899  if (grp)
900  *grp = new_grp;
901 
902  return NC_NOERR;
903 }
904 
918 int
919 nc4_check_dup_name(NC_GRP_INFO_T *grp, char *name)
920 {
921  NC_TYPE_INFO_T *type;
922  NC_GRP_INFO_T *g;
923  NC_VAR_INFO_T *var;
924 
925  /* Any types of this name? */
926  type = (NC_TYPE_INFO_T*)ncindexlookup(grp->type,name);
927  if(type != NULL)
928  return NC_ENAMEINUSE;
929 
930  /* Any child groups of this name? */
931  g = (NC_GRP_INFO_T*)ncindexlookup(grp->children,name);
932  if(g != NULL)
933  return NC_ENAMEINUSE;
934 
935  /* Any variables of this name? */
936  var = (NC_VAR_INFO_T*)ncindexlookup(grp->vars,name);
937  if(var != NULL)
938  return NC_ENAMEINUSE;
939 
940  return NC_NOERR;
941 }
942 
956 int
957 nc4_type_new(size_t size, const char *name, int assignedid,
958  NC_TYPE_INFO_T **type)
959 {
960  NC_TYPE_INFO_T *new_type;
961 
962  LOG((4, "%s: size %d name %s assignedid %d", __func__, size, name, assignedid));
963 
964  /* Check inputs. */
965  assert(type);
966 
967  /* Allocate memory for the type */
968  if (!(new_type = calloc(1, sizeof(NC_TYPE_INFO_T))))
969  return NC_ENOMEM;
970  new_type->hdr.sort = NCTYP;
971 
972  /* Remember info about this type. */
973  new_type->hdr.id = assignedid;
974  new_type->size = size;
975  if (!(new_type->hdr.name = strdup(name))) {
976  free(new_type);
977  return NC_ENOMEM;
978  }
979 
980  new_type->hdr.hashkey = NC_hashmapkey(name, strlen(name));
981 
982  /* Return a pointer to the new type. */
983  *type = new_type;
984 
985  return NC_NOERR;
986 }
987 
1001 int
1002 nc4_type_list_add(NC_GRP_INFO_T *grp, size_t size, const char *name,
1003  NC_TYPE_INFO_T **type)
1004 {
1005  NC_TYPE_INFO_T *new_type;
1006  int retval;
1007 
1008  /* Check inputs. */
1009  assert(grp && name && type);
1010  LOG((4, "%s: size %d name %s", __func__, size, name));
1011 
1012  /* Create the new TYPE_INFO struct. */
1013  if ((retval = nc4_type_new(size, name, grp->nc4_info->next_typeid,
1014  &new_type)))
1015  return retval;
1016  grp->nc4_info->next_typeid++;
1017 
1018  /* Increment the ref. count on the type */
1019  new_type->rc++;
1020 
1021  /* Add object to lists */
1022  ncindexadd(grp->type, (NC_OBJ *)new_type);
1023  obj_track(grp->nc4_info,(NC_OBJ*)new_type);
1024 
1025  /* Return a pointer to the new type. */
1026  *type = new_type;
1027 
1028  return NC_NOERR;
1029 }
1030 
1044 int
1045 nc4_field_list_add(NC_TYPE_INFO_T *parent, const char *name,
1046  size_t offset, nc_type xtype, int ndims,
1047  const int *dim_sizesp)
1048 {
1049  NC_FIELD_INFO_T *field;
1050 
1051  /* Name has already been checked and UTF8 normalized. */
1052  if (!name)
1053  return NC_EINVAL;
1054 
1055  /* Allocate storage for this field information. */
1056  if (!(field = calloc(1, sizeof(NC_FIELD_INFO_T))))
1057  return NC_ENOMEM;
1058  field->hdr.sort = NCFLD;
1059 
1060  /* Store the information about this field. */
1061  if (!(field->hdr.name = strdup(name)))
1062  {
1063  free(field);
1064  return NC_ENOMEM;
1065  }
1066  field->hdr.hashkey = NC_hashmapkey(field->hdr.name,strlen(field->hdr.name));
1067  field->nc_typeid = xtype;
1068  field->offset = offset;
1069  field->ndims = ndims;
1070  if (ndims)
1071  {
1072  int i;
1073  if (!(field->dim_size = malloc(ndims * sizeof(int))))
1074  {
1075  free(field->hdr.name);
1076  free(field);
1077  return NC_ENOMEM;
1078  }
1079  for (i = 0; i < ndims; i++)
1080  field->dim_size[i] = dim_sizesp[i];
1081  }
1082 
1083  /* Add object to lists */
1084  field->hdr.id = nclistlength(parent->u.c.field);
1085  nclistpush(parent->u.c.field,field);
1086 
1087  return NC_NOERR;
1088 }
1089 
1102 int
1103 nc4_enum_member_add(NC_TYPE_INFO_T *parent, size_t size,
1104  const char *name, const void *value)
1105 {
1106  NC_ENUM_MEMBER_INFO_T *member;
1107 
1108  /* Name has already been checked. */
1109  assert(name && size > 0 && value);
1110  LOG((4, "%s: size %d name %s", __func__, size, name));
1111 
1112  /* Allocate storage for this field information. */
1113  if (!(member = calloc(1, sizeof(NC_ENUM_MEMBER_INFO_T))))
1114  return NC_ENOMEM;
1115  if (!(member->value = malloc(size))) {
1116  free(member);
1117  return NC_ENOMEM;
1118  }
1119  if (!(member->name = strdup(name))) {
1120  free(member->value);
1121  free(member);
1122  return NC_ENOMEM;
1123  }
1124 
1125  /* Store the value for this member. */
1126  memcpy(member->value, value, size);
1127 
1128  /* Add object to list */
1129  nclistpush(parent->u.e.enum_member,member);
1130 
1131  return NC_NOERR;
1132 }
1133 
1142 static void
1143 field_free(NC_FIELD_INFO_T *field)
1144 {
1145  /* Free some stuff. */
1146  if (field->hdr.name)
1147  free(field->hdr.name);
1148  if (field->dim_size)
1149  free(field->dim_size);
1150 
1151  /* Nc_Free the memory. */
1152  free(field);
1153 }
1154 
1164 int
1165 nc4_type_free(NC_TYPE_INFO_T *type)
1166 {
1167  int i;
1168 
1169  assert(type && type->rc && type->hdr.name);
1170 
1171  /* Decrement the ref. count on the type */
1172  type->rc--;
1173 
1174  /* Release the type, if the ref. count drops to zero */
1175  if (type->rc == 0)
1176  {
1177  LOG((4, "%s: deleting type %s", __func__, type->hdr.name));
1178 
1179  /* Free the name. */
1180  free(type->hdr.name);
1181 
1182  /* Enums and compound types have lists of fields to clean up. */
1183  switch (type->nc_type_class)
1184  {
1185  case NC_COMPOUND:
1186  {
1187  NC_FIELD_INFO_T *field;
1188 
1189  /* Delete all the fields in this type (there will be some if its a
1190  * compound). */
1191  for(i=0;i<nclistlength(type->u.c.field);i++) {
1192  field = nclistget(type->u.c.field,i);
1193  field_free(field);
1194  }
1195  nclistfree(type->u.c.field);
1196  }
1197  break;
1198 
1199  case NC_ENUM:
1200  {
1201  NC_ENUM_MEMBER_INFO_T *enum_member;
1202 
1203  /* Delete all the enum_members, if any. */
1204  for(i=0;i<nclistlength(type->u.e.enum_member);i++) {
1205  enum_member = nclistget(type->u.e.enum_member,i);
1206  free(enum_member->value);
1207  free(enum_member->name);
1208  free(enum_member);
1209  }
1210  nclistfree(type->u.e.enum_member);
1211  }
1212  break;
1213 
1214  default:
1215  break;
1216  }
1217 
1218  /* Release any HDF5-specific type info. */
1219  if (type->format_type_info)
1220  free(type->format_type_info);
1221 
1222  /* Release the memory. */
1223  free(type);
1224  }
1225 
1226  return NC_NOERR;
1227 }
1228 
1237 static int
1238 att_free(NC_ATT_INFO_T *att)
1239 {
1240  int i;
1241 
1242  assert(att);
1243  LOG((3, "%s: name %s ", __func__, att->hdr.name));
1244 
1245  /* Free memory that was malloced to hold data for this
1246  * attribute. */
1247  if (att->data)
1248  free(att->data);
1249 
1250  /* Free the name. */
1251  if (att->hdr.name)
1252  free(att->hdr.name);
1253 
1254  /* If this is a string array attribute, delete all members of the
1255  * string array, then delete the array of pointers to strings. (The
1256  * array was filled with pointers by HDF5 when the att was read,
1257  * and memory for each string was allocated by HDF5. That's why I
1258  * use free and not nc_free, because the netCDF library didn't
1259  * allocate the memory that is being freed.) */
1260  if (att->stdata)
1261  {
1262  for (i = 0; i < att->len; i++)
1263  if(att->stdata[i])
1264  free(att->stdata[i]);
1265  free(att->stdata);
1266  }
1267 
1268  /* If this att has vlen data, release it. */
1269  if (att->vldata)
1270  {
1271  for (i = 0; i < att->len; i++)
1272  nc_free_vlen(&att->vldata[i]);
1273  free(att->vldata);
1274  }
1275 
1276  /* Free any format-sepecific info. Some formats use this (ex. HDF5)
1277  * and some don't (ex. HDF4). So it may be NULL. */
1278  if (att->format_att_info)
1279  free(att->format_att_info);
1280 
1281  free(att);
1282  return NC_NOERR;
1283 }
1284 
1294 static int
1295 var_free(NC_VAR_INFO_T *var)
1296 {
1297  int i;
1298  int retval;
1299 
1300  assert(var);
1301  LOG((4, "%s: deleting var %s", __func__, var->hdr.name));
1302 
1303  /* First delete all the attributes attached to this var. */
1304  for (i = 0; i < ncindexsize(var->att); i++)
1305  if ((retval = att_free((NC_ATT_INFO_T *)ncindexith(var->att, i))))
1306  return retval;
1307  ncindexfree(var->att);
1308 
1309  /* Free some things that may be allocated. */
1310  if (var->chunksizes)
1311  free(var->chunksizes);
1312 
1313  if (var->hdf5_name)
1314  free(var->hdf5_name);
1315 
1316  if (var->hdr.name)
1317  free(var->hdr.name);
1318 
1319  if (var->dimids)
1320  free(var->dimids);
1321 
1322  if (var->dim)
1323  free(var->dim);
1324 
1325  /* Delete any fill value allocation. */
1326  if (var->fill_value)
1327  free(var->fill_value);
1328 
1329  /* Release type information */
1330  if (var->type_info)
1331  if ((retval = nc4_type_free(var->type_info)))
1332  return retval;
1333 
1334  /* Delete information about the attachment status of dimscales. */
1335  if (var->dimscale_attached)
1336  free(var->dimscale_attached);
1337 
1338  /* Release parameter information. */
1339  if (var->params)
1340  free(var->params);
1341 
1342  /* Delete any format-specific info. */
1343  if (var->format_var_info)
1344  free(var->format_var_info);
1345 
1346  /* Delete the var. */
1347  free(var);
1348 
1349  return NC_NOERR;
1350 }
1351 
1361 int
1362 nc4_var_list_del(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var)
1363 {
1364  int i;
1365 
1366  assert(var && grp);
1367 
1368  /* Remove from lists */
1369  i = ncindexfind(grp->vars, (NC_OBJ *)var);
1370  if (i >= 0)
1371  ncindexidel(grp->vars, i);
1372 
1373  return var_free(var);
1374 }
1375 
1384 static int
1385 dim_free(NC_DIM_INFO_T *dim)
1386 {
1387  assert(dim);
1388  LOG((4, "%s: deleting dim %s", __func__, dim->hdr.name));
1389 
1390  /* Free memory allocated for names. */
1391  if (dim->hdr.name)
1392  free(dim->hdr.name);
1393 
1394  /* Release any format-specific information. */
1395  if (dim->format_dim_info)
1396  free(dim->format_dim_info);
1397 
1398  free(dim);
1399  return NC_NOERR;
1400 }
1401 
1411 int
1412 nc4_dim_list_del(NC_GRP_INFO_T *grp, NC_DIM_INFO_T *dim)
1413 {
1414  if (grp && dim)
1415  {
1416  int pos = ncindexfind(grp->dim, (NC_OBJ *)dim);
1417  if(pos >= 0)
1418  ncindexidel(grp->dim, pos);
1419  }
1420 
1421  return dim_free(dim);
1422 }
1423 
1433 int
1434 nc4_rec_grp_del(NC_GRP_INFO_T *grp)
1435 {
1436  int i;
1437  int retval;
1438 
1439  assert(grp);
1440  LOG((3, "%s: grp->name %s", __func__, grp->hdr.name));
1441 
1442  /* Recursively call this function for each child, if any, stopping
1443  * if there is an error. */
1444  for (i = 0; i < ncindexsize(grp->children); i++)
1445  if ((retval = nc4_rec_grp_del((NC_GRP_INFO_T *)ncindexith(grp->children,
1446  i))))
1447  return retval;
1448  ncindexfree(grp->children);
1449 
1450  /* Free attributes, but leave in parent list */
1451  for (i = 0; i < ncindexsize(grp->att); i++)
1452  if ((retval = att_free((NC_ATT_INFO_T *)ncindexith(grp->att, i))))
1453  return retval;
1454  ncindexfree(grp->att);
1455 
1456  /* Delete all vars. */
1457  for (i = 0; i < ncindexsize(grp->vars); i++)
1458  if ((retval = var_free((NC_VAR_INFO_T *)ncindexith(grp->vars, i))))
1459  return retval;
1460  ncindexfree(grp->vars);
1461 
1462  /* Delete all dims, and free the list of dims. */
1463  for (i = 0; i < ncindexsize(grp->dim); i++)
1464  if ((retval = dim_free((NC_DIM_INFO_T *)ncindexith(grp->dim, i))))
1465  return retval;
1466  ncindexfree(grp->dim);
1467 
1468  /* Delete all types. */
1469  for (i = 0; i < ncindexsize(grp->type); i++)
1470  if ((retval = nc4_type_free((NC_TYPE_INFO_T *)ncindexith(grp->type, i))))
1471  return retval;
1472  ncindexfree(grp->type);
1473 
1474  /* Free the name. */
1475  free(grp->hdr.name);
1476 
1477  /* Release any format-specific information about this group. */
1478  if (grp->format_grp_info)
1479  free(grp->format_grp_info);
1480 
1481  /* Free up this group */
1482  free(grp);
1483 
1484  return NC_NOERR;
1485 }
1486 
1497 int
1498 nc4_att_list_del(NCindex *list, NC_ATT_INFO_T *att)
1499 {
1500  assert(att && list);
1501  ncindexidel(list, ((NC_OBJ *)att)->id);
1502  return att_free(att);
1503 }
1504 
1518 int
1519 nc4_file_list_del(int ncid)
1520 {
1521  NC_FILE_INFO_T *h5;
1522  int retval;
1523 
1524  /* Find our metadata for this file. */
1525  if ((retval = nc4_find_grp_h5(ncid, NULL, &h5)))
1526  return retval;
1527  assert(h5);
1528 
1529  /* Delete the file resources. */
1530  if ((retval = nc4_nc4f_list_del(h5)))
1531  return retval;
1532 
1533  return NC_NOERR;
1534 }
1535 
1545 int
1546 nc4_nc4f_list_del(NC_FILE_INFO_T *h5)
1547 {
1548  int retval;
1549 
1550  assert(h5);
1551 
1552  /* Delete all the list contents for vars, dims, and atts, in each
1553  * group. */
1554  if ((retval = nc4_rec_grp_del(h5->root_grp)))
1555  return retval;
1556 
1557  /* Cleanup these (extra) lists of all dims, groups, and types. */
1558  nclistfree(h5->alldims);
1559  nclistfree(h5->allgroups);
1560  nclistfree(h5->alltypes);
1561 
1562  /* Free the NC_FILE_INFO_T struct. */
1563  free(h5);
1564 
1565  return NC_NOERR;
1566 }
1567 
1581 int
1582 nc4_normalize_name(const char *name, char *norm_name)
1583 {
1584  char *temp_name;
1585  int stat = nc_utf8_normalize((const unsigned char *)name,(unsigned char **)&temp_name);
1586  if(stat != NC_NOERR)
1587  return stat;
1588  if (strlen(temp_name) > NC_MAX_NAME)
1589  {
1590  free(temp_name);
1591  return NC_EMAXNAME;
1592  }
1593  strcpy(norm_name, temp_name);
1594  free(temp_name);
1595  return NC_NOERR;
1596 }
1597 
1598 #ifdef ENABLE_SET_LOG_LEVEL
1599 
1614 int
1615 nc_set_log_level(int new_level)
1616 {
1617 #ifdef LOGGING
1618  /* Remember the new level. */
1619  nc_log_level = new_level;
1620  LOG((4, "log_level changed to %d", nc_log_level));
1621 #endif /*LOGGING */
1622  return 0;
1623 }
1624 #endif /* ENABLE_SET_LOG_LEVEL */
1625 
1626 #ifdef LOGGING
1627 #define MAX_NESTS 10
1628 
1637 static int
1638 rec_print_metadata(NC_GRP_INFO_T *grp, int tab_count)
1639 {
1640  NC_ATT_INFO_T *att;
1641  NC_VAR_INFO_T *var;
1642  NC_DIM_INFO_T *dim;
1643  NC_TYPE_INFO_T *type;
1644  NC_FIELD_INFO_T *field;
1645  char tabs[MAX_NESTS+1] = "";
1646  char *dims_string = NULL;
1647  char temp_string[10];
1648  int t, retval, d, i;
1649 
1650  /* Come up with a number of tabs relative to the group. */
1651  for (t = 0; t < tab_count && t < MAX_NESTS; t++)
1652  tabs[t] = '\t';
1653  tabs[t] = '\0';
1654 
1655  LOG((2, "%s GROUP - %s nc_grpid: %d nvars: %d natts: %d",
1656  tabs, grp->hdr.name, grp->hdr.id, ncindexsize(grp->vars), ncindexsize(grp->att)));
1657 
1658  for (i = 0; i < ncindexsize(grp->att); i++)
1659  {
1660  att = (NC_ATT_INFO_T *)ncindexith(grp->att, i);
1661  assert(att);
1662  LOG((2, "%s GROUP ATTRIBUTE - attnum: %d name: %s type: %d len: %d",
1663  tabs, att->hdr.id, att->hdr.name, att->nc_typeid, att->len));
1664  }
1665 
1666  for (i = 0; i < ncindexsize(grp->dim); i++)
1667  {
1668  dim = (NC_DIM_INFO_T *)ncindexith(grp->dim, i);
1669  assert(dim);
1670  LOG((2, "%s DIMENSION - dimid: %d name: %s len: %d unlimited: %d",
1671  tabs, dim->hdr.id, dim->hdr.name, dim->len, dim->unlimited));
1672  }
1673 
1674  for (i = 0; i < ncindexsize(grp->vars); i++)
1675  {
1676  int j;
1677  var = (NC_VAR_INFO_T*)ncindexith(grp->vars,i);
1678  assert(var);
1679  if (var->ndims > 0)
1680  {
1681  if (!(dims_string = malloc(sizeof(char) * var->ndims * 4)))
1682  return NC_ENOMEM;
1683  strcpy(dims_string, "");
1684  for (d = 0; d < var->ndims; d++)
1685  {
1686  sprintf(temp_string, " %d", var->dimids[d]);
1687  strcat(dims_string, temp_string);
1688  }
1689  }
1690  LOG((2, "%s VARIABLE - varid: %d name: %s ndims: %d dimscale: %d dimids:%s",
1691  tabs, var->hdr.id, var->hdr.name, var->ndims, (int)var->dimscale,
1692  (dims_string ? dims_string : " -")));
1693  for (j = 0; j < ncindexsize(var->att); j++)
1694  {
1695  att = (NC_ATT_INFO_T *)ncindexith(var->att, j);
1696  assert(att);
1697  LOG((2, "%s VAR ATTRIBUTE - attnum: %d name: %s type: %d len: %d",
1698  tabs, att->hdr.id, att->hdr.name, att->nc_typeid, att->len));
1699  }
1700  if (dims_string)
1701  free(dims_string);
1702  }
1703 
1704  for (i = 0; i < ncindexsize(grp->type); i++)
1705  {
1706  type = (NC_TYPE_INFO_T*)ncindexith(grp->type, i);
1707  assert(type);
1708  LOG((2, "%s TYPE - nc_typeid: %d size: %d committed: %d name: %s",
1709  tabs, type->hdr.id, type->size, (int)type->committed, type->hdr.name));
1710  /* Is this a compound type? */
1711  if (type->nc_type_class == NC_COMPOUND)
1712  {
1713  int j;
1714  LOG((3, "compound type"));
1715  for (j = 0; j < nclistlength(type->u.c.field); j++)
1716  {
1717  field = (NC_FIELD_INFO_T *)nclistget(type->u.c.field, j);
1718  LOG((4, "field %s offset %d nctype %d ndims %d", field->hdr.name,
1719  field->offset, field->nc_typeid, field->ndims));
1720  }
1721  }
1722  else if (type->nc_type_class == NC_VLEN)
1723  {
1724  LOG((3, "VLEN type"));
1725  LOG((4, "base_nc_type: %d", type->u.v.base_nc_typeid));
1726  }
1727  else if (type->nc_type_class == NC_OPAQUE)
1728  LOG((3, "Opaque type"));
1729  else if (type->nc_type_class == NC_ENUM)
1730  {
1731  LOG((3, "Enum type"));
1732  LOG((4, "base_nc_type: %d", type->u.e.base_nc_typeid));
1733  }
1734  else
1735  {
1736  LOG((0, "Unknown class: %d", type->nc_type_class));
1737  return NC_EBADTYPE;
1738  }
1739  }
1740 
1741  /* Call self for each child of this group. */
1742  for (i = 0; i < ncindexsize(grp->children); i++)
1743  if ((retval = rec_print_metadata((NC_GRP_INFO_T *)ncindexith(grp->children, i),
1744  tab_count + 1)))
1745  return retval;
1746 
1747  return NC_NOERR;
1748 }
1749 
1760 int
1761 log_metadata_nc(NC_FILE_INFO_T *h5)
1762 {
1763  LOG((2, "*** NetCDF-4 Internal Metadata: int_ncid 0x%x ext_ncid 0x%x",
1764  h5->root_grp->nc4_info->controller->int_ncid,
1765  h5->root_grp->nc4_info->controller->ext_ncid));
1766  if (!h5)
1767  {
1768  LOG((2, "This is a netCDF-3 file."));
1769  return NC_NOERR;
1770  }
1771  LOG((2, "FILE - path: %s cmode: 0x%x parallel: %d redef: %d "
1772  "fill_mode: %d no_write: %d next_nc_grpid: %d", h5->root_grp->nc4_info->controller->path,
1773  h5->cmode, (int)h5->parallel, (int)h5->redef, h5->fill_mode, (int)h5->no_write,
1774  h5->next_nc_grpid));
1775  if(nc_log_level >= 2)
1776  return rec_print_metadata(h5->root_grp, 0);
1777  return NC_NOERR;
1778 }
1779 
1780 #endif /*LOGGING */
1781 
1793 int
1794 NC4_show_metadata(int ncid)
1795 {
1796  int retval = NC_NOERR;
1797 #ifdef LOGGING
1798  NC_FILE_INFO_T *h5;
1799  int old_log_level = nc_log_level;
1800 
1801  /* Find file metadata. */
1802  if ((retval = nc4_find_grp_h5(ncid, NULL, &h5)))
1803  return retval;
1804 
1805  /* Log level must be 2 to see metadata. */
1806  nc_log_level = 2;
1807  retval = log_metadata_nc(h5);
1808  nc_log_level = old_log_level;
1809 #endif /*LOGGING*/
1810  return retval;
1811 }
NC_NOERR
#define NC_NOERR
No Error.
Definition: netcdf.h:325
NC_EINVAL
#define NC_EINVAL
Invalid Argument.
Definition: netcdf.h:335
NC_EBADTYPID
#define NC_EBADTYPID
Bad type ID.
Definition: netcdf.h:454
NC_VLEN
#define NC_VLEN
vlen (variable-length) types
Definition: netcdf.h:53
NC_ENAMEINUSE
#define NC_ENAMEINUSE
String match to name in use.
Definition: netcdf.h:364
nc4_chunk_cache_preemption
float nc4_chunk_cache_preemption
Default chunk cache preemption.
Definition: nc4internal.c:27
NC_MAX_NAME
#define NC_MAX_NAME
Maximum for classic library.
Definition: netcdf.h:275
NC_GLOBAL
#define NC_GLOBAL
Attribute id to put/get a global attribute.
Definition: netcdf.h:248
NC_EMAXNAME
#define NC_EMAXNAME
NC_MAX_NAME exceeded.
Definition: netcdf.h:383
nc4_chunk_cache_size
size_t nc4_chunk_cache_size
Default chunk cache size.
Definition: nc4internal.c:25
NC_UNLIMITED
#define NC_UNLIMITED
Size argument to nc_def_dim() for an unlimited dimension.
Definition: netcdf.h:245
NC_ENOTATT
#define NC_ENOTATT
Attribute not found.
Definition: netcdf.h:365
NC_COMPOUND
#define NC_COMPOUND
compound types
Definition: netcdf.h:56
NC_EIO
#define NC_EIO
Generic IO error.
Definition: netcdf.h:414
NC_OPAQUE
#define NC_OPAQUE
opaque types
Definition: netcdf.h:54
nc4_chunk_cache_nelems
size_t nc4_chunk_cache_nelems
Default chunk cache number of elements.
Definition: nc4internal.c:26
nc_type
int nc_type
The nc_type type is just an int.
Definition: netcdf.h:25
NC_EBADTYPE
#define NC_EBADTYPE
Not a netcdf data type.
Definition: netcdf.h:367
NC_ENUM
#define NC_ENUM
enum types
Definition: netcdf.h:55
nc_free_vlen
EXTERNL int nc_free_vlen(nc_vlen_t *vl)
Definition: dvlen.c:41
NC_ENOMEM
#define NC_ENOMEM
Memory allocation (malloc) failure.
Definition: netcdf.h:405
NC_STRING
#define NC_STRING
string
Definition: netcdf.h:47
NC_EBADID
#define NC_EBADID
Not a netcdf id.
Definition: netcdf.h:332
NC_EBADDIM
#define NC_EBADDIM
Invalid dimension id or name.
Definition: netcdf.h:368
NC_ENOTVAR
#define NC_ENOTVAR
Variable not found.
Definition: netcdf.h:379

Return to the Main Unidata NetCDF page.
Generated on Thu Jan 23 2020 04:18:16 for NetCDF. NetCDF is a Unidata library.