NetCDF 4.9.2
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 "netcdf.h"
20#include "netcdf_filter.h"
21#include "netcdf_meta.h"
22#include "nc4internal.h"
23#include "nc.h" /* from libsrc */
24#include "ncdispatch.h" /* from libdispatch */
25#include "ncutf8.h"
26#include <stdarg.h>
27#include "ncrc.h"
28
39static const NC_reservedatt NC_reserved[] = {
40 {NC_ATT_CLASS, READONLYFLAG|HIDDENATTRFLAG}, /*CLASS*/
41 {NC_ATT_DIMENSION_LIST, READONLYFLAG|HIDDENATTRFLAG}, /*DIMENSION_LIST*/
42 {NC_ATT_NAME, READONLYFLAG|HIDDENATTRFLAG}, /*NAME*/
43 {NC_ATT_REFERENCE_LIST, READONLYFLAG|HIDDENATTRFLAG}, /*REFERENCE_LIST*/
44 {NC_XARRAY_DIMS, READONLYFLAG|NAMEONLYFLAG|HIDDENATTRFLAG}, /*_ARRAY_DIMENSIONS*/
45 {NC_ATT_CODECS, VARFLAG|READONLYFLAG|NAMEONLYFLAG}, /*_Codecs*/
46 {NC_ATT_FORMAT, READONLYFLAG}, /*_Format*/
47 {ISNETCDF4ATT, READONLYFLAG|NAMEONLYFLAG}, /*_IsNetcdf4*/
48 {NCPROPS,READONLYFLAG|NAMEONLYFLAG|HIDDENATTRFLAG}, /*_NCProperties*/
49 {NC_NCZARR_ATTR_UC, READONLYFLAG|HIDDENATTRFLAG}, /*_NCZARR_ATTR */
50 {NC_ATT_COORDINATES, READONLYFLAG|HIDDENATTRFLAG}, /*_Netcdf4Coordinates*/
51 {NC_ATT_DIMID_NAME, READONLYFLAG|HIDDENATTRFLAG}, /*_Netcdf4Dimid*/
52 {SUPERBLOCKATT, READONLYFLAG|NAMEONLYFLAG}, /*_SuperblockVersion*/
53 {NC_ATT_NC3_STRICT_NAME, READONLYFLAG}, /*_nc3_strict*/
54 {NC_ATT_NC3_STRICT_NAME, READONLYFLAG}, /*_nc3_strict*/
55 {NC_NCZARR_ATTR, READONLYFLAG|HIDDENATTRFLAG}, /*_nczarr_attr */
56};
57#define NRESERVED (sizeof(NC_reserved) / sizeof(NC_reservedatt)) /*|NC_reservedatt|*/
58
59static int NC4_move_in_NCList(NC* nc, int new_id);
60
61#if NC_HAS_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. */
65int nc_log_level = NC_TURN_OFF_LOGGING;
66#if NC_HAS_PARALLEL4
67/* File pointer for the parallel I/O log file. */
68FILE *LOG_FILE = NULL;
69#endif /* NC_HAS_PARALLEL4 */
70
71/* This function prints out a message, if the severity of
72 * the message is lower than the global nc_log_level. To use it, do
73 * something like this:
74 *
75 * nc_log(0, "this computer will explode in %d seconds", i);
76 *
77 * After the first arg (the severity), use the rest like a normal
78 * printf statement. Output will appear on stderr for sequential
79 * builds, and in a file nc4_log_R.log for each process for a parallel
80 * build, where R is the rank of the process.
81 *
82 * Ed Hartnett
83 */
84void
85nc_log(int severity, const char *fmt, ...)
86{
87 va_list argp;
88 int t;
89 FILE *f = stderr;
90
91 /* If the severity is greater than the log level, we don't print
92 * this message. */
93 if (severity > nc_log_level)
94 return;
95
96#if NC_HAS_PARALLEL4
97 /* For parallel I/O build, if MPI has been initialized, instead of
98 * printing logging output to stderr, it goes to a file for each
99 * process. */
100 {
101 int mpi_initialized;
102 int mpierr;
103
104 /* Check to see if MPI has been initialized. */
105 if ((mpierr = MPI_Initialized(&mpi_initialized)))
106 return;
107
108 /* If MPI has been initialized use a log file. */
109 assert(LOG_FILE);
110 if (mpi_initialized)
111 f = LOG_FILE;
112 }
113#endif /* NC_HAS_PARALLEL4 */
114
115 /* If the severity is zero, this is an error. Otherwise insert that
116 many tabs before the message. */
117 if (!severity)
118 fprintf(f, "ERROR: ");
119 for (t = 0; t < severity; t++)
120 fprintf(f, "\t");
121
122 /* Print out the variable list of args with vprintf. */
123 va_start(argp, fmt);
124 vfprintf(f, fmt, argp);
125 va_end(argp);
126
127 /* Put on a final linefeed. */
128 fprintf(f, "\n");
129 fflush(f);
130}
131#endif /* NC_HAS_LOGGING */
132
145int
146nc4_check_name(const char *name, char *norm_name)
147{
148 char *temp;
149 int retval;
150
151 assert(norm_name);
152
153 /* Check for NULL. */
154 if (!name)
155 return NC_EINVAL;
156
157 /* Make sure this is a valid netcdf name. This should be done
158 * before the name is normalized, because it gives better error
159 * codes for bad utf8 strings. */
160 if ((retval = NC_check_name(name)))
161 return retval;
162
163 /* Normalize the name. */
164 if ((retval = nc_utf8_normalize((const unsigned char *)name,
165 (unsigned char **)&temp)))
166 return retval;
167
168 /* Check length of normalized name. */
169 if (strlen(temp) > NC_MAX_NAME)
170 {
171 free(temp);
172 return NC_EMAXNAME;
173 }
174
175 /* Copy the normalized name. */
176 strcpy(norm_name, temp);
177 free(temp);
178
179 return NC_NOERR;
180}
181
202int
203nc4_file_list_add(int ncid, const char *path, int mode, void **dispatchdata)
204{
205 NC *nc;
206 int ret;
207
208 /* Find NC pointer for this file. */
209 if ((ret = NC_check_id(ncid, &nc)))
210 return ret;
211
212 /* Add necessary structs to hold netcdf-4 file data. This is where
213 * the NC_FILE_INFO_T struct is allocated for the file. */
214 if ((ret = nc4_nc4f_list_add(nc, path, mode)))
215 return ret;
216
217 /* If the user wants a pointer to the NC_FILE_INFO_T, then provide
218 * it. */
219 if (dispatchdata)
220 *dispatchdata = nc->dispatchdata;
221
222 return NC_NOERR;
223}
224
238int
239nc4_file_change_ncid(int ncid, unsigned short new_ncid_index)
240{
241 NC *nc;
242 int ret;
243
244 LOG((2, "%s: ncid %d new_ncid_index %d", __func__, ncid, new_ncid_index));
245
246 /* Find NC pointer for this file. */
247 if ((ret = NC_check_id(ncid, &nc)))
248 return ret;
249
250 /* Move it in the list. It will faile if list spot is already
251 * occupied. */
252 LOG((3, "moving nc->ext_ncid %d nc->ext_ncid >> ID_SHIFT %d",
253 nc->ext_ncid, nc->ext_ncid >> ID_SHIFT));
254 if (NC4_move_in_NCList(nc, new_ncid_index))
255 return NC_EIO;
256 LOG((3, "moved to new_ncid_index %d new nc->ext_ncid %d", new_ncid_index,
257 nc->ext_ncid));
258
259 return NC_NOERR;
260}
261
281int
282nc4_file_list_get(int ncid, char **path, int *mode, void **dispatchdata)
283{
284 NC *nc;
285 int ret;
286
287 /* Find NC pointer for this file. */
288 if ((ret = NC_check_id(ncid, &nc)))
289 return ret;
290
291 /* If the user wants path, give it. */
292 if (path)
293 strncpy(*path, nc->path, NC_MAX_NAME);
294
295 /* If the user wants mode, give it. */
296 if (mode)
297 *mode = nc->mode;
298
299 /* If the user wants dispatchdata, give it. */
300 if (dispatchdata)
301 *dispatchdata = nc->dispatchdata;
302
303 return NC_NOERR;
304}
305
320int
321nc4_nc4f_list_add(NC *nc, const char *path, int mode)
322{
323 NC_FILE_INFO_T *h5;
324 int retval;
325
326 assert(nc && !NC4_DATA(nc) && path);
327
328 /* We need to malloc and initialize the substructure
329 NC_FILE_INFO_T. */
330 if (!(h5 = calloc(1, sizeof(NC_FILE_INFO_T))))
331 return NC_ENOMEM;
332 nc->dispatchdata = h5;
333 h5->controller = nc;
334
335 h5->hdr.sort = NCFIL;
336 h5->hdr.name = strdup(path);
337 h5->hdr.id = nc->ext_ncid;
338
339 /* Hang on to cmode, and note that we're in define mode. */
340 h5->cmode = mode | NC_INDEF;
341
342 /* The next_typeid needs to be set beyond the end of our atomic
343 * types. */
344 h5->next_typeid = NC_FIRSTUSERTYPEID;
345
346 /* Initialize lists for dimensions, types, and groups. */
347 h5->alldims = nclistnew();
348 h5->alltypes = nclistnew();
349 h5->allgroups = nclistnew();
350
351 /* There's always at least one open group - the root
352 * group. Allocate space for one group's worth of information. Set
353 * its grp id, name, and allocate associated empty lists. */
354 if ((retval = nc4_grp_list_add(h5, NULL, NC_GROUP_NAME, &h5->root_grp)))
355 return retval;
356
357 return NC_NOERR;
358}
359
372int
373nc4_find_nc4_grp(int ncid, NC_GRP_INFO_T **grp)
374{
375 return nc4_find_nc_grp_h5(ncid, NULL, grp, NULL);
376}
377
393int
394nc4_find_grp_h5(int ncid, NC_GRP_INFO_T **grp, NC_FILE_INFO_T **h5)
395{
396 return nc4_find_nc_grp_h5(ncid, NULL, grp, h5);
397}
398
413int
414nc4_find_nc_grp_h5(int ncid, NC **nc, NC_GRP_INFO_T **grp, NC_FILE_INFO_T **h5)
415{
416 NC_GRP_INFO_T *my_grp = NULL;
417 NC_FILE_INFO_T *my_h5 = NULL;
418 NC *my_nc;
419 int retval;
420 size_t index;
421
422 /* Look up file metadata. */
423 if ((retval = NC_check_id(ncid, &my_nc)))
424 return retval;
425 my_h5 = my_nc->dispatchdata;
426 assert(my_h5 && my_h5->root_grp);
427
428 /* If we can't find it, the grp id part of ncid is bad. */
429 index = (ncid & GRP_ID_MASK);
430 if (!(my_grp = nclistget(my_h5->allgroups,index)))
431 return NC_EBADID;
432
433 /* Return pointers to caller, if desired. */
434 if (nc)
435 *nc = my_nc;
436 if (h5)
437 *h5 = my_h5;
438 if (grp)
439 *grp = my_grp;
440
441 return NC_NOERR;
442}
443
459int
460nc4_find_grp_h5_var(int ncid, int varid, NC_FILE_INFO_T **h5, NC_GRP_INFO_T **grp,
461 NC_VAR_INFO_T **var)
462{
463 NC_FILE_INFO_T *my_h5;
464 NC_GRP_INFO_T *my_grp;
465 NC_VAR_INFO_T *my_var;
466 int retval;
467
468 /* Look up file and group metadata. */
469 if ((retval = nc4_find_grp_h5(ncid, &my_grp, &my_h5)))
470 return retval;
471 assert(my_grp && my_h5);
472
473 /* Find the var. */
474 if (!(my_var = (NC_VAR_INFO_T *)ncindexith(my_grp->vars, varid)))
475 return NC_ENOTVAR;
476 assert(my_var && my_var->hdr.id == varid);
477
478 /* Return pointers that caller wants. */
479 if (h5)
480 *h5 = my_h5;
481 if (grp)
482 *grp = my_grp;
483 if (var)
484 *var = my_var;
485
486 return NC_NOERR;
487}
488
502int
503nc4_find_dim(NC_GRP_INFO_T *grp, int dimid, NC_DIM_INFO_T **dim,
504 NC_GRP_INFO_T **dim_grp)
505{
506 assert(grp && grp->nc4_info && dim);
507 LOG((4, "%s: dimid %d", __func__, dimid));
508
509 /* Find the dim info. */
510 if (!((*dim) = nclistget(grp->nc4_info->alldims, dimid)))
511 return NC_EBADDIM;
512
513 /* Give the caller the group the dimension is in. */
514 if (dim_grp)
515 *dim_grp = (*dim)->container;
516
517 return NC_NOERR;
518}
519
530int
531nc4_find_var(NC_GRP_INFO_T *grp, const char *name, NC_VAR_INFO_T **var)
532{
533 assert(grp && var && name);
534
535 /* Find the var info. */
536 *var = (NC_VAR_INFO_T*)ncindexlookup(grp->vars,name);
537 return NC_NOERR;
538}
539
549NC_TYPE_INFO_T *
550nc4_rec_find_named_type(NC_GRP_INFO_T *start_grp, char *name)
551{
552 NC_GRP_INFO_T *g;
553 NC_TYPE_INFO_T *type, *res;
554 int i;
555
556 assert(start_grp);
557
558 /* Does this group have the type we are searching for? */
559 type = (NC_TYPE_INFO_T*)ncindexlookup(start_grp->type,name);
560 if(type != NULL)
561 return type;
562
563 /* Search subgroups. */
564 for(i=0;i<ncindexsize(start_grp->children);i++) {
565 g = (NC_GRP_INFO_T*)ncindexith(start_grp->children,i);
566 if(g == NULL) continue;
567 if ((res = nc4_rec_find_named_type(g, name)))
568 return res;
569 }
570 /* Can't find it. Oh, woe is me! */
571 return NULL;
572}
573
585int
586nc4_find_type(const NC_FILE_INFO_T *h5, nc_type typeid, NC_TYPE_INFO_T **type)
587{
588 /* Check inputs. */
589 assert(h5);
590 if (typeid < 0 || !type)
591 return NC_EINVAL;
592 *type = NULL;
593
594 /* Atomic types don't have associated NC_TYPE_INFO_T struct, just
595 * return NOERR. */
596 if (typeid <= NC_STRING)
597 return NC_NOERR;
598
599 /* Find the type. */
600 if (!(*type = nclistget(h5->alltypes,typeid)))
601 return NC_EBADTYPID;
602
603 return NC_NOERR;
604}
605
621int
622nc4_find_grp_att(NC_GRP_INFO_T *grp, int varid, const char *name, int attnum,
623 NC_ATT_INFO_T **att)
624{
625 NC_VAR_INFO_T *var;
626 NC_ATT_INFO_T *my_att;
627 NCindex *attlist = NULL;
628
629 assert(grp && grp->hdr.name && att);
630
631 LOG((4, "%s: grp->name %s varid %d attnum %d", __func__, grp->hdr.name,
632 varid, attnum));
633
634 /* Get either the global or a variable attribute list. */
635 if (varid == NC_GLOBAL)
636 {
637 attlist = grp->att;
638 }
639 else
640 {
641 var = (NC_VAR_INFO_T*)ncindexith(grp->vars,varid);
642 if (!var) return NC_ENOTVAR;
643
644 attlist = var->att;
645 }
646 assert(attlist);
647
648 /* Now find the attribute by name or number. If a name is provided,
649 * ignore the attnum. */
650 if (name)
651 my_att = (NC_ATT_INFO_T *)ncindexlookup(attlist, name);
652 else
653 my_att = (NC_ATT_INFO_T *)ncindexith(attlist, attnum);
654
655 if (!my_att)
656 return NC_ENOTATT;
657
658 *att = my_att;
659 return NC_NOERR;
660}
661
678int
679nc4_find_nc_att(int ncid, int varid, const char *name, int attnum,
680 NC_ATT_INFO_T **att)
681{
682 NC_GRP_INFO_T *grp;
683 int retval;
684
685 LOG((4, "nc4_find_nc_att: ncid 0x%x varid %d name %s attnum %d",
686 ncid, varid, name, attnum));
687
688 /* Find info for this file and group, and set pointer to each. */
689 if ((retval = nc4_find_grp_h5(ncid, &grp, NULL)))
690 return retval;
691 assert(grp);
692
693 return nc4_find_grp_att(grp, varid, name, attnum, att);
694}
695
704static void
705obj_track(NC_FILE_INFO_T* file, NC_OBJ* obj)
706{
707 NClist* list = NULL;
708 /* record the object in the file */
709 switch (obj->sort) {
710 case NCDIM: list = file->alldims; break;
711 case NCTYP: list = file->alltypes; break;
712 case NCGRP: list = file->allgroups; break;
713 default:
714 assert(NC_FALSE);
715 }
716 /* Insert at the appropriate point in the list */
717 nclistset(list,obj->id,obj);
718}
719
734int
735nc4_var_list_add2(NC_GRP_INFO_T *grp, const char *name, NC_VAR_INFO_T **var)
736{
737 NC_VAR_INFO_T *new_var = NULL;
738 NCglobalstate* gs = NC_getglobalstate();
739
740 /* Allocate storage for new variable. */
741 if (!(new_var = calloc(1, sizeof(NC_VAR_INFO_T))))
742 return NC_ENOMEM;
743 new_var->hdr.sort = NCVAR;
744 new_var->container = grp;
745
746 /* These are the HDF5-1.8.4 defaults. */
747 new_var->chunkcache.size = gs->chunkcache.size;
748 new_var->chunkcache.nelems = gs->chunkcache.nelems;
749 new_var->chunkcache.preemption = gs->chunkcache.preemption;
750
751 /* Now fill in the values in the var info structure. */
752 new_var->hdr.id = ncindexsize(grp->vars);
753 if (!(new_var->hdr.name = strdup(name))) {
754 if(new_var)
755 free(new_var);
756 return NC_ENOMEM;
757 }
758
759 /* Create an indexed list for the attributes. */
760 new_var->att = ncindexnew(0);
761
762 /* Officially track it */
763 ncindexadd(grp->vars, (NC_OBJ *)new_var);
764
765 /* Set the var pointer, if one was given */
766 if (var)
767 *var = new_var;
768
769 return NC_NOERR;
770}
771
784int
785nc4_var_set_ndims(NC_VAR_INFO_T *var, int ndims)
786{
787 assert(var);
788
789 /* Remember the number of dimensions. */
790 var->ndims = ndims;
791
792 /* Allocate space for dimension information. */
793 if (ndims)
794 {
795 if (!(var->dim = calloc(ndims, sizeof(NC_DIM_INFO_T *))))
796 return NC_ENOMEM;
797 if (!(var->dimids = calloc(ndims, sizeof(int))))
798 return NC_ENOMEM;
799
800 /* Initialize dimids to illegal values (-1). See the comment
801 in nc4_rec_match_dimscales(). */
802 memset(var->dimids, -1, ndims * sizeof(int));
803 }
804
805 return NC_NOERR;
806}
807
822int
823nc4_var_list_add(NC_GRP_INFO_T* grp, const char* name, int ndims,
824 NC_VAR_INFO_T **var)
825{
826 int retval;
827
828 if ((retval = nc4_var_list_add2(grp, name, var)))
829 return retval;
830 if ((retval = nc4_var_set_ndims(*var, ndims)))
831 return retval;
832
833 return NC_NOERR;
834}
835
849int
850nc4_dim_list_add(NC_GRP_INFO_T *grp, const char *name, size_t len,
851 int assignedid, NC_DIM_INFO_T **dim)
852{
853 NC_DIM_INFO_T *new_dim = NULL;
854
855 assert(grp && name);
856
857 /* Allocate memory for dim metadata. */
858 if (!(new_dim = calloc(1, sizeof(NC_DIM_INFO_T))))
859 return NC_ENOMEM;
860
861 new_dim->hdr.sort = NCDIM;
862
863 /* Assign the dimension ID. */
864 if (assignedid >= 0)
865 new_dim->hdr.id = assignedid;
866 else
867 new_dim->hdr.id = grp->nc4_info->next_dimid++;
868
869 /* Remember the name and create a hash. */
870 if (!(new_dim->hdr.name = strdup(name))) {
871 if(new_dim)
872 free(new_dim);
873
874 return NC_ENOMEM;
875 }
876
877 /* Is dimension unlimited? */
878 new_dim->len = len;
879 if (len == NC_UNLIMITED)
880 new_dim->unlimited = NC_TRUE;
881
882 /* Remember the containing group. */
883 new_dim->container = grp;
884
885 /* Add object to dimension list for this group. */
886 ncindexadd(grp->dim, (NC_OBJ *)new_dim);
887 obj_track(grp->nc4_info, (NC_OBJ *)new_dim);
888
889 /* Set the dim pointer, if one was given */
890 if (dim)
891 *dim = new_dim;
892
893 return NC_NOERR;
894}
895
908int
909nc4_att_list_add(NCindex *list, const char *name, NC_ATT_INFO_T **att)
910{
911 NC_ATT_INFO_T *new_att = NULL;
912
913 LOG((3, "%s: name %s ", __func__, name));
914
915 if (!(new_att = calloc(1, sizeof(NC_ATT_INFO_T))))
916 return NC_ENOMEM;
917 new_att->hdr.sort = NCATT;
918
919 /* Fill in the information we know. */
920 new_att->hdr.id = ncindexsize(list);
921 if (!(new_att->hdr.name = strdup(name))) {
922 if(new_att)
923 free(new_att);
924 return NC_ENOMEM;
925 }
926
927 /* Add object to list as specified by its number */
928 ncindexadd(list, (NC_OBJ *)new_att);
929
930 /* Set the attribute pointer, if one was given */
931 if (att)
932 *att = new_att;
933
934 return NC_NOERR;
935}
936
951int
952nc4_grp_list_add(NC_FILE_INFO_T *h5, NC_GRP_INFO_T *parent, char *name,
953 NC_GRP_INFO_T **grp)
954{
955 NC_GRP_INFO_T *new_grp;
956
957 /* Check inputs. */
958 assert(h5 && name);
959 LOG((3, "%s: name %s ", __func__, name));
960
961 /* Get the memory to store this groups info. */
962 if (!(new_grp = calloc(1, sizeof(NC_GRP_INFO_T))))
963 return NC_ENOMEM;
964
965 /* Fill in this group's information. */
966 new_grp->hdr.sort = NCGRP;
967 new_grp->nc4_info = h5;
968 new_grp->parent = parent;
969
970 /* Assign the group ID. The root group will get id 0. */
971 new_grp->hdr.id = h5->next_nc_grpid++;
972 assert(parent || !new_grp->hdr.id);
973
974 /* Handle the group name. */
975 if (!(new_grp->hdr.name = strdup(name)))
976 {
977 free(new_grp);
978 return NC_ENOMEM;
979 }
980
981 /* Set up new indexed lists for stuff this group can contain. */
982 new_grp->children = ncindexnew(0);
983 new_grp->dim = ncindexnew(0);
984 new_grp->att = ncindexnew(0);
985 new_grp->type = ncindexnew(0);
986 new_grp->vars = ncindexnew(0);
987
988 /* Add object to lists */
989 if (parent)
990 ncindexadd(parent->children, (NC_OBJ *)new_grp);
991 obj_track(h5, (NC_OBJ *)new_grp);
992
993 /* Set the group pointer, if one was given */
994 if (grp)
995 *grp = new_grp;
996
997 return NC_NOERR;
998}
999
1013int
1014nc4_check_dup_name(NC_GRP_INFO_T *grp, char *name)
1015{
1016 NC_TYPE_INFO_T *type;
1017 NC_GRP_INFO_T *g;
1018 NC_VAR_INFO_T *var;
1019
1020 /* Any types of this name? */
1021 type = (NC_TYPE_INFO_T*)ncindexlookup(grp->type,name);
1022 if(type != NULL)
1023 return NC_ENAMEINUSE;
1024
1025 /* Any child groups of this name? */
1026 g = (NC_GRP_INFO_T*)ncindexlookup(grp->children,name);
1027 if(g != NULL)
1028 return NC_ENAMEINUSE;
1029
1030 /* Any variables of this name? */
1031 var = (NC_VAR_INFO_T*)ncindexlookup(grp->vars,name);
1032 if(var != NULL)
1033 return NC_ENAMEINUSE;
1034
1035 return NC_NOERR;
1036}
1037
1051int
1052nc4_type_new(size_t size, const char *name, int assignedid,
1053 NC_TYPE_INFO_T **type)
1054{
1055 NC_TYPE_INFO_T *new_type;
1056
1057 LOG((4, "%s: size %d name %s assignedid %d", __func__, size, name, assignedid));
1058
1059 /* Check inputs. */
1060 assert(type);
1061
1062 /* Allocate memory for the type */
1063 if (!(new_type = calloc(1, sizeof(NC_TYPE_INFO_T))))
1064 return NC_ENOMEM;
1065 new_type->hdr.sort = NCTYP;
1066 new_type->hdr.id = assignedid;
1067
1068 /* Remember info about this type. */
1069 new_type->size = size;
1070 if (!(new_type->hdr.name = strdup(name))) {
1071 free(new_type);
1072 return NC_ENOMEM;
1073 }
1074
1075 /* Return a pointer to the new type. */
1076 *type = new_type;
1077
1078 return NC_NOERR;
1079}
1080
1094int
1095nc4_type_list_add(NC_GRP_INFO_T *grp, size_t size, const char *name,
1096 NC_TYPE_INFO_T **type)
1097{
1098 NC_TYPE_INFO_T *new_type;
1099 int retval;
1100
1101 /* Check inputs. */
1102 assert(grp && name && type);
1103 LOG((4, "%s: size %d name %s", __func__, size, name));
1104
1105 /* Create the new TYPE_INFO struct. */
1106 if ((retval = nc4_type_new(size, name, grp->nc4_info->next_typeid,
1107 &new_type)))
1108 return retval;
1109 grp->nc4_info->next_typeid++;
1110
1111 /* Increment the ref. count on the type */
1112 new_type->rc++;
1113
1114 /* Add object to lists */
1115 ncindexadd(grp->type, (NC_OBJ *)new_type);
1116 obj_track(grp->nc4_info,(NC_OBJ*)new_type);
1117
1118 /* Return a pointer to the new type. */
1119 *type = new_type;
1120
1121 return NC_NOERR;
1122}
1123
1137int
1138nc4_field_list_add(NC_TYPE_INFO_T *parent, const char *name,
1139 size_t offset, nc_type xtype, int ndims,
1140 const int *dim_sizesp)
1141{
1142 NC_FIELD_INFO_T *field;
1143
1144 /* Name has already been checked and UTF8 normalized. */
1145 if (!name)
1146 return NC_EINVAL;
1147
1148 /* Allocate storage for this field information. */
1149 if (!(field = calloc(1, sizeof(NC_FIELD_INFO_T))))
1150 return NC_ENOMEM;
1151 field->hdr.sort = NCFLD;
1152
1153 /* Store the information about this field. */
1154 if (!(field->hdr.name = strdup(name)))
1155 {
1156 free(field);
1157 return NC_ENOMEM;
1158 }
1159 field->nc_typeid = xtype;
1160 field->offset = offset;
1161 field->ndims = ndims;
1162 if (ndims)
1163 {
1164 int i;
1165 if (!(field->dim_size = malloc(ndims * sizeof(int))))
1166 {
1167 free(field->hdr.name);
1168 free(field);
1169 return NC_ENOMEM;
1170 }
1171 for (i = 0; i < ndims; i++)
1172 field->dim_size[i] = dim_sizesp[i];
1173 }
1174
1175 /* Add object to lists */
1176 field->hdr.id = nclistlength(parent->u.c.field);
1177 nclistpush(parent->u.c.field,field);
1178
1179 return NC_NOERR;
1180}
1181
1194int
1195nc4_enum_member_add(NC_TYPE_INFO_T *parent, size_t size,
1196 const char *name, const void *value)
1197{
1198 NC_ENUM_MEMBER_INFO_T *member;
1199
1200 /* Name has already been checked. */
1201 assert(name && size > 0 && value);
1202 LOG((4, "%s: size %d name %s", __func__, size, name));
1203
1204 /* Allocate storage for this field information. */
1205 if (!(member = calloc(1, sizeof(NC_ENUM_MEMBER_INFO_T))))
1206 return NC_ENOMEM;
1207 if (!(member->value = malloc(size))) {
1208 free(member);
1209 return NC_ENOMEM;
1210 }
1211 if (!(member->name = strdup(name))) {
1212 free(member->value);
1213 free(member);
1214 return NC_ENOMEM;
1215 }
1216
1217 /* Store the value for this member. */
1218 memcpy(member->value, value, size);
1219
1220 /* Add object to list */
1221 nclistpush(parent->u.e.enum_member,member);
1222
1223 return NC_NOERR;
1224}
1225
1234static void
1235field_free(NC_FIELD_INFO_T *field)
1236{
1237 /* Free some stuff. */
1238 if (field->hdr.name)
1239 free(field->hdr.name);
1240 if (field->dim_size)
1241 free(field->dim_size);
1242
1243 /* Nc_Free the memory. */
1244 free(field);
1245}
1246
1256int
1257nc4_type_free(NC_TYPE_INFO_T *type)
1258{
1259 int i;
1260
1261 assert(type && type->rc && type->hdr.name);
1262
1263 /* Decrement the ref. count on the type */
1264 type->rc--;
1265
1266 /* Release the type, if the ref. count drops to zero */
1267 if (type->rc == 0)
1268 {
1269 LOG((4, "%s: deleting type %s", __func__, type->hdr.name));
1270
1271 /* Free the name. */
1272 free(type->hdr.name);
1273
1274 /* Enums and compound types have lists of fields to clean up. */
1275 switch (type->nc_type_class)
1276 {
1277 case NC_COMPOUND:
1278 {
1279 NC_FIELD_INFO_T *field;
1280
1281 /* Delete all the fields in this type (there will be some if its a
1282 * compound). */
1283 for(i=0;i<nclistlength(type->u.c.field);i++) {
1284 field = nclistget(type->u.c.field,i);
1285 field_free(field);
1286 }
1287 nclistfree(type->u.c.field);
1288 }
1289 break;
1290
1291 case NC_ENUM:
1292 {
1293 NC_ENUM_MEMBER_INFO_T *enum_member;
1294
1295 /* Delete all the enum_members, if any. */
1296 for(i=0;i<nclistlength(type->u.e.enum_member);i++) {
1297 enum_member = nclistget(type->u.e.enum_member,i);
1298 free(enum_member->value);
1299 free(enum_member->name);
1300 free(enum_member);
1301 }
1302 nclistfree(type->u.e.enum_member);
1303 }
1304 break;
1305
1306 default:
1307 break;
1308 }
1309
1310 /* Release the memory. */
1311 free(type);
1312 }
1313
1314 return NC_NOERR;
1315}
1316
1325int
1326nc4_att_free(NC_ATT_INFO_T *att)
1327{
1328 int stat = NC_NOERR;
1329
1330 assert(att);
1331 LOG((3, "%s: name %s ", __func__, att->hdr.name));
1332
1333 /* Free the name. */
1334 if (att->hdr.name)
1335 free(att->hdr.name);
1336
1337#ifdef SEPDATA
1338 /* Free memory that was malloced to hold data for this
1339 * attribute. */
1340 if (att->data) {
1341 free(att->data);
1342 }
1343
1344 /* If this is a string array attribute, delete all members of the
1345 * string array, then delete the array of pointers to strings. (The
1346 * array was filled with pointers by HDF5 when the att was read,
1347 * and memory for each string was allocated by HDF5. That's why I
1348 * use free and not nc_free, because the netCDF library didn't
1349 * allocate the memory that is being freed.) */
1350 if (att->stdata)
1351 {
1352 int i;
1353 for (i = 0; i < att->len; i++)
1354 if(att->stdata[i])
1355 free(att->stdata[i]);
1356 free(att->stdata);
1357 }
1358
1359 /* If this att has vlen data, release it. */
1360 if (att->vldata)
1361 {
1362 int i;
1363 for (i = 0; i < att->len; i++)
1364 nc_free_vlen(&att->vldata[i]);
1365 free(att->vldata);
1366 }
1367#else
1368 if (att->data) {
1369 NC_OBJ* parent;
1370 NC_FILE_INFO_T* h5 = NULL;
1371
1372 /* Locate relevant objects */
1373 parent = att->container;
1374 if(parent->sort == NCVAR) parent = (NC_OBJ*)(((NC_VAR_INFO_T*)parent)->container);
1375 assert(parent->sort == NCGRP);
1376 h5 = ((NC_GRP_INFO_T*)parent)->nc4_info;
1377 /* Reclaim the attribute data */
1378 if((stat = nc_reclaim_data(h5->controller->ext_ncid,att->nc_typeid,att->data,att->len))) goto done;
1379 free(att->data); /* reclaim top level */
1380 att->data = NULL;
1381 }
1382#endif
1383
1384done:
1385 free(att);
1386 return stat;
1387}
1388
1398static int
1399var_free(NC_VAR_INFO_T *var)
1400{
1401 int i;
1402 int retval;
1403
1404 assert(var);
1405 LOG((4, "%s: deleting var %s", __func__, var->hdr.name));
1406
1407 /* First delete all the attributes attached to this var. */
1408 for (i = 0; i < ncindexsize(var->att); i++)
1409 if ((retval = nc4_att_free((NC_ATT_INFO_T *)ncindexith(var->att, i))))
1410 return retval;
1411 ncindexfree(var->att);
1412
1413 /* Free some things that may be allocated. */
1414 if (var->chunksizes)
1415 free(var->chunksizes);
1416
1417 if (var->alt_name)
1418 free(var->alt_name);
1419
1420 if (var->dimids)
1421 free(var->dimids);
1422
1423 if (var->dim)
1424 free(var->dim);
1425
1426 /* Delete any fill value allocation. */
1427 if (var->fill_value) {
1428 int ncid = var->container->nc4_info->controller->ext_ncid;
1429 int tid = var->type_info->hdr.id;
1430 if((retval = nc_reclaim_data_all(ncid, tid, var->fill_value, 1))) return retval;
1431 var->fill_value = NULL;
1432 }
1433
1434 /* Release type information */
1435 if (var->type_info)
1436 if ((retval = nc4_type_free(var->type_info)))
1437 return retval;
1438
1439 /* Do this last because debugging may need it */
1440 if (var->hdr.name)
1441 free(var->hdr.name);
1442
1443 /* Delete the var. */
1444 free(var);
1445
1446 return NC_NOERR;
1447}
1448
1458int
1459nc4_var_list_del(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var)
1460{
1461 int i;
1462
1463 assert(var && grp);
1464
1465 /* Remove from lists */
1466 i = ncindexfind(grp->vars, (NC_OBJ *)var);
1467 if (i >= 0)
1468 ncindexidel(grp->vars, i);
1469
1470 return var_free(var);
1471}
1472
1481static int
1482dim_free(NC_DIM_INFO_T *dim)
1483{
1484 assert(dim);
1485 LOG((4, "%s: deleting dim %s", __func__, dim->hdr.name));
1486
1487 /* Free memory allocated for names. */
1488 if (dim->hdr.name)
1489 free(dim->hdr.name);
1490
1491 free(dim);
1492 return NC_NOERR;
1493}
1494
1504int
1505nc4_dim_list_del(NC_GRP_INFO_T *grp, NC_DIM_INFO_T *dim)
1506{
1507 if (grp && dim)
1508 {
1509 int pos = ncindexfind(grp->dim, (NC_OBJ *)dim);
1510 if(pos >= 0)
1511 ncindexidel(grp->dim, pos);
1512 }
1513
1514 return dim_free(dim);
1515}
1516
1526int
1527nc4_rec_grp_del(NC_GRP_INFO_T *grp)
1528{
1529 int i;
1530 int retval;
1531
1532 assert(grp);
1533 LOG((3, "%s: grp->name %s", __func__, grp->hdr.name));
1534
1535 /* Recursively call this function for each child, if any, stopping
1536 * if there is an error. */
1537 for (i = 0; i < ncindexsize(grp->children); i++)
1538 if ((retval = nc4_rec_grp_del((NC_GRP_INFO_T *)ncindexith(grp->children,
1539 i))))
1540 return retval;
1541 ncindexfree(grp->children);
1542
1543 /* Free attributes */
1544 for (i = 0; i < ncindexsize(grp->att); i++)
1545 if ((retval = nc4_att_free((NC_ATT_INFO_T *)ncindexith(grp->att, i))))
1546 return retval;
1547 ncindexfree(grp->att);
1548
1549 /* Delete all vars. */
1550 for (i = 0; i < ncindexsize(grp->vars); i++) {
1551 NC_VAR_INFO_T* v = (NC_VAR_INFO_T *)ncindexith(grp->vars, i);
1552 if ((retval = var_free(v)))
1553 return retval;
1554 }
1555 ncindexfree(grp->vars);
1556
1557 /* Delete all dims, and free the list of dims. */
1558 for (i = 0; i < ncindexsize(grp->dim); i++)
1559 if ((retval = dim_free((NC_DIM_INFO_T *)ncindexith(grp->dim, i))))
1560 return retval;
1561 ncindexfree(grp->dim);
1562
1563 /* Delete all types. */
1564 for (i = 0; i < ncindexsize(grp->type); i++)
1565 if ((retval = nc4_type_free((NC_TYPE_INFO_T *)ncindexith(grp->type, i))))
1566 return retval;
1567 ncindexfree(grp->type);
1568
1569 /* Free the name. */
1570 free(grp->hdr.name);
1571
1572 /* Free up this group */
1573 free(grp);
1574
1575 return NC_NOERR;
1576}
1577
1587int
1588nc4_rec_grp_del_att_data(NC_GRP_INFO_T *grp)
1589{
1590 int i;
1591 int retval;
1592
1593 assert(grp);
1594 LOG((3, "%s: grp->name %s", __func__, grp->hdr.name));
1595
1596 /* Recursively call this function for each child, if any, stopping
1597 * if there is an error. */
1598 for (i = 0; i < ncindexsize(grp->children); i++)
1599 if ((retval = nc4_rec_grp_del_att_data((NC_GRP_INFO_T *)ncindexith(grp->children, i))))
1600 return retval;
1601
1602 /* Free attribute data in this group */
1603 for (i = 0; i < ncindexsize(grp->att); i++) {
1604 NC_ATT_INFO_T * att = (NC_ATT_INFO_T*)ncindexith(grp->att, i);
1605 if((retval = nc_reclaim_data_all(grp->nc4_info->controller->ext_ncid,att->nc_typeid,att->data,att->len)))
1606 return retval;
1607 att->data = NULL;
1608 att->len = 0;
1609 att->dirty = 0;
1610 }
1611
1612 /* Delete att data from all contained vars in this group */
1613 for (i = 0; i < ncindexsize(grp->vars); i++) {
1614 int j;
1615 NC_VAR_INFO_T* v = (NC_VAR_INFO_T *)ncindexith(grp->vars, i);
1616 for(j=0;j<ncindexsize(v->att);j++) {
1617 NC_ATT_INFO_T* att = (NC_ATT_INFO_T*)ncindexith(v->att, j);
1618 if((retval = nc_reclaim_data_all(grp->nc4_info->controller->ext_ncid,att->nc_typeid,att->data,att->len)))
1619 return retval;
1620 att->data = NULL;
1621 att->len = 0;
1622 att->dirty = 0;
1623 }
1624 }
1625
1626 return NC_NOERR;
1627}
1628
1639int
1640nc4_att_list_del(NCindex *list, NC_ATT_INFO_T *att)
1641{
1642 assert(att && list);
1643 ncindexidel(list, ((NC_OBJ *)att)->id);
1644 return nc4_att_free(att);
1645}
1646
1660int
1661nc4_file_list_del(int ncid)
1662{
1663 NC_FILE_INFO_T *h5;
1664 int retval;
1665
1666 /* Find our metadata for this file. */
1667 if ((retval = nc4_find_grp_h5(ncid, NULL, &h5)))
1668 return retval;
1669 assert(h5);
1670
1671 /* Delete the file resources. */
1672 if ((retval = nc4_nc4f_list_del(h5)))
1673 return retval;
1674
1675 return NC_NOERR;
1676}
1677
1687int
1688nc4_nc4f_list_del(NC_FILE_INFO_T *h5)
1689{
1690 int retval;
1691
1692 assert(h5);
1693
1694 /* Order is important here. We must delete the attribute contents
1695 before deleteing any metadata because nc_reclaim_data depends
1696 on the existence of the type info.
1697 */
1698
1699 /* Delete all the attribute data contents in each group and variable. */
1700 if ((retval = nc4_rec_grp_del_att_data(h5->root_grp)))
1701 return retval;
1702
1703 /* Delete all the list contents for vars, dims, and atts, in each
1704 * group. */
1705 if ((retval = nc4_rec_grp_del(h5->root_grp)))
1706 return retval;
1707
1708 /* Cleanup these (extra) lists of all dims, groups, and types. */
1709 nclistfree(h5->alldims);
1710 nclistfree(h5->allgroups);
1711 nclistfree(h5->alltypes);
1712
1713 /* Free the NC_FILE_INFO_T struct. */
1714 nullfree(h5->hdr.name);
1715 free(h5);
1716
1717 return NC_NOERR;
1718}
1719
1733int
1734nc4_normalize_name(const char *name, char *norm_name)
1735{
1736 char *temp_name;
1737 int stat = nc_utf8_normalize((const unsigned char *)name,(unsigned char **)&temp_name);
1738 if(stat != NC_NOERR)
1739 return stat;
1740 if (strlen(temp_name) > NC_MAX_NAME)
1741 {
1742 free(temp_name);
1743 return NC_EMAXNAME;
1744 }
1745 strcpy(norm_name, temp_name);
1746 free(temp_name);
1747 return NC_NOERR;
1748}
1749
1750#ifdef ENABLE_SET_LOG_LEVEL
1751
1758int
1759nc4_init_logging(void)
1760{
1761 int ret = NC_NOERR;
1762
1763#if NC_HAS_LOGGING
1764#if NC_HAS_PARALLEL4
1765 if (!LOG_FILE && nc_log_level >= 0)
1766 {
1767 char log_filename[NC_MAX_NAME];
1768 int my_rank = 0;
1769 int mpierr;
1770 int mpi_initialized;
1771
1772 /* If MPI has been initialized find the rank. */
1773 if ((mpierr = MPI_Initialized(&mpi_initialized)))
1774 return NC_EMPI;
1775 if (mpi_initialized)
1776 {
1777 if ((mpierr = MPI_Comm_rank(MPI_COMM_WORLD, &my_rank)))
1778 return NC_EMPI;
1779 }
1780
1781 /* Create a filename with the rank in it. */
1782 sprintf(log_filename, "nc4_log_%d.log", my_rank);
1783
1784 /* Open a file for this rank to log messages. */
1785 if (!(LOG_FILE = fopen(log_filename, "w")))
1786 return NC_EINTERNAL;
1787 }
1788#endif /* NC_HAS_PARALLEL4 */
1789#endif /* NC_HAS_LOGGING */
1790
1791 return ret;
1792}
1793
1800void
1801nc4_finalize_logging(void)
1802{
1803#if NC_HAS_LOGGING
1804#if NC_HAS_PARALLEL4
1805 if (LOG_FILE)
1806 {
1807 fclose(LOG_FILE);
1808 LOG_FILE = NULL;
1809 }
1810#endif /* NC_HAS_PARALLEL4 */
1811#endif /* NC_HAS_LOGGING */
1812}
1813
1827int
1828nc_set_log_level(int new_level)
1829{
1830#if NC_HAS_LOGGING
1831 /* Remember the new level. */
1832 nc_log_level = new_level;
1833
1834#if NC_HAS_PARALLEL4
1835 /* For parallel I/O builds, call the log init/finalize functions
1836 * as needed, to open and close the log files. */
1837 if (new_level >= 0)
1838 {
1839 if (!LOG_FILE)
1840 nc4_init_logging();
1841 }
1842 else
1843 nc4_finalize_logging();
1844#endif /* NC_HAS_PARALLEL4 */
1845
1846 LOG((1, "log_level changed to %d", nc_log_level));
1847#endif /*NC_HAS_LOGGING */
1848
1849 return NC_NOERR;
1850}
1851#endif /* ENABLE_SET_LOG_LEVEL */
1852
1853#if NC_HAS_LOGGING
1854#define MAX_NESTS 10
1864static int
1865rec_print_metadata(NC_GRP_INFO_T *grp, int tab_count)
1866{
1867 NC_ATT_INFO_T *att;
1868 NC_VAR_INFO_T *var;
1869 NC_DIM_INFO_T *dim;
1870 NC_TYPE_INFO_T *type;
1871 NC_FIELD_INFO_T *field;
1872 char tabs[MAX_NESTS+1] = "";
1873 char temp_string[10];
1874 int t, retval, d, i;
1875
1876 /* Come up with a number of tabs relative to the group. */
1877 for (t = 0; t < tab_count && t < MAX_NESTS; t++)
1878 tabs[t] = '\t';
1879 tabs[t] = '\0';
1880
1881 LOG((2, "%s GROUP - %s nc_grpid: %d nvars: %d natts: %d",
1882 tabs, grp->hdr.name, grp->hdr.id, ncindexsize(grp->vars), ncindexsize(grp->att)));
1883
1884 for (i = 0; i < ncindexsize(grp->att); i++)
1885 {
1886 att = (NC_ATT_INFO_T *)ncindexith(grp->att, i);
1887 assert(att);
1888 LOG((2, "%s GROUP ATTRIBUTE - attnum: %d name: %s type: %d len: %d",
1889 tabs, att->hdr.id, att->hdr.name, att->nc_typeid, att->len));
1890 }
1891
1892 for (i = 0; i < ncindexsize(grp->dim); i++)
1893 {
1894 dim = (NC_DIM_INFO_T *)ncindexith(grp->dim, i);
1895 assert(dim);
1896 LOG((2, "%s DIMENSION - dimid: %d name: %s len: %d unlimited: %d",
1897 tabs, dim->hdr.id, dim->hdr.name, dim->len, dim->unlimited));
1898 }
1899
1900 for (i = 0; i < ncindexsize(grp->vars); i++)
1901 {
1902 int j;
1903 char storage_str[NC_MAX_NAME] = "";
1904 char *dims_string = NULL;
1905
1906 var = (NC_VAR_INFO_T*)ncindexith(grp->vars,i);
1907 assert(var);
1908 if (var->ndims > 0)
1909 {
1910 if (!(dims_string = malloc(sizeof(char) * var->ndims * 4)))
1911 return NC_ENOMEM;
1912 strcpy(dims_string, "");
1913 for (d = 0; d < var->ndims; d++)
1914 {
1915 sprintf(temp_string, " %d", var->dimids[d]);
1916 strcat(dims_string, temp_string);
1917 }
1918 }
1919 if (!var->meta_read)
1920 strcat(storage_str, "unknown");
1921 else if (var->storage == NC_CONTIGUOUS)
1922 strcat(storage_str, "contiguous");
1923 else if (var->storage == NC_COMPACT)
1924 strcat(storage_str, "compact");
1925 else if (var->storage == NC_CHUNKED)
1926 strcat(storage_str, "chunked");
1927 else if (var->storage == NC_VIRTUAL)
1928 strcat(storage_str, "virtual");
1929 else
1930 strcat(storage_str, "unknown");
1931 LOG((2, "%s VARIABLE - varid: %d name: %s ndims: %d "
1932 "dimids:%s storage: %s", tabs, var->hdr.id, var->hdr.name,
1933 var->ndims,
1934 (dims_string ? dims_string : " -"), storage_str));
1935 for (j = 0; j < ncindexsize(var->att); j++)
1936 {
1937 att = (NC_ATT_INFO_T *)ncindexith(var->att, j);
1938 assert(att);
1939 LOG((2, "%s VAR ATTRIBUTE - attnum: %d name: %s type: %d len: %d",
1940 tabs, att->hdr.id, att->hdr.name, att->nc_typeid, att->len));
1941 }
1942 if (dims_string)
1943 free(dims_string);
1944 }
1945
1946 for (i = 0; i < ncindexsize(grp->type); i++)
1947 {
1948 type = (NC_TYPE_INFO_T*)ncindexith(grp->type, i);
1949 assert(type);
1950 LOG((2, "%s TYPE - nc_typeid: %d size: %d committed: %d name: %s",
1951 tabs, type->hdr.id, type->size, (int)type->committed, type->hdr.name));
1952 /* Is this a compound type? */
1953 if (type->nc_type_class == NC_COMPOUND)
1954 {
1955 int j;
1956 LOG((3, "compound type"));
1957 for (j = 0; j < nclistlength(type->u.c.field); j++)
1958 {
1959 field = (NC_FIELD_INFO_T *)nclistget(type->u.c.field, j);
1960 LOG((4, "field %s offset %d nctype %d ndims %d", field->hdr.name,
1961 field->offset, field->nc_typeid, field->ndims));
1962 }
1963 }
1964 else if (type->nc_type_class == NC_VLEN)
1965 {
1966 LOG((3, "VLEN type"));
1967 LOG((4, "base_nc_type: %d", type->u.v.base_nc_typeid));
1968 }
1969 else if (type->nc_type_class == NC_OPAQUE)
1970 LOG((3, "Opaque type"));
1971 else if (type->nc_type_class == NC_ENUM)
1972 {
1973 LOG((3, "Enum type"));
1974 LOG((4, "base_nc_type: %d", type->u.e.base_nc_typeid));
1975 }
1976 else
1977 {
1978 LOG((0, "Unknown class: %d", type->nc_type_class));
1979 return NC_EBADTYPE;
1980 }
1981 }
1982
1983 /* Call self for each child of this group. */
1984 for (i = 0; i < ncindexsize(grp->children); i++)
1985 if ((retval = rec_print_metadata((NC_GRP_INFO_T *)ncindexith(grp->children, i),
1986 tab_count + 1)))
1987 return retval;
1988
1989 return NC_NOERR;
1990}
1991
2002int
2003log_metadata_nc(NC_FILE_INFO_T *h5)
2004{
2005 LOG((2, "*** NetCDF-4 Internal Metadata: int_ncid 0x%x ext_ncid 0x%x",
2006 h5->root_grp->nc4_info->controller->int_ncid,
2007 h5->root_grp->nc4_info->controller->ext_ncid));
2008 if (!h5)
2009 {
2010 LOG((2, "This is a netCDF-3 file."));
2011 return NC_NOERR;
2012 }
2013 LOG((2, "FILE - path: %s cmode: 0x%x parallel: %d redef: %d "
2014 "fill_mode: %d no_write: %d next_nc_grpid: %d", h5->root_grp->nc4_info->controller->path,
2015 h5->cmode, (int)h5->parallel, (int)h5->redef, h5->fill_mode, (int)h5->no_write,
2016 h5->next_nc_grpid));
2017 if(nc_log_level >= 2)
2018 return rec_print_metadata(h5->root_grp, 0);
2019 return NC_NOERR;
2020}
2021
2022#endif /*NC_HAS_LOGGING */
2023
2035int
2036NC4_show_metadata(int ncid)
2037{
2038 int retval = NC_NOERR;
2039#if NC_HAS_LOGGING
2040 NC_FILE_INFO_T *h5;
2041 int old_log_level = nc_log_level;
2042
2043 /* Find file metadata. */
2044 if ((retval = nc4_find_grp_h5(ncid, NULL, &h5)))
2045 return retval;
2046
2047 /* Log level must be 2 to see metadata. */
2048 nc_log_level = 2;
2049 retval = log_metadata_nc(h5);
2050 nc_log_level = old_log_level;
2051#endif /*NC_HAS_LOGGING*/
2052 return retval;
2053}
2054
2062const NC_reservedatt*
2063NC_findreserved(const char* name)
2064{
2065 int n = NRESERVED;
2066 int L = 0;
2067 int R = (n - 1);
2068
2069 for(;;) {
2070 if(L > R) break;
2071 int m = (L + R) / 2;
2072 const NC_reservedatt* p = &NC_reserved[m];
2073 int cmp = strcmp(p->name,name);
2074 if(cmp == 0) return p;
2075 if(cmp < 0)
2076 L = (m + 1);
2077 else /*cmp > 0*/
2078 R = (m - 1);
2079 }
2080 return NULL;
2081}
2082
2083static int
2084NC4_move_in_NCList(NC* nc, int new_id)
2085{
2086 int stat = move_in_NCList(nc,new_id);
2087 if(stat == NC_NOERR) {
2088 /* Synchronize header */
2089 if(nc->dispatchdata)
2090 ((NC_OBJ*)nc->dispatchdata)->id = nc->ext_ncid;
2091 }
2092 return stat;
2093}
2094
2095/**************************************************/
2096/* NCglobal state management */
2097
2098static NCglobalstate* nc_globalstate = NULL;
2099
2100static int
2102{
2103 int stat = NC_NOERR;
2104 const char* tmp = NULL;
2105
2106 if(nc_globalstate == NULL) {
2107 nc_globalstate = calloc(1,sizeof(NCglobalstate));
2108 }
2109 /* Initialize struct pointers */
2110 if((nc_globalstate->rcinfo = calloc(1,sizeof(struct NCRCinfo)))==NULL)
2111 {stat = NC_ENOMEM; goto done;}
2112 if((nc_globalstate->rcinfo->entries = nclistnew())==NULL)
2113 {stat = NC_ENOMEM; goto done;}
2114 if((nc_globalstate->rcinfo->s3profiles = nclistnew())==NULL)
2115 {stat = NC_ENOMEM; goto done;}
2116
2117 /* Get environment variables */
2118 if(getenv(NCRCENVIGNORE) != NULL)
2119 nc_globalstate->rcinfo->ignore = 1;
2120 tmp = getenv(NCRCENVRC);
2121 if(tmp != NULL && strlen(tmp) > 0)
2122 nc_globalstate->rcinfo->rcfile = strdup(tmp);
2123 /* Initialize chunk cache defaults */
2124 nc_globalstate->chunkcache.size = CHUNK_CACHE_SIZE;
2125 nc_globalstate->chunkcache.nelems = CHUNK_CACHE_NELEMS;
2126 nc_globalstate->chunkcache.preemption = CHUNK_CACHE_PREEMPTION;
2128done:
2129 return stat;
2130}
2131
2132/* Get global state */
2133NCglobalstate*
2134NC_getglobalstate(void)
2135{
2136 if(nc_globalstate == NULL)
2138 return nc_globalstate;
2139}
2140
2141void
2142NC_freeglobalstate(void)
2143{
2144 if(nc_globalstate != NULL) {
2145 nullfree(nc_globalstate->tempdir);
2146 nullfree(nc_globalstate->home);
2147 nullfree(nc_globalstate->cwd);
2148 NC_rcclear(nc_globalstate->rcinfo);
2149 free(nc_globalstate->rcinfo);
2150 free(nc_globalstate);
2151 nc_globalstate = NULL;
2152 }
2153}
2154/**************************************************/
2155/* Specific property functions */
2156
2203int
2204nc_set_alignment(int threshold, int alignment)
2205{
2206 NCglobalstate* gs = NC_getglobalstate();
2207 gs->alignment.threshold = threshold;
2208 gs->alignment.alignment = alignment;
2209 gs->alignment.defined = 1;
2210 return NC_NOERR;
2211}
2212
2230int
2231nc_get_alignment(int* thresholdp, int* alignmentp)
2232{
2233 NCglobalstate* gs = NC_getglobalstate();
2234 if(thresholdp) *thresholdp = gs->alignment.threshold;
2235 if(alignmentp) *alignmentp = gs->alignment.alignment;
2236 return NC_NOERR;
2237}
int nc_get_alignment(int *thresholdp, int *alignmentp)
Provide get function to retrieve global data alignment information.
int nc_set_alignment(int threshold, int alignment)
Provide a function to store global data alignment information.
EXTERNL int nc_free_vlen(nc_vlen_t *vl)
Free memory in a VLEN object.
Definition dvlen.c:43
static int NC_createglobalstate(void)
Main header file for the C API.
#define NC_UNLIMITED
Size argument to nc_def_dim() for an unlimited dimension.
Definition netcdf.h:251
#define NC_EBADTYPE
Not a netcdf data type.
Definition netcdf.h:410
#define NC_VIRTUAL
In HDF5 files you can set storage for each variable to be either contiguous or chunked,...
Definition netcdf.h:308
#define NC_VLEN
vlen (variable-length) types
Definition netcdf.h:53
#define NC_ENAMEINUSE
String match to name in use.
Definition netcdf.h:407
#define NC_ENOMEM
Memory allocation (malloc) failure.
Definition netcdf.h:448
#define NC_COMPOUND
compound types
Definition netcdf.h:56
#define NC_EINTERNAL
NetCDF Library Internal Error.
Definition netcdf.h:474
#define NC_CHUNKED
In HDF5 files you can set storage for each variable to be either contiguous or chunked,...
Definition netcdf.h:304
#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:305
#define NC_GLOBAL
Attribute id to put/get a global attribute.
Definition netcdf.h:254
#define NC_EMAXNAME
NC_MAX_NAME exceeded.
Definition netcdf.h:426
#define NC_ENOTATT
Attribute not found.
Definition netcdf.h:408
EXTERNL int nc_reclaim_data(int ncid, nc_type xtypeid, void *memory, size_t count)
Reclaim a vector of instances of arbitrary type.
#define NC_COMPACT
In HDF5 files you can set storage for each variable to be either contiguous or chunked,...
Definition netcdf.h:306
#define NC_ENOTVAR
Variable not found.
Definition netcdf.h:422
#define NC_EINVAL
Invalid Argument.
Definition netcdf.h:378
#define NC_MAX_NAME
Maximum for classic library.
Definition netcdf.h:281
#define NC_NOERR
No Error.
Definition netcdf.h:368
#define NC_EMPI
MPI operation failed.
Definition netcdf.h:511
#define NC_OPAQUE
opaque types
Definition netcdf.h:54
#define NC_EIO
Generic IO error.
Definition netcdf.h:457
#define NC_STRING
string
Definition netcdf.h:47
#define NC_EBADID
Not a netcdf id.
Definition netcdf.h:375
#define NC_EBADTYPID
Bad type ID.
Definition netcdf.h:497
#define NC_EBADDIM
Invalid dimension id or name.
Definition netcdf.h:411
int nc_type
The nc_type type is just an int.
Definition netcdf.h:25