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