NetCDF  4.8.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 "netcdf.h"
20 #include "netcdf_filter.h"
21 #include "nc4internal.h"
22 #include "nc.h" /* from libsrc */
23 #include "ncdispatch.h" /* from libdispatch */
24 #include "ncutf8.h"
25 #include "netcdf_aux.h"
26 
37 static const NC_reservedatt NC_reserved[] = {
38  {NC_ATT_CLASS, READONLYFLAG|HIDDENATTRFLAG}, /*CLASS*/
39  {NC_ATT_DIMENSION_LIST, READONLYFLAG|HIDDENATTRFLAG}, /*DIMENSION_LIST*/
40  {NC_ATT_NAME, READONLYFLAG|HIDDENATTRFLAG}, /*NAME*/
41  {NC_ATT_REFERENCE_LIST, READONLYFLAG|HIDDENATTRFLAG}, /*REFERENCE_LIST*/
42  {NC_XARRAY_DIMS, READONLYFLAG|HIDDENATTRFLAG}, /*_ARRAY_DIMENSIONS*/
43  {NC_ATT_FORMAT, READONLYFLAG}, /*_Format*/
44  {ISNETCDF4ATT, READONLYFLAG|NAMEONLYFLAG}, /*_IsNetcdf4*/
45  {NCPROPS, READONLYFLAG|NAMEONLYFLAG|MATERIALIZEDFLAG}, /*_NCProperties*/
46  {NC_NCZARR_ATTR, READONLYFLAG|HIDDENATTRFLAG}, /*_NCZARR_ATTR*/
47  {NC_ATT_COORDINATES, READONLYFLAG|HIDDENATTRFLAG|MATERIALIZEDFLAG}, /*_Netcdf4Coordinates*/
48  {NC_ATT_DIMID_NAME, READONLYFLAG|HIDDENATTRFLAG|MATERIALIZEDFLAG}, /*_Netcdf4Dimid*/
49  {SUPERBLOCKATT, READONLYFLAG|NAMEONLYFLAG}, /*_SuperblockVersion*/
50  {NC_ATT_NC3_STRICT_NAME, READONLYFLAG|MATERIALIZEDFLAG}, /*_nc3_strict*/
51 };
52 #define NRESERVED (sizeof(NC_reserved) / sizeof(NC_reservedatt)) /*|NC_reservedatt|*/
53 
54 /* These hold the file caching settings for the library. */
55 size_t nc4_chunk_cache_size = CHUNK_CACHE_SIZE;
56 size_t nc4_chunk_cache_nelems = CHUNK_CACHE_NELEMS;
57 float nc4_chunk_cache_preemption = CHUNK_CACHE_PREEMPTION;
59 static int NC4_move_in_NCList(NC* nc, int new_id);
60 
61 #ifdef LOGGING
62 /* This is the severity level of messages which will be logged. Use
63  severity 0 for errors, 1 for important log messages, 2 for less
64  important, etc. */
65 int nc_log_level = NC_TURN_OFF_LOGGING;
66 #endif /* LOGGING */
67 
80 int
81 nc4_check_name(const char *name, char *norm_name)
82 {
83  char *temp;
84  int retval;
85 
86  assert(norm_name);
87 
88  /* Check for NULL. */
89  if (!name)
90  return NC_EINVAL;
91 
92  /* Make sure this is a valid netcdf name. This should be done
93  * before the name is normalized, because it gives better error
94  * codes for bad utf8 strings. */
95  if ((retval = NC_check_name(name)))
96  return retval;
97 
98  /* Normalize the name. */
99  if ((retval = nc_utf8_normalize((const unsigned char *)name,
100  (unsigned char **)&temp)))
101  return retval;
102 
103  /* Check length of normalized name. */
104  if (strlen(temp) > NC_MAX_NAME)
105  {
106  free(temp);
107  return NC_EMAXNAME;
108  }
109 
110  /* Copy the normalized name. */
111  strcpy(norm_name, temp);
112  free(temp);
113 
114  return NC_NOERR;
115 }
116 
137 int
138 nc4_file_list_add(int ncid, const char *path, int mode, void **dispatchdata)
139 {
140  NC *nc;
141  int ret;
142 
143  /* Find NC pointer for this file. */
144  if ((ret = NC_check_id(ncid, &nc)))
145  return ret;
146 
147  /* Add necessary structs to hold netcdf-4 file data. This is where
148  * the NC_FILE_INFO_T struct is allocated for the file. */
149  if ((ret = nc4_nc4f_list_add(nc, path, mode)))
150  return ret;
151 
152  /* If the user wants a pointer to the NC_FILE_INFO_T, then provide
153  * it. */
154  if (dispatchdata)
155  *dispatchdata = nc->dispatchdata;
156 
157  return NC_NOERR;
158 }
159 
173 int
174 nc4_file_change_ncid(int ncid, unsigned short new_ncid_index)
175 {
176  NC *nc;
177  int ret;
178 
179  LOG((2, "%s: ncid %d new_ncid_index %d", __func__, ncid, new_ncid_index));
180 
181  /* Find NC pointer for this file. */
182  if ((ret = NC_check_id(ncid, &nc)))
183  return ret;
184 
185  /* Move it in the list. It will faile if list spot is already
186  * occupied. */
187  LOG((3, "moving nc->ext_ncid %d nc->ext_ncid >> ID_SHIFT %d",
188  nc->ext_ncid, nc->ext_ncid >> ID_SHIFT));
189  if (NC4_move_in_NCList(nc, new_ncid_index))
190  return NC_EIO;
191  LOG((3, "moved to new_ncid_index %d new nc->ext_ncid %d", new_ncid_index,
192  nc->ext_ncid));
193 
194  return NC_NOERR;
195 }
196 
216 int
217 nc4_file_list_get(int ncid, char **path, int *mode, void **dispatchdata)
218 {
219  NC *nc;
220  int ret;
221 
222  /* Find NC pointer for this file. */
223  if ((ret = NC_check_id(ncid, &nc)))
224  return ret;
225 
226  /* If the user wants path, give it. */
227  if (path)
228  strncpy(*path, nc->path, NC_MAX_NAME);
229 
230  /* If the user wants mode, give it. */
231  if (mode)
232  *mode = nc->mode;
233 
234  /* If the user wants dispatchdata, give it. */
235  if (dispatchdata)
236  *dispatchdata = nc->dispatchdata;
237 
238  return NC_NOERR;
239 }
240 
255 int
256 nc4_nc4f_list_add(NC *nc, const char *path, int mode)
257 {
258  NC_FILE_INFO_T *h5;
259  int retval;
260 
261  assert(nc && !NC4_DATA(nc) && path);
262 
263  /* We need to malloc and initialize the substructure
264  NC_FILE_INFO_T. */
265  if (!(h5 = calloc(1, sizeof(NC_FILE_INFO_T))))
266  return NC_ENOMEM;
267  nc->dispatchdata = h5;
268  h5->controller = nc;
269 
270  h5->hdr.sort = NCFIL;
271  h5->hdr.name = strdup(path);
272  h5->hdr.id = nc->ext_ncid;
273 
274  /* Hang on to cmode, and note that we're in define mode. */
275  h5->cmode = mode | NC_INDEF;
276 
277  /* The next_typeid needs to be set beyond the end of our atomic
278  * types. */
279  h5->next_typeid = NC_FIRSTUSERTYPEID;
280 
281  /* Initialize lists for dimensions, types, and groups. */
282  h5->alldims = nclistnew();
283  h5->alltypes = nclistnew();
284  h5->allgroups = nclistnew();
285 
286  /* There's always at least one open group - the root
287  * group. Allocate space for one group's worth of information. Set
288  * its grp id, name, and allocate associated empty lists. */
289  if ((retval = nc4_grp_list_add(h5, NULL, NC_GROUP_NAME, &h5->root_grp)))
290  return retval;
291 
292  return NC_NOERR;
293 }
294 
307 int
308 nc4_find_nc4_grp(int ncid, NC_GRP_INFO_T **grp)
309 {
310  return nc4_find_nc_grp_h5(ncid, NULL, grp, NULL);
311 }
312 
328 int
329 nc4_find_grp_h5(int ncid, NC_GRP_INFO_T **grp, NC_FILE_INFO_T **h5)
330 {
331  return nc4_find_nc_grp_h5(ncid, NULL, grp, h5);
332 }
333 
348 int
349 nc4_find_nc_grp_h5(int ncid, NC **nc, NC_GRP_INFO_T **grp, NC_FILE_INFO_T **h5)
350 {
351  NC_GRP_INFO_T *my_grp = NULL;
352  NC_FILE_INFO_T *my_h5 = NULL;
353  NC *my_nc;
354  int retval;
355 
356  /* Look up file metadata. */
357  if ((retval = NC_check_id(ncid, &my_nc)))
358  return retval;
359  my_h5 = my_nc->dispatchdata;
360  assert(my_h5 && my_h5->root_grp);
361 
362  /* If we can't find it, the grp id part of ncid is bad. */
363  if (!(my_grp = nclistget(my_h5->allgroups, (ncid & GRP_ID_MASK))))
364  return NC_EBADID;
365 
366  /* Return pointers to caller, if desired. */
367  if (nc)
368  *nc = my_nc;
369  if (h5)
370  *h5 = my_h5;
371  if (grp)
372  *grp = my_grp;
373 
374  return NC_NOERR;
375 }
376 
392 int
393 nc4_find_grp_h5_var(int ncid, int varid, NC_FILE_INFO_T **h5, NC_GRP_INFO_T **grp,
394  NC_VAR_INFO_T **var)
395 {
396  NC_FILE_INFO_T *my_h5;
397  NC_GRP_INFO_T *my_grp;
398  NC_VAR_INFO_T *my_var;
399  int retval;
400 
401  /* Look up file and group metadata. */
402  if ((retval = nc4_find_grp_h5(ncid, &my_grp, &my_h5)))
403  return retval;
404  assert(my_grp && my_h5);
405 
406  /* Find the var. */
407  if (!(my_var = (NC_VAR_INFO_T *)ncindexith(my_grp->vars, varid)))
408  return NC_ENOTVAR;
409  assert(my_var && my_var->hdr.id == varid);
410 
411  /* Return pointers that caller wants. */
412  if (h5)
413  *h5 = my_h5;
414  if (grp)
415  *grp = my_grp;
416  if (var)
417  *var = my_var;
418 
419  return NC_NOERR;
420 }
421 
435 int
436 nc4_find_dim(NC_GRP_INFO_T *grp, int dimid, NC_DIM_INFO_T **dim,
437  NC_GRP_INFO_T **dim_grp)
438 {
439  assert(grp && grp->nc4_info && dim);
440  LOG((4, "%s: dimid %d", __func__, dimid));
441 
442  /* Find the dim info. */
443  if (!((*dim) = nclistget(grp->nc4_info->alldims, dimid)))
444  return NC_EBADDIM;
445 
446  /* Give the caller the group the dimension is in. */
447  if (dim_grp)
448  *dim_grp = (*dim)->container;
449 
450  return NC_NOERR;
451 }
452 
463 int
464 nc4_find_var(NC_GRP_INFO_T *grp, const char *name, NC_VAR_INFO_T **var)
465 {
466  assert(grp && var && name);
467 
468  /* Find the var info. */
469  *var = (NC_VAR_INFO_T*)ncindexlookup(grp->vars,name);
470  return NC_NOERR;
471 }
472 
482 NC_TYPE_INFO_T *
483 nc4_rec_find_named_type(NC_GRP_INFO_T *start_grp, char *name)
484 {
485  NC_GRP_INFO_T *g;
486  NC_TYPE_INFO_T *type, *res;
487  int i;
488 
489  assert(start_grp);
490 
491  /* Does this group have the type we are searching for? */
492  type = (NC_TYPE_INFO_T*)ncindexlookup(start_grp->type,name);
493  if(type != NULL)
494  return type;
495 
496  /* Search subgroups. */
497  for(i=0;i<ncindexsize(start_grp->children);i++) {
498  g = (NC_GRP_INFO_T*)ncindexith(start_grp->children,i);
499  if(g == NULL) continue;
500  if ((res = nc4_rec_find_named_type(g, name)))
501  return res;
502  }
503  /* Can't find it. Oh, woe is me! */
504  return NULL;
505 }
506 
518 int
519 nc4_find_type(const NC_FILE_INFO_T *h5, nc_type typeid, NC_TYPE_INFO_T **type)
520 {
521  /* Check inputs. */
522  assert(h5);
523  if (typeid < 0 || !type)
524  return NC_EINVAL;
525  *type = NULL;
526 
527  /* Atomic types don't have associated NC_TYPE_INFO_T struct, just
528  * return NOERR. */
529  if (typeid <= NC_STRING)
530  return NC_NOERR;
531 
532  /* Find the type. */
533  if (!(*type = nclistget(h5->alltypes,typeid)))
534  return NC_EBADTYPID;
535 
536  return NC_NOERR;
537 }
538 
554 int
555 nc4_find_grp_att(NC_GRP_INFO_T *grp, int varid, const char *name, int attnum,
556  NC_ATT_INFO_T **att)
557 {
558  NC_VAR_INFO_T *var;
559  NC_ATT_INFO_T *my_att;
560  NCindex *attlist = NULL;
561 
562  assert(grp && grp->hdr.name && att);
563 
564  LOG((4, "%s: grp->name %s varid %d attnum %d", __func__, grp->hdr.name,
565  varid, attnum));
566 
567  /* Get either the global or a variable attribute list. */
568  if (varid == NC_GLOBAL)
569  {
570  attlist = grp->att;
571  }
572  else
573  {
574  var = (NC_VAR_INFO_T*)ncindexith(grp->vars,varid);
575  if (!var) return NC_ENOTVAR;
576 
577  attlist = var->att;
578  }
579  assert(attlist);
580 
581  /* Now find the attribute by name or number. If a name is provided,
582  * ignore the attnum. */
583  if (name)
584  my_att = (NC_ATT_INFO_T *)ncindexlookup(attlist, name);
585  else
586  my_att = (NC_ATT_INFO_T *)ncindexith(attlist, attnum);
587 
588  if (!my_att)
589  return NC_ENOTATT;
590 
591  *att = my_att;
592  return NC_NOERR;
593 }
594 
611 int
612 nc4_find_nc_att(int ncid, int varid, const char *name, int attnum,
613  NC_ATT_INFO_T **att)
614 {
615  NC_GRP_INFO_T *grp;
616  int retval;
617 
618  LOG((4, "nc4_find_nc_att: ncid 0x%x varid %d name %s attnum %d",
619  ncid, varid, name, attnum));
620 
621  /* Find info for this file and group, and set pointer to each. */
622  if ((retval = nc4_find_grp_h5(ncid, &grp, NULL)))
623  return retval;
624  assert(grp);
625 
626  return nc4_find_grp_att(grp, varid, name, attnum, att);
627 }
628 
637 static void
638 obj_track(NC_FILE_INFO_T* file, NC_OBJ* obj)
639 {
640  NClist* list = NULL;
641  /* record the object in the file */
642  switch (obj->sort) {
643  case NCDIM: list = file->alldims; break;
644  case NCTYP: list = file->alltypes; break;
645  case NCGRP: list = file->allgroups; break;
646  default:
647  assert(NC_FALSE);
648  }
649  /* Insert at the appropriate point in the list */
650  nclistset(list,obj->id,obj);
651 }
652 
667 int
668 nc4_var_list_add2(NC_GRP_INFO_T *grp, const char *name, NC_VAR_INFO_T **var)
669 {
670  NC_VAR_INFO_T *new_var = NULL;
671 
672  /* Allocate storage for new variable. */
673  if (!(new_var = calloc(1, sizeof(NC_VAR_INFO_T))))
674  return NC_ENOMEM;
675  new_var->hdr.sort = NCVAR;
676  new_var->container = grp;
677 
678  /* These are the HDF5-1.8.4 defaults. */
679  new_var->chunk_cache_size = nc4_chunk_cache_size;
680  new_var->chunk_cache_nelems = nc4_chunk_cache_nelems;
681  new_var->chunk_cache_preemption = nc4_chunk_cache_preemption;
682 
683  /* Now fill in the values in the var info structure. */
684  new_var->hdr.id = ncindexsize(grp->vars);
685  if (!(new_var->hdr.name = strdup(name))) {
686  if(new_var)
687  free(new_var);
688  return NC_ENOMEM;
689  }
690 
691  /* Create an indexed list for the attributes. */
692  new_var->att = ncindexnew(0);
693 
694  /* Officially track it */
695  ncindexadd(grp->vars, (NC_OBJ *)new_var);
696 
697  /* Set the var pointer, if one was given */
698  if (var)
699  *var = new_var;
700 
701  return NC_NOERR;
702 }
703 
716 int
717 nc4_var_set_ndims(NC_VAR_INFO_T *var, int ndims)
718 {
719  assert(var);
720 
721  /* Remember the number of dimensions. */
722  var->ndims = ndims;
723 
724  /* Allocate space for dimension information. */
725  if (ndims)
726  {
727  if (!(var->dim = calloc(ndims, sizeof(NC_DIM_INFO_T *))))
728  return NC_ENOMEM;
729  if (!(var->dimids = calloc(ndims, sizeof(int))))
730  return NC_ENOMEM;
731 
732  /* Initialize dimids to illegal values (-1). See the comment
733  in nc4_rec_match_dimscales(). */
734  memset(var->dimids, -1, ndims * sizeof(int));
735  }
736 
737  return NC_NOERR;
738 }
739 
754 int
755 nc4_var_list_add(NC_GRP_INFO_T* grp, const char* name, int ndims,
756  NC_VAR_INFO_T **var)
757 {
758  int retval;
759 
760  if ((retval = nc4_var_list_add2(grp, name, var)))
761  return retval;
762  if ((retval = nc4_var_set_ndims(*var, ndims)))
763  return retval;
764 
765  return NC_NOERR;
766 }
767 
781 int
782 nc4_dim_list_add(NC_GRP_INFO_T *grp, const char *name, size_t len,
783  int assignedid, NC_DIM_INFO_T **dim)
784 {
785  NC_DIM_INFO_T *new_dim = NULL;
786 
787  assert(grp && name);
788 
789  /* Allocate memory for dim metadata. */
790  if (!(new_dim = calloc(1, sizeof(NC_DIM_INFO_T))))
791  return NC_ENOMEM;
792 
793  new_dim->hdr.sort = NCDIM;
794 
795  /* Assign the dimension ID. */
796  if (assignedid >= 0)
797  new_dim->hdr.id = assignedid;
798  else
799  new_dim->hdr.id = grp->nc4_info->next_dimid++;
800 
801  /* Remember the name and create a hash. */
802  if (!(new_dim->hdr.name = strdup(name))) {
803  if(new_dim)
804  free(new_dim);
805 
806  return NC_ENOMEM;
807  }
808 
809  /* Is dimension unlimited? */
810  new_dim->len = len;
811  if (len == NC_UNLIMITED)
812  new_dim->unlimited = NC_TRUE;
813 
814  /* Remember the containing group. */
815  new_dim->container = grp;
816 
817  /* Add object to dimension list for this group. */
818  ncindexadd(grp->dim, (NC_OBJ *)new_dim);
819  obj_track(grp->nc4_info, (NC_OBJ *)new_dim);
820 
821  /* Set the dim pointer, if one was given */
822  if (dim)
823  *dim = new_dim;
824 
825  return NC_NOERR;
826 }
827 
840 int
841 nc4_att_list_add(NCindex *list, const char *name, NC_ATT_INFO_T **att)
842 {
843  NC_ATT_INFO_T *new_att = NULL;
844 
845  LOG((3, "%s: name %s ", __func__, name));
846 
847  if (!(new_att = calloc(1, sizeof(NC_ATT_INFO_T))))
848  return NC_ENOMEM;
849  new_att->hdr.sort = NCATT;
850 
851  /* Fill in the information we know. */
852  new_att->hdr.id = ncindexsize(list);
853  if (!(new_att->hdr.name = strdup(name))) {
854  if(new_att)
855  free(new_att);
856  return NC_ENOMEM;
857  }
858 
859  /* Add object to list as specified by its number */
860  ncindexadd(list, (NC_OBJ *)new_att);
861 
862  /* Set the attribute pointer, if one was given */
863  if (att)
864  *att = new_att;
865 
866  return NC_NOERR;
867 }
868 
883 int
884 nc4_grp_list_add(NC_FILE_INFO_T *h5, NC_GRP_INFO_T *parent, char *name,
885  NC_GRP_INFO_T **grp)
886 {
887  NC_GRP_INFO_T *new_grp;
888 
889  /* Check inputs. */
890  assert(h5 && name);
891  LOG((3, "%s: name %s ", __func__, name));
892 
893  /* Get the memory to store this groups info. */
894  if (!(new_grp = calloc(1, sizeof(NC_GRP_INFO_T))))
895  return NC_ENOMEM;
896 
897  /* Fill in this group's information. */
898  new_grp->hdr.sort = NCGRP;
899  new_grp->nc4_info = h5;
900  new_grp->parent = parent;
901 
902  /* Assign the group ID. The root group will get id 0. */
903  new_grp->hdr.id = h5->next_nc_grpid++;
904  assert(parent || !new_grp->hdr.id);
905 
906  /* Handle the group name. */
907  if (!(new_grp->hdr.name = strdup(name)))
908  {
909  free(new_grp);
910  return NC_ENOMEM;
911  }
912 
913  /* Set up new indexed lists for stuff this group can contain. */
914  new_grp->children = ncindexnew(0);
915  new_grp->dim = ncindexnew(0);
916  new_grp->att = ncindexnew(0);
917  new_grp->type = ncindexnew(0);
918  new_grp->vars = ncindexnew(0);
919 
920  /* Add object to lists */
921  if (parent)
922  ncindexadd(parent->children, (NC_OBJ *)new_grp);
923  obj_track(h5, (NC_OBJ *)new_grp);
924 
925  /* Set the group pointer, if one was given */
926  if (grp)
927  *grp = new_grp;
928 
929  return NC_NOERR;
930 }
931 
945 int
946 nc4_check_dup_name(NC_GRP_INFO_T *grp, char *name)
947 {
948  NC_TYPE_INFO_T *type;
949  NC_GRP_INFO_T *g;
950  NC_VAR_INFO_T *var;
951 
952  /* Any types of this name? */
953  type = (NC_TYPE_INFO_T*)ncindexlookup(grp->type,name);
954  if(type != NULL)
955  return NC_ENAMEINUSE;
956 
957  /* Any child groups of this name? */
958  g = (NC_GRP_INFO_T*)ncindexlookup(grp->children,name);
959  if(g != NULL)
960  return NC_ENAMEINUSE;
961 
962  /* Any variables of this name? */
963  var = (NC_VAR_INFO_T*)ncindexlookup(grp->vars,name);
964  if(var != NULL)
965  return NC_ENAMEINUSE;
966 
967  return NC_NOERR;
968 }
969 
983 int
984 nc4_type_new(size_t size, const char *name, int assignedid,
985  NC_TYPE_INFO_T **type)
986 {
987  NC_TYPE_INFO_T *new_type;
988 
989  LOG((4, "%s: size %d name %s assignedid %d", __func__, size, name, assignedid));
990 
991  /* Check inputs. */
992  assert(type);
993 
994  /* Allocate memory for the type */
995  if (!(new_type = calloc(1, sizeof(NC_TYPE_INFO_T))))
996  return NC_ENOMEM;
997  new_type->hdr.sort = NCTYP;
998  new_type->hdr.id = assignedid;
999 
1000  /* Remember info about this type. */
1001  new_type->size = size;
1002  if (!(new_type->hdr.name = strdup(name))) {
1003  free(new_type);
1004  return NC_ENOMEM;
1005  }
1006 
1007  /* Return a pointer to the new type. */
1008  *type = new_type;
1009 
1010  return NC_NOERR;
1011 }
1012 
1026 int
1027 nc4_type_list_add(NC_GRP_INFO_T *grp, size_t size, const char *name,
1028  NC_TYPE_INFO_T **type)
1029 {
1030  NC_TYPE_INFO_T *new_type;
1031  int retval;
1032 
1033  /* Check inputs. */
1034  assert(grp && name && type);
1035  LOG((4, "%s: size %d name %s", __func__, size, name));
1036 
1037  /* Create the new TYPE_INFO struct. */
1038  if ((retval = nc4_type_new(size, name, grp->nc4_info->next_typeid,
1039  &new_type)))
1040  return retval;
1041  grp->nc4_info->next_typeid++;
1042 
1043  /* Increment the ref. count on the type */
1044  new_type->rc++;
1045 
1046  /* Add object to lists */
1047  ncindexadd(grp->type, (NC_OBJ *)new_type);
1048  obj_track(grp->nc4_info,(NC_OBJ*)new_type);
1049 
1050  /* Return a pointer to the new type. */
1051  *type = new_type;
1052 
1053  return NC_NOERR;
1054 }
1055 
1069 int
1070 nc4_field_list_add(NC_TYPE_INFO_T *parent, const char *name,
1071  size_t offset, nc_type xtype, int ndims,
1072  const int *dim_sizesp)
1073 {
1074  NC_FIELD_INFO_T *field;
1075 
1076  /* Name has already been checked and UTF8 normalized. */
1077  if (!name)
1078  return NC_EINVAL;
1079 
1080  /* Allocate storage for this field information. */
1081  if (!(field = calloc(1, sizeof(NC_FIELD_INFO_T))))
1082  return NC_ENOMEM;
1083  field->hdr.sort = NCFLD;
1084 
1085  /* Store the information about this field. */
1086  if (!(field->hdr.name = strdup(name)))
1087  {
1088  free(field);
1089  return NC_ENOMEM;
1090  }
1091  field->nc_typeid = xtype;
1092  field->offset = offset;
1093  field->ndims = ndims;
1094  if (ndims)
1095  {
1096  int i;
1097  if (!(field->dim_size = malloc(ndims * sizeof(int))))
1098  {
1099  free(field->hdr.name);
1100  free(field);
1101  return NC_ENOMEM;
1102  }
1103  for (i = 0; i < ndims; i++)
1104  field->dim_size[i] = dim_sizesp[i];
1105  }
1106 
1107  /* Add object to lists */
1108  field->hdr.id = nclistlength(parent->u.c.field);
1109  nclistpush(parent->u.c.field,field);
1110 
1111  return NC_NOERR;
1112 }
1113 
1126 int
1127 nc4_enum_member_add(NC_TYPE_INFO_T *parent, size_t size,
1128  const char *name, const void *value)
1129 {
1130  NC_ENUM_MEMBER_INFO_T *member;
1131 
1132  /* Name has already been checked. */
1133  assert(name && size > 0 && value);
1134  LOG((4, "%s: size %d name %s", __func__, size, name));
1135 
1136  /* Allocate storage for this field information. */
1137  if (!(member = calloc(1, sizeof(NC_ENUM_MEMBER_INFO_T))))
1138  return NC_ENOMEM;
1139  if (!(member->value = malloc(size))) {
1140  free(member);
1141  return NC_ENOMEM;
1142  }
1143  if (!(member->name = strdup(name))) {
1144  free(member->value);
1145  free(member);
1146  return NC_ENOMEM;
1147  }
1148 
1149  /* Store the value for this member. */
1150  memcpy(member->value, value, size);
1151 
1152  /* Add object to list */
1153  nclistpush(parent->u.e.enum_member,member);
1154 
1155  return NC_NOERR;
1156 }
1157 
1166 static void
1167 field_free(NC_FIELD_INFO_T *field)
1168 {
1169  /* Free some stuff. */
1170  if (field->hdr.name)
1171  free(field->hdr.name);
1172  if (field->dim_size)
1173  free(field->dim_size);
1174 
1175  /* Nc_Free the memory. */
1176  free(field);
1177 }
1178 
1188 int
1189 nc4_type_free(NC_TYPE_INFO_T *type)
1190 {
1191  int i;
1192 
1193  assert(type && type->rc && type->hdr.name);
1194 
1195  /* Decrement the ref. count on the type */
1196  type->rc--;
1197 
1198  /* Release the type, if the ref. count drops to zero */
1199  if (type->rc == 0)
1200  {
1201  LOG((4, "%s: deleting type %s", __func__, type->hdr.name));
1202 
1203  /* Free the name. */
1204  free(type->hdr.name);
1205 
1206  /* Enums and compound types have lists of fields to clean up. */
1207  switch (type->nc_type_class)
1208  {
1209  case NC_COMPOUND:
1210  {
1211  NC_FIELD_INFO_T *field;
1212 
1213  /* Delete all the fields in this type (there will be some if its a
1214  * compound). */
1215  for(i=0;i<nclistlength(type->u.c.field);i++) {
1216  field = nclistget(type->u.c.field,i);
1217  field_free(field);
1218  }
1219  nclistfree(type->u.c.field);
1220  }
1221  break;
1222 
1223  case NC_ENUM:
1224  {
1225  NC_ENUM_MEMBER_INFO_T *enum_member;
1226 
1227  /* Delete all the enum_members, if any. */
1228  for(i=0;i<nclistlength(type->u.e.enum_member);i++) {
1229  enum_member = nclistget(type->u.e.enum_member,i);
1230  free(enum_member->value);
1231  free(enum_member->name);
1232  free(enum_member);
1233  }
1234  nclistfree(type->u.e.enum_member);
1235  }
1236  break;
1237 
1238  default:
1239  break;
1240  }
1241 
1242  /* Release the memory. */
1243  free(type);
1244  }
1245 
1246  return NC_NOERR;
1247 }
1248 
1257 int
1258 nc4_att_free(NC_ATT_INFO_T *att)
1259 {
1260  int i;
1261 
1262  assert(att);
1263  LOG((3, "%s: name %s ", __func__, att->hdr.name));
1264 
1265  /* Free memory that was malloced to hold data for this
1266  * attribute. */
1267  if (att->data)
1268  free(att->data);
1269 
1270  /* Free the name. */
1271  if (att->hdr.name)
1272  free(att->hdr.name);
1273 
1274  /* If this is a string array attribute, delete all members of the
1275  * string array, then delete the array of pointers to strings. (The
1276  * array was filled with pointers by HDF5 when the att was read,
1277  * and memory for each string was allocated by HDF5. That's why I
1278  * use free and not nc_free, because the netCDF library didn't
1279  * allocate the memory that is being freed.) */
1280  if (att->stdata)
1281  {
1282  for (i = 0; i < att->len; i++)
1283  if(att->stdata[i])
1284  free(att->stdata[i]);
1285  free(att->stdata);
1286  }
1287 
1288  /* If this att has vlen data, release it. */
1289  if (att->vldata)
1290  {
1291  for (i = 0; i < att->len; i++)
1292  nc_free_vlen(&att->vldata[i]);
1293  free(att->vldata);
1294  }
1295 
1296  free(att);
1297  return NC_NOERR;
1298 }
1299 
1309 static int
1310 var_free(NC_VAR_INFO_T *var)
1311 {
1312  int i;
1313  int retval;
1314 
1315  assert(var);
1316  LOG((4, "%s: deleting var %s", __func__, var->hdr.name));
1317 
1318  /* First delete all the attributes attached to this var. */
1319  for (i = 0; i < ncindexsize(var->att); i++)
1320  if ((retval = nc4_att_free((NC_ATT_INFO_T *)ncindexith(var->att, i))))
1321  return retval;
1322  ncindexfree(var->att);
1323 
1324  /* Free some things that may be allocated. */
1325  if (var->chunksizes)
1326  free(var->chunksizes);
1327 
1328  if (var->alt_name)
1329  free(var->alt_name);
1330 
1331  if (var->dimids)
1332  free(var->dimids);
1333 
1334  if (var->dim)
1335  free(var->dim);
1336 
1337  /* Delete any fill value allocation. */
1338  if (var->fill_value)
1339  free(var->fill_value);
1340 
1341  /* Release type information */
1342  if (var->type_info)
1343  if ((retval = nc4_type_free(var->type_info)))
1344  return retval;
1345 
1346  /* Do this last because debugging may need it */
1347  if (var->hdr.name)
1348  free(var->hdr.name);
1349 
1350  /* Delete the var. */
1351  free(var);
1352 
1353  return NC_NOERR;
1354 }
1355 
1365 int
1366 nc4_var_list_del(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var)
1367 {
1368  int i;
1369 
1370  assert(var && grp);
1371 
1372  /* Remove from lists */
1373  i = ncindexfind(grp->vars, (NC_OBJ *)var);
1374  if (i >= 0)
1375  ncindexidel(grp->vars, i);
1376 
1377  return var_free(var);
1378 }
1379 
1388 static int
1389 dim_free(NC_DIM_INFO_T *dim)
1390 {
1391  assert(dim);
1392  LOG((4, "%s: deleting dim %s", __func__, dim->hdr.name));
1393 
1394  /* Free memory allocated for names. */
1395  if (dim->hdr.name)
1396  free(dim->hdr.name);
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 */
1451  for (i = 0; i < ncindexsize(grp->att); i++)
1452  if ((retval = nc4_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  NC_VAR_INFO_T* v = (NC_VAR_INFO_T *)ncindexith(grp->vars, i);
1459  if ((retval = var_free(v)))
1460  return retval;
1461  }
1462  ncindexfree(grp->vars);
1463 
1464  /* Delete all dims, and free the list of dims. */
1465  for (i = 0; i < ncindexsize(grp->dim); i++)
1466  if ((retval = dim_free((NC_DIM_INFO_T *)ncindexith(grp->dim, i))))
1467  return retval;
1468  ncindexfree(grp->dim);
1469 
1470  /* Delete all types. */
1471  for (i = 0; i < ncindexsize(grp->type); i++)
1472  if ((retval = nc4_type_free((NC_TYPE_INFO_T *)ncindexith(grp->type, i))))
1473  return retval;
1474  ncindexfree(grp->type);
1475 
1476  /* Free the name. */
1477  free(grp->hdr.name);
1478 
1479  /* Free up this group */
1480  free(grp);
1481 
1482  return NC_NOERR;
1483 }
1484 
1495 int
1496 nc4_att_list_del(NCindex *list, NC_ATT_INFO_T *att)
1497 {
1498  assert(att && list);
1499  ncindexidel(list, ((NC_OBJ *)att)->id);
1500  return nc4_att_free(att);
1501 }
1502 
1516 int
1517 nc4_file_list_del(int ncid)
1518 {
1519  NC_FILE_INFO_T *h5;
1520  int retval;
1521 
1522  /* Find our metadata for this file. */
1523  if ((retval = nc4_find_grp_h5(ncid, NULL, &h5)))
1524  return retval;
1525  assert(h5);
1526 
1527  /* Delete the file resources. */
1528  if ((retval = nc4_nc4f_list_del(h5)))
1529  return retval;
1530 
1531  return NC_NOERR;
1532 }
1533 
1543 int
1544 nc4_nc4f_list_del(NC_FILE_INFO_T *h5)
1545 {
1546  int retval;
1547 
1548  assert(h5);
1549 
1550  /* Delete all the list contents for vars, dims, and atts, in each
1551  * group. */
1552  if ((retval = nc4_rec_grp_del(h5->root_grp)))
1553  return retval;
1554 
1555  /* Cleanup these (extra) lists of all dims, groups, and types. */
1556  nclistfree(h5->alldims);
1557  nclistfree(h5->allgroups);
1558  nclistfree(h5->alltypes);
1559 
1560  /* Free the NC_FILE_INFO_T struct. */
1561  nullfree(h5->hdr.name);
1562  free(h5);
1563 
1564  return NC_NOERR;
1565 }
1566 
1580 int
1581 nc4_normalize_name(const char *name, char *norm_name)
1582 {
1583  char *temp_name;
1584  int stat = nc_utf8_normalize((const unsigned char *)name,(unsigned char **)&temp_name);
1585  if(stat != NC_NOERR)
1586  return stat;
1587  if (strlen(temp_name) > NC_MAX_NAME)
1588  {
1589  free(temp_name);
1590  return NC_EMAXNAME;
1591  }
1592  strcpy(norm_name, temp_name);
1593  free(temp_name);
1594  return NC_NOERR;
1595 }
1596 
1597 #ifdef ENABLE_SET_LOG_LEVEL
1598 
1613 int
1614 nc_set_log_level(int new_level)
1615 {
1616 #ifdef LOGGING
1617  /* Remember the new level. */
1618  nc_log_level = new_level;
1619  LOG((4, "log_level changed to %d", nc_log_level));
1620 #endif /*LOGGING */
1621  return 0;
1622 }
1623 #endif /* ENABLE_SET_LOG_LEVEL */
1624 
1625 #ifdef LOGGING
1626 #define MAX_NESTS 10
1627 
1636 static int
1637 rec_print_metadata(NC_GRP_INFO_T *grp, int tab_count)
1638 {
1639  NC_ATT_INFO_T *att;
1640  NC_VAR_INFO_T *var;
1641  NC_DIM_INFO_T *dim;
1642  NC_TYPE_INFO_T *type;
1643  NC_FIELD_INFO_T *field;
1644  char tabs[MAX_NESTS+1] = "";
1645  char temp_string[10];
1646  int t, retval, d, i;
1647 
1648  /* Come up with a number of tabs relative to the group. */
1649  for (t = 0; t < tab_count && t < MAX_NESTS; t++)
1650  tabs[t] = '\t';
1651  tabs[t] = '\0';
1652 
1653  LOG((2, "%s GROUP - %s nc_grpid: %d nvars: %d natts: %d",
1654  tabs, grp->hdr.name, grp->hdr.id, ncindexsize(grp->vars), ncindexsize(grp->att)));
1655 
1656  for (i = 0; i < ncindexsize(grp->att); i++)
1657  {
1658  att = (NC_ATT_INFO_T *)ncindexith(grp->att, i);
1659  assert(att);
1660  LOG((2, "%s GROUP ATTRIBUTE - attnum: %d name: %s type: %d len: %d",
1661  tabs, att->hdr.id, att->hdr.name, att->nc_typeid, att->len));
1662  }
1663 
1664  for (i = 0; i < ncindexsize(grp->dim); i++)
1665  {
1666  dim = (NC_DIM_INFO_T *)ncindexith(grp->dim, i);
1667  assert(dim);
1668  LOG((2, "%s DIMENSION - dimid: %d name: %s len: %d unlimited: %d",
1669  tabs, dim->hdr.id, dim->hdr.name, dim->len, dim->unlimited));
1670  }
1671 
1672  for (i = 0; i < ncindexsize(grp->vars); i++)
1673  {
1674  int j;
1675  char storage_str[NC_MAX_NAME] = "";
1676  char *dims_string = NULL;
1677 
1678  var = (NC_VAR_INFO_T*)ncindexith(grp->vars,i);
1679  assert(var);
1680  if (var->ndims > 0)
1681  {
1682  if (!(dims_string = malloc(sizeof(char) * var->ndims * 4)))
1683  return NC_ENOMEM;
1684  strcpy(dims_string, "");
1685  for (d = 0; d < var->ndims; d++)
1686  {
1687  sprintf(temp_string, " %d", var->dimids[d]);
1688  strcat(dims_string, temp_string);
1689  }
1690  }
1691  if (!var->meta_read)
1692  strcat(storage_str, "unknown");
1693  else if (var->storage == NC_CONTIGUOUS)
1694  strcat(storage_str, "contiguous");
1695  else if (var->storage == NC_COMPACT)
1696  strcat(storage_str, "compact");
1697  else if (var->storage == NC_CHUNKED)
1698  strcat(storage_str, "chunked");
1699  else if (var->storage == NC_VIRTUAL)
1700  strcat(storage_str, "virtual");
1701  else
1702  strcat(storage_str, "unknown");
1703  LOG((2, "%s VARIABLE - varid: %d name: %s ndims: %d "
1704  "dimids:%s storage: %s", tabs, var->hdr.id, var->hdr.name,
1705  var->ndims,
1706  (dims_string ? dims_string : " -"), storage_str));
1707  for (j = 0; j < ncindexsize(var->att); j++)
1708  {
1709  att = (NC_ATT_INFO_T *)ncindexith(var->att, j);
1710  assert(att);
1711  LOG((2, "%s VAR ATTRIBUTE - attnum: %d name: %s type: %d len: %d",
1712  tabs, att->hdr.id, att->hdr.name, att->nc_typeid, att->len));
1713  }
1714  if (dims_string)
1715  free(dims_string);
1716  }
1717 
1718  for (i = 0; i < ncindexsize(grp->type); i++)
1719  {
1720  type = (NC_TYPE_INFO_T*)ncindexith(grp->type, i);
1721  assert(type);
1722  LOG((2, "%s TYPE - nc_typeid: %d size: %d committed: %d name: %s",
1723  tabs, type->hdr.id, type->size, (int)type->committed, type->hdr.name));
1724  /* Is this a compound type? */
1725  if (type->nc_type_class == NC_COMPOUND)
1726  {
1727  int j;
1728  LOG((3, "compound type"));
1729  for (j = 0; j < nclistlength(type->u.c.field); j++)
1730  {
1731  field = (NC_FIELD_INFO_T *)nclistget(type->u.c.field, j);
1732  LOG((4, "field %s offset %d nctype %d ndims %d", field->hdr.name,
1733  field->offset, field->nc_typeid, field->ndims));
1734  }
1735  }
1736  else if (type->nc_type_class == NC_VLEN)
1737  {
1738  LOG((3, "VLEN type"));
1739  LOG((4, "base_nc_type: %d", type->u.v.base_nc_typeid));
1740  }
1741  else if (type->nc_type_class == NC_OPAQUE)
1742  LOG((3, "Opaque type"));
1743  else if (type->nc_type_class == NC_ENUM)
1744  {
1745  LOG((3, "Enum type"));
1746  LOG((4, "base_nc_type: %d", type->u.e.base_nc_typeid));
1747  }
1748  else
1749  {
1750  LOG((0, "Unknown class: %d", type->nc_type_class));
1751  return NC_EBADTYPE;
1752  }
1753  }
1754 
1755  /* Call self for each child of this group. */
1756  for (i = 0; i < ncindexsize(grp->children); i++)
1757  if ((retval = rec_print_metadata((NC_GRP_INFO_T *)ncindexith(grp->children, i),
1758  tab_count + 1)))
1759  return retval;
1760 
1761  return NC_NOERR;
1762 }
1763 
1774 int
1775 log_metadata_nc(NC_FILE_INFO_T *h5)
1776 {
1777  LOG((2, "*** NetCDF-4 Internal Metadata: int_ncid 0x%x ext_ncid 0x%x",
1778  h5->root_grp->nc4_info->controller->int_ncid,
1779  h5->root_grp->nc4_info->controller->ext_ncid));
1780  if (!h5)
1781  {
1782  LOG((2, "This is a netCDF-3 file."));
1783  return NC_NOERR;
1784  }
1785  LOG((2, "FILE - path: %s cmode: 0x%x parallel: %d redef: %d "
1786  "fill_mode: %d no_write: %d next_nc_grpid: %d", h5->root_grp->nc4_info->controller->path,
1787  h5->cmode, (int)h5->parallel, (int)h5->redef, h5->fill_mode, (int)h5->no_write,
1788  h5->next_nc_grpid));
1789  if(nc_log_level >= 2)
1790  return rec_print_metadata(h5->root_grp, 0);
1791  return NC_NOERR;
1792 }
1793 
1794 #endif /*LOGGING */
1795 
1807 int
1808 NC4_show_metadata(int ncid)
1809 {
1810  int retval = NC_NOERR;
1811 #ifdef LOGGING
1812  NC_FILE_INFO_T *h5;
1813  int old_log_level = nc_log_level;
1814 
1815  /* Find file metadata. */
1816  if ((retval = nc4_find_grp_h5(ncid, NULL, &h5)))
1817  return retval;
1818 
1819  /* Log level must be 2 to see metadata. */
1820  nc_log_level = 2;
1821  retval = log_metadata_nc(h5);
1822  nc_log_level = old_log_level;
1823 #endif /*LOGGING*/
1824  return retval;
1825 }
1826 
1834 const NC_reservedatt*
1835 NC_findreserved(const char* name)
1836 {
1837  int n = NRESERVED;
1838  int L = 0;
1839  int R = (n - 1);
1840  for(;;) {
1841  if(L > R) break;
1842  int m = (L + R) / 2;
1843  const NC_reservedatt* p = &NC_reserved[m];
1844  int cmp = strcmp(p->name,name);
1845  if(cmp == 0) return p;
1846  if(cmp < 0)
1847  L = (m + 1);
1848  else /*cmp > 0*/
1849  R = (m - 1);
1850  }
1851  return NULL;
1852 }
1853 
1854 static int
1855 NC4_move_in_NCList(NC* nc, int new_id)
1856 {
1857  int stat = move_in_NCList(nc,new_id);
1858  if(stat == NC_NOERR) {
1859  /* Synchronize header */
1860  if(nc->dispatchdata)
1861  ((NC_OBJ*)nc->dispatchdata)->id = nc->ext_ncid;
1862  }
1863  return stat;
1864 }
NC_NOERR
#define NC_NOERR
No Error.
Definition: netcdf.h:333
NC_EINVAL
#define NC_EINVAL
Invalid Argument.
Definition: netcdf.h:343
NC_EBADTYPID
#define NC_EBADTYPID
Bad type ID.
Definition: netcdf.h:462
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:372
NC_CONTIGUOUS
#define NC_CONTIGUOUS
In HDF5 files you can set storage for each variable to be either contiguous or chunked,...
Definition: netcdf.h:300
NC_CHUNKED
#define NC_CHUNKED
In HDF5 files you can set storage for each variable to be either contiguous or chunked,...
Definition: netcdf.h:299
nc4_chunk_cache_preemption
float nc4_chunk_cache_preemption
Default chunk cache preemption.
Definition: nc4internal.c:57
NC_MAX_NAME
#define NC_MAX_NAME
Maximum for classic library.
Definition: netcdf.h:276
NC_GLOBAL
#define NC_GLOBAL
Attribute id to put/get a global attribute.
Definition: netcdf.h:249
NC_EMAXNAME
#define NC_EMAXNAME
NC_MAX_NAME exceeded.
Definition: netcdf.h:391
NC_VIRTUAL
#define NC_VIRTUAL
In HDF5 files you can set storage for each variable to be either contiguous or chunked,...
Definition: netcdf.h:303
nc4_chunk_cache_size
size_t nc4_chunk_cache_size
Default chunk cache size.
Definition: nc4internal.c:55
NC_UNLIMITED
#define NC_UNLIMITED
Size argument to nc_def_dim() for an unlimited dimension.
Definition: netcdf.h:246
NC_ENOTATT
#define NC_ENOTATT
Attribute not found.
Definition: netcdf.h:373
NC_COMPACT
#define NC_COMPACT
In HDF5 files you can set storage for each variable to be either contiguous or chunked,...
Definition: netcdf.h:301
NC_COMPOUND
#define NC_COMPOUND
compound types
Definition: netcdf.h:56
netcdf.h
NC_EIO
#define NC_EIO
Generic IO error.
Definition: netcdf.h:422
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:56
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:375
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:413
NC_STRING
#define NC_STRING
string
Definition: netcdf.h:47
NC_EBADID
#define NC_EBADID
Not a netcdf id.
Definition: netcdf.h:340
NC_EBADDIM
#define NC_EBADDIM
Invalid dimension id or name.
Definition: netcdf.h:376
NC_ENOTVAR
#define NC_ENOTVAR
Variable not found.
Definition: netcdf.h:387