NetCDF 4.10.1
Loading...
Searching...
No Matches
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 <stdarg.h>
20#include <stddef.h>
21#include "netcdf.h"
22#include "netcdf_filter.h"
23#include "netcdf_meta.h"
24#include "nc4internal.h"
25#include "nc.h" /* from libsrc */
26#include "ncdispatch.h" /* from libdispatch */
27#include "ncutf8.h"
28#include "ncrc.h"
29#include "nc4internal.h"
30
38
43static NC_reservedatt NC_reserved[] = {
44 {NC_ATT_CLASS, READONLYFLAG|HIDDENATTRFLAG}, /*CLASS*/
45 {NC_ATT_DIMENSION_LIST, READONLYFLAG|HIDDENATTRFLAG}, /*DIMENSION_LIST*/
46 {NC_ATT_NAME, READONLYFLAG|HIDDENATTRFLAG}, /*NAME*/
47 {NC_ATT_REFERENCE_LIST, READONLYFLAG|HIDDENATTRFLAG}, /*REFERENCE_LIST*/
48 {NC_XARRAY_DIMS, READONLYFLAG|HIDDENATTRFLAG}, /*_ARRAY_DIMENSIONS*/
49 {NC_ATT_CODECS, VARFLAG|READONLYFLAG|NAMEONLYFLAG}, /*_Codecs*/
50 {NC_ATT_FORMAT, READONLYFLAG}, /*_Format*/
51 {ISNETCDF4ATT, READONLYFLAG|NAMEONLYFLAG|VIRTUALFLAG}, /*_IsNetcdf4*/
52 {NCPROPS,READONLYFLAG|NAMEONLYFLAG|HIDDENATTRFLAG}, /*_NCProperties*/
53 {NC_ATT_COORDINATES, READONLYFLAG|HIDDENATTRFLAG}, /*_Netcdf4Coordinates*/
54 {NC_ATT_DIMID_NAME, READONLYFLAG|HIDDENATTRFLAG}, /*_Netcdf4Dimid*/
55 {SUPERBLOCKATT, READONLYFLAG|NAMEONLYFLAG|VIRTUALFLAG}, /*_SuperblockVersion*/
56 {NC_ATT_NC3_STRICT_NAME, READONLYFLAG}, /*_nc3_strict*/
57 {NC_NCZARR_ATTR, READONLYFLAG|HIDDENATTRFLAG}, /*_nczarr_attr */
58 {NC_NCZARR_GROUP, READONLYFLAG|HIDDENATTRFLAG}, /*_nczarr_group */
59 {NC_NCZARR_ARRAY, READONLYFLAG|HIDDENATTRFLAG}, /*_nczarr_array */
60 {NC_NCZARR_SUPERBLOCK, READONLYFLAG|HIDDENATTRFLAG}, /*_nczarr_superblock */
61};
62#define NRESERVED (sizeof(NC_reserved) / sizeof(NC_reservedatt)) /*|NC_reservedatt*/
63
64/*Forward */
65static int NC4_move_in_NCList(NC* nc, int new_id);
66static int bincmp(const void* arg1, const void* arg2);
67static int sortcmp(const void* arg1, const void* arg2);
68
69#if LOGGING
70/* This is the severity level of messages which will be logged. Use
71 severity 0 for errors, 1 for important log messages, 2 for less
72 important, etc. */
73int nc_log_level = NC_TURN_OFF_LOGGING;
74
75
76#if NC_HAS_PARALLEL4
77/* File pointer for the parallel I/O log file. */
78FILE *LOG_FILE = NULL;
79#endif /* NC_HAS_PARALLEL4 */
80
81/* This function prints out a message, if the severity of
82 * the message is lower than the global nc_log_level. To use it, do
83 * something like this:
84 *
85 * nc_log(0, "this computer will explode in %d seconds", i);
86 *
87 * After the first arg (the severity), use the rest like a normal
88 * printf statement. Output will appear on stderr for sequential
89 * builds, and in a file nc4_log_R.log for each process for a parallel
90 * build, where R is the rank of the process.
91 *
92 * Ed Hartnett
93 */
94void
95nc_log(int severity, const char *fmt, ...)
96{
97 va_list argp;
98 int t;
99 FILE *f = stderr;
100
101 const char* envv = NULL;
102 envv = getenv("NC4LOGGING");
103 if(envv != NULL) {
104 nc_log_level = atoi(envv);
105 }
106
107 /* If the severity is greater than the log level, we don't print
108 * this message. */
109 if (severity > nc_log_level)
110 return;
111
112#if NC_HAS_PARALLEL4
113 /* For parallel I/O build, if MPI has been initialized, instead of
114 * printing logging output to stderr, it goes to a file for each
115 * process. */
116 {
117 int mpi_initialized;
118 int mpierr;
119
120 /* Check to see if MPI has been initialized. */
121 if ((mpierr = MPI_Initialized(&mpi_initialized)))
122 return;
123
124 /* If MPI has been initialized use a log file. */
125 assert(LOG_FILE);
126 if (mpi_initialized)
127 f = LOG_FILE;
128 }
129#endif /* NC_HAS_PARALLEL4 */
130
131 /* If the severity is zero, this is an error. Otherwise insert that
132 many tabs before the message. */
133 if (!severity)
134 fprintf(f, "ERROR: ");
135 for (t = 0; t < severity; t++)
136 fprintf(f, "\t");
137
138 /* Print out the variable list of args with vprintf. */
139 va_start(argp, fmt);
140 vfprintf(f, fmt, argp);
141 va_end(argp);
142
143 /* Put on a final linefeed. */
144 fprintf(f, "\n");
145 fflush(f);
146}
147#endif /* LOGGING */
148
161int
162nc4_check_name(const char *name, char *norm_name)
163{
164 char *temp;
165 int retval;
166
167 assert(norm_name);
168
169 /* Check for NULL. */
170 if (!name)
171 return NC_EINVAL;
172
173 /* Make sure this is a valid netcdf name. This should be done
174 * before the name is normalized, because it gives better error
175 * codes for bad utf8 strings. */
176 if ((retval = NC_check_name(name)))
177 return retval;
178
179 /* Normalize the name. */
180 if ((retval = nc_utf8_normalize((const unsigned char *)name,
181 (unsigned char **)&temp)))
182 return retval;
183
184 /* Check length of normalized name. */
185 if (strlen(temp) > NC_MAX_NAME)
186 {
187 free(temp);
188 return NC_EMAXNAME;
189 }
190
191 /* Copy the normalized name. */
192 strcpy(norm_name, temp);
193 free(temp);
194
195 return NC_NOERR;
196}
197
218int
219nc4_file_list_add(int ncid, const char *path, int mode, void **dispatchdata)
220{
221 NC *nc;
222 int ret;
223
224 /* Find NC pointer for this file. */
225 if ((ret = NC_check_id(ncid, &nc)))
226 return ret;
227
228 /* Add necessary structs to hold netcdf-4 file data. This is where
229 * the NC_FILE_INFO_T struct is allocated for the file. */
230 if ((ret = nc4_nc4f_list_add(nc, path, mode)))
231 return ret;
232
233 /* If the user wants a pointer to the NC_FILE_INFO_T, then provide
234 * it. */
235 if (dispatchdata)
236 *dispatchdata = nc->dispatchdata;
237
238 return NC_NOERR;
239}
240
254int
255nc4_file_change_ncid(int ncid, unsigned short new_ncid_index)
256{
257 NC *nc;
258 int ret;
259
260 LOG((2, "%s: ncid %d new_ncid_index %d", __func__, ncid, new_ncid_index));
261
262 /* Find NC pointer for this file. */
263 if ((ret = NC_check_id(ncid, &nc)))
264 return ret;
265
266 /* Move it in the list. It will fail if list spot is already
267 * occupied. */
268 LOG((3, "moving nc->ext_ncid %d nc->ext_ncid >> ID_SHIFT %d",
269 nc->ext_ncid, nc->ext_ncid >> ID_SHIFT));
270 if (NC4_move_in_NCList(nc, new_ncid_index))
271 return NC_EIO;
272 LOG((3, "moved to new_ncid_index %d new nc->ext_ncid %d", new_ncid_index,
273 nc->ext_ncid));
274
275 return NC_NOERR;
276}
277
297int
298nc4_file_list_get(int ncid, char **path, int *mode, void **dispatchdata)
299{
300 NC *nc;
301 int ret;
302
303 /* Find NC pointer for this file. */
304 if ((ret = NC_check_id(ncid, &nc)))
305 return ret;
306
307 /* If the user wants path, give it. */
308 if (path)
309 strncpy(*path, nc->path, NC_MAX_NAME);
310
311 /* If the user wants mode, give it. */
312 if (mode)
313 *mode = nc->mode;
314
315 /* If the user wants dispatchdata, give it. */
316 if (dispatchdata)
317 *dispatchdata = nc->dispatchdata;
318
319 return NC_NOERR;
320}
321
336int
337nc4_nc4f_list_add(NC *nc, const char *path, int mode)
338{
339 NC_FILE_INFO_T *h5;
340 int retval;
341
342 assert(nc && !NC4_DATA(nc) && path);
343
344 /* We need to malloc and initialize the substructure
345 NC_FILE_INFO_T. */
346 if (!(h5 = calloc(1, sizeof(NC_FILE_INFO_T))))
347 return NC_ENOMEM;
348 nc->dispatchdata = h5;
349 h5->controller = nc;
350
351 h5->hdr.sort = NCFIL;
352 h5->hdr.name = strdup(path);
353 h5->hdr.id = nc->ext_ncid;
354
355 /* Hang on to cmode, and note that we're in define mode. */
356 h5->cmode = mode | NC_INDEF;
357
358 /* The next_typeid needs to be set beyond the end of our atomic
359 * types. */
360 h5->next_typeid = NC_FIRSTUSERTYPEID;
361
362 /* Initialize lists for dimensions, types, and groups. */
363 h5->alldims = nclistnew();
364 h5->alltypes = nclistnew();
365 h5->allgroups = nclistnew();
366
367 /* There's always at least one open group - the root
368 * group. Allocate space for one group's worth of information. Set
369 * its grp id, name, and allocate associated empty lists. */
370 if ((retval = nc4_grp_list_add(h5, NULL, NC_GROUP_NAME, &h5->root_grp)))
371 {
372 /* Free everything allocated above before returning, otherwise
373 * the NC_hashmap inside each NCindex leaks (issue #2665). */
374 free(h5->hdr.name);
375 nclistfree(h5->alldims);
376 nclistfree(h5->alltypes);
377 nclistfree(h5->allgroups);
378 free(h5);
379 nc->dispatchdata = NULL;
380 return retval;
381 }
382
383 return NC_NOERR;
384}
385
398int
399nc4_find_nc4_grp(int ncid, NC_GRP_INFO_T **grp)
400{
401 return nc4_find_nc_grp_h5(ncid, NULL, grp, NULL);
402}
403
419int
420nc4_find_grp_h5(int ncid, NC_GRP_INFO_T **grp, NC_FILE_INFO_T **h5)
421{
422 return nc4_find_nc_grp_h5(ncid, NULL, grp, h5);
423}
424
439int
440nc4_find_nc_grp_h5(int ncid, NC **nc, NC_GRP_INFO_T **grp, NC_FILE_INFO_T **h5)
441{
442 NC_GRP_INFO_T *my_grp = NULL;
443 NC_FILE_INFO_T *my_h5 = NULL;
444 NC *my_nc;
445 int retval;
446 size_t index;
447
448 /* Look up file metadata. */
449 if ((retval = NC_check_id(ncid, &my_nc)))
450 return retval;
451 my_h5 = my_nc->dispatchdata;
452 assert(my_h5 && my_h5->root_grp);
453
454 /* If we can't find it, the grp id part of ncid is bad. */
455 index = (ncid & GRP_ID_MASK);
456 if (!(my_grp = nclistget(my_h5->allgroups,index)))
457 return NC_EBADID;
458
459 /* Return pointers to caller, if desired. */
460 if (nc)
461 *nc = my_nc;
462 if (h5)
463 *h5 = my_h5;
464 if (grp)
465 *grp = my_grp;
466
467 return NC_NOERR;
468}
469
485int
486nc4_find_grp_h5_var(int ncid, int varid, NC_FILE_INFO_T **h5, NC_GRP_INFO_T **grp,
487 NC_VAR_INFO_T **var)
488{
489 NC_FILE_INFO_T *my_h5;
490 NC_GRP_INFO_T *my_grp;
491 NC_VAR_INFO_T *my_var;
492 int retval;
493
494 /* Look up file and group metadata. */
495 if ((retval = nc4_find_grp_h5(ncid, &my_grp, &my_h5)))
496 return retval;
497 assert(my_grp && my_h5);
498
499 /* Find the var. */
500 if (!(my_var = (NC_VAR_INFO_T *)ncindexith(my_grp->vars, (size_t)varid)))
501 return NC_ENOTVAR;
502 assert(my_var && my_var->hdr.id == varid);
503
504 /* Return pointers that caller wants. */
505 if (h5)
506 *h5 = my_h5;
507 if (grp)
508 *grp = my_grp;
509 if (var)
510 *var = my_var;
511
512 return NC_NOERR;
513}
514
528int
529nc4_find_dim(NC_GRP_INFO_T *grp, int dimid, NC_DIM_INFO_T **dim,
530 NC_GRP_INFO_T **dim_grp)
531{
532 assert(grp && grp->nc4_info && dim);
533 LOG((4, "%s: dimid %d", __func__, dimid));
534
535 /* Find the dim info. */
536 if (!((*dim) = nclistget(grp->nc4_info->alldims, (size_t)dimid)))
537 return NC_EBADDIM;
538
539 /* Give the caller the group the dimension is in. */
540 if (dim_grp)
541 *dim_grp = (*dim)->container;
542
543 return NC_NOERR;
544}
545
556int
557nc4_find_var(NC_GRP_INFO_T *grp, const char *name, NC_VAR_INFO_T **var)
558{
559 assert(grp && var && name);
560
561 /* Find the var info. */
562 *var = (NC_VAR_INFO_T*)ncindexlookup(grp->vars,name);
563 return NC_NOERR;
564}
565
575NC_TYPE_INFO_T *
576nc4_rec_find_named_type(NC_GRP_INFO_T *start_grp, char *name)
577{
578 NC_GRP_INFO_T *g;
579 NC_TYPE_INFO_T *type, *res;
580
581 assert(start_grp);
582
583 /* Does this group have the type we are searching for? */
584 type = (NC_TYPE_INFO_T*)ncindexlookup(start_grp->type,name);
585 if(type != NULL)
586 return type;
587
588 /* Search subgroups. */
589 for(size_t i=0;i<ncindexsize(start_grp->children);i++) {
590 g = (NC_GRP_INFO_T*)ncindexith(start_grp->children,i);
591 if(g == NULL) continue;
592 if ((res = nc4_rec_find_named_type(g, name)))
593 return res;
594 }
595 /* Can't find it. Oh, woe is me! */
596 return NULL;
597}
598
610int
611nc4_find_type(const NC_FILE_INFO_T *h5, nc_type typeid, NC_TYPE_INFO_T **type)
612{
613 /* Check inputs. */
614 assert(h5);
615 if (typeid < 0 || !type)
616 return NC_EINVAL;
617 *type = NULL;
618
619 /* Atomic types don't have associated NC_TYPE_INFO_T struct, just
620 * return NOERR. */
621 if (typeid <= NC_STRING)
622 return NC_NOERR;
623
624 /* Find the type. */
625 if (!(*type = nclistget(h5->alltypes, (size_t)typeid)))
626 return NC_EBADTYPID;
627
628 return NC_NOERR;
629}
630
646int
647nc4_find_grp_att(NC_GRP_INFO_T *grp, int varid, const char *name, int attnum,
648 NC_ATT_INFO_T **att)
649{
650 NC_VAR_INFO_T *var;
651 NC_ATT_INFO_T *my_att;
652 NCindex *attlist = NULL;
653
654 assert(grp && grp->hdr.name && att);
655
656 LOG((4, "%s: grp->name %s varid %d attnum %d", __func__, grp->hdr.name,
657 varid, attnum));
658
659 /* Get either the global or a variable attribute list. */
660 if (varid == NC_GLOBAL)
661 {
662 attlist = grp->att;
663 }
664 else
665 {
666 var = (NC_VAR_INFO_T*)ncindexith(grp->vars,(size_t)varid);
667 if (!var) return NC_ENOTVAR;
668
669 attlist = var->att;
670 }
671 assert(attlist);
672
673 /* Now find the attribute by name or number. If a name is provided,
674 * ignore the attnum. */
675 if (name)
676 my_att = (NC_ATT_INFO_T *)ncindexlookup(attlist, name);
677 else
678 my_att = (NC_ATT_INFO_T *)ncindexith(attlist, (size_t)attnum);
679
680 if (!my_att)
681 return NC_ENOTATT;
682
683 *att = my_att;
684 return NC_NOERR;
685}
686
703int
704nc4_find_nc_att(int ncid, int varid, const char *name, int attnum,
705 NC_ATT_INFO_T **att)
706{
707 NC_GRP_INFO_T *grp;
708 int retval;
709
710 LOG((4, "nc4_find_nc_att: ncid 0x%x varid %d name %s attnum %d",
711 ncid, varid, name, attnum));
712
713 /* Find info for this file and group, and set pointer to each. */
714 if ((retval = nc4_find_grp_h5(ncid, &grp, NULL)))
715 return retval;
716 assert(grp);
717
718 return nc4_find_grp_att(grp, varid, name, attnum, att);
719}
720
729static void
730obj_track(NC_FILE_INFO_T* file, NC_OBJ* obj)
731{
732 NClist* list = NULL;
733 /* record the object in the file */
734 switch (obj->sort) {
735 case NCDIM: list = file->alldims; break;
736 case NCTYP: list = file->alltypes; break;
737 case NCGRP: list = file->allgroups; break;
738 default:
739 assert(NC_FALSE);
740 }
741 /* Insert at the appropriate point in the list */
742 nclistset(list,(size_t)obj->id,obj);
743}
744
757int
758nc4_var_list_add2(NC_GRP_INFO_T *grp, const char *name, NC_VAR_INFO_T **var)
759{
760 NC_VAR_INFO_T *new_var = NULL;
761 NCglobalstate* gs = NC_getglobalstate();
762
763 /* Allocate storage for new variable. */
764 if (!(new_var = calloc(1, sizeof(NC_VAR_INFO_T))))
765 return NC_ENOMEM;
766 new_var->hdr.sort = NCVAR;
767 new_var->container = grp;
768
769 memset(&new_var->chunkcache,0,sizeof(struct ChunkCache));
770
771 /* These are the HDF5-1.8.4 defaults. */
772 new_var->chunkcache.size = gs->chunkcache.size;
773 new_var->chunkcache.nelems = gs->chunkcache.nelems;
774 new_var->chunkcache.preemption = gs->chunkcache.preemption;
775
776 /* Now fill in the values in the var info structure. */
777 new_var->hdr.id = (int)ncindexsize(grp->vars);
778 if (!(new_var->hdr.name = strdup(name))) {
779 if(new_var)
780 free(new_var);
781 return NC_ENOMEM;
782 }
783
784 /* Create an indexed list for the attributes. */
785 new_var->att = ncindexnew(0);
786
787 /* Officially track it */
788 ncindexadd(grp->vars, (NC_OBJ *)new_var);
789
790 /* Set the var pointer, if one was given */
791 if (var)
792 *var = new_var;
793
794 return NC_NOERR;
795}
796
807int
808nc4_var_set_ndims(NC_VAR_INFO_T *var, int ndims)
809{
810 assert(var);
811
812 /* Remember the number of dimensions. */
813 var->ndims = (size_t)ndims;
814
815 /* Allocate space for dimension information. */
816 if (ndims)
817 {
818 if (!(var->dim = calloc((size_t)ndims, sizeof(NC_DIM_INFO_T *))))
819 return NC_ENOMEM;
820 if (!(var->dimids = calloc((size_t)ndims, sizeof(int))))
821 return NC_ENOMEM;
822
823 /* Initialize dimids to illegal values (-1). See the comment
824 in nc4_rec_match_dimscales(). */
825 memset(var->dimids, -1, (size_t)ndims * sizeof(int));
826 }
827
828 return NC_NOERR;
829}
830
843int
844nc4_var_list_add(NC_GRP_INFO_T* grp, const char* name, int ndims,
845 NC_VAR_INFO_T **var)
846{
847 int retval;
848
849 if ((retval = nc4_var_list_add2(grp, name, var)))
850 return retval;
851 if ((retval = nc4_var_set_ndims(*var, ndims)))
852 return retval;
853
854 return NC_NOERR;
855}
856
870int
871nc4_dim_list_add(NC_GRP_INFO_T *grp, const char *name, size_t len,
872 int assignedid, NC_DIM_INFO_T **dim)
873{
874 NC_DIM_INFO_T *new_dim = NULL;
875
876 assert(grp && name);
877
878 /* Allocate memory for dim metadata. */
879 if (!(new_dim = calloc(1, sizeof(NC_DIM_INFO_T))))
880 return NC_ENOMEM;
881
882 new_dim->hdr.sort = NCDIM;
883
884 /* Assign the dimension ID. */
885 if (assignedid >= 0)
886 new_dim->hdr.id = assignedid;
887 else
888 new_dim->hdr.id = grp->nc4_info->next_dimid++;
889
890 /* Remember the name and create a hash. */
891 if (!(new_dim->hdr.name = strdup(name))) {
892 if(new_dim)
893 free(new_dim);
894
895 return NC_ENOMEM;
896 }
897
898 /* Is dimension unlimited? */
899 new_dim->len = len;
900 if (len == NC_UNLIMITED)
901 new_dim->unlimited = NC_TRUE;
902
903 /* Remember the containing group. */
904 new_dim->container = grp;
905
906 /* Add object to dimension list for this group. */
907 ncindexadd(grp->dim, (NC_OBJ *)new_dim);
908 obj_track(grp->nc4_info, (NC_OBJ *)new_dim);
909
910 /* Set the dim pointer, if one was given */
911 if (dim)
912 *dim = new_dim;
913
914 return NC_NOERR;
915}
916
929int
930nc4_att_list_add(NCindex *list, const char *name, NC_ATT_INFO_T **att)
931{
932 NC_ATT_INFO_T *new_att = NULL;
933
934 LOG((3, "%s: name %s ", __func__, name));
935
936 if (!(new_att = calloc(1, sizeof(NC_ATT_INFO_T))))
937 return NC_ENOMEM;
938 new_att->hdr.sort = NCATT;
939
940 /* Fill in the information we know. */
941 new_att->hdr.id = (int)ncindexsize(list);
942 if (!(new_att->hdr.name = strdup(name))) {
943 if(new_att)
944 free(new_att);
945 return NC_ENOMEM;
946 }
947
948 /* Add object to list as specified by its number */
949 ncindexadd(list, (NC_OBJ *)new_att);
950
951 /* Set the attribute pointer, if one was given */
952 if (att)
953 *att = new_att;
954
955 return NC_NOERR;
956}
957
972int
973nc4_grp_list_add(NC_FILE_INFO_T *h5, NC_GRP_INFO_T *parent, char *name,
974 NC_GRP_INFO_T **grp)
975{
976 NC_GRP_INFO_T *new_grp;
977
978 /* Check inputs. */
979 assert(h5 && name);
980 LOG((3, "%s: name %s ", __func__, name));
981
982 /* Get the memory to store this groups info. */
983 if (!(new_grp = calloc(1, sizeof(NC_GRP_INFO_T))))
984 return NC_ENOMEM;
985
986 /* Fill in this group's information. */
987 new_grp->hdr.sort = NCGRP;
988 new_grp->nc4_info = h5;
989 new_grp->parent = parent;
990
991 /* Assign the group ID. The root group will get id 0. */
992 new_grp->hdr.id = h5->next_nc_grpid++;
993 assert(parent || !new_grp->hdr.id);
994
995 /* Handle the group name. */
996 if (!(new_grp->hdr.name = strdup(name)))
997 {
998 free(new_grp);
999 return NC_ENOMEM;
1000 }
1001
1002 /* Set up new indexed lists for stuff this group can contain. */
1003 new_grp->children = ncindexnew(0);
1004 new_grp->dim = ncindexnew(0);
1005 new_grp->att = ncindexnew(0);
1006 new_grp->type = ncindexnew(0);
1007 new_grp->vars = ncindexnew(0);
1008
1009 /* Add object to lists */
1010 if (parent)
1011 ncindexadd(parent->children, (NC_OBJ *)new_grp);
1012 obj_track(h5, (NC_OBJ *)new_grp);
1013
1014 /* Set the group pointer, if one was given */
1015 if (grp)
1016 *grp = new_grp;
1017
1018 return NC_NOERR;
1019}
1020
1034int
1035nc4_check_dup_name(NC_GRP_INFO_T *grp, char *name)
1036{
1037 NC_TYPE_INFO_T *type;
1038 NC_GRP_INFO_T *g;
1039 NC_VAR_INFO_T *var;
1040
1041 /* Any types of this name? */
1042 type = (NC_TYPE_INFO_T*)ncindexlookup(grp->type,name);
1043 if(type != NULL)
1044 return NC_ENAMEINUSE;
1045
1046 /* Any child groups of this name? */
1047 g = (NC_GRP_INFO_T*)ncindexlookup(grp->children,name);
1048 if(g != NULL)
1049 return NC_ENAMEINUSE;
1050
1051 /* Any variables of this name? */
1052 var = (NC_VAR_INFO_T*)ncindexlookup(grp->vars,name);
1053 if(var != NULL)
1054 return NC_ENAMEINUSE;
1055
1056 return NC_NOERR;
1057}
1058
1072int
1073nc4_type_new(size_t size, const char *name, int assignedid,
1074 NC_TYPE_INFO_T **type)
1075{
1076 NC_TYPE_INFO_T *new_type;
1077
1078 LOG((4, "%s: size %d name %s assignedid %d", __func__, size, name, assignedid));
1079
1080 /* Check inputs. */
1081 assert(type);
1082
1083 /* Allocate memory for the type */
1084 if (!(new_type = calloc(1, sizeof(NC_TYPE_INFO_T))))
1085 return NC_ENOMEM;
1086 new_type->hdr.sort = NCTYP;
1087 new_type->hdr.id = assignedid;
1088
1089 /* Remember info about this type. */
1090 new_type->size = size;
1091 if (!(new_type->hdr.name = strdup(name))) {
1092 free(new_type);
1093 return NC_ENOMEM;
1094 }
1095
1096 /* Return a pointer to the new type. */
1097 *type = new_type;
1098
1099 return NC_NOERR;
1100}
1101
1115int
1116nc4_type_list_add(NC_GRP_INFO_T *grp, size_t size, const char *name,
1117 NC_TYPE_INFO_T **type)
1118{
1119 NC_TYPE_INFO_T *new_type;
1120 int retval;
1121
1122 /* Check inputs. */
1123 assert(grp && name && type);
1124 LOG((4, "%s: size %d name %s", __func__, size, name));
1125
1126 /* Create the new TYPE_INFO struct. */
1127 if ((retval = nc4_type_new(size, name, grp->nc4_info->next_typeid,
1128 &new_type)))
1129 return retval;
1130 grp->nc4_info->next_typeid++;
1131
1132 /* Increment the ref. count on the type */
1133 new_type->rc++;
1134
1135 /* Add object to lists */
1136 ncindexadd(grp->type, (NC_OBJ *)new_type);
1137 obj_track(grp->nc4_info,(NC_OBJ*)new_type);
1138
1139 /* back link */
1140 new_type->container = grp;
1141
1142 /* Return a pointer to the new type. */
1143 *type = new_type;
1144
1145 return NC_NOERR;
1146}
1147
1161int
1162nc4_field_list_add(NC_TYPE_INFO_T *parent, const char *name,
1163 size_t offset, nc_type xtype, int ndims,
1164 const int *dim_sizesp)
1165{
1166 NC_FIELD_INFO_T *field;
1167
1168 /* Name has already been checked and UTF8 normalized. */
1169 if (!name)
1170 return NC_EINVAL;
1171
1172 /* Allocate storage for this field information. */
1173 if (!(field = calloc(1, sizeof(NC_FIELD_INFO_T))))
1174 return NC_ENOMEM;
1175 field->hdr.sort = NCFLD;
1176
1177 /* Store the information about this field. */
1178 if (!(field->hdr.name = strdup(name)))
1179 {
1180 free(field);
1181 return NC_ENOMEM;
1182 }
1183 field->nc_typeid = xtype;
1184 field->offset = offset;
1185 field->ndims = ndims;
1186 if (ndims)
1187 {
1188 int i;
1189 if (!(field->dim_size = malloc((size_t)ndims * sizeof(int))))
1190 {
1191 free(field->hdr.name);
1192 free(field);
1193 return NC_ENOMEM;
1194 }
1195 for (i = 0; i < ndims; i++)
1196 field->dim_size[i] = dim_sizesp[i];
1197 }
1198
1199 /* Add object to lists */
1200 field->hdr.id = (int)nclistlength(parent->u.c.field);
1201 nclistpush(parent->u.c.field,field);
1202
1203 return NC_NOERR;
1204}
1205
1218int
1219nc4_enum_member_add(NC_TYPE_INFO_T *parent, size_t size,
1220 const char *name, const void *value)
1221{
1222 NC_ENUM_MEMBER_INFO_T *member;
1223
1224 /* Name has already been checked. */
1225 assert(name && size > 0 && value);
1226 LOG((4, "%s: size %d name %s", __func__, size, name));
1227
1228 /* Allocate storage for this field information. */
1229 if (!(member = calloc(1, sizeof(NC_ENUM_MEMBER_INFO_T))))
1230 return NC_ENOMEM;
1231 if (!(member->value = malloc(size))) {
1232 free(member);
1233 return NC_ENOMEM;
1234 }
1235 if (!(member->name = strdup(name))) {
1236 free(member->value);
1237 free(member);
1238 return NC_ENOMEM;
1239 }
1240
1241 /* Store the value for this member. */
1242 memcpy(member->value, value, size);
1243
1244 /* Add object to list */
1245 nclistpush(parent->u.e.enum_member,member);
1246
1247 return NC_NOERR;
1248}
1249
1257static void
1258field_free(NC_FIELD_INFO_T *field)
1259{
1260 /* Free some stuff. */
1261 if (field->hdr.name)
1262 free(field->hdr.name);
1263 if (field->dim_size)
1264 free(field->dim_size);
1265
1266 /* Nc_Free the memory. */
1267 free(field);
1268}
1269
1279int
1280nc4_type_free(NC_TYPE_INFO_T *type)
1281{
1282 size_t i;
1283
1284 assert(type && type->rc && type->hdr.name);
1285
1286 /* Decrement the ref. count on the type */
1287 type->rc--;
1288
1289 /* Release the type, if the ref. count drops to zero */
1290 if (type->rc == 0)
1291 {
1292 LOG((4, "%s: deleting type %s", __func__, type->hdr.name));
1293
1294 /* Free the name. */
1295 free(type->hdr.name);
1296
1297 /* Enums and compound types have lists of fields to clean up. */
1298 switch (type->nc_type_class)
1299 {
1300 case NC_COMPOUND:
1301 {
1302 NC_FIELD_INFO_T *field;
1303
1304 /* Delete all the fields in this type (there will be some if its a
1305 * compound). */
1306 for(i=0;i<nclistlength(type->u.c.field);i++) {
1307 field = nclistget(type->u.c.field,i);
1308 field_free(field);
1309 }
1310 nclistfree(type->u.c.field);
1311 }
1312 break;
1313
1314 case NC_ENUM:
1315 {
1316 NC_ENUM_MEMBER_INFO_T *enum_member;
1317
1318 /* Delete all the enum_members, if any. */
1319 for(i=0;i<nclistlength(type->u.e.enum_member);i++) {
1320 enum_member = nclistget(type->u.e.enum_member,i);
1321 free(enum_member->value);
1322 free(enum_member->name);
1323 free(enum_member);
1324 }
1325 nclistfree(type->u.e.enum_member);
1326 }
1327 break;
1328
1329 default:
1330 break;
1331 }
1332
1333 /* Release the memory. */
1334 free(type);
1335 }
1336
1337 return NC_NOERR;
1338}
1339
1348int
1349nc4_att_free(NC_ATT_INFO_T *att)
1350{
1351 int stat = NC_NOERR;
1352
1353 assert(att);
1354 LOG((3, "%s: name %s ", __func__, att->hdr.name));
1355
1356 /* Free the name. */
1357 if (att->hdr.name)
1358 free(att->hdr.name);
1359
1360 if (att->data) {
1361 NC_OBJ* parent;
1362 NC_FILE_INFO_T* h5 = NULL;
1363
1364 /* Locate relevant objects */
1365 parent = att->container;
1366 if(parent->sort == NCVAR) parent = (NC_OBJ*)(((NC_VAR_INFO_T*)parent)->container);
1367 assert(parent->sort == NCGRP);
1368 h5 = ((NC_GRP_INFO_T*)parent)->nc4_info;
1369 /* Reclaim the attribute data */
1370 if((stat = NC_reclaim_data(h5->controller,att->nc_typeid,att->data,att->len))) goto done;
1371 free(att->data); /* reclaim top level */
1372 att->data = NULL;
1373 }
1374
1375done:
1376 free(att);
1377 return stat;
1378}
1379
1389static int
1390var_free(NC_VAR_INFO_T *var)
1391{
1392 int retval;
1393
1394 assert(var);
1395 LOG((4, "%s: deleting var %s", __func__, var->hdr.name));
1396
1397 /* First delete all the attributes attached to this var. */
1398 for (size_t i = 0; i < ncindexsize(var->att); i++)
1399 if ((retval = nc4_att_free((NC_ATT_INFO_T *)ncindexith(var->att, i))))
1400 return retval;
1401 ncindexfree(var->att);
1402
1403 /* Free some things that may be allocated. */
1404 if (var->chunksizes)
1405 free(var->chunksizes);
1406
1407 if (var->alt_name)
1408 free(var->alt_name);
1409
1410 if (var->dimids)
1411 free(var->dimids);
1412
1413 if (var->dim)
1414 free(var->dim);
1415
1416 memset(&var->chunkcache,0,sizeof(struct ChunkCache));
1417
1418 /* Delete any fill value allocation. */
1419 if (var->fill_value) {
1420 int tid = var->type_info->hdr.id;
1421 if((retval = NC_reclaim_data_all(var->container->nc4_info->controller, tid, var->fill_value, 1))) return retval;
1422 var->fill_value = NULL;
1423 }
1424
1425 /* Release type information */
1426 if (var->type_info)
1427 if ((retval = nc4_type_free(var->type_info)))
1428 return retval;
1429
1430 /* Do this last because debugging may need it */
1431 if (var->hdr.name)
1432 free(var->hdr.name);
1433
1434 /* Delete the var. */
1435 free(var);
1436
1437 return NC_NOERR;
1438}
1439
1449int
1450nc4_var_list_del(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var)
1451{
1452 int i;
1453
1454 assert(var && grp);
1455
1456 /* Remove from lists */
1457 i = ncindexfind(grp->vars, (NC_OBJ *)var);
1458 if (i >= 0)
1459 ncindexidel(grp->vars, (size_t)i);
1460
1461 return var_free(var);
1462}
1463
1472static int
1473dim_free(NC_DIM_INFO_T *dim)
1474{
1475 assert(dim);
1476 LOG((4, "%s: deleting dim %s", __func__, dim->hdr.name));
1477
1478 /* Free memory allocated for names. */
1479 if (dim->hdr.name)
1480 free(dim->hdr.name);
1481
1482 free(dim);
1483 return NC_NOERR;
1484}
1485
1495int
1496nc4_dim_list_del(NC_GRP_INFO_T *grp, NC_DIM_INFO_T *dim)
1497{
1498 if (grp && dim)
1499 {
1500 int pos = ncindexfind(grp->dim, (NC_OBJ *)dim);
1501 if(pos >= 0)
1502 ncindexidel(grp->dim, (size_t)pos);
1503 }
1504
1505 return dim_free(dim);
1506}
1507
1517int
1518nc4_rec_grp_del(NC_GRP_INFO_T *grp)
1519{
1520 int retval;
1521
1522 assert(grp);
1523 LOG((3, "%s: grp->name %s", __func__, grp->hdr.name));
1524
1525 /* Recursively call this function for each child, if any, stopping
1526 * if there is an error. */
1527 for (size_t i = 0; i < ncindexsize(grp->children); i++)
1528 if ((retval = nc4_rec_grp_del((NC_GRP_INFO_T *)ncindexith(grp->children,
1529 i))))
1530 return retval;
1531 ncindexfree(grp->children);
1532
1533 /* Free attributes */
1534 for (size_t i = 0; i < ncindexsize(grp->att); i++)
1535 if ((retval = nc4_att_free((NC_ATT_INFO_T *)ncindexith(grp->att, i))))
1536 return retval;
1537 ncindexfree(grp->att);
1538
1539 /* Delete all vars. */
1540 for (size_t i = 0; i < ncindexsize(grp->vars); i++) {
1541 NC_VAR_INFO_T* v = (NC_VAR_INFO_T *)ncindexith(grp->vars, i);
1542 if ((retval = var_free(v)))
1543 return retval;
1544 }
1545 ncindexfree(grp->vars);
1546
1547 /* Delete all dims, and free the list of dims. */
1548 for (size_t i = 0; i < ncindexsize(grp->dim); i++)
1549 if ((retval = dim_free((NC_DIM_INFO_T *)ncindexith(grp->dim, i))))
1550 return retval;
1551 ncindexfree(grp->dim);
1552
1553 /* Delete all types. */
1554 for (size_t i = 0; i < ncindexsize(grp->type); i++)
1555 if ((retval = nc4_type_free((NC_TYPE_INFO_T *)ncindexith(grp->type, i))))
1556 return retval;
1557 ncindexfree(grp->type);
1558
1559 /* Free the name. */
1560 free(grp->hdr.name);
1561
1562 /* Free up this group */
1563 free(grp);
1564
1565 return NC_NOERR;
1566}
1567
1577int
1578nc4_rec_grp_del_att_data(NC_GRP_INFO_T *grp)
1579{
1580 int retval;
1581
1582 assert(grp);
1583 LOG((3, "%s: grp->name %s", __func__, grp->hdr.name));
1584
1585 /* Recursively call this function for each child, if any, stopping
1586 * if there is an error. */
1587 for (size_t i = 0; i < ncindexsize(grp->children); i++)
1588 if ((retval = nc4_rec_grp_del_att_data((NC_GRP_INFO_T *)ncindexith(grp->children, i))))
1589 return retval;
1590
1591 /* Free attribute data in this group */
1592 for (size_t i = 0; i < ncindexsize(grp->att); i++) {
1593 NC_ATT_INFO_T * att = (NC_ATT_INFO_T*)ncindexith(grp->att, i);
1594 if((retval = NC_reclaim_data_all(grp->nc4_info->controller,att->nc_typeid,att->data,att->len)))
1595 return retval;
1596 att->data = NULL;
1597 att->len = 0;
1598 att->dirty = 0;
1599 }
1600
1601 /* Delete att data from all contained vars in this group */
1602 for (size_t i = 0; i < ncindexsize(grp->vars); i++) {
1603 NC_VAR_INFO_T* v = (NC_VAR_INFO_T *)ncindexith(grp->vars, i);
1604 for(size_t j=0;j<ncindexsize(v->att);j++) {
1605 NC_ATT_INFO_T* att = (NC_ATT_INFO_T*)ncindexith(v->att, j);
1606 if((retval = NC_reclaim_data_all(grp->nc4_info->controller,att->nc_typeid,att->data,att->len)))
1607 return retval;
1608 att->data = NULL;
1609 att->len = 0;
1610 att->dirty = 0;
1611 }
1612 }
1613
1614 return NC_NOERR;
1615}
1616
1627int
1628nc4_att_list_del(NCindex *list, NC_ATT_INFO_T *att)
1629{
1630 assert(att && list);
1631 ncindexidel(list, (size_t)((NC_OBJ *)att)->id);
1632 return nc4_att_free(att);
1633}
1634
1648int
1649nc4_file_list_del(int ncid)
1650{
1651 NC_FILE_INFO_T *h5;
1652 int retval;
1653
1654 /* Find our metadata for this file. */
1655 if ((retval = nc4_find_grp_h5(ncid, NULL, &h5)))
1656 return retval;
1657 assert(h5);
1658
1659 /* Delete the file resources. */
1660 if ((retval = nc4_nc4f_list_del(h5)))
1661 return retval;
1662
1663 return NC_NOERR;
1664}
1665
1675int
1676nc4_nc4f_list_del(NC_FILE_INFO_T *h5)
1677{
1678 int retval;
1679
1680 assert(h5);
1681
1682 /* Order is important here. We must delete the attribute contents
1683 before deleting any metadata because nc_reclaim_data depends
1684 on the existence of the type info.
1685 */
1686
1687 /* Delete all the attribute data contents in each group and variable. */
1688 if ((retval = nc4_rec_grp_del_att_data(h5->root_grp)))
1689 return retval;
1690
1691 /* Delete all the list contents for vars, dims, and atts, in each
1692 * group. */
1693 if ((retval = nc4_rec_grp_del(h5->root_grp)))
1694 return retval;
1695
1696 /* Cleanup these (extra) lists of all dims, groups, and types. */
1697 nclistfree(h5->alldims);
1698 nclistfree(h5->allgroups);
1699 nclistfree(h5->alltypes);
1700
1701 /* Free the NC_FILE_INFO_T struct. */
1702 nullfree(h5->hdr.name);
1703 free(h5);
1704
1705 return NC_NOERR;
1706}
1707
1721int
1722nc4_normalize_name(const char *name, char *norm_name)
1723{
1724 char *temp_name;
1725 int stat = nc_utf8_normalize((const unsigned char *)name,(unsigned char **)&temp_name);
1726 if(stat != NC_NOERR)
1727 return stat;
1728 if (strlen(temp_name) > NC_MAX_NAME)
1729 {
1730 free(temp_name);
1731 return NC_EMAXNAME;
1732 }
1733 strcpy(norm_name, temp_name);
1734 free(temp_name);
1735 return NC_NOERR;
1736}
1737
1738#ifdef NETCDF_ENABLE_SET_LOG_LEVEL
1739
1746int
1747nc4_init_logging(void)
1748{
1749 int ret = NC_NOERR;
1750
1751#if LOGGING
1752#if NC_HAS_PARALLEL4
1753 if (!LOG_FILE && nc_log_level >= 0)
1754 {
1755 char log_filename[NC_MAX_NAME];
1756 int my_rank = 0;
1757 int mpierr;
1758 int mpi_initialized;
1759
1760 /* If MPI has been initialized find the rank. */
1761 if ((mpierr = MPI_Initialized(&mpi_initialized)))
1762 return NC_EMPI;
1763 if (mpi_initialized)
1764 {
1765 if ((mpierr = MPI_Comm_rank(MPI_COMM_WORLD, &my_rank)))
1766 return NC_EMPI;
1767 }
1768
1769 /* Create a filename with the rank in it. */
1770 snprintf(log_filename, sizeof(log_filename), "nc4_log_%d.log", my_rank);
1771
1772 /* Open a file for this rank to log messages. */
1773 if (!(LOG_FILE = fopen(log_filename, "w")))
1774 return NC_EINTERNAL;
1775 }
1776#endif /* NC_HAS_PARALLEL4 */
1777#endif /* LOGGING */
1778
1779 return ret;
1780}
1781
1788void
1789nc4_finalize_logging(void)
1790{
1791#if LOGGING
1792#if NC_HAS_PARALLEL4
1793 if (LOG_FILE)
1794 {
1795 fclose(LOG_FILE);
1796 LOG_FILE = NULL;
1797 }
1798#endif /* NC_HAS_PARALLEL4 */
1799#endif /* LOGGING */
1800}
1801
1815int
1816nc_set_log_level(int new_level)
1817{
1818#if LOGGING
1819 /* Remember the new level. */
1820 nc_log_level = new_level;
1821
1822#if NC_HAS_PARALLEL4
1823 /* For parallel I/O builds, call the log init/finalize functions
1824 * as needed, to open and close the log files. */
1825 if (new_level >= 0)
1826 {
1827 if (!LOG_FILE)
1828 nc4_init_logging();
1829 }
1830 else
1831 nc4_finalize_logging();
1832#endif /* NC_HAS_PARALLEL4 */
1833
1834 LOG((1, "log_level changed to %d", nc_log_level));
1835#endif /* LOGGING */
1836
1837 return NC_NOERR;
1838}
1839#endif /* NETCDF_ENABLE_SET_LOG_LEVEL */
1840
1841#if LOGGING
1842#define MAX_NESTS 10
1852static int
1853rec_print_metadata(NC_GRP_INFO_T *grp, int tab_count)
1854{
1855 NC_ATT_INFO_T *att;
1856 NC_VAR_INFO_T *var;
1857 NC_DIM_INFO_T *dim;
1858 NC_TYPE_INFO_T *type;
1859 NC_FIELD_INFO_T *field;
1860 char tabs[MAX_NESTS+1] = "";
1861 char temp_string[10];
1862 int t, retval, d, i;
1863
1864 /* Come up with a number of tabs relative to the group. */
1865 for (t = 0; t < tab_count && t < MAX_NESTS; t++)
1866 tabs[t] = '\t';
1867 tabs[t] = '\0';
1868
1869 LOG((2, "%s GROUP - %s nc_grpid: %d nvars: %d natts: %d",
1870 tabs, grp->hdr.name, grp->hdr.id, ncindexsize(grp->vars), ncindexsize(grp->att)));
1871
1872 for (i = 0; i < ncindexsize(grp->att); i++)
1873 {
1874 att = (NC_ATT_INFO_T *)ncindexith(grp->att, i);
1875 assert(att);
1876 LOG((2, "%s GROUP ATTRIBUTE - attnum: %d name: %s type: %d len: %d",
1877 tabs, att->hdr.id, att->hdr.name, att->nc_typeid, att->len));
1878 }
1879
1880 for (i = 0; i < ncindexsize(grp->dim); i++)
1881 {
1882 dim = (NC_DIM_INFO_T *)ncindexith(grp->dim, i);
1883 assert(dim);
1884 LOG((2, "%s DIMENSION - dimid: %d name: %s len: %d unlimited: %d",
1885 tabs, dim->hdr.id, dim->hdr.name, dim->len, dim->unlimited));
1886 }
1887
1888 for (i = 0; i < ncindexsize(grp->vars); i++)
1889 {
1890 int j;
1891 char storage_str[NC_MAX_NAME] = "";
1892 char *dims_string = NULL;
1893
1894 var = (NC_VAR_INFO_T*)ncindexith(grp->vars,i);
1895 assert(var);
1896 if (var->ndims > 0)
1897 {
1898 if (!(dims_string = malloc(sizeof(char) * var->ndims * 4)))
1899 return NC_ENOMEM;
1900 strcpy(dims_string, "");
1901 for (d = 0; d < var->ndims; d++)
1902 {
1903 snprintf(temp_string, sizeof(temp_string), " %d", var->dimids[d]);
1904 strcat(dims_string, temp_string);
1905 }
1906 }
1907 if (!var->meta_read)
1908 strcat(storage_str, "unknown");
1909 else if (var->storage == NC_CONTIGUOUS)
1910 strcat(storage_str, "contiguous");
1911 else if (var->storage == NC_COMPACT)
1912 strcat(storage_str, "compact");
1913 else if (var->storage == NC_CHUNKED)
1914 strcat(storage_str, "chunked");
1915 else if (var->storage == NC_VIRTUAL)
1916 strcat(storage_str, "virtual");
1917 else
1918 strcat(storage_str, "unknown");
1919 LOG((2, "%s VARIABLE - varid: %d name: %s ndims: %d "
1920 "dimids:%s storage: %s", tabs, var->hdr.id, var->hdr.name,
1921 var->ndims,
1922 (dims_string ? dims_string : " -"), storage_str));
1923 for (j = 0; j < ncindexsize(var->att); j++)
1924 {
1925 att = (NC_ATT_INFO_T *)ncindexith(var->att, j);
1926 assert(att);
1927 LOG((2, "%s VAR ATTRIBUTE - attnum: %d name: %s type: %d len: %d",
1928 tabs, att->hdr.id, att->hdr.name, att->nc_typeid, att->len));
1929 }
1930 if (dims_string)
1931 free(dims_string);
1932 }
1933
1934 for (i = 0; i < ncindexsize(grp->type); i++)
1935 {
1936 type = (NC_TYPE_INFO_T*)ncindexith(grp->type, i);
1937 assert(type);
1938 LOG((2, "%s TYPE - nc_typeid: %d size: %d committed: %d name: %s",
1939 tabs, type->hdr.id, type->size, (int)type->committed, type->hdr.name));
1940 /* Is this a compound type? */
1941 if (type->nc_type_class == NC_COMPOUND)
1942 {
1943 int j;
1944 LOG((3, "compound type"));
1945 for (j = 0; j < nclistlength(type->u.c.field); j++)
1946 {
1947 field = (NC_FIELD_INFO_T *)nclistget(type->u.c.field, j);
1948 LOG((4, "field %s offset %d nctype %d ndims %d", field->hdr.name,
1949 field->offset, field->nc_typeid, field->ndims));
1950 }
1951 }
1952 else if (type->nc_type_class == NC_VLEN)
1953 {
1954 LOG((3, "VLEN type"));
1955 LOG((4, "base_nc_type: %d", type->u.v.base_nc_typeid));
1956 }
1957 else if (type->nc_type_class == NC_OPAQUE)
1958 LOG((3, "Opaque type"));
1959 else if (type->nc_type_class == NC_ENUM)
1960 {
1961 LOG((3, "Enum type"));
1962 LOG((4, "base_nc_type: %d", type->u.e.base_nc_typeid));
1963 }
1964 else
1965 {
1966 LOG((0, "Unknown class: %d", type->nc_type_class));
1967 return NC_EBADTYPE;
1968 }
1969 }
1970
1971 /* Call self for each child of this group. */
1972 for (i = 0; i < ncindexsize(grp->children); i++)
1973 if ((retval = rec_print_metadata((NC_GRP_INFO_T *)ncindexith(grp->children, i),
1974 tab_count + 1)))
1975 return retval;
1976
1977 return NC_NOERR;
1978}
1979
1990int
1991log_metadata_nc(NC_FILE_INFO_T *h5)
1992{
1993 LOG((2, "*** NetCDF-4 Internal Metadata: int_ncid 0x%x ext_ncid 0x%x",
1994 h5->root_grp->nc4_info->controller->int_ncid,
1995 h5->root_grp->nc4_info->controller->ext_ncid));
1996 if (!h5)
1997 {
1998 LOG((2, "This is a netCDF-3 file."));
1999 return NC_NOERR;
2000 }
2001 LOG((2, "FILE - path: %s cmode: 0x%x parallel: %d redef: %d "
2002 "fill_mode: %d no_write: %d next_nc_grpid: %d", h5->root_grp->nc4_info->controller->path,
2003 h5->cmode, (int)h5->parallel, (int)h5->redef, h5->fill_mode, (int)h5->no_write,
2004 h5->next_nc_grpid));
2005 if(nc_log_level >= 2)
2006 return rec_print_metadata(h5->root_grp, 0);
2007 return NC_NOERR;
2008}
2009
2010#endif /*LOGGING */
2011
2023int
2024NC4_show_metadata(int ncid)
2025{
2026 int retval = NC_NOERR;
2027#if LOGGING
2028 NC_FILE_INFO_T *h5;
2029 int old_log_level = nc_log_level;
2030
2031 /* Find file metadata. */
2032 if ((retval = nc4_find_grp_h5(ncid, NULL, &h5)))
2033 return retval;
2034
2035 /* Log level must be 2 to see metadata. */
2036 nc_log_level = 2;
2037 retval = log_metadata_nc(h5);
2038 nc_log_level = old_log_level;
2039#endif /*LOGGING*/
2040 return retval;
2041}
2042
2050const NC_reservedatt*
2051NC_findreserved(const char* name)
2052{
2053#if 0
2054 int n = NRESERVED;
2055 int L = 0;
2056 int R = (n - 1);
2057
2058 for(;;) {
2059 if(L > R) break;
2060 int m = (L + R) / 2;
2061 const NC_reservedatt* p = &NC_reserved[m];
2062 int cmp = strcmp(p->name,name);
2063 if(cmp == 0) return p;
2064 if(cmp < 0)
2065 L = (m + 1);
2066 else /*cmp > 0*/
2067 R = (m - 1);
2068 }
2069 return NULL;
2070#else
2071 return (const NC_reservedatt*)bsearch(name,NC_reserved,NRESERVED,sizeof(NC_reservedatt),bincmp);
2072#endif
2073}
2074
2075/* Ed Hartness requires this function */
2076static int
2077NC4_move_in_NCList(NC* nc, int new_id)
2078{
2079 int stat = move_in_NCList(nc,new_id);
2080 if(stat == NC_NOERR) {
2081 /* Synchronize header */
2082 if(nc->dispatchdata)
2083 ((NC_OBJ*)nc->dispatchdata)->id = nc->ext_ncid;
2084 }
2085 return stat;
2086}
2087
2088static int
2089sortcmp(const void* arg1, const void* arg2)
2090{
2091 NC_reservedatt* r1 = (NC_reservedatt*)arg1;
2092 NC_reservedatt* r2 = (NC_reservedatt*)arg2;
2093 return strcmp(r1->name,r2->name);
2094}
2095
2096static int
2097bincmp(const void* arg1, const void* arg2)
2098{
2099 const char* name = (const char*)arg1;
2100 NC_reservedatt* ra = (NC_reservedatt*)arg2;
2101 return strcmp(name,ra->name);
2102}
2103
2104void
2105NC_initialize_reserved(void)
2106{
2107 /* Guarantee the reserved attribute list is sorted */
2108 qsort((void*)NC_reserved,NRESERVED,sizeof(NC_reservedatt),sortcmp);
2109}
Main header file for the C API.
#define NC_UNLIMITED
Size argument to nc_def_dim() for an unlimited dimension.
Definition netcdf.h:300
#define NC_EBADTYPE
Not a netcdf data type.
Definition netcdf.h:459
#define NC_VIRTUAL
In HDF5 files you can set storage for each variable to be either contiguous or chunked,...
Definition netcdf.h:357
#define NC_VLEN
vlen (variable-length) types
Definition netcdf.h:53
#define NC_ENAMEINUSE
String match to name in use.
Definition netcdf.h:456
#define NC_ENOMEM
Memory allocation (malloc) failure.
Definition netcdf.h:497
#define NC_COMPOUND
compound types
Definition netcdf.h:56
#define NC_EINTERNAL
NetCDF Library Internal Error.
Definition netcdf.h:523
#define NC_CHUNKED
In HDF5 files you can set storage for each variable to be either contiguous or chunked,...
Definition netcdf.h:353
#define NC_ENUM
enum types
Definition netcdf.h:55
#define NC_CONTIGUOUS
In HDF5 files you can set storage for each variable to be either contiguous or chunked,...
Definition netcdf.h:354
#define NC_GLOBAL
Attribute id to put/get a global attribute.
Definition netcdf.h:303
#define NC_EMAXNAME
NC_MAX_NAME exceeded.
Definition netcdf.h:475
#define NC_ENOTATT
Attribute not found.
Definition netcdf.h:457
#define NC_COMPACT
In HDF5 files you can set storage for each variable to be either contiguous or chunked,...
Definition netcdf.h:355
#define NC_ENOTVAR
Variable not found.
Definition netcdf.h:471
#define NC_EINVAL
Invalid Argument.
Definition netcdf.h:427
#define NC_MAX_NAME
Maximum for classic library.
Definition netcdf.h:330
#define NC_NOERR
No Error.
Definition netcdf.h:417
#define NC_EMPI
MPI operation failed.
Definition netcdf.h:560
#define NC_OPAQUE
opaque types
Definition netcdf.h:54
#define NC_EIO
Generic IO error.
Definition netcdf.h:506
#define NC_STRING
string
Definition netcdf.h:47
#define NC_EBADID
Not a netcdf id.
Definition netcdf.h:424
#define NC_EBADTYPID
Bad type ID.
Definition netcdf.h:546
#define NC_EBADDIM
Invalid dimension id or name.
Definition netcdf.h:460
int nc_type
The nc_type type is just an int.
Definition netcdf.h:25